Документация по LLMClient
🔹
Как I. Введение и суть нового паттерна с LLMClient
🎯 Что изменилось?работает
РаньшеLLMClient мыреализует создавалиключевой "агента"паттерн Metabot Agent System (MAS) — фреймворк для построения мультиагентных систем через объекткомпозицию Agents,простых, устанавливалипонятных промптыблоков кода.
MAS следует принципу "сложное через setStartInstruction, setFinalInstruction, сохраняли историю и вызывали generateActiveAgentAnswer(...). Этот подход оставался привязанным к структуре агентов как сущностейпростое".
Теперь — всё по-другому.
👉 Вы сами создаете "агента" как сценарий или flow (поток диалога), используя LLMClient, и назначаете ему столько задач, сколько нужно — через разные этапы flow, инструкции и промпты. Каждый шаг — просто JS-код, больше не нужно регистрировать агентов отдельно.
🧠 Что такое LLMClient?
Это универсальный компонент для общения с LLM::
- Декларативность:
формируетСложныесписокAI-операциипромптовописываются(впростыми,нужномчитаемымипорядке),выражениями - Модульность:
беретКаждыйпромптыflowкак— независимая единица работы с собственным контекстом
$name@commonвставляет значения из lead и bot (макропеременные),
может подставить историю диалога в нужное место,
делает асинхронный запрос (через MBQuery),
обрабатывает ответ в этом же скрипте и отправляет дальше.
Методы класса LLMClient
new LLMClient(sessionName, agentName = "", apiFormat = "")
Создаёт новый экземпляр клиента для работы с LLM.
✅ Почему это лучше?Параметры
Тип |
Описание |
|
|---|---|---|
Возвращает
LLMClient — экземпляр клиента.
setPromptTable(tableName, agentName)
Устанавливает таблицу промптов и имя агента.
Параметры
LLMFollowUpKnowbaseSearchaddUserQuery(content)
Сохраняет пользовательский запрос для текущей сессии.
🔹 II. Жизненный цикл работы с ПараметрыLLMClient
🟦 1. Инициализация
| Имя |
|---|
getUserQuery()
constПолучает LLMClientпоследний пользовательский запрос.
Параметры
Нет
Возвращает
String — последний пользовательский запрос.
addPrompt(role, content)
Добавляет промпт с указанной ролью.
Параметры
addRawPrompts(prompts)
Добавляет массив промптов без обработки.
Параметры
addSystemPrompt(content)
Добавляет системный промпт.
Параметры
addUserPrompt(content)
Добавляет пользовательский промпт.
Параметры
addAssistantPrompt(content)
Добавляет промпт ассистента.
Параметры
addHistoryToPrompts(historyOverride = require("Common.MetabotAI.LLMClient")null)
Добавляет историю сообщений к промптам.
Параметры
clearPrompts()
Очищает все промпты текущей сессии.
Параметры
Нет
setHistoryMaxLength(lmax)
Устанавливает максимальную длину истории сообщений.
Параметры
setHistory(messages)
Сохраняет историю сообщений.
Параметры
getHistory()
Получает историю сообщений.
Параметры
Нет
Возвращает
Array — история сообщений.
addToHistory(message)
Добавляет сообщение в историю.
Параметры
disableHistory()
Отключает сохранение истории сообщений.
Параметры
Нет
clearHistory()
Очищает историю сообщений.
Параметры
Нет
getHistoryStr()
Получает историю сообщений в виде строки.
Параметры
Нет
Возвращает
String — история сообщений.
setModel(model)
Устанавливает модель для генерации ответа.
Параметры
setProvider(providerName)
Устанавливает провайдера LLM.
Параметры
getProvider()
Получает текущего провайдера.
Параметры
Нет
Возвращает
String — название провайдера.
setApiFormat(apiFormat)
Устанавливает формат API.
Параметры
setModelParams(params)
Устанавливает параметры модели.
Параметры
setTemperature(temp)
Устанавливает температуру генерации.
Параметры
getParams()
Получает параметры модели.
Параметры
Нет
Возвращает
Object — параметры модели.
getMessages()
Получает промпты запроса.
Параметры
Нет
Возвращает
Array — промпты запроса.
deleteMessages()
Удаляет промпты запроса.
Параметры
Нет
prepareRequest(callbackScript = null)
Сохраняет промпты и задаёт callback-скрипт.
Параметры
sendRequest()
Отправляет асинхронный запрос к LLM.
Параметры
Нет
Пример
const llm = new LLMClient("DetectIntent")
// session name
Пример подключения gpt-3.5-turbo:
🟦 2. Добавление промптов
llm.setPromptTable("gpt_prompts", "MyAgent")
llm.addSystemPrompt("$start")
// из таблицы (по имени)llm.addSystemPrompt("@common_instruction") // глобальный prompt
Прямо в коде:
llm.addUserPrompt(`Сообщение пользователя: ${user_input}`)
llm.addUserPrompt(`Имя пользователя: ${lead.getAttr('name')}`)
🟦 3. Макросы и подстановки в таблице промптов
Можно использовать:
{{$lead_attr}}{{@bot_attr}}Или можно подставлять значения прямо в коде:
🟦 4. История
По умолчанию история включена, но вы можете:
llm.disableHistory()
// полностью отключить
llm.clearHistory()
// очиститьllm.addHistoryToPrompts() // вручную подставить историю
📌 Важно!
Управляйте порядком промптов прямо в коде:сначала — system, instruction, потом history, потом user.Иначе GPT не поймет, что от него хотят.
🟦 5. Подготовка и отправка
llm.prepareRequest()
// собираем промпты и сохраняем
llm.sendRequest()
// отправка асинхронного запроса
Можно указать другой скрипт, куда прилетит асинхронный ответ:
🟦 6. Обработка ответа
Ответ приходит в этот же скрипт, в блоке ниже:
📌 Не нужно проверять статус — если была ошибка, сработает скрипт обработки ошибки, устанавливаемый через setErrorScript(...), если всё ОК — данные уже подготовлены для дальнейшего использования.
🟦 7. Работа с результатом
llm.sendResponse() // показать как есть
llm.sendFormattedResponse()
// markdown-оформление
llm.nextFlow("MyAgent:NextStep") // перейти на следующий скрипт
llm.finishFlow() // завершить текущий шаг
🔚 Завершение диалога: LLMFollowUp
Для ожидания ответа от пользователя — текстового или кнопочного — используем LLMFollowUp.
Добавьте новую команду JavaScript Callback.
🔹 Ожидание текста
🔹 С выводом сообщения
🔹 Подмена поля для ввода
По умолчанию, ввод от пользователя запишется в лида в user_input, но вы можете переопределить это поле (третий параметр):
🔹 Ожидание текста или кнопки
В скрипте добавьте нужные вам кнопки.
В коде:
🔹 III. Архитектура команды (скрипта)
Каждый LLM-запрос реализуется в одной JS-команде, которая состоит из 3-х логических блоков:
🟦 1. Инициализация и запуск запроса (вверху)
Это всегда первый запуск команды (isFirstImmediateCall):
const LLMClient = require("Common.MetabotAI.LLMClient")
const llm = new LLMClient("MyLLMSession")
if (isFirstImmediateCall) {
llm.setProvider("OpenAI")
llm.setModel("gpt-3.5-turbo")
llm.setPromptTable("gpt_prompts", "MyAgent")
llm.addSystemPrompt("$start")
// инструкция
llm.addUserPrompt(`Запрос пользователя: ${lead.getAttr("user_input")}`)
llm.prepareRequest("MyAgent:MyScript")
// указываем этот же скрипт
llm.setErrorScript("MyAgent:ErrorFlow")
return llm.sendRequest()}
🟦 2. Обработка ответа (ниже, после if (isFirstImmediateCall)handleResponse()
ОтветОбрабатывает приходитответ сюда,от автоматически:LLM, сохраняет результат и историю.
Параметры
Нет
setErrorScript(scriptCode)
Назначает fallback-скрипт при ошибке.
Параметры
|
|---|
📌 Если в запросе произошла ошибка, LLMClient автоматически вызовет setErrorScript(...).Если всё хорошо — handleResponse() сохраняет результат и позволяет продолжить.
🟦 3. UI, кнопки, меню (опционально)
Кнопки настраиваются в этом же скрипте или можете перенаправить в другой скрипт, где настроить кнопки и подключить JavaScript Callback c LLMFollowUp.
📦 Пример структуры скрипта (общее):
// ВЕРХ -- запуск запросаif (isFirstImmediateCall) {
// ... init return llm.sendRequest()}
// ЦЕНТР -- handleResponse()
llm.handleResponse()
// НИЖЕ -- логика ответа
llm.sendResponse()
llm.nextFlow("MyAgent:NextStep")
// или если нужно завершить работу с ИИ
// и далее предоставить пользователю выбор
llm.finishFlow()
🔹 IV. Работа с вводом пользователя и кнопками
После ответа от LLM мы часто хотим:
задать уточняющий вопрос пользователю,
дождаться текста,
или предложить кнопки с вариантами.
Для этого используется мощный компонент:
📦 LLMFollowUp
(из Common.MetabotAI.LLMFollowUp)
🟦 1. Ожидание только текста
const LLMFollowUp = require("Common.MetabotAI.LLMFollowUp")
LLMFollowUp.waitForInput( "MyAgent:NextStep", // скрипт, куда перейти "✍️ Введите ваш номер телефона:", // текст-приглашение "user_phone" // атрибут для сохранения)
📌 После того, как пользователь напишет, значение попадет в:
🟦 2. Ожидание текста или кнопки
Частый сценарий: предложить выбор + оставить возможность ввести свой текст.
const LLMFollowUp = require("Common.MetabotAI.LLMFollowUp")
LLMFollowUp.waitForInputOrButton( "MyAgent:HandleCustomInput", // targetScriptCode для текстового ввода "👇 Выберите вопрос или напишите свой:", "user_input")
🛎️ А кнопки добавляем в этом же скрипте в меню:
Button 1 ("Где мой заказ?", "MyAgent:Flow_OrderStatus")
Button 2 ("Связаться с оператором", "MyAgent:Flow_Operator")
📎 Примечания
Все кнопки работают как меню, определяемое в скрипте.
Если пользователь нажал кнопку — мы сразу переходим по скрипту и там запускаем следующий флоу.
Если ввел текст — идем в targetScriptCode и берем lead.getAttr("user_input")
✅ Резюме
С помощью LLMFollowUp вы:
задаёте гибкие формы обратной связи,
даёте кнопки без необходимости их отдельно обрабатывать,
делаете UX максимально удобным.
Отлично! Ниже — готовый рабочий пример агента из двух flow, реализованного через LLMClient:
🤖 Агент с двумя флоу: INTENT ➜ ANSWER
Сценарий:
Пользователь пишет сообщение.
Первый flow (IntentDetect) распознаёт интент и (опционально) ищет в БЗ/таблице.
Второй flow (FinalAnswer) формирует финальный ответ на основе результата первого шага и истории.
📁 Структура скриптов:
1️⃣ Скрипт: MyAgent:Start
Описание
Код скрипта для
ошибки
getErrorScript()
Получает fallback-скрипт.
2️⃣Параметры
Нет
Возвращает
String — код fallback-скрипта.MyAgent:DetectIntent
setFallbackConfig(scriptCode, timeout)
Настраивает резервный сценарий и таймаут.
Параметры
Описание |
||
|---|---|---|
| String |
const
const
llm.setProvider("OpenAI")
llm.setModel("gpt-3.5-turbo")
llm.setErrorScript("MyAgent:ErrorFlow")
llm.setPromptTable("gpt_prompts", "SupportBot")
llm.disableHistory() // Отключаем сохранение истории
if (isFirstImmediateCall) { // Берем историю из следующего флоу
const dialog = new LLMClient("UserDialog")
const history = dialog.getHistory()
llm.addSystemPrompt( `По контексту общения и сообщению пользователя, `+ `определи истинное намерение пользователя.\n` + `Контекст общения: ${JSON.stringify(history)}\n` + `Сообщение пользователя: ${lead.getAttr("user_input")}\n` + `Ответь строго
llm.prepareRequest()
return llm.sendRequest()}
llm.handleResponse()
// Обрабатываем ответ от LLM
bot.sendMessage(`Ответ от LLM: ${llm.getResponseText()}`)
// Получаем JSON и излекаем поле intent
const result = llm.getLastJSON()
const userIntent = result?.intentlead.setAttr("user_intent", userIntent)// Если интент есть -- ищем по базе знаний
if (userIntent) { const KnowbaseSearch = require('Common.MetabotAI.KnowbaseSearch')
const kbSearch = new KnowbaseSearch()
const chunks = kbSearch.findBestChunks("DefaultKB", userIntent, "rehau")
// Сохраняем все, что нашли в kb_chunks
lead.setJsonAttr("kb_chunks", chunks)
bot.sendMessage(`chunks: ${JSON.stringify(chunks)}`)} else {
lead.setJsonAttr("kb_chunks", [])
}// Переходим к следующему этапу
llm.nextFlow("MyAgent:FinalAnswer")
секундах
scheduleFallback()
Запланировать отложенный запуск fallback-скрипта.
3️⃣Параметры
Нет
MyAgent:FinalAnswerunscheduleFallback()
Удалить отложенный запуск fallback-скрипта.
Параметры
Нет
getResponseResult()
Получает результат запроса (объект ответа провайдера).
Параметры
Нет
Возвращает
Object — объект ответа провайдера.
getProviderResult()
Получает "сырые" данные от провайдера.
Параметры
Нет
Возвращает
Object — исходные данные от провайдера.
getResponseText()
Извлекает текст ответа из результата.
Параметры
Нет
Возвращает
String — текст ответа.
extractAnswerForModel(content)
Извлекает ответ по формату модели.
Параметры
| Тип |
|---|
getModelContextSize(modelName = null)
Получает максимальный размер контекста модели.
Параметры
Возвращает
Number — максимальный размер контекста.
getLastJSON(text = null)
Извлекает JSON из текста ответа.
Параметры
Возвращает
Object — найденный JSON.
extractTextWithoutJSON(text = null)
Удаляет JSON из текста и возвращает чистый текст.
Параметры
Возвращает
String — текст без JSON.
removeMarkdownHeaders(text = null)
Удаляет заголовки Markdown из текста.
Параметры
Возвращает
String — текст без заголовков.
getAgentAnswer(agentName)
Получает ответ агента по имени.
Параметры
Возвращает
String — ответ агента.
getLastTokenUsage()
Получает статистику токенов последнего запроса.
Параметры
Нет
Возвращает
Object — статистика токенов.
setStatus(status)
Устанавливает статус сессии.
Параметры
getStatus()
Получает текущий статус.
Параметры
Нет
Возвращает
String — текущий статус.
clearStatus()
Очищает статус.
Параметры
Нет
nextFlow(scriptCode)
Переходит к следующему flow-скрипту.
Параметры
sendResponse()
Отправляет ответ в лог админа.
Параметры
Нет
sendFormattedResponse(format = 'Markdown')
Отправляет ответ в заданном формате.
Параметры
finishFlow()
Завершает работу сессии.
Параметры
Нет
Примеры использования
const LLMClient = require("Common.MetabotAI.LLMClient")const
llm = new LLMClient("FinalAnswer")llm.setProvider("OpenAI")llm.setModel("gpt-3.5-turbo")llm.setErrorScript("MyAgent:ErrorFlow")llm.setPromptTable("gpt_prompts", "SupportBot")if (isFirstImmediateCall) { llm.addSystemPrompt(`Ты должен ответить пользователю, используя найденную информацию из базы знаний.`) llm.addSystemPrompt( `Если в базе знаний будут найдены ссылки на медиа контент, `+ `определи релевантность контента, проанализировав их описание, и включи релевантные ссылки в формате markdown. ` + `Сам ссылки не придумывай!`) llm.addSystemPrompt(`Информация из базы: {{$kb_chunks}}`) llm.addSystemPrompt(`Распознаннный интент: {{$user_intent}}`) llm.addHistoryToPrompts() // Добавляем историю llm.addUserPrompt(`{{$user_input}}`) llm.addSystemPrompt(`$UserDialog:final`) // Промпт агента из таблицы llm.addSystemPrompt(`@общий`) // Общий промпт из таблицы llm.prepareRequest() return llm.sendRequest()}llm.handleResponse()llm.sendFormattedResponse()return llm.finishFlow() // Завершаем
Выполнить JavaScript Callback
const LLMFollowUp = require("Common.MetabotAI.LLMFollowUp")// Просто ожидание ввода от пользователя без сообщенияLLMFollowUp.waitForInput("MyAgent:DetectIntent")// СЦЕНАРИЙ 2: Ожидание ввода + кнопки меню//LLMFollowUp.waitForInputOrButton("SupportBot:DetectIntentAndSearch")// СЦЕНАРИЙ 3: Ввод + кнопки + своё сообщение //LLMFollowUp.waitForInputOrButton(// "SupportBot:DetectIntentAndSearch",// "✍️ Можете задать новый вопрос или выбрать из меню:"//)// СЦЕНАРИЙ 4: Используем другую переменную вместо user_input//LLMFollowUp.waitForInputOrButton(// "SupportBot:DetectIntentAndSearch",// "Выберите вариант или напишите свой вопрос:",// "my_user_input"//)
🛑 Скрипт: MyAgent:ErrorFlow
🧠 Почему история не в первом флоу?
📋 Промпты в таблице gpt_prompts
Промпты вы может указать, как прямо в коде, как в примере выше, так и в таблице, например так:
Отлично! Мы уже прошли:
Введение
Жизненный цикл LLMClient
Архитектуру команды
Ввод пользователя и кнопки
Пример из двух flow ✅
👉 Следующим по плану был:
🔹 V. Замена агентов: теперь всё делается через LLMClient
🧠 Раньше:
Чтобы использовать GPT, приходилось:
явно создавать "агента" через Agents()
регистрировать имя, провайдера, параметры
использовать методы вроде generateActiveAgentAnswer(...)
вызывать агентов из конкретных скриптов по имени
копить историю автоматически
Это был плотно связанный black-box, не всегда удобный для многошаговых диалогов.
✅ Теперь:
Агент — это просто набор флоу-сценариев, реализованных на LLMClient.
Вы управляете:
моделью (gpt-3.5-turbo, gpt-4, и др.)
провайдером (OpenAI, GigaChat, и т.п.)
промптами (из кода или из таблицы)
структурой диалога (разбиваете на флоу)
когда и где включать/выключать историю
форматированием, ошибками, кнопками, интерактивом
📌 А "агент" — это просто имя сессии и структура ваших флоу.
💡 Пример:
const llm = new LLMClient("SalesAssistant")
// Это и есть "агент", но он нигде не регистрируется
// Вы просто пишете логику под это имя
Вы можете в одном проекте создать десятки таких "агентов", не создавая ни одной сущности в базе.
🛠 Агент = LLMClient + промпты + flow-сценарии
Вы теперь сами:
назначаете, какие шаги делает LLM,
подсказываете ему через $prompts,
вставляете куски истории (или не вставляете),
вызываете API, ищете в таблицах, всё вручную комбинируется.
Отлично, поехали 👇
🔹 VI. Варианты источников данных: Knowbase / Таблицы / API
Когда вы строите flow на LLMClient, вы можете дополнительно обогатить ответы LLM:
фрагментами из базы знаний (RAG),
результатами поиска в таблице,
ответами из внешних API,
вообще любой своей логикой.
👉 Всё, что вам нужно — вставить результат в system или user prompt.
🧠 1. Поиск в базе знаний (Knowbase)
Если у вас уже загружена база знаний (Knowbase), можно:
📌 Не забудь: база знаний должна быть создана и векторизована заранее, например через knowbaseCreate(...).
📦 Альтернатива базе знаний:
Ты не обязан использовать именно Knowbase. Можно:
📊 2. Поиск в таблице (любая логика)
🌐 3. Обращение к API
| const city = lead.getAttr("user_city")const url = `https://my-api/weather?city=${encodeURIComponent(city)}\`const response = api.getJson(url)const weather = response?.forecast || "Погода недоступна"lead.setAttr("weather_info", weather) || :---- |
А затем подставить результат как промпт
🧠 Суть:
Все эти данные (таблицы, API, поиск) не обрабатываются автоматически — вы сами решаете:
где выполнить логику,
как вставить результат в prompt,
стоит ли сохранять это в lead для следующих шагов,
нужно ли показывать пользователю или использовать только для генерации.
🔹 VIII. Статусы жизненного цикла LLMClient
Взято напрямую из исходника Common.MetabotAI.LLMClient, в том числе с точным моментом установки каждого статуса.
🧭 Таблица: жизненныйЖизненный цикл и статусы LLMClient
| Статус | ||
|---|---|---|
IDLE |
new LLMClient(...) |
|
PREPARED |
prepareRequest() |
Промпты собраны, |
WAITING |
sendRequest() |
Запрос |
SUCCESS |
handleResponse() (200) |
Ответ успешно |
ERROR |
handleResponse() (≠200) |
|
ERROR_HANDLED |
handleResponse() → fallback |
|
DONE |
Не используется |
🛠 Как посмотреть текущий статус?
✅ Где он хранится?
🔹 IX. ПеременныеОтладка и атрибуты для отладки в LLMClientпеременные
Компонент LLMClient автоматически сохраняет множество атрибутов в lead, чтобы вы могли отлаживать поведение прямо внутри скрипта.
🧪 Таблица: отладочные переменные LLMClient
| Переменная | Пример значения | |
|---|---|---|
llm_<session>_status |
WAITING |
Текущий статус запроса |
llm_<session>_provider |
OpenAI |
Название LLM-провайдера |
llm_<session>_params |
{ model: "gpt-3.5-turbo", temperature: 0.7 } |
Параметры модели |
llm_<session>_messages |
[{"role": "system", ...}, ...] |
Все |
llm_<session>_history |
[{"role": "user", ...}, ...] |
История переписки |
llm_<session>_callback_script |
MyAgent:NextStep |
|
llm_<session>_error_script |
MyAgent:Fallback |
|
llm_<session>_raw_response |
Вот ваш ответ... |
|
llm_<session>_user_query |
Сколько лет космосу? |
Последний пользовательский запрос |
🔹 X. Таблица методов LLMClient
📦 Версия: Common.MetabotAI.LLMClient v2.0
📌 🔧 Базовые методы управления
new LLMClient(session)sessionsetModel(model)"gpt-3.5-turbo"setProvider(provider)"OpenAI""GigaChat"setModelParams(params)FAQ
🧠Вопрос: РаботаКак сдобавить промптамисвой промпт?
Ответ:
addSystemPrompt(text)addUserPrompt(text)addAssistantPrompt(text)setPromptTable(table, name)$promptaddSystemPrompt, addUserPrompt @commonaddAssistantPrompt. Можно ссылаться addHistoryToPrompts()clearPrompts()🕓 Управление историей
disableHistory()clearHistory()addToHistory(msg)getHistory()🚀 Запуск запроса
prepareRequest([script])sendRequest()MBQuery$name или @common_name.
Вопрос: Как обработать ошибку?
Ответ: Назначьте обработчик через setErrorScript(script)scriptCode)
setFallbackConfig(scriptCode, timeout).
Вопрос:
Как получить статистику токенов?
📥Ответ: ОтветВызовите и логика
handleResponse(getLastTokenUsage() Вопрос: Как интегрировать с другими компонентами?
Ответ: Используйте методы перехода (вnextFlow), этом же скрипте)
getResponseText()getResponseResult()getLastJSON([text])extractTextWithoutJSON()📦 Постобработка и переход
sendResponse()sendFormattedResponse()nextFlow("ScriptName")finishFlow()🧩 Внутренние утилиты (для макросов и отладки)
_applyMacros(str){{$lead_attr}}sendResponse, {{@bot_attr}}sendFormattedResponse) и setStatus(status)WAITINGSUCCESSgetStatus()