Перейти к основному контенту

Документация по 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.

✅ Почему это лучше?Параметры

📌 ВозможностьИмя AgentsТип LLMClientОписание
Многоагентные шаги (несколько запросов подряд)sessionName ⚠️ ОграниченоString ✅Уникальное Полностьюимя контролируемосессии
Промпты из таблицы ($name / @common)agentName ✅ ДаString ✅Имя Даагента (опционально)
Порядок промптовapiFormat ❌ Неявный (в коде разбросано)String ✅Формат ВыAPI задаёте(опционально)
руками

Возвращает
LLMClient — экземпляр клиента.


setPromptTable(tableName, agentName)

Устанавливает таблицу промптов и имя агента.

Параметры

Имя Тип Описание tableName String Имя таблицы промптов Управление историейagentName ⚠️ Встроено, не выключаетсяString ✅Имя Можно включать, отключать, вставлять вручную Асинхронность ✅ Да ✅ Да Обработка ошибок 🔧 Сложно ✅ Полный контроль на каждом запросе к ИИ Переподключение flow ⚠️ Привязано к агенту ✅ Любая логика, любой скрипт Переиспользование компонентов ⚠️ Мало ✅ Есть LLMFollowUp, KnowbaseSearch, макросыагента

addUserQuery(content)

Сохраняет пользовательский запрос для текущей сессии.

🔹 II. Жизненный цикл работы с LLMClientПараметры


🟦 1. Инициализация

Имя
Тип Описание content String Пользовательский запрос

getUserQuery()

constПолучает LLMClientпоследний пользовательский запрос.

Параметры
Нет

Возвращает
String — последний пользовательский запрос.


addPrompt(role, content)

Добавляет промпт с указанной ролью.

Параметры

Имя Тип Описание role String Роль: 'system', 'user', 'assistant' content String/Array Текст или массив строк

addRawPrompts(prompts)

Добавляет массив промптов без обработки.

Параметры

Имя Тип Описание prompts Array Массив объектов {role, content}

addSystemPrompt(content)

Добавляет системный промпт.

Параметры

Имя Тип Описание content String Системный промпт

addUserPrompt(content)

Добавляет пользовательский промпт.

Параметры

Имя Тип Описание content String Пользовательский промпт

addAssistantPrompt(content)

Добавляет промпт ассистента.

Параметры

Имя Тип Описание content String Промпт ассистента

addHistoryToPrompts(historyOverride = require("Common.MetabotAI.LLMClient")null)

Добавляет историю сообщений к промптам.

Параметры

Имя Тип Описание historyOverride Array/Null Массив сообщений или null

clearPrompts()

Очищает все промпты текущей сессии.

Параметры
Нет


setHistoryMaxLength(lmax)

Устанавливает максимальную длину истории сообщений.

Параметры

Имя Тип Описание lmax Number Максимальная длина истории

setHistory(messages)

Сохраняет историю сообщений.

Параметры

Имя Тип Описание messages Array Массив объектов {role, content}

getHistory()

Получает историю сообщений.

Параметры
Нет

Возвращает
Array — история сообщений.


addToHistory(message)

Добавляет сообщение в историю.

Параметры

Имя Тип Описание message Object Объект {role, content}

disableHistory()

Отключает сохранение истории сообщений.

Параметры
Нет


clearHistory()

Очищает историю сообщений.

Параметры
Нет


getHistoryStr()

Получает историю сообщений в виде строки.

Параметры
Нет

Возвращает
String — история сообщений.


setModel(model)

Устанавливает модель для генерации ответа.

Параметры

Имя Тип Описание model String Название модели

setProvider(providerName)

Устанавливает провайдера LLM.

Параметры

Имя Тип Описание providerName String Название провайдера

getProvider()

Получает текущего провайдера.

Параметры
Нет

Возвращает
String — название провайдера.


setApiFormat(apiFormat)

Устанавливает формат API.

Параметры

Имя Тип Описание apiFormat String Формат API

setModelParams(params)

Устанавливает параметры модели.

Параметры

Имя Тип Описание params Object Объект с параметрами модели

setTemperature(temp)

Устанавливает температуру генерации.

Параметры

Имя Тип Описание temp Number Температура генерации

getParams()

Получает параметры модели.

Параметры
Нет

Возвращает
Object — параметры модели.


getMessages()

Получает промпты запроса.

Параметры
Нет

Возвращает
Array — промпты запроса.


deleteMessages()

Удаляет промпты запроса.

Параметры
Нет


prepareRequest(callbackScript = null)

Сохраняет промпты и задаёт callback-скрипт.

Параметры

Имя Тип Описание callbackScript String Код скрипта для обработки ответа (опц.)

sendRequest()

Отправляет асинхронный запрос к LLM.

Параметры
Нет

Пример

const llm = new LLMClient("DetectIntent")
// session name




Пример подключения gpt-3.5-turbo:

llm.setModel("gpt-3.5-turbo") llm.setProvider("OpenAI")

🟦 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}} → из бота

    Или можно подставлять значения прямо в коде:

    llm.addUserPrompt(`Город пользователя: ${lead.getAttr('city')}`)

    🟦 4. История

    По умолчанию история включена, но вы можете:

    llm.disableHistory()

    // полностью отключить

    llm.clearHistory()

    // очиститьllm.addHistoryToPrompts() // вручную подставить историю

    📌 Важно!

    Управляйте порядком промптов прямо в коде:
    сначала — system, instruction, потом history, потом user.
    Иначе GPT не поймет, что от него хотят.


    🟦 5. Подготовка и отправка

    llm.prepareRequest()

    // собираем промпты и сохраняем

    llm.sendRequest()

    // отправка асинхронного запроса

    Можно указать другой скрипт, куда прилетит асинхронный ответ:

    llm.prepareRequest("AgentName:MyFlow")

    🟦 6. Обработка ответа

    Ответ приходит в этот же скрипт, в блоке ниже:

    llm.handleResponse()

    📌 Не нужно проверять статус — если была ошибка, сработает скрипт обработки ошибки, устанавливаемый через setErrorScript(...), если всё ОК — данные уже подготовлены для дальнейшего использования.


    🟦 7. Работа с результатом

    llm.sendResponse() // показать как есть

    llm.sendFormattedResponse()

    // markdown-оформление

    llm.nextFlow("MyAgent:NextStep") // перейти на следующий скрипт

    llm.finishFlow() // завершить текущий шаг


    🔚 Завершение диалога: LLMFollowUp

    Для ожидания ответа от пользователя — текстового или кнопочного — используем LLMFollowUp.

    Добавьте новую команду JavaScript Callback.

    const LLMFollowUp = require("Common.MetabotAI.LLMFollowUp")

    🔹 Ожидание текста

    LLMFollowUp.waitForInput("MyAgent:Step2")

    🔹 С выводом сообщения

    LLMFollowUp.waitForInput("MyAgent:Step2", "Введите ваш номер телефона:")

    🔹 Подмена поля для ввода

    По умолчанию, ввод от пользователя запишется в лида в user_input, но вы можете переопределить это поле (третий параметр):

    LLMFollowUp.waitForInput("MyAgent:Step2", "", "my_user_input")

    🔹 Ожидание текста или кнопки

      В скрипте добавьте нужные вам кнопки.

      В коде:

      LLMFollowUp.waitForInputOrButton("MyAgent:Step2", "Выберите или напишите свой вопрос:")

      🔹 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-скрипт при ошибке.

      Параметры

      llm.handleResponse()

      // Далее логика ответа

      llm.sendFormattedResponse()

      llm.nextFlow("MyAgent:NextStep")

      📌 Если в запросе произошла ошибка, 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" // атрибут для сохранения)

        📌 После того, как пользователь напишет, значение попадет в:

        lead.getAttr("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) формирует финальный ответ на основе результата первого шага и истории.


              📁 Структура скриптов:

              MyAgent/├── Start -- Точка входа├── DetectIntent -- Flow 1: извлечение намерения├── FinalAnswer -- Flow 2: генерация ответа├── ErrorFlow -- Обработка ошибок

              1️⃣ Скрипт: MyAgent:Start

              Запросить значениеИмя Что бы вы хотели узнать или сделать? 👇: [ user_input ]Тип
              Описание Выполнить JavaScriptscriptCode // Очищаем историю диалога основного флоу const LLMClient = require("Common.MetabotAI.LLMClient") const dialog = new LLMClient("FinalAnswer") dialog.clearHistory()String
              Код скрипта для Выполнитьобработки скрипт 🔹 Flow 1: Определение интента и KB поиск
              ошибки

              getErrorScript()

              Получает fallback-скрипт.

              2️⃣Параметры
              Нет

              Скрипт:

              Возвращает
              String MyAgent:DetectIntent— код fallback-скрипта.


              setFallbackConfig(scriptCode, timeout)

              Настраивает резервный сценарий и таймаут.

              Параметры

              Отправить текстИмя Думаю. Подождите... 🕐Тип
              Описание
              Выполнить асинхронный API-запросscriptCode String

              const

              Код LLMClientрезервного =скрипта require("Common.MetabotAI.LLMClient")

              timeout

              const

              Number llm = new LLMClient("DetectIntent");

               

              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` + `Ответь строго

              Таймаут в JSON в поле intent в развернутом виде на русском языке.`)

               

              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:FinalAnswer

              unscheduleFallback()

              Удалить отложенный запуск fallback-скрипта.

              Параметры
              Нет


              getResponseResult()

              Получает результат запроса (объект ответа провайдера).

              Параметры
              Нет

              Возвращает
              Object — объект ответа провайдера.


              getProviderResult()

              Получает "сырые" данные от провайдера.

              Параметры
              Нет

              Возвращает
              Object — исходные данные от провайдера.


              getResponseText()

              Извлекает текст ответа из результата.

              Параметры
              Нет

              Возвращает
              String — текст ответа.


              extractAnswerForModel(content)

              Извлекает ответ по формату модели.

              Параметры

              Выполнить асинхронный API-запросИмя Тип
              Описание content Object Объект ответа провайдера

              getModelContextSize(modelName = null)

              Получает максимальный размер контекста модели.

              Параметры

              Имя Тип Описание modelName String Название модели или null

              Возвращает
              Number — максимальный размер контекста.


              getLastJSON(text = null)

              Извлекает JSON из текста ответа.

              Параметры

              Имя Тип Описание text String Текст ответа или null

              Возвращает
              Object — найденный JSON.


              extractTextWithoutJSON(text = null)

              Удаляет JSON из текста и возвращает чистый текст.

              Параметры

              Имя Тип Описание text String Текст ответа или null

              Возвращает
              String — текст без JSON.


              removeMarkdownHeaders(text = null)

              Удаляет заголовки Markdown из текста.

              Параметры

              Имя Тип Описание text String Текст ответа или null

              Возвращает
              String — текст без заголовков.


              getAgentAnswer(agentName)

              Получает ответ агента по имени.

              Параметры

              Имя Тип Описание agentName String Имя агента

              Возвращает
              String — ответ агента.


              getLastTokenUsage()

              Получает статистику токенов последнего запроса.

              Параметры
              Нет

              Возвращает
              Object — статистика токенов.


              setStatus(status)

              Устанавливает статус сессии.

              Параметры

              Имя Тип Описание status String Статус: 'IDLE', 'PREPARED', ...

              getStatus()

              Получает текущий статус.

              Параметры
              Нет

              Возвращает
              String — текущий статус.


              clearStatus()

              Очищает статус.

              Параметры
              Нет


              nextFlow(scriptCode)

              Переходит к следующему flow-скрипту.

              Параметры

              Имя Тип Описание scriptCode String Код следующего flow-скрипта

              sendResponse()

              Отправляет ответ в лог админа.

              Параметры
              Нет


              sendFormattedResponse(format = 'Markdown')

              Отправляет ответ в заданном формате.

              Параметры

              Имя Тип Описание format String Формат: 'Markdown', 'HTML', ...

              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

              Выполнить асинхронный API-запрос const LLMClient = require("Common.MetabotAI.LLMClient");const llm = new LLMClient("DetectIntent");// Можноllm.setModel("gpt-3.5-turbo") дополнительноllm.setProvider("OpenAI") отправить системное сообщениеbot.sendMessage(llm.setPromptTable("⚠️ Произошла ошибка при обращении к ИИ. Давайте попробуем ещё раз!");// Очищаем временные данные (если нужно)lead.setAttr("user_intent"gpt_prompts", ""MyAgent");lead.setJsonAttr("intent_payload", {});lead.setJsonAttr("kb_chunks", []);// Переходим к начальному этапуllm.nextFlow("SupportBot:DetectIntent")

              🧠 Почему история не в первом флоу?

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

                📋 Промпты в таблице gpt_prompts

                Промпты вы может указать, как прямо в коде, как в примере выше, так и в таблице, например так:

                agent_name name prompt MyAgent start Ты ассистент техподдержки. Помогай пользователям ясно. MyAgent intent Определи намерение пользователя в JSON: {intent, topic}.

                Отлично! Мы уже прошли:

                  Введение

                  Жизненный цикл 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), можно:

                          const KnowbaseSearch = require("Common.MetabotAI.KnowbaseSearch")const search = new KnowbaseSearch()const chunks = search.findBestChunks("MyKnowledgeBase", lead.getAttr("user_input"), "domain")const result = chunks.map(c => c.content).join("\n\n")llm.addSystemPrompt(`Вот"$start") полезная информация из базы знаний:\n\n${result}`)

                          📌 Не забудь: база знаний должна быть создана и векторизована заранее, например через knowbaseCreate(...).


                          📦 Альтернатива базе знаний:

                          Ты не обязан использовать именно Knowbase. Можно:


                          📊 2. Поиск в таблице (любая логика)

                          const items = table.find("product_catalog", ["title", "desc", "price"], [["category", "=", "laptop"]])const top3 = items.slice(0, 3)let txt = top3.map(p => `• ${p.title} -- ${p.price}₽\n${p.desc}`).join("\n\n")llm.addSystemPrompt(`Вот найденные товары:\n\n${txt}`)

                          🌐 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) |
                          | :---- |

                          А затем подставить результат как промпт

                          llm.addUserPrompt(`Вот погода дляЗапрос пользователя: ${lead.getAttr("weather_info"user_input")}`) llm.prepareRequest("MyAgent:MyScript") llm.setErrorScript("MyAgent:ErrorFlow") return llm.sendRequest()

                          🧠 Суть:

                          Все эти данные (таблицы, API, поиск) не обрабатываются автоматически — вы сами решаете:

                            где выполнить логику,

                            как вставить результат в prompt,

                            стоит ли сохранять это в lead для следующих шагов,

                            нужно ли показывать пользователю или использовать только для генерации.

                            🔹 VIII. Статусы жизненного цикла LLMClient

                            Взято напрямую из исходника Common.MetabotAI.LLMClient, в том числе с точным моментом установки каждого статуса.


                            🧭 Таблица: жизненныйЖизненный цикл и статусы LLMClient

                            Статус УстанавливаетсяКогда послеустанавливается Что означаетОписание
                            IDLE new LLMClient(...) Начальное состояние. Клиент создан, но ничего ещё не сделано.
                            PREPARED prepareRequest() Промпты собраны, requestзапрос готов к отправке.готов.
                            WAITING sendRequest() Запрос ушёл,отправлен, ожидаем ответ от провайдера.ответ.
                            SUCCESS handleResponse() (200) Ответ успешно получен, результат готов для логики.получен.
                            ERROR handleResponse() (≠200) Произошла ошибкаОшибка при получении ответа.
                            ERROR_HANDLED handleResponse() → fallback ОбработчикСработал ошибкиобработчик сработал (если задан через setErrorScript).ошибки.
                            DONE (опционально вручную)вручную Не используется напрямую — можно установить в логике вручную.напрямую.

                            🛠 Как посмотреть текущий статус?

                            llm.getStatus() // вернёт текущий статус, например: "WAITING"

                            ✅ Где он хранится?

                            lead.getAttr("llm_<sessionName>_status")

                            🔹 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ответа
                            llm_<session>_error_script MyAgent:Fallback Скрипт,Скрипт куда уйдёт в случаедля ошибки
                            llm_<session>_raw_response Вот ваш ответ... Текст,Текст возвращённый моделью,ответа до форматирования
                            llm_<session>_user_query Сколько лет космосу? Последний пользовательский запрос (если использован addUserPrompt)

                            🔹 X. Таблица методов LLMClient

                            📦 Версия: Common.MetabotAI.LLMClient v2.0


                            📌 🔧 Базовые методы управления

                            Метод Назначение new LLMClient(session) Создание клиента. session — уникальное имя для группы запросов. setModel(model) Установить модель (например "gpt-3.5-turbo") setProvider(provider) Установить провайдера ("OpenAI", "GigaChat", и т.д.) setModelParams(params) Установить параметры модели (temperature, max_tokens, и т.д.)

                            FAQ

                            🧠Вопрос: РаботаКак сдобавить промптамисвой промпт?
                            Ответ:

                            Метод Назначение addSystemPrompt(text) Добавить системный промпт (не сохраняется в историю по умолчанию) addUserPrompt(text) Добавить промпт от пользователя (сохраняется в историю) addAssistantPrompt(text) Добавить промпт от ассистента (опционально в историю) setPromptTable(table, name) Назначить таблицу и имя агента дляИспользуйте $promptaddSystemPrompt, addUserPrompt /или @commonaddAssistantPrompt. Можно ссылаться addHistoryToPrompts() Добавить сохранённую историю в промпты clearPrompts() Очистить текущий список промптов

                            🕓 Управление историей

                            Метод Назначение disableHistory() Отключить накопление истории clearHistory() Очистить историю addToHistory(msg) Добавить сообщение в историю вручную getHistory() Получить сохранённую историю

                            🚀 Запуск запроса

                            Метод Назначение prepareRequest([script]) Сохранитьна промпты ииз задать callback-скрипт sendRequest() Отправить асинхронный запрос к LLMтаблицы через MBQuery$name или @common_name.

                            Вопрос: Как обработать ошибку?
                            Ответ: Назначьте обработчик через setErrorScript(script)scriptCode)

                            Назначитьили fallback-скриптиспользуйте прирезервный ошибкесценарий через setFallbackConfig(scriptCode, timeout).

                            Вопрос:

                            Как получить статистику токенов?
                            📥Ответ: ОтветВызовите и логика

                            Метод Назначение handleResponse(getLastTokenUsage() Обработкапосле ответаполучения отответа. LLM

                            Вопрос: Как интегрировать с другими компонентами?
                            Ответ: Используйте методы перехода (вnextFlow), этом же скрипте)

                            getResponseText() Извлечь текст ответа getResponseResult() Получить весь JSON-ответ getLastJSON([text]) Извлечь JSON из текста ответаотправки (если там JSON) extractTextWithoutJSON() Удалить JSON из текста и вернуть только чистый текст

                            📦 Постобработка и переход

                            Метод Назначение sendResponse() Отправить текст ответа пользователю sendFormattedResponse() Отправить форматированный markdown-ответ nextFlow("ScriptName") Перейти к следующему скрипту finishFlow() Завершить текущий flow

                            🧩 Внутренние утилиты (для макросов и отладки)

                            Метод Назначение _applyMacros(str) Подставить макропеременные {{$lead_attr}}sendResponse, {{@bot_attr}}sendFormattedResponse) и т.д.работы с setStatus(status) Установить статус (WAITING, SUCCESS, и т.д.) getStatus() Получить текущий статус историей.