Обучение ИИ векторному методу
Эксперт: Юлия Голощапова
Искусственный интеллект стал надёжным помощником в решении множества повседневных и профессиональных задач — от написания текстов до анализа данных. Наибольшую популярность обрели Генеративные модели ИИ благодаря своей способности создавать новые данные, опираясь на информацию, использованную в процессе их обучения. Объясняя простым языком, они могут создавать тексты, изображения, музыку или другие типы контента, имитируя стиль и структуру исходных данных, при этом формируя уникальные и оригинальные варианты ответа, не являющиеся дословным повторением исходного материала.
Одна из проблем, с которой часто сталкиваются пользователи, которые используют Генеративную модель ИИ – получение ложной или искаженной информации. Искусственный интеллект может "уверенно" отвечать неправильно, если не ограничен контекстом или не знает, где искать достоверный источник. Данное явление называют "галлюцинацией ИИ".
Такое поведение недопустимо, если мы работаем с технической, юридической документацией или другими материалами, где чрезвычайно важна точность ответа.
Решением становится метод подбора — подход, при котором ИИ не "выдумывает" ответ, а выбирает наиболее релевантный фрагмент из заранее подготовленной базы знаний.
В данной инструкции мы подробно рассмотрим процесс обучения ИИ методу подбора.
Что такое метод подбора?
Метод подбора — это способ, с помощью которого искусственный интеллект находит наиболее подходящий объект из множества возможных, основываясь на определённой логике или метрике сходства. Такой подход позволяет извлекать наиболее релевантные данные из подготовленного набора, минимизируя риск ошибки.
Для обучения нам понадобятся следующие платформы и сервисы:
NocoDB
n8n
Pinecone
OpenAI
Формирование базы данных
В первую очередь нам необходимо подготовить данные для загрузки в ИИ и сформировать базу данных в формате вопрос-ответ. Сделать это можно на платформе NocoDB, однако быстрее и проще будет создать подходящий список в Google Sheets.
Открываем Google Sheets и создаем таблицу в нем:
В созданной таблице создаем две колонки – question (вопрос) и answer (ответ).
Берем интересующий материал и перерабатываем его в виде вопросов и ответов на него.
!Важно: Чем больше будет синонимичных вопросов, тем более точно ИИ будет подбирать ответ. Лучше сделать минимум вопросов 10 на каждый ответ. Один вопрос – одна строка.
Также советуем делать в Google Sheet не более 150 строчек на каждом листе, чтобы в будущем при загрузке в базу NocoDB у нас не возникло проблем с импортированием.
После формирования базы вопросов и ответов скачиваем каждый лист в формате CSV.
Открываем NocoDB и создаем в нем новую базу, для этого нажимаем на кнопочку Create Base.
В открывшемся окошке даем наименование и еще раз жмем на кнопку Create Base.
Перед импортированием таблицы из Google Sheet мы создаем новую таблицу.
Присваиваем ей наименование и жмем Create Table.
У нас по умолчанию открывается вот такое поле:
Поскольку таблица у нас пустая, мы должны ее заполнить колонками и выбрать в них необходимый тип данных для записи. Для начала переименуем по умолчанию созданную колонку с названием Title. Сделать это можно, нажав на стрелочку вниз.
Данная кнопочка развернет параметры колонки. В раскрывшемся списке действий выбираем Edit field.
После этого появится окошко редактирования названия столбца и типа данных.
В нашем случае лучше выбрать Long text, чтобы было удобнее просматривать таблицу.
Сохраняем название и тип данных по кнопке Update Field
Теперь нам нужно создать еще 4 колонки. Сделать это можно по кнопке "+"
Всего у нас должно получиться 5 колонок со следующим типом данных:
question
Field type – Long text
answer
Field type – Long text
emdedded
Field type – Checkbox
to_embed
Field type – Checkbox
А еще в значении Defalut value должна стоять галочка
to_delete
Field type – Checkbox
В конечном итоге у нас должно это выглядеть так:
Импортируем данные. Для того чтобы загрузить нашу имеющуюся таблицу с вопросами и ответами, нам необходимо нажать на три вертикальных строчки в верхней панели, затем Upload → Upload CSV
Перед нами откроется окошко загрузки файлов. Перетягиваем таблицу из загрузок, либо загружаем по кнопке из внутреннего хранилища компьютера.
Нажимаем Import.
Важно: Названия колонок в обеих таблицах должны совпадать! Либо необходимо вручную выбрать, какой столбец из Google Sheets соответствует столбцу в NocoDB. Нажимаем Import еще раз, если все верно.
При успешном импортировании должен получиться такой результат:
Создание индексов в Pinecone
Pinecone — это облачная векторная база данных, которую мы будем использовать для работы с искусственным интеллектом.
Когда мы передаём в ИИ текст (например, вопрос или описание), он преобразует его в вектор – массив чисел, который отражает смысл и контекст данного текста. Эти векторы можно сравнивать между собой: чем они ближе друг к другу в многомерном пространстве, тем более они схожи с текстами, из которых были получены.
При работе с большим объёмом векторных данных важно эффективно находить похожие объекты. Для этого используется индекс – специальная структура данных, оптимизированная для быстрого поиска схожих векторов.
Откроем интерфейс Pinecone и нажмем кнопку Create index.
После нажатия кнопки откроется окошко с настройками индекса. Здесь мы пишем название нашего индекса и ставим галочку на Custom settings.
В разделе Configuration указываем размерность: В поле Dimension вводим значение – 3072.
Затем нажимаем Create index.
После создания индекс появится в списке. Скопируйте его ссылку – она потребуется в дальнейшем.
Обучение ИИ по базе знаний
Открываем n8n и создаем в нем новый Workflow
Наша цепочка будет выглядеть следующим образом:
Краткое описание узлов цепочки:
Schedule Trigger — запускает процесс по расписанию.
NocoDB — получает данные из таблицы NocoDB (вопросы и ответы).
HTTP Request — отправляет запрос к OpenAI для генерации эмбеддингов.
Embeddings — формирует массив векторов.
50 Vectors — подготавливает массив из 50 векторов для загрузки.
Upsert — загружает векторы в Pinecone.
Mark as Embedded — помечает обработанные строки в базе как embedded.
Рассмотрим параметры каждого узла более детально:
Schedule Trigger
В данном узле мы устанавливаем временной интервал, с которым будет запускаться цепочка, если захотим автоматизировать пополнение базы векторов.

NocoDB1


!Важный момент. В n8n у вас должны быть созданы Credential с NocoDB и Pinecone. При создании Credential для NocoDB требуется указать Название и API Token А при создании Credential для Pinecone требуется Название, Ключ API
Это нужно для получения доступа к сервисам.
В текущем узле мы выбираем нужный 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) }}

Сохраняем Workflow в n8n
Нажимаем на кнопочку запуска
После запуска цепочки в таблице появятся галочки в колонке embedded. Это значит, что данные вопросы и ответы были загружены в векторную базу Pinecone
Настройка сценария в Smartbot
Заходим в личный кабинет Smartbot и переходим в раздел "Сценарии".
Нажимаем на кнопку "Создать сценарий"
В открывшемся окошке пишем название сценария, затем нажимаем "Создать"
Рассмотрим схематически, как должен выглядеть сценарий, и разберем каждый блок по отдельности:
Наш сценарий будет состоять из 7 блоков:
Нет подходящего сценария
Выполнить SmartQuery
Выполнить SmartQuery
Отправить HTTP-запрос
Webhook
Выполнить SmartQuery
Отправить сообщение
Блок 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
Открываем n8n. Создаем новый workflow.
Наша логика будет выглядеть следующим образом:
Краткое описание узлов цепочки:
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