Перейти к основному содержимому
Версия: 3.0

ИИ-агент на основе GPT

Для диалогов, которые трудно или нецелесообразно описывать жёстким сценарием, в конструктор процессов можно добавить звено «ИИ-агент» — компонент обращения к GPT-модели. У бота «НашБанк» это процесс Свободный_вопрос: пользователь описывает вопрос своими словами, запрос уходит в GPT-модель, а ответ возвращается пользователю без необходимости заранее прописывать сценарий под каждую возможную формулировку.

Процесс «Свободный_вопрос»: запрос пользователя → звено ИИ-агента с превью системного промта → ответ

Что настраивается в звене ИИ-агента​

При добавлении звена открывается форма с тремя вкладками:

  • Промт — здесь задаётся:
    • системный промт — инструкция для модели: в каком стиле отвечать, какие у неё границы компетенции, что делать, если модель не уверена в ответе. Для бота «НашБанк» системный промт звучит так: «Ты — вежливый ассистент банка «НашБанк». Отвечай кратко и по делу, на русском языке. Если не уверен в ответе — предложи связаться с оператором.»;
    • пользовательское сообщение — что именно передаётся модели как вопрос пользователя; по умолчанию это {{event.preview}} — последнее сообщение пользователя как есть.
    • история диалога — сколько последних реплик разговора передать модели вместе с вопросом; см. «Контекст диалога». По умолчанию пусто: модель получает только вопрос.
  • Параметры — к какому шлюзу и как обращаться:
    • профиль шлюза — готовый набор настроек (адрес, модель, заголовки, тайм-аут, параметры модели), который администратор описал в настройках модуля; см. «Профили шлюза». Вариант «По умолчанию» берёт профиль, выбранный администратором для всех звеньев;
    • адрес, идентификатор RAG Flow (источник знаний, из которого шлюз берёт фрагменты для ответа) и модель — необязательные поля; если заполнить, они заменяют значения профиля только в этом звене;
    • параметры модели в формате JSON — например, температура. Они дополняют значения по умолчанию, а не заменяют их: если указать только temperature, остальные параметры (top_p, top_k, chat_template_kwargs и другие) сохранятся.
  • Ответ — куда сохранить результат (область памяти — временная, сессионная и т. д. — и имя переменной; по умолчанию temp.response) и нужно ли разобрать ответ модели как JSON.

Форма не даст вставить звено, пока пользовательское сообщение или имя переменной пусты, а параметры модели не являются корректным JSON.

Что получает модель​

Сообщение пользователя уходит модели ровно так, как он его написал: кавычки, амперсанды и ссылки не искажаются. Шаблоны вида {{...}}, которые клиент мог набрать в сообщении, не выполняются и не могут прочитать переменные бота или сессии. Подстановки работают только в тексте, который написали вы: например, в системном промте можно использовать {{user.name}}.

Системный промт необязателен. Если он пуст, модели уходит одно сообщение пользователя. Для фрагментов из базы знаний в системном промте используйте {wiki_data} в одинарных фигурных скобках: их подставляет сам шлюз.

Потоковый ответ не поддерживается: звено всегда запрашивает ответ целиком, даже если в параметрах указан stream: true.

Контекст диалога​

Чтобы модель понимала уточняющие вопросы вроде «А в Казань?», в поле История диалога укажите, сколько последних реплик передавать. Реплики клиента уходят модели как user, ответы бота как assistant, а текущий вопрос идёт последним. Сам вопрос в историю не входит, поэтому дублироваться он не будет.

Что важно знать:

  • в историю попадают все ответы бота, и отправленные звеньями «Сказать», и отправленные скриптами; карточки и картинки передаются короткой пометкой вроде [Изображение: схема];
  • максимум 100 реплик за один вызов, и чем их больше, тем дольше и дороже запрос;
  • историю хранит сама платформа. Срок хранения и число реплик в диалоге задаёт администратор в разделе dialogHistory файла iqbot.config.json: по умолчанию 7 дней и 200 реплик, при enabled: false история отключена и модель получает только вопрос;
  • если историю прочитать не удалось, вопрос всё равно уходит модели без неё, а причина записывается в журнал.

Получить историю можно и в своём действии: await iqbot.dialog.getHistory(event, { count: 10 }).

Профили шлюза​

Адрес шлюза, модель и ключ доступа не нужно прописывать в каждом звене. Администратор описывает профили в настройках модуля «Базовые элементы» (файл data/global/config/basic-skills.json):

{
"defaultGptProfile": "local",
"defaultGptTimeoutMs": 60000,
"gptProfiles": {
"local": {
"url": "http://gpt.local:8001/v1/chat/completions",
"model": "Qwen3-8B",
"ragflow": "support"
},
"cloud": {
"url": "https://gpt.example.com/v1/chat/completions",
"model": "big-model",
"timeoutMs": 30000,
"headers": { "Authorization": "Bearer ${EXPOSED_GPT_KEY}" },
"params": { "temperature": 0.2 }
}
}
}
Поле профиляЧто задаёт
urlАдрес шлюза.
modelНазвание модели. Если не задано, берётся defaultGptModel.
timeoutMsТайм-аут запроса, мс. Если не задан, берётся defaultGptTimeoutMs, по умолчанию 60000.
ragflowИсточник знаний по умолчанию.
headersЗаголовки запроса.
paramsПараметры модели для всех звеньев с этим профилем.

Ключи доступа. В значении заголовка можно сослаться на переменную окружения: Bearer ${EXPOSED_GPT_KEY}. Сам ключ задаётся в окружении сервера и не попадает ни в файлы настроек, ни в архив бота. Доступны только переменные, имя которых начинается с EXPOSED_. Если переменная не задана, запрос не отправляется, а звено сообщает об ошибке.

Приоритет. Значения встроенных настроек заменяются значениями профиля, а их, в свою очередь, заменяют поля самого звена.

Переключение между локальной моделью, GPU-сервером и облаком. Опишите по профилю на каждый вариант и выберите нужный в звене либо поменяйте defaultGptProfile: тогда все звенья без явного выбора переедут на другой шлюз без правки бота. Если звено ссылается на профиль, которого нет в настройках, оно завершается ошибкой, а не обращается молча к другому шлюзу.

Звенья, у которых профиль не выбран, а defaultGptProfile пуст, работают как раньше: адрес и модель берутся из defaultGptUrl и defaultGptModel.

Превью промта прямо на схеме​

Чтобы не открывать звено каждый раз, когда нужно вспомнить, какую инструкцию получает модель, звено ИИ-агента показывает на холсте до трёх первых непустых строк системного промта — это видно на звене «ИИ-агент | ИИ_агент_GPT» на скриншоте выше:

Ты — вежливый ассистент банка «НашБанк».
Отвечай кратко и по делу, на русском языке.
Если не уверен в ответе — предложи связаться с оператором.

Если в промте больше трёх строк, на холсте показываются только первые три — откройте звено, чтобы увидеть промт целиком. Пустые строки (например, разделяющие смысловые блоки промта) в превью не учитываются, поэтому даже структурированный многоабзацный промт покажет содержательные три строки, а не случайные пустые.

Переходы после ИИ-агента​

Звено ИИ-агента, как и другие звенья-навыки, возвращает два исхода, которые нужно обработать переходами:

  • «Успех» — запрос к модели выполнен корректно; ведите пользователя к звену, которое покажет ответ (в боте «НашБанк» это звено «Ответ», которое показывает переменную temp.gptResponse, выбранную на вкладке «Ответ»).
  • «Ошибка» — модель оказалась недоступна или вернула некорректный результат. Хорошая практика — не оставлять пользователя без ответа, а направить его дальше по понятному пути; в демонстрационном боте переход «Ошибка» ведёт в звено «Сбой»: оно честно говорит, что ответить не получилось, и возвращает клиента в главное меню, где есть пункт «Связаться с оператором».

Что лежит в переменной при ошибке​

При ошибке в переменную ответа записывается объект с двумя полями: status и message. Так вы можете различить причины и ответить пользователю по-разному.

statusПричина
400, 401, 500 и другие кодыШлюз ответил этим HTTP-кодом.
timeoutШлюз не ответил за отведённое время.
empty_responseШлюз вернул пустой ответ или ответ неизвестного формата.
empty_messageМодели нечего отправить: сообщение пользователя пустое, например, он прислал картинку.
profile_not_foundВ звене выбран профиль, которого нет в настройках модуля.
missing_secretЗаголовок профиля ссылается на переменную окружения, которая не задана.
invalid_paramsПараметры модели не являются корректным JSON-объектом.
ECONNREFUSED, ECONNRESET и другие коды сетиНе удалось соединиться со шлюзом.

При успехе в переменной лежит строка с ответом модели. Если включён разбор JSON, а модель обернула ответ в блок из тройных обратных кавычек, обёртка снимается перед разбором. Если ответ всё равно не является JSON, он сохраняется как { "message": "<текст ответа>" }, и звено считает это успехом.

Тайм-аут и повтор​

Запрос ограничен по времени (по умолчанию 60 секунд), чтобы зависший шлюз не подвешивал диалог. Если шлюз ответил кодом 502, 503 или 504, либо соединение оборвалось до ответа, запрос повторяется один раз через полсекунды. После тайм-аута повтор не выполняется: диалог уже ждал отведённое время.

Журнал​

Текст сообщений пользователя, системный промт и ключи доступа в журнал не пишутся. В журнале остаются адрес шлюза, профиль, код и краткая причина ошибки.

Когда использовать ИИ-агента, а когда — обычный сценарий​

ИИ-агента имеет смысл добавлять там, где заранее перечислить все формулировки вопроса нереалистично — общие консультационные вопросы, помощь в формулировке обращения. Для действий с чёткими шагами и последствиями (блокировка карты, оформление заявки) используйте обычные звенья сценария с явными подтверждениями — так проще гарантировать предсказуемое поведение бота и проверить его автотестами (см. «Тестирование»). ИИ-агент и обычные звенья сценария можно свободно сочетать в одном процессе и в одном боте, как это сделано у «НашБанк»: часть диалога ведётся по жёсткому сценарию, а часть — передаётся модели.