Обучение ИИ векторному методу

Эксперт: Юлия Голощапова

Искусственный интеллект стал надёжным помощником в решении множества повседневных и профессиональных задач — от написания текстов до анализа данных. Наибольшую популярность обрели Генеративные модели ИИ благодаря своей способности создавать новые данные, опираясь на информацию, использованную в процессе их обучения. Объясняя простым языком, они могут создавать тексты, изображения, музыку или другие типы контента, имитируя стиль и структуру исходных данных, при этом формируя уникальные и оригинальные варианты ответа, не являющиеся дословным повторением исходного материала.

Одна из проблем, с которой часто сталкиваются пользователи, которые используют Генеративную модель ИИ – получение ложной или искаженной информации. Искусственный интеллект может "уверенно" отвечать неправильно, если не ограничен контекстом или не знает, где искать достоверный источник. Данное явление называют "галлюцинацией ИИ".

Такое поведение недопустимо, если мы работаем с технической, юридической документацией или другими материалами, где чрезвычайно важна точность ответа.

Решением становится метод подбора — подход, при котором ИИ не "выдумывает" ответ, а выбирает наиболее релевантный фрагмент из заранее подготовленной базы знаний.

В данной инструкции мы подробно рассмотрим процесс обучения ИИ методу подбора.

Что такое метод подбора?

Для обучения нам понадобятся следующие платформы и сервисы:

  • NocoDB

  • n8n

  • Pinecone

  • OpenAI

Формирование базы данных

В первую очередь нам необходимо подготовить данные для загрузки в ИИ и сформировать базу данных в формате вопрос-ответ. Сделать это можно на платформе NocoDB, однако быстрее и проще будет создать подходящий список в Google Sheets.

  1. Открываем Google Sheets и создаем таблицу в нем:

    1. В созданной таблице создаем две колонки – question (вопрос) и answer (ответ).

  2. Берем интересующий материал и перерабатываем его в виде вопросов и ответов на него.

    !Важно: Чем больше будет синонимичных вопросов, тем более точно ИИ будет подбирать ответ. Лучше сделать минимум вопросов 10 на каждый ответ. Один вопрос – одна строка.

    Также советуем делать в Google Sheet не более 150 строчек на каждом листе, чтобы в будущем при загрузке в базу NocoDB у нас не возникло проблем с импортированием.

  3. После формирования базы вопросов и ответов скачиваем каждый лист в формате CSV.

  4. Открываем NocoDB и создаем в нем новую базу, для этого нажимаем на кнопочку Create Base.

  5. В открывшемся окошке даем наименование и еще раз жмем на кнопку Create Base.

  6. Перед импортированием таблицы из Google Sheet мы создаем новую таблицу.

  7. Присваиваем ей наименование и жмем Create Table.

    У нас по умолчанию открывается вот такое поле:

  8. Поскольку таблица у нас пустая, мы должны ее заполнить колонками и выбрать в них необходимый тип данных для записи. Для начала переименуем по умолчанию созданную колонку с названием Title. Сделать это можно, нажав на стрелочку вниз.

  9. Данная кнопочка развернет параметры колонки. В раскрывшемся списке действий выбираем Edit field.

  10. После этого появится окошко редактирования названия столбца и типа данных.

    В нашем случае лучше выбрать Long text, чтобы было удобнее просматривать таблицу.

  11. Сохраняем название и тип данных по кнопке Update Field

  12. Теперь нам нужно создать еще 4 колонки. Сделать это можно по кнопке "+"

    Всего у нас должно получиться 5 колонок со следующим типом данных:

    1. question

      Field type – Long text

    2. answer

      Field type – Long text

    3. emdedded

      Field type – Checkbox

    4. to_embed

      Field type – Checkbox

      А еще в значении Defalut value должна стоять галочка

    5. to_delete

      Field type – Checkbox

    В конечном итоге у нас должно это выглядеть так:

  13. Импортируем данные. Для того чтобы загрузить нашу имеющуюся таблицу с вопросами и ответами, нам необходимо нажать на три вертикальных строчки в верхней панели, затем Upload → Upload CSV

  14. Перед нами откроется окошко загрузки файлов. Перетягиваем таблицу из загрузок, либо загружаем по кнопке из внутреннего хранилища компьютера.

  15. Нажимаем Import.

  16. Важно: Названия колонок в обеих таблицах должны совпадать! Либо необходимо вручную выбрать, какой столбец из Google Sheets соответствует столбцу в NocoDB. Нажимаем Import еще раз, если все верно.

  17. При успешном импортировании должен получиться такой результат:

Создание индексов в Pinecone

Pinecone — это облачная векторная база данных, которую мы будем использовать для работы с искусственным интеллектом.

Когда мы передаём в ИИ текст (например, вопрос или описание), он преобразует его в вектор – массив чисел, который отражает смысл и контекст данного текста. Эти векторы можно сравнивать между собой: чем они ближе друг к другу в многомерном пространстве, тем более они схожи с текстами, из которых были получены.

При работе с большим объёмом векторных данных важно эффективно находить похожие объекты. Для этого используется индекс – специальная структура данных, оптимизированная для быстрого поиска схожих векторов.

  1. Откроем интерфейс Pinecone и нажмем кнопку Create index.

  2. После нажатия кнопки откроется окошко с настройками индекса. Здесь мы пишем название нашего индекса и ставим галочку на Custom settings.

  3. В разделе Configuration указываем размерность: В поле Dimension вводим значение – 3072.

  4. Затем нажимаем Create index.

  5. После создания индекс появится в списке. Скопируйте его ссылку – она потребуется в дальнейшем.

Обучение ИИ по базе знаний

  1. Открываем n8n и создаем в нем новый Workflow

  2. Наша цепочка будет выглядеть следующим образом:

Краткое описание узлов цепочки:

Schedule Trigger — запускает процесс по расписанию.

NocoDB — получает данные из таблицы NocoDB (вопросы и ответы).

HTTP Request — отправляет запрос к OpenAI для генерации эмбеддингов.

Embeddings — формирует массив векторов.

50 Vectors — подготавливает массив из 50 векторов для загрузки.

Upsert — загружает векторы в Pinecone.

Mark as Embedded — помечает обработанные строки в базе как embedded.

Рассмотрим параметры каждого узла более детально:

Schedule Trigger

В данном узле мы устанавливаем временной интервал, с которым будет запускаться цепочка, если захотим автоматизировать пополнение базы векторов.

NocoDB1

В текущем узле мы выбираем нужный Credential, Project Name и Table name (пространство в NocoDB, база в NocoDB и таблица)

В разделе Options в поле Fields пишем - Id,question,answer. В поле Filter by Formula устанавливаем фильтр:

(embedded,eq,false)~and(to_embed,eq,true)~and(question,neq,)~and(question,isnot,null)~and(answer,neq,)~and(answer,isnot,null)~and(to_delete,eq,false)

HTTP-request

В данном узле мы заполняем параметры для отправки запроса, выбираем метод, пишем адрес. В Header Parameters пишем название заголовка Authorization и значение API-ключа, используемого для доступа к OpenAI в формате Bearar OPENAI_KEY.

В теле запроса в Body Parameters мы пишем:

Name: input

Value: {{ $json.question }}

Так мы передадим значение вопроса. Также необходимо передать данные о модели ИИ, которая нам нужна:

Name: model

Value: text-embedding-3-large

Embeddings

50 vectors

В ноде code мы пишем код:

const vectors = $input.all()

.map(i => i.json)

.map((vector,index) => {

return {

values: vector.data[0].embedding,

id: "Id-" + vector.Id.toString(),

metadata: {

question: vector.question,

answer: vector.answer

}

}

})

const mark_as_embedded = vectors.map(vector => ({Id: Number(vector.id.split('-')[1]), embedded: true}))

return [{vectors,mark_as_embedded}];

Данный код обрабатывает данные, полученные после создания эмбеддингов, и готовит их для загрузки в векторную базу Pinecone, а также для пометки в базе NocoDB, что эти строки уже были обработаны.

Upsert

Ранее мы создавали индекс в Pinecone и сохраняли ссылку. Ее мы вставляем в поле URL и дописываем в адресе /vectors/upsert, чтобы у нас получилось:

https://<cсылка_на_pinecone>/vectors/upsert

Установим следующие параметры:

  • Method: POST

  • URL: https://<cсылка_на_pinecone>/vectors/upsert

  • Authentication: Predefined

  • Credential Type: PineconeApi

  • PineconeApi: Выбираем заранее сохранённый API-ключ Pinecone для авторизации.

В Header Parameters:

Name: accept

Value: application/json

В Body Parameters:

Name: vectors

Value: {{ $json.vectors }}

Mark as Embedded

В заключительном узле цепочки обновляем данные таблицы NocoDB. Для этого в URL указываем адрес базы NocoDB со следующей структурой:

https://<Адрес_nocodb>/api/v2/tables/<айди_таблицы>/records.

Выбираем следующие значения:

  • Method: PATCH

  • URL: https://<Адрес_nocodb>/api/v2/tables/<айди_таблицы>/records.

  • Authentication: Predefined Credential type

  • Credential Type: NocoDB API Token

  • NocoDB API Token: (выбираем Credential нужной базы NocoDB)

В Header Parameters указываем:

Name: accept

Value: application/json

В Body пишем в поле JSON, меняя тип с Fixed на Expression:

{{ JSON.stringify($('50 Vectors').first().json.mark_as_embedded) }}
  1. Сохраняем Workflow в n8n

  2. Нажимаем на кнопочку запуска

  3. После запуска цепочки в таблице появятся галочки в колонке embedded. Это значит, что данные вопросы и ответы были загружены в векторную базу Pinecone

Настройка сценария в Smartbot

  1. Заходим в личный кабинет Smartbot и переходим в раздел "Сценарии".

  2. Нажимаем на кнопку "Создать сценарий"

  3. В открывшемся окошке пишем название сценария, затем нажимаем "Создать"

  4. Рассмотрим схематически, как должен выглядеть сценарий, и разберем каждый блок по отдельности:

Наш сценарий будет состоять из 7 блоков:

  1. Нет подходящего сценария

  2. Выполнить SmartQuery

  3. Выполнить SmartQuery

  4. Отправить HTTP-запрос

  5. Webhook

  6. Выполнить SmartQuery

  7. Отправить сообщение

Блок 1: Нет подходящего сценария

Реагирует на любое сообщение пользователя в боте. Он запускает всю цепочку сценария.

Блок 2: Выполнить SmartQuery

Выполняет функцию промежуточного блока. Не обрабатывает данные, но требуется для технической связки.

Блок 3: Выполнить SmartQuery

В данном блоке мы подготавливаем данные, создаем URL и тело запроса.

%string_temp% = %n8n_url% + "/webhook/test_new_request"

%body% = {
    "question": %message_text%,
    "user_id": %user_id%
}

%response_data% = {}
%response_data_status% = 0

Используемые переменные:

%string_temp% — (тип: строка) итоговый URL.

%body% — (тип: словарь) передаём вопрос и ID пользователя.

%n8n_url% — (тип: строка) переменная со ссылкой на ваш сервер n8n.

!Важно: URL должен совпадать с URL вызова вебхука в n8n.

Блок 4: Отправить HTTP-запрос

Устанавливаем следующие параметры:

  • Метод: POST

  • URL: %string_temp%

  • Тип тела: Текст

  • Значение тела: {{ %body% | to_json }}

В заголовках:

  • Наименование: content-type

  • Значение: application/json

Блок 5: Webhook

Через этот блок мы получаем ответ из n8n. Чтобы он работал, мы должны создать API-токен, либо выбрать уже существующий.

В API-токены выбираем "Создать токен".

В открывшемся окошке нажимаем на кнопку "Cоздать токен".

Придумываем название и создаем токен.

Выбираем созданный токен и канал.

Данные из Webhook нам понадобятся в дальнейшей настройке Workflow в n8n.

Блок 6: Выполнить SmartQuery

Извлекаем текст ответа из Webhook и сохраняем его в переменную %bot_message%.

%bot_message% = %public_api_data%['answer']

Блок 7: Отправить сообщение

Выводим значение переменной %bot_message%в блоке "Отправить сообщение".

Отправка ответа из Pinecone в Smartbot

В данной части инструкции мы по шагам разберём, как настроить рабочий процесс в n8n, который будет:

  • принимать запрос от пользователя через Smartbot

  • искать наиболее подходящий ответ через Pinecone (векторную БД)

  • отправлять его обратно пользователю

Создаём Workflow в n8n

  1. Открываем n8n. Создаем новый workflow.

  2. Наша логика будет выглядеть следующим образом:

Краткое описание узлов цепочки:

Webhook — принимает запрос от Smartbot (вопрос пользователя).

Get vectorized — отправляет вопрос в OpenAi для получения вектора.

Get the nearest reply — ищет наиболее близкие к вопросу вектора (совпадения) в Pinecone.

if — проверяет, нашлось ли совпадение.

Code (успех) — формирует тело ответа из Pinecone.

HTTP Request (успех) — отправляет ответ пользователю в Smartbot.

Code (неудача) — формирует тело ответа в случае отсутствия совпадения.

HTTP Request (неудача) — отправляет ответ в Smartbot.

Рассмотрим параметры каждого узла более детально:

Webhook

Данный узел запускает весь workflow. Через него мы принимаем данные из Смартбота, а именно, вопрос пользователя и его ID.

Параметры узла:

  • Method: POST

  • Path: (часть URL, по которой по которой вызывается этот Webhook)

  • Respond: Immediately

!Важный момент: Path должен быть идентичен тому, который мы указывали в Смартботе ранее.

Get vectorized

Отправляет вопрос в OpenAI и получает его векторное представление.

Параметры узла:

  • Method: POST

  • URL: https://api.openai.com/v1/embeddings

  • Authentication: Predefined Credential Type

  • Credential Type: OpenAi

  • OpenAi: (Выбираем нужный Credential OpenAi)

  • Model: text-embedding-3-large

В Body Parameters:

Name: input

Value: {{ $json.question }}

Передаем вопрос и данные модели ИИ.

Name: model

Value: text-embedding-3-large

Get the nearest reply

Формируем запрос в векторную базу Pinecone, для поиска совпадений вектора вопроса с векторами из базы данных. Для этого заполняем следующие параметры:

  • Method: POST

  • URL: https://наpinecone>/query

  • Authentication: Predefined

  • Credential Type: PineconeApi

  • PineconeApi: Выбираем заранее сохранённый API-ключ Pinecone для авторизации.

Header Parameters:

Name: accept

Value: application/json

Body Parameters:

Name: vector

Value: {{ $json.data[0].embedding }}

Векторное представление вопроса пользователя. Отправляем этот вектор, чтобы Pinecone сравнил его с уже сохранёнными векторами и нашёл наиболее подходящие.

Name: topK

Value: 10

Указываем, сколько самых близких векторов (записей) мы хотим получить в ответ. В нашем случае - 10.

Name: includeMetadata

Value: {{ true }}

Указываем, что хотим получить из вектора Pinecone метаданные о вопросе и ответе.

If

Проверяем, были ли найдены совпадения:

{{ $('Get the nearest reply').first().json.matches }}

= is not empty

Code

Создаем тело (body) для отправки данных в Smartbot.

var data = {
  "answer": $('Get the nearest reply').first().json.matches[0].metadata.answer,//.replaceAll('"', '\"').replaceAll('\n', '\\n'),
  "score": $('Get the nearest reply').item.json.matches[0].score
}

/*Создаем переменную data, чтобы передать: ответ, найденный через Pinecone (answer) и оценку совпадения (score)
*/

var body = {
  "access_token": "d_RzF82z4TXML5_ZnMcrdJS2Y_K8kQNZNzkJZ-ORgI24v1STJEt55EgFXGEaILR6",
  "v": "0.0.1",
  "channel_id": "7779600502",
  "block_id": "6808dbe10aa22020da97a62f",
  "peer_id": $('Webhook').first().json.body.user_id,
  "data": data
}

return {
  body
}

В тело запроса добавляем тело вебхука из Смартбота:

HTTP Request:

Устанавливаем параметры для отправки подобранного ответа в Smartbot:

  • Method: POST

  • URL: https://api.smartbotpro.ru/blocks/execute

  • Authentication: None

  • Body Content Type: JSON

  • Body Parameters:{{ JSON.stringify($json.body) }}

Code1 (совпадений не найдено)

Отправляем ответ в случае отсутcтвия совпадений по векторам.

var data = {
  "answer": 'Ответ не найден',
  "score": 0.00
}

var body = {
   "access_token": "d_RzF82z4TXML5_ZnMcrdJS2Y_K8kQNZNzkJZ-ORgI24v1STJEt55EgFXGEaILR6",
    "v": "0.0.1",
    "channel_id": "7779600502",
    "block_id": "6808dbe10aa22020da97a62f",
    "peer_id": $('Webhook').first().json.body.user_id,
    "data": data
}

return {
  body
}

HTTP Request1 (совпадений не найдено)

Устанавливаем параметры для отправки ответа в Smartbot:

  • Method: POST

  • URL: https://api.smartbotpro.ru/blocks/execute

  • Authentication: None

  • Body Content Type: JSON

  • Body Parameters:{{ JSON.stringify($json.body) }}

Last updated