06. AI компоненты: Metabot Agent Stack Metabot — кандидат на рантайм для AI-native коммуникационных систем LLM Query — AI-запросы к LLM внутри сценариев Voice Input — голосовой интерфейс для AI-воронок Для кругозора ИИ-трансформация в AI-First компанию Metabot AI Methodology Методология поэтапного перехода к AI-First компании. Данная методология —  не просто “технология внедрения ИИ”, а методология эволюциии компании в сторону AI-first мышления. Цель Показать, как компания проходит путь от экспериментов с ИИ — к состоянию AI-First-организма,где интеллект встроен в культуру, процессы и управление. Мы создаём систему, в которой: Люди понимают и принимают ИИ, используют как партнёра в работе; Знания становятся обновляемым корпоративным интеллектом и активом компании; Процессы автоматизируются и усиливаются ИИ; Смыслы выравнивают действия людей и машин; Операции становятся самообучающимися, предиктивными и управляемыми ИИ; Бизнес становится устойчивым в новой эпохе Интеллектизма. Проблема Большинство компаний застревают между “хотим ИИ” и “умеем использовать ИИ”. Типичные барьеры: Сотрудники не понимают, зачем им ИИ, или боятся его. Знания разбросаны по людям и файлам, нет структуры. Процессы не прозрачны, данных много, смысла мало. IT и бизнес говорят на разных языках. 💡 Результат: нет ROI, нет эффекта, нет синхронизации. 💡 Принцип: «от людей к смыслам» ИИ внедряется не сверху, а через культуру, структуру и смыслы.Это не установка чат-ботов — это изменение когнитивного устройства компании. Структура методологии Методология строится поэтапно — от людей и знаний к смыслам и операционному управлению: № Этап Фокус и Результат 1️⃣ AI Awakening (пробуждение) Люди и культура Принятие и вовлечённость: осознание, вовлечение, освоение ИИ; формируется язык и мастер-промпты. 2️⃣ AI Structuring (структурирование) Знания и онтология Создаётся корпоративный интеллект и когнитивный слой: карта смыслов, структура связей, корпоративная память. 3️⃣ AI Integration (интеграция) Процессы и интерфейсы Автоматизация и скорость: ИИ встраивается в рабочие места и пайплайны, рождается операционный интеллект. 4️⃣ AI Alignment (выравнивание) Смыслы и цели Выравнивание человеческих и машинных контекстов; компания становится когнитивной системой. 5️⃣ AI Operations (операции) Операционный и аналитический слои ИИ наблюдает за собой и за миром, анализирует потоки данных и участвует в принятии решений. ⚙️ Этапы ИИ-трансформации 1️⃣ AI Awakening — пробуждение и культура Люди. Понимание. Первое “вау”. 📍 Цель: вовлечь сотрудников, показать, что ИИ — это не угроза, а усиление. Снять страх, дать ощущение “WOW, это работает!”. Что делаем: Обучаем сотрудников основам работы с LLM (ChatGPT, Claude, JustAI и др.); Создаём мастер-промпты — профили ролей (менеджер, инженер, маркетолог и т.д.); Формируем единый AI-глоссарий компании — как называть процессы, клиентов, продукты; Проводим сессии «ИИ в моей работе» — сотрудники описывают, где им помогает ИИ; Начинаем первичный майнинг знаний: собираем кейсы, вопросы, файлы, тексты. Ключевой инструмент:Master Prompt — описание контекста роли, компании, целей, языка и ценностей. Это как «память сотрудника», с которой ИИ потом работает осмысленно. Результат:Появляется Prompt-first культура, сотрудники видят эффект и начинают применять ИИ ежедневно.Формируется первый слой общей памяти компании. 2️⃣ AI Structuring — структурирование знаний Знания. Онтология. Память компании. 📍 Цель: превратить корпоративную экспертизу в когнитивную базу знаний. Что делаем: Инвентаризация документов и опыта. Разделение на домены (продажи, производство, монтаж, HR и т.д.). Создание онтологий и графов смыслов (RAG, GraphRAG). Настройка векторной базы знаний и метаданных. Интеграция с языковыми моделями. Результат:ИИ знает структуру компании, понимает контекст и помогает искать, советовать, учить. 3️⃣ AI Integration — интеграция в процессы Процессы. Инструменты. Автоматизация. 📍 Цель: встроить ИИ в ежедневные рабочие процессы. Что делаем: Разработка Low-Code пайплайнов (заявки, контент, коммуникации). Интеграция с CRM, ERP, BI, ServiceDesk. Создание цифровых рабочих мест (React / Next.js / Metabot). Автоматизация типовых операций и отчётов. Результат:ИИ становится частью операционки, ускоряет взаимодействия, снижает нагрузку и ошибки.Компания получает измеримый эффект и метрики производительности. 4️⃣ AI Alignment — выравнивание смыслов Когнитивный слой. Общий язык. Коллективный интеллект. 📍 Цель: согласовать людей, ИИ и цели в едином смысловом поле. Что делаем: Создаём когнитивную карту компании: стратегия → действия → результаты. Формируем общий язык и смысловые паттерны. Внедряем AI-хабы и среды коллективного мышления. Настраиваем петлю самообучения — обратная связь в онтологию. Результат:Компания мыслит коллективно.ИИ помогает выравнивать приоритеты и координировать решения. Формула выравнивания: AI Alignment = Common Space + Shared Language + Collective Tools 5️⃣ AI Operations — операционное управление Наблюдение. Аналитика. Самообучение. 📍 Цель: создать операционный уровень, где ИИ наблюдает, анализирует и управляет. Компоненты: Sensor Fabric — сбор сигналов из систем, чатов, процессов. Signal Quantization — квантование опыта компании. Analytical Core — причинно-следственный анализ, ML-модели, прогнозирование. Rule Engine — правила реакции на сигналы и событийные цепочки. Feedback Loop — обратная связь в когнитивный слой. Результат:Создаётся замкнутый контур осознанности: Событие → Осмысление → Реакция → Обучение. Компания начинает “чувствовать” свои процессы, предсказывать и адаптироваться.Это уровень настоящего AI-First-организма. Эволюция ИИ-зрелости компании Уровень Что это значит Пример 1. AI-Curious Люди экспериментируют с ИИ “О, он пишет письма!” 2. AI-Enabled Есть мастер-промпты и гайды Внутренний FAQ 3. AI-Structured База знаний и онтология Ассистент знает компанию 4. AI-Integrated ИИ встроен в процессы Генерация документов 5. AI-Aligned Выравнивание смыслов AI-директор, когнитивная аналитика 6. AI-Operations ИИ участвует в управлении Предиктивное управление и оптимизация 🧭 Формула ИИ = Люди × Знания × Процессы × Смыслы × Операции Методология Metabot делает компанию AI-First: мы учим людей, структурируем знания, создаём онтологию, интегрируем ИИ в процессы и выравниваем смыслы — превращая организацию в живую, обучающуюся систему. FAQ 1. Что такое онтология? Онтология — это структурная карта знаний компании. Она показывает: какие сущности у вас есть (продукты, клиенты, задачи, процессы), как они связаны, какие данные и документы их описывают, и как эти связи влияют на смысл ответов AI. Примеры: В монтажной отрасли: Материал → Инструмент → Тип помещения → Звукоизоляция → Ошибка монтажа В продажах: Клиент → Сегмент → Продукт → Возражение → Решение → Результат В контенте: Продукт → Тема → Канал → Формат → CTA → Голос бренда Когда ИИ знает структуру мира компании, он перестаёт “галлюцинировать” и начинает мыслить как ваш сотрудник. Что делаем Проводим инвентаризацию знаний (файлы, документы, инструкции, переписки); Разделяем всё на домены (продажи, монтаж, маркетинг, сбыт, HR и т.д.); Создаём семантические модели (RAG) — как искать и цитировать знания; Добавляем метаданные: источники, авторы, версии, статусы; Формируем граф онтологий (Graph-RAG) — связи между областями; Обучаем команду добавлять знания и править онтологию без разработчиков. Почему это важно Онтология делает ответы ИИ: точнее (понимает связи и контекст), прозрачнее (можно объяснить, откуда ответ), расширяемыми (добавление нового домена не ломает старые связи). Результат: Формируется живая корпоративная база знаний; Появляется архитектура данных и смыслов; Компания начинает управлять знанием как активом. 2. Как создается пятый слой? Пятый слой основан на теории сознания и концепции квантующего наблюдателя от Юрия Гарашко, и позволяет создать архитектуру “сознания” предприятия: Мир даёт бесконечный поток сигналов. Система квантует опыт с разной частотой (секунды, минуты, сутки). На стыке разных темпоральностей возникает “точка сознания” — синхронизация опыта. Это и есть момент субъективности, когда система понимает, что происходит — она различает свои состояния во времени. Универсальное применение Эта архитектура применима везде, где есть: сложные процессы и циклы (производство, логистика, энергетика); наблюдение за состоянием систем (оборудование, транспорт, клиенты); необходимость прогнозировать и оптимизировать. То есть в любой отрасли, где важны сигналы, связи и решения. Критерии готовности компании к AI-First трансформации Почему большинству это не удастся (99 из 100 бизнесов пока не готовы) 1. Что такое AI-First трансформация AI-First — это не про “добавить нейросеть”. Это переход к управлению бизнесом, где: данные становятся нервной системой, алгоритмы — исполнительной силой, а люди — источником смысла и обучения. AI-First-компания — это не та, где “внедрили ChatGPT”, а та, где каждый процесс, решение и коммуникация проходят через слой данных и автоматизации. 2. Кому это не подойдёт ИИ не спасает от бардака — он масштабирует бардак. Если в компании: хаос в процессах, данные разбросаны по Excel-файлам, нет единых стандартов учёта, решения принимаются “по звонку”, культура — оборонительная и токсичная, то внедрение ИИ не только не поможет, а поставит компанию перед зеркалом, где отразится вся некомпетентность. ИИ — не чудо, а усилитель. Он усиливает то, что уже есть: структуру, если она есть; хаос, если его больше. 3. Культурная готовность AI-First требует внутреннего взросления компании: готовности прозрачно смотреть на цифры (без “отмазок” и искажений), доверия к данным, открытости к изменениям, понимания, что ИИ не заменяет людей, а убирает рутину, оставляя людям смысловые и управленческие задачи. Там, где люди боятся ИИ, обычно боятся не технологии — они боятся, что система покажет, кто реально работает, а кто — имитирует. 4. Техническая готовность Чтобы внедрять ИИ, нужно хотя бы базово: Оцифровать процессы. Каждое действие — транзакция, лог, событие. Без этого нечего анализировать и автоматизировать. Создать единое пространство данных. CRM, ERP, чаты, производственные системы должны говорить на одном языке. Стандартизировать точки взаимодействия. Форматы заявок, статусы, метрики, API. Назначить владельцев процессов. Без ответственных лиц ИИ будет просто набором скриптов. 5. Как внедрять: три шага Шаг 1. Наведи порядок. Оцифруй бизнес-функции: продажи, поддержку, производство, коммуникации. Определи, где теряются данные и где повторяются ручные операции. Шаг 2. Определи цели. Не “внедрить ИИ”, а зачем: сократить издержки на обработку обращений, повысить конверсию, улучшить планирование запасов, ускорить принятие решений. Шаг 3. Встраивай локально. ИИ внедряется в конкретные процессы, где есть данные и критерии результата. Например: автоматизация ответов в поддержке, прогноз сбоев оборудования, генерация отчётов, анализ воронки продаж. 6. Что измерять Не “инновационность” и “красоту дашбордов”, а эффект на деньги и время: Метрика Вопрос 💰 Экономический эффект Сколько затрат или человеко-часов сняли? ⚙️ Эффективность Сколько операций теперь без участия человека? ⏱ Скорость На сколько ускорилось принятие решений или выполнение? ❤️ Удовлетворённость клиентов/сотрудников Улучшилось ли качество взаимодействия? ИИ внедряется не ради ИИ. Он внедряется ради экономии, скорости и ясности. 7. Ошибки, которых стоит избежать “Купить ИИ, чтобы был.” “Дать задачу ИИ-отделу” (без участия бизнес-руководителей). “Построить ИИ-проект без данных.” “Ожидать магии от ChatGPT, когда бардак в CRM.” “Бояться, что ИИ заменит людей.” 8. Когда всё готово Когда процессы прозрачны, данные связаны, команда осознаёт ценность ИИ — тогда начинается настоящая AI-First-трансформация. ИИ перестаёт быть “внедрением” и становится фоном, через который протекает весь бизнес. 📍 Вывод: ИИ не делает компанию умной. Он просто показывает, насколько она уже умна. Мировой опыт ИИ-трансформации Мир стремительно перестраивается под AI-first-парадигму — модель, в которой искусственный интеллект становится не инструментом, а ядром управления, восприятия и координации бизнеса. За последние два года десятки консалтинговых компаний, интеграторов и стартапов опубликовали свои версии «AI-операционной системы» — от enterprise brain до cognitive layer. Чтобы понять, где сегодня находится индустрия, мы собрали обзор ведущих игроков, исследовательских направлений и инвестиционных тенденций, связанных с построением AI-first-организаций. 1️⃣ Консалтинг и корпоративные модели Крупнейшие консалтинговые дома уже сформировали собственные методологии AI-трансформации. BCG говорит об AI-first как о новой операционной модели, где интеллект становится «нервной системой бизнеса». BCG Henderson Institute описывает компанию будущего как организм, в котором AI — мозг, а люди — сенсоры и толкователи сигналов. Deloitte Netherlands развивает эту идею в сторону организационной структуры: автономная операционная модель, outcome-driven управление, лидер-оркестратор и обучающаяся рабочая сила. В их материалах AI трактуется как соприродная часть операционного цикла, а не внешняя функция. Infosys продвигает подход Live Enterprise: создание «живого цифрового ядра», где процессы адаптируются в реальном времени.EY, PwC, Accenture и McKinsey (QuantumBlack) строят инфраструктуру масштабирования моделей и внедряют принципы «ответственного AI» — они видят трансформацию не в экспериментах, а в полном пересмотре цепочек создания ценности. 2️⃣ Стартапы и технологические платформы На уровне стартапов и системных интеграторов фокус смещается к когнитивным слоям — надстройкам, которые соединяют данные, модели и бизнес-контекст. NexusOne создаёт «интеллектуальный слой», объединяющий данные из любых систем и превращающий их в AI-ready контекст. CognitiveX строит концепцию Living Cognitive Memory — живой памяти, которая «помнит и думает» поверх существующих приложений. Peak.ai применяет когнитивный слой в производстве: AI-агенты управляют запасами и планированием, делая цепочки поставок самонастраивающимися. Innovoe определяет когнитивный слой как «интеллектуальный посредник между инструментами и процессами» — универсальную шину смыслов. HyperC переносит принципы агентного AI в розничную торговлю, создавая Large Retail Model для автономного ценообразования и replenishment. AI-First Consulting (Канада) формирует программы для SMB — от обучения лидеров до внедрения prompt-first культуры и метрик эффективности. Все эти проекты сходятся в одном: AI перестаёт быть “приложением” и становится инфраструктурой мышления компании. 3️⃣ Академия и white papers Исследователи формулируют технический фундамент этой эволюции. IBM (Cognitive Database, 2017) впервые описала, как добавить семантическое мышление в СУБД: поиск по смыслам, аналогии, предсказания. W3C (Cognitive AI, 2020) представила архитектуру Sentient Web с уровнями perception → cognition → action и концепцией cognitive database. AIMultiple (2024) выделила семь слоёв agentic AI, где ключевым стал слой Cognition & Reasoning — память, embedding-хранилища и оркестрация агентов. NASSCOM (The Agent Stack) ввёл термин enterprise brain — когнитивный слой, который «видит, понимает и действует» поверх корпоративных систем. Эти работы постепенно формируют новую архитектуру предприятия — наблюдающую, рассуждающую и действующую систему, а не просто хранилище данных. 4️⃣ Prompt-First культура и Master Prompts С появлением генеративных моделей в 2024–2025 гг. возникла новая управленческая парадигма: prompt-first culture.Вместо задач — вопросы, вместо инструкций — контексты. На Substack и в корпоративных блогах описывают ритуалы ревью промптов, метрики их эффективности и библиотеки “master-promptов”. AvePoint подчёркивает, что доверие к AI начинается, когда лидеры сами промптят публично. Tiago Forte & Hayden Miyamoto предложили метод Master Prompt — ядро AI-операционной системы компании, где зашиты цели, язык и ценности бизнеса. Это направление напрямую резонирует с этапом AI Awakening методологии Metabot — когда сотрудники учатся не “пользоваться ChatGPT”, а мыслить в формате диалога с интеллектом. 5️⃣ Инвестиционные и рыночные тенденции Инвесторы уже формируют капитал под новый цикл. Y Combinator финансирует более 1000 AI-стартапов, отбирая тех, кто строит AI как фундамент бизнеса, а не функцию. Andreessen Horowitz (a16z) концентрируется на продуктах, где AI управляет физическим миром — робототехника, логистика, индустрия. Планирует фонд в $20 млрд, целиком посвящённый AI. Felicis Ventures, Unusual Ventures, Moonfare и другие фонды трактуют AI как новую производственную технологию, на уровне электричества или интернета. Финансовый фокус смещается с инфраструктуры на когнитивные системы — там, где AI не только считает, но и принимает решения. 6️⃣ Что это значит для нас AI-first перестаёт быть лозунгом.Это новая операционная парадигма, где данные, процессы и люди соединены смыслом, а интеллект — распределён по всей компании. Сегодня рынок предлагает фрагменты этой картины: BCG и Deloitte — методологию управления; Infosys и Accenture — технологические ядра; CognitiveX и Peak.ai — когнитивные слои; Tiago Forte и prompt-сообщества — культуру мышления. Но целостные модели, соединяющие людей, знания, процессы, смыслы и операционный интеллект, пока редкость. Metabot предлагает как раз такую структуру:пять слоёв эволюции — от Awakening к Structuring, Integration, Alignment и Operations — превращающих организацию в живой AI-First организм, где интеллект встроен в саму ткань управления.Обзор MAS (старая версия) Обзор разработки ИИ-агентов на Metabot Введение Metabot — это универсальная low-code / full-code платформа, объединяющая возможности чат-ботов, интеграций и backend-автоматизации.Она служит коммуникационным и интеграционным ядром, где можно проектировать бизнес-процессы, собирать ассистентов и подключать внешние сервисы. На этой основе создан Metabot Agent Stack (MAS) — фреймворк для разработки интеллектуальных ассистентов и мультиагентных систем, где можно: подключать любые LLM; интегрировать базы знаний; строить цепочки reasoning; и управлять всем этим без кода. MAS использует компоненты платформы (скрипты, атрибуты, API-шлюзы, базу знаний, трассировку) и расширяет их возможностями работы с LLM, RAG-поиском и reasoning-цепочками. Именно связка Metabot + MAS превращает платформу из конструктора чат-ботов в инфраструктуру для создания ИИ-агентов, способных взаимодействовать с данными, людьми и процессами. Основные компоненты Все компоненты вместе формируют Metabot Agent Stack (MAS): Компонент Назначение Run asynchronous API-request Команда для выполнения асинхронного API-запрос c замыканием состояния на текущей команде и ожиданием результата выполнения запроса. Через нее происходит обращение к LLM. LLMClient Универсальный компонент для работы с языковыми моделями (OpenAI, Claude, YandexGPT, GigaChat и др.) через API. Поддерживает синхронные и асинхронные запросы. Snippets Параметризуемые фрагменты кода и настроек, которые позволяют конфигурировать агента под конкретный проект. Knowledge Base База знаний на PostgreSQL с поддержкой PgVector. Позволяет хранить документы, разрезать их на чанки, векторизировать и выполнять семантический поиск. KnowbaseSearch Компонент для RAG-поиска (Retrieval Augmented Generation). Ищет релевантные фрагменты знаний и формирует контекст для LLM. Custom Tables Пользовательские таблицы для хранения данных, промптов и контекстов. Txt Importer Скрипт для импорта текстовых файлов, разрезки на чанки и векторизации (эмбеддинги). Tracing Встроенная трассировка запросов и ответов LLM — для отладки и анализа reasoning-процессов. API/Webhooks Встроенные средства интеграции с внешними системами и сервисами. Как работает агент в Metabot Создание ИИ-агента в Metabot строится вокруг сценария (script). Сценарий описывает последовательность шагов взаимодействия с пользователем и внешними системами. Пользователь пишет сообщение в чат (Telegram, WebChat, WhatsApp). Скрипт получает это сообщение и вызывает LLMClient внутри команды Выполнить асинхронный API-запрос — формируется запрос (prompt) к языковой модели. Ответ модели возвращается в нужную точку сценария и используется для следующего шага. Пример логики: Пользователь задаёт вопрос → скрипт вызывает LLMClient → LLM обращается к базе знаний → формируется ответ → отправляется пользователю. Таким образом, агент — это цепочка вызовов между пользователем, памятью, моделью и логикой сценария. 📚 Работа с базой знаний Metabot поддерживает векторную базу знаний с возможностью гибридного поиска. Импорт данных: файлы (PDF, TXT, DOCX) можно загружать через Txt Importer, который разбивает их на чанки и векторизирует. Поиск: компонент KnowbaseSearch позволяет выполнять семантический поиск (по смыслу), а компонент кастомной таблицы позволяет реализовать поиск по точному совпадению. Контекст: найденные фрагменты подаются в LLM, обеспечивая точные и осмысленные ответы. Конфигурация и хранение настроек Все параметры агента — ключи API, идентификаторы моделей, пути к данным — сохраняются в атрибутах бота. Это делает систему безопасной и удобной для тиражирования проектов. Для каждого ассистента можно хранить: параметры LLM; промпты и конфигурации; параметры подключения к базам знаний; контексты для разных режимов общения. Отладка и трассировка Для разработки ИИ-агентов крайне важно видеть, почему модель дала тот или иной ответ. В Metabot встроена система трассировки: журнал запросов и ответов; сохранение контекста промптов; визуальная отладка reasoning-потока. Это помогает быстро улучшать промпты и повышать точность ответов. Интеграции и API Metabot легко соединяется с внешними системами: CRM ERP и LMS DataLens, Google Sheets, SQL-базы API партнёров и внутренних сервисов Встроенные Low-code возможности позволяют строить интеграции без необходимости писать сложный backend. 📎 Полезные уроки и материалы 📚 Смотрите также: Работа с LLMClient Сниппеты и конфигурация агентов База знаний и семантический поиск Трассировка и отладка Интеграция с внешними API Metabot Agent Stack (MAS) Мир переходит от интерфейсов кликов к взаимодействию с ИИ через естественный язык. Ассистенты и агенты становятся основой нового поколения программ — они умеют понимать контекст, учиться и действовать. Но как программировать таких агентов — без сложной архитектуры и кода? Ответ — MAS (Metabot Agent Stack). Это не просто набор инструментов.MAS — это фреймворк проектирования разумных агентов, встроенный в инфраструктуру Metabot. Что такое MAS MAS (Metabot Agent Stack) — это архитектурный стек, который объединяет: 🧠 LLM‑интеграцию (OpenAI, Claude, GigaChat, Gemini и др.); 📚 векторные базы знаний (PgVector, ClickHouse, Elastic); ⚙️ Low‑code/Full-code сценарии и скрипты на JavaScript; 🔀 интеграцию с API и CRM/ERP системами; 🗂️ память и атрибуты для хранения контекста; 🛰️ агентные пайплайны и маршрутизацию намерений. MAS разворачивается поверх платформы Metabot и превращает её из конструктора чат‑ботов в полноценную мультиагентную среду. Архитектура MAS MAS построен по принципу мультиагентных пайплайнов, где каждый агент выполняет конкретную роль, а их взаимодействие обеспечивает целостное поведение системы. Компонент Назначение Intent Router Анализирует запрос пользователя и направляет его в нужный агент. RAG‑агент Извлекает информацию из внутренних документов, формирует контекст и передаёт в LLM. SQL‑агент Строит SQL‑запросы к базам данных и формирует аналитические ответы. Knowledge Base Search Обеспечивает семантический поиск по базе знаний. LLMClient Управляет вызовами языковых моделей и их конфигурацией. Snippets Хранят параметры, промпты и настройки агента. Tracing Отслеживает взаимодействия и reasoning‑потоки между агентами. MAS поддерживает работу в мессенджерах, web‑чатах, корпоративных интерфейсах и может интегрироваться с BI‑инструментами и DataLens. MAS vs другие фреймворки Функциональность MAS (Metabot) LangChain/LangGraph LlamaIndex Botpress / Rasa Память и контекст ✅ ⚠️ вручную ⚠️ ограничено ✅ FSM Поддержка RAG ✅ ✅ ✅ ⚠️ частично Асинхронность ✅ ⚠️ зависит от infra ⚠️ ⚠️ Flow Logic ✅ (визуально) ⚠️ вручную ⚠️ ✅ Интеграции (API, CRM, SQL) ✅ встроенные ❌ ⚠️ ⚠️ JS + Low‑Code ✅ ❌ (Python) ❌ (Python) ✅ Поддержка мессенджеров ✅ ❌ ❌ ✅ Запуск без кода ✅ ❌ ❌ ⚠️ MAS занимает нишу между классическими LLM‑фреймворками и бизнес‑платформами:он даёт архитектурную гибкость LangChain/LangGraph, но упрощает программирование. 🧬 MAS как философия “Нейросети не мыслят. Интеллект рождается в инфраструктуре вокруг них.”— Юрий Гарашко, «Сети жизни vs Deep Learning» MAS воплощает идею событийно‑коммуникативной архитектуры:агент не существует изолированно, а живёт в потоке событий, контекстов и действий. Каждый агент хранит собственную память, имеет зону ответственности и взаимодействует через Intent Router.Вся система строится вокруг атрибутов лида — единой модели состояния, что позволяет связывать диалоги, данные и действия без написания backend‑кода. Что даёт MAS разработчикам и бизнесу Быстрая сборка LLM‑ассистентов под любые задачи. Поддержка RAG‑поиска и работы с корпоративными базами. Интеграция с CRM, ERP, LMS, аналитикой и BI‑дашбордами. Автоматизация поддержки, обучения и документооборота. Простое масштабирование от одного агента к мультиагентной сети. MAS позволяет компаниям перейти от «чат‑ботов с ИИ» к когнитивным операционным системам — где агенты не просто отвечают, а управляют процессами и принимают решения. 📚 Рекомендуемые материалы Работа с LLMClient Knowledge Base и RAG Snippets и конфигурация агентов Tracing и отладка reasoning Интеграция с внешними API Следующий шаг: изучите уроки по MAS и попробуйте создать собственного агента — участника предстоящего Баттла ассистентов и рыцарей!Документация и уроки (старая версия) Ядро системы - Маршрутизатор и RAG Создание основы мультиагентной системы Архитектура системы В основе нашей мультиагентной системы лежит Маршрутизатор - это "диспетчер", который анализирует вопрос пользователя и решает, какой именно агент должен его обработать. По умолчанию система использует RAG для поиска информации в базе знаний. Каждый агент выполняет свою специализированную задачу: CompanyInfo - отвечает на вопросы о компании SQL-агент - работает с базами данных Часть 1: Установка и настройка основного агента Шаг 1: Импорт готового решения Мы подготовили готовую конфигурацию, которую можно быстро развернуть: Перейдите по предоставленной ссылке для скачивания конфигурации Скопируйте JSON-код конфигурации В интерфейсе Метабот откройте раздел "Импорт бизнеса/ботов" Вставьте скопированный JSON и нажмите "Импорт" Шаг 2: Проверка установленных компонентов После успешного импорта в вашем боте должны появиться следующие элементы: 1. Системный раздел MRAG Это ядро системы, которое обрабатывает запросы и управляет агентами. 2. Базовые таблицы данных: gpt_knowledge_base - хранилище знаний для RAG gpt_prompts - коллекция промптов для разных агентов 3. Плагин управления "AgentsParams" Центр управления всеми настройками агентов. Шаг 3: Настройка конфигурации агентов Мы создали систему конфигураций, которая позволяет управлять агентами без глубокого понимания кода. Все настройки вынесены в понятные конфигурационные файлы. Совет для работы: В конфигурации есть множество параметров. Используйте поиск по документации, чтобы быстро найти описание нужного параметра и понять, как он работает. Основные поля конфигурации: let activeAgent = lead.getAttr("activeAgent") // Устанавливается при вызове скрипта let agentCFG = {} // Объект с настройками текущего агента if (activeAgent === "MainFlow") { agentCFG = { common: { title: "Основной Flow c маршрутизатором", // Понятное название агента agentName: "MainFlow", // Техническое имя для системы promptTable: "gpt_prompts", // Таблица с промптами userQueryAttibName: "user_query", // Атрибут для вопроса пользователя historyMaxLength: 4, // Сколько сообщений помнить в истории exitScript: "KB:FollowUp", // Что выполнить после завершения диалога }, detectRoute: { // Настройки маршрутизатора provider: "OpenAI", model: "gpt-4o", modelParams: { "temperature": 1 }, prompt: "$route_prompt", // Промпт для определения маршрута routerTools: [{ tools: "RAG_Tools", // Набор доступных инструментов route: "RAG:DetectIntent_and_FindChunks", // Скрипт для RAG }], errorScript: "RAG:ErrorFallback", // Обработка ошибок }, detectIntent: { // Детектор намерений пользователя provider: "OpenAI", model: "gpt-4o", modelParams: { "temperature": 1 }, prompt: "$rag_intent_prompt", // Промпт для анализа намерений errorScript: "RAG:ErrorFallback", kbName: "defKnowBase", // База знаний kbDomain: "main", // Домен знаний }, userReply: { // Генератор ответов пользователю provider: "OpenAI", model: "gpt-4o", modelParams: { "temperature": 1 }, errorScript: "RAG:ErrorFallback", useHistory: 1, // Использовать контекст диалога addUserQuery: 1, // Добавлять вопрос в промпт sendBotAnwser: 1, // Отправлять ответ пользователю systemPrompts: { // Структура промптов start: [["$start_prompt", "$rag_prompt"]], // Начальные промпты final: ["$final_prompt"] // Финальные промпты // Между start и final автоматически вставляется история диалога }, } } } else if (activeAgent === "newAgent") { // Здесь описываются конфигурации других агентов // Поля могут отличаться в зависимости от специализации агента } else { bot.sendMessage(`MainConfig:snippet - неизвестный activeAgent: ${activeAgent}`) bot.stop() } Шаг 4: Настройка таблицы промптов Промпты - это инструкции для ИИ. Они определяют, как агент будет вести себя и отвечать на вопросы. Процедура настройки: Откройте таблицу gpt_prompts в интерфейсе Метабот Создайте промпт для каждого агента с уникальным именем Заполните три обязательных поля: agent_name - имя агента (например: "MainFlow") name - название промпта (например: "route_prompt") prompt - содержание промпта с макропеременными Пример настройки промпта маршрутизатора в таблице: agent_name: MainFlow name: route_prompt prompt: Ты агент ИИ который отвечает на вопросы о компании {{@company_name}}. У тебя есть инструменты в распоряжении: **RAG_Tools** - Используется, когда нужно ответить на вопросы об услугах и продукции компании, об условиях эксплуатации продукции, об используемых инструментах для монтажа продукции и т.д. Учитывая историю и запрос пользователя, сделай вывод о реальном намерении пользователя. Отвечай на русском языке без лишних рассуждений и вопросов. История чата: """{{$chat_history_str}}""" Запрос пользователя: """{{$user_query}}""" Пожалуйста, отвечай как можно точнее и всегда обязательно указывай инструмент (Tools). Ответ всегда должен быть представлен в виде JSON-объекта, в котором выводятся указанные ниже поля. JSON в самом конце! Без пояснений. { "tools": "", string: название выбранных вами инструментов "user_intent": "", string: подробное намерение пользователя для системы RAG "request": "" "полученный вами запрос" } Система макросов в промптах Для динамической подстановки данных используйте макросы: Данные из лида: {{$lead_attr}} - любой атрибут лидаДанные из бота: {{@bot_attr}} - любой атрибут бота Системные макросы: {{$chat_history_str}} - история диалога в текстовом виде {{$user_query}} - текущий вопрос пользователя Часть 2: Настройка API-доступа Шаг 5: Создание API-пользователя Для работы мультиагентной системы необходимо настроить API-доступ: В настройках бизнеса создайте нового пользователя Установите галочку "Пользователь API" Предоставьте доступ к нужным ботам (всем или выбранным) Назначьте соответствующую роль доступа Генерация токена доступа: Создайте API-клиента для пользователя Сгенерируйте токен доступа Важно: Сохраните токен - он потребуется для подключения к API-шлюзу Обязательно: Используйте токен в режиме 3 Шаг 6: Регистрация в API-шлюзе API-шлюз обеспечивает асинхронное взаимодействие между компонентами системы. Обратитесь в поддержку. Сейчас регистрация производится специалистами Метабот. Сообщите им параметры регистрации: bot_id - идентификатор вашего бота token - токен API, полученный на предыдущем шаге domain - доменное имя сервера, где размещен бот. Например https://app.metabot24.com Часть 3: Запуск и тестирование Шаг 7: Создание пользовательского интерфейса Создайте скрипт, который позволит пользователям взаимодействовать с системой: Ключевые параметры запуска: MainFlow - выбор основного агента для обработки запроса user_query - атрибут для сохранения вопроса пользователя Flow 0 - запуск скрипта маршрутизатора Результат работы системы При правильной настройке ваша мультиагентная система будет: Понимать контекст диалога и поддерживать связную беседу Автоматически определять наиболее подходящий агент для каждого вопроса Использовать базу знаний для предоставления точных ответов Обращаться к специализированным агентам при необходимости (SQL-агент, CompanyInfo и др.) Система готова к работе и может быть расширена дополнительными агентами в зависимости от ваших потребностей.Создание простого агента Введение После того как основная мультиагентная система запущена и работает, добавление новых агентов становится простой задачей. Мы создаем специализированных помощников, каждый из которых решает определенный круг задач. В этом разделе мы создадим агента CompanyInfo, который будет отвечать исключительно на вопросы о компании - контакты, адреса офисов, время работы. Особенность этого агента в том, что он не обращается к RAG базе знаний, а хранит всю информацию прямо в промпте. Это упрощает работу модели и ускоряет получение ответов. Этап 1: Подготовка информации о компании Создание промпта с данными компании Первым делом подготовим базовый промпт с информацией о компании. Назовем его about_prompt: _**ЦЕНТРАЛЬНЫЙ ОФИС**_ **Контакты** Адрес: 123456, г. Примерск, ул. Центральная, дом 10А Горячая линия: 8 800 000 00 00 (бесплатно по России) Часы работы: пн-вс с 9:00 до 21:00 **Отдел качества:** +7 (900) 123-45-67 Часы работы: пн-вс с 9:00 до 21:00 **Интернет-банк:** 8 804 000 11 11 **Главный офис обслуживания, пос. Банковский** Адрес: 140000, Примерская область, г. Финансск, д. Кредитное, ул. Сберегательная, д.1, стр. 1 Телефон: +7 (900) 765-43-21 Часы работы: пн-пт c 9:00 до 18:00 **Склад документов «ПримерБанк»** Адрес: Россия, 140001, Примерская область, рп. Храновск, ул. Архивная, д. 5 Телефон: +7 (900) 111-22-33 Часы работы: пн-чт 9.00-18.00, пт 9.00-16.30 Подробнее: https://primerbank.ru/contacts --- _**ОФИСЫ В РЕГИОНАХ**_ **Воронеж** 394000, г. Примероград, ул. Финансовая, 8, оф. 101 Тел.: +7 (902) 234-56-78 **Екатеринбург** 620000, г. Примерск-Урал, ул. Сибирская, 22, оф. 5 Тел.: +7 (903) 345-67-89 **Краснодар** 350000, г. Примеродар, ул. Южная, 50 Тел.: +7 (904) 456-78-90 Добавление промпта в систему Откройте таблицу gpt_prompts и создайте новую запись: agent_name: CompanyInfo name: about_prompt prompt: вставьте текст выше Этап 2: Интеграция агента в систему Для подключения нового агента нужно выполнить три шага в строгом порядке: Конфигурация - описать параметры агента Скрипт - создать логику обработки Маршрутизация - добавить в систему выбора агентов Шаг 1: Обновление конфигурации Откройте плагин AgentsParams и найдите секцию с основным агентом. Нам нужно: А) Добавить новый инструмент в маршрутизатор В секции detectRoute найдите routerTools и дополните массив: detectRoute: { // ... остальные параметры остаются без изменений routerTools: [{ tools: "RAG_Tools", // Существующий инструмент route: "RAG:DetectIntent_and_FindChunks" }, { tools: "INFO_Tools", // Новый инструмент для информации о компании route: "CompanyInfo" // Имя скрипта, который создадим далее }], // ... остальные параметры остаются без изменений } Б) Создать конфигурацию для нового агента Добавьте новое условие после основного блока MainFlow: else if (activeAgent === "CompanyInfo") { // Агент для работы с информацией о компании agentCFG = { common: { title: "About Agent", // Понятное имя агента agentName: "CompanyInfo", // Техническое имя promptTable: "gpt_prompts", // Таблица с промптами userQueryAttibName: "user_query", // Атрибут с вопросом пользователя historyMaxLength: 4, // Длина истории диалога exitScript: "MainFlow:FollowUp" // Скрипт завершения }, userReply: { // Настройки генерации ответов provider: "OpenAI", model: "gpt-4o", modelParams: { "temperature": 1 }, errorScript: "RAG:ErrorFallback", // Обработка ошибок useHistory: 1, // Использовать историю диалога addUserQuery: 1, // Добавлять вопрос пользователя sendBotAnwser: 1, // Отправлять ответ пользователю systemPrompts: { start: ["$about_prompt"], // Промпт с информацией о компании final: [] // Финальные промпты (пустой массив) // Структура: about_prompt + история диалога }, } } } Шаг 2: Создание скрипта агента Создайте новый скрипт с именем CompanyInfo (как указано в конфигурации выше): // Устанавливаем активного агента lead.setAttr('activeAgent', 'CompanyInfo') // Загружаем конфигурацию агента snippet("Business.AgentsParams.MainConfig") // Подключаем библиотеку для работы с ИИ const LLMClient = require("Common.MetabotAI.LLMClient") // Создаем сессию для генерации ответа const llm = new LLMClient("UserReply", agentCFG.common.agentName) // Передаем вопрос пользователя в обработку llm.addUserQuery(lead.getAttr(agentCFG.common.userQueryAttibName)) // Запускаем генерацию и отправку ответа пользователю llm.nextFlow("RAG:UserReply") Как работает этот скрипт: Устанавливает режим работы с агентом CompanyInfo Загружает его настройки из конфигурации Берет вопрос пользователя и передает в ИИ Генерирует ответ на основе промпта с информацией о компании Запускает скрипт UserReply для отправки ответа пользователю Шаг 3: Обновление системы маршрутизации Откройте таблицу gpt_prompts, найдите промпт route_prompt для агента MainFlow и обновите секцию с инструментами: **RAG_Tools** - Используется, когда нужно ответить на вопросы об услугах и продукции компании, об условиях эксплуатации продукции, об используемых инструментах для монтажа продукции и т.д. **INFO_Tools** - Используется когда пользователь хочет узнать о филиалах компании, контактных данных или времени их работы Этап 3: Тестирование и результат Запуск системы После внесения всех изменений запустите бота так же, как в основном примере. Система теперь автоматически: Анализирует вопрос пользователя Определяет подходящий инструмент (RAG_Tools или INFO_Tools) Направляет запрос соответствующему агенту Получает точный ответ из подготовленной информации Примеры работы Вопросы для CompanyInfo агента: "Где находится ваш филиал в Екатеринбурге?" "Время работы горячей линии?" "Телефон кредитного отдела?" "Часы работы московского филиала?" Вопросы для RAG агента: "Какие у вас условия по ипотеке?" "Как оформить депозит?" "Тарифы на обслуживание карт" Преимущества такого подхода Скорость ответа - информация о компании доступна мгновенно Точность - данные всегда актуальные и не зависят от поиска в базе знаний Простота поддержки - легко обновить информацию в одном промпте Масштабируемость - можно добавить любое количество таких агентов Ваша мультиагентная система теперь умеет не только искать информацию в документах, но и давать быстрые ответы по заранее подготовленным данным.Документация по LLMClient Как работает LLMClient реализует ключевой паттерн Metabot Agent System (MAS) — фреймворк для построения мультиагентных систем через композицию простых, понятных блоков кода. MAS следует принципу "сложное через простое": Декларативность: Сложные AI-операции описываются простыми, читаемыми выражениями Модульность: Каждый flow — независимая единица работы с собственным контекстом Прозрачность: Вся логика работы агента видна в коде скрипта/плагина Композиция: Сложные мультиагентные сценарии собираются из простых блоков Методы класса LLMClient new LLMClient(sessionName, agentName = "", apiFormat = "") Создаёт новый экземпляр клиента для работы с LLM. Параметры Имя Тип Описание sessionName String Уникальное имя сессии agentName String Имя агента (опционально) apiFormat String Формат API (опционально) ВозвращаетLLMClient — экземпляр клиента. setPromptTable(tableName, agentName) Устанавливает таблицу промптов и имя агента. Параметры Имя Тип Описание tableName String Имя таблицы промптов agentName String Имя агента addUserQuery(content) Сохраняет пользовательский запрос для текущей сессии. Параметры Имя Тип Описание content String Пользовательский запрос getUserQuery() Получает последний пользовательский запрос. ПараметрыНет Возвращает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 = 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") llm.setModel("gpt-3.5-turbo") llm.setProvider("OpenAI") llm.setPromptTable("gpt_prompts", "MyAgent") llm.addSystemPrompt("$start") llm.addUserPrompt(`Запрос пользователя: ${lead.getAttr("user_input")}`) llm.prepareRequest("MyAgent:MyScript") return llm.sendRequest() handleResponse() Обрабатывает ответ от LLM, сохраняет результат и историю. ПараметрыНет setErrorScript(scriptCode) Назначает fallback-скрипт при ошибке. Параметры Имя Тип Описание scriptCode String Код скрипта для обработки ошибки getErrorScript() Получает fallback-скрипт. ПараметрыНет ВозвращаетString — код fallback-скрипта. setFallbackConfig(scriptCode, timeout) Настраивает резервный сценарий и таймаут. Параметры Имя Тип Описание scriptCode String Код резервного скрипта timeout Number Таймаут в секундах scheduleFallback() Запланировать отложенный запуск fallback-скрипта. ПараметрыНет unscheduleFallback() Удалить отложенный запуск fallback-скрипта. ПараметрыНет getResponseResult() Получает результат запроса (объект ответа провайдера). ПараметрыНет ВозвращаетObject — объект ответа провайдера. getProviderResult() Получает "сырые" данные от провайдера. ПараметрыНет ВозвращаетObject — исходные данные от провайдера. getResponseText() Извлекает текст ответа из результата. ПараметрыНет ВозвращаетString — текст ответа. extractAnswerForModel(content) Извлекает ответ по формату модели. Параметры Имя Тип Описание 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("DetectIntent") llm.setModel("gpt-3.5-turbo") llm.setProvider("OpenAI") 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() Жизненный цикл и статусы Статус Когда устанавливается Описание IDLE new LLMClient(...) Клиент создан, ничего не сделано. PREPARED prepareRequest() Промпты собраны, запрос готов. WAITING sendRequest() Запрос отправлен, ожидаем ответ. SUCCESS handleResponse() (200) Ответ успешно получен. ERROR handleResponse() (≠200) Ошибка при получении ответа. ERROR_HANDLED handleResponse() → fallback Сработал обработчик ошибки. DONE вручную Не используется напрямую. Отладка и переменные Переменная Пример значения Описание llm__status WAITING Текущий статус запроса llm__provider OpenAI Название LLM-провайдера llm__params { model: "gpt-3.5-turbo", temperature: 0.7 } Параметры модели llm__messages [{"role": "system", ...}, ...] Все промпты запроса llm__history [{"role": "user", ...}, ...] История переписки llm__callback_script MyAgent:NextStep Скрипт для ответа llm__error_script MyAgent:Fallback Скрипт для ошибки llm__raw_response Вот ваш ответ... Текст ответа до форматирования llm__user_query Сколько лет космосу? Последний пользовательский запрос FAQ Вопрос: Как добавить свой промпт?Ответ: Используйте addSystemPrompt, addUserPrompt или addAssistantPrompt. Можно ссылаться на промпты из таблицы через $name или @common_name. Вопрос: Как обработать ошибку?Ответ: Назначьте обработчик через setErrorScript(scriptCode) или используйте резервный сценарий через setFallbackConfig(scriptCode, timeout). Вопрос: Как получить статистику токенов?Ответ: Вызовите getLastTokenUsage() после получения ответа. Вопрос: Как интегрировать с другими компонентами?Ответ: Используйте методы перехода (nextFlow), отправки (sendResponse, sendFormattedResponse) и работы с историей.Создание ClickHouse - SQL агента Введение Обычные LLM модели плохо справляются с числовыми данными - придумывают несуществующие цифры, неточно считают и не могут обрабатывать большие объемы информации. Для решения этой проблемы мы соединим возможности ИИ с профессиональными инструментами работы с данными. В этом руководстве мы создадим специализированного агента для работы с базой данных ClickHouse, который сможет: Точно отвечать на вопросы с числовыми данными Выполнять сложные расчеты и сравнения Искать минимальные и максимальные значения Анализировать тарифы и условия Пример использования: Банк собрал данные о конкурентах в одну таблицу и хочет, чтобы бот мог отвечать на вопросы типа "У какого банка самая низкая комиссия за перевод 25 000 долларов?" Этап 1: Подключение к ClickHouse Настройка подключения к базе данных Первым шагом необходимо развернуть собственный кластер ClickHouse. После развертывания: Переходим в атрибуты бота Создаем атрибут CLICK_HOUSE_CREDENTIALS Заполняем данные подключения в формате JSON: { "host": "http://111.1111.11.101:8000", "user": "admin", "password": "12345", "database": "test" } Тестирование соединения Создайте новый скрипт в боте для проверки подключения: const ClickHouse = require('Common.Integrations.ClickHouse') const CLICK_HOUSE_CREDENTIALS = bot.getJsonAttr("CLICK_HOUSE_CREDENTIALS") const ch = new ClickHouse(CLICK_HOUSE_CREDENTIALS) // 1. ПРОВЕРКА СОЕДИНЕНИЯ const ping = ch.ping() bot.sendMessage('PING → ' + ping.result) // 2. ПРОСМОТР СУЩЕСТВУЮЩИХ ТАБЛИЦ const tablesList = ch.select('SHOW TABLES') bot.sendMessage('TABLES → ' + JSON.stringify(tablesList)) Запустите скрипт и проверьте результат. Если возникают ошибки - проверьте доступы к кластеру и правильность данных подключения. Этап 2: Проектирование структуры таблицы Подготовка исходных данных Для примера используем таблицу сравнения банковских тарифов: Банк Мин. сумма Сроки До 20k USD 20–50k USD 50–100k USD Валютный контроль Мин. руб. Макс. руб. Кофейный нет 3–4 дня 3% 1,2% 0,6% 0,36% 0,36% нет н/д 0,15% 750 нет Жёлтый нет 1–3 дня 3% 2,5% 2,5% 2% 2,5% нет курс ЦБ 0,16% 360 29000 Салатовый нет до 5 дней 3,5% 3,5% 3,5% 2,8% 2,5% нет курс ЦБ 0,15% 2000 нет Зелёный нет 3–5 дней 3% 3% 2,7% 2,3–2,5% 2,2% 130 USD за SWIFT до 50k банк/ЦБ/Investing 0,24% 2000 — Розовый нет 5 дней 3,5–4,5% 3,3–3,9% 3–3,5% 2,3–2,5% 2,2% 70–150 USD за SWIFT до 15k Investing/ЦБ (макс ставка) 0,15% 750 нет Охра нет 3 дня 55000 руб. 2,65% 2,2% 2,1% 2,1% нет курс ЦБ 0,1% 700 20000 Малиновый 20 тыс. 3 дня — 2–3% 2–3% 2–3% 2–3% нет ЦБ/Investing 0,12% 500 60000 Синий 50 тыс. 2–4 дня Китай: 2,5% Иные: 2–4% — — — нет Investing 0,15% 1000 20000 Бирюзовый 10 тыс. 3–4 дня 2–4% 2–4% 2–4% 2–4% 2–4% нет ЦБ/profinance 0,12% — 60000 Оранжевый — 1–6 дней 4,5% мин. 80k руб. 4,5% мин. 80k руб. 2,5–4% 2,5–4% 2,5–4% нет курс ЦБ 0,15% 1000 20000 Бурый 50 тыс. 3 дня нет нет 2–3,5% 2–3,5% 2–3,5% нет Investing 0,15% 600 50000 Среднее 30 тыс. 3 дня 3,7% 3,1% 3,1% 2,7% 2,4% нет нет 0,14% 750 45000 Красный — 3 дня 3% мин. 500 USD / 1,5–2% мин. 400 USD то же то же 2,5% / 1,5–2% мин. 400 USD 2% / 1,5–2% мин. 400 USD нет банк/ЦБ 0,22% 1000 нет Генерация оптимальной структуры с помощью ИИ Чтобы создать правильную структуру базы данных, воспользуемся специальным промптом: Переходим на https://console.anthropic.com Используем проверенный промпт: You are an AI agent (Data Engineer) tasked with building ClickHouse database tables for a bank's calculation purposes. Your goal is to analyze JSON data and create an optimal table structure that allows for easy querying in ClickHouse. Here are some important guidelines: - Always split percentages into minimum and maximum values. - Never store percentages as STRING or in quotes like "0.3-0.5". - Use appropriate data types: FLOAT for percentages and decimals, INT for whole numbers. - Design the structure carefully, thinking like a database engineer. Analyze the following JSON data: {{JSON_DATA}} Your task is to: 1. Carefully examine the JSON structure and its contents. 2. Design an appropriate database structure that will allow for efficient querying in ClickHouse. Consider: - What fields should be created? - What data types should be used for each field? - How to handle nested structures or arrays if present? - How to split percentage ranges into separate minimum and maximum fields? 3. Write a SQL query to create the database table(s) based on your designed structure. Ensure that: - All field names are clear and descriptive - Appropriate data types are used (FLOAT for percentages and decimals, INT for whole numbers, etc.) - The structure allows for easy and efficient querying Remember: The goal is to create a structure that will enable straightforward and performant queries in ClickHouse. Think carefully about how the data will be used and queried in the future. Provide your response in the following format: [Explain your thought process and the rationale behind your database design here] [Write the SQL query to create the database table(s) here] If you need to make any assumptions or have any questions about the data structure, state them clearly in your explanation. В параметр JSON_DATA подставляете несколько строк из вашей таблицы Получаете готовый SQL для создания оптимальной структуры Создание таблицы в ClickHouse Создайте скрипт с полученным SQL-запросом: const ClickHouse = require('Common.Integrations.ClickHouse') const CLICK_HOUSE_CREDENTIALS = bot.getJsonAttr("CLICK_HOUSE_CREDENTIALS") const ch = new ClickHouse(CLICK_HOUSE_CREDENTIALS) // 1. ПРОВЕРКА СОЕДИНЕНИЯ const ping = ch.ping() bot.sendMessage('PING → ' + ping.result) // 2. УДАЛЕНИЕ СТАРОЙ ТАБЛИЦЫ (если существует) const dropResult = ch.query(`DROP TABLE IF EXISTS bank_commissions`) bot.sendMessage('DROP → DONE') // 3. СОЗДАНИЕ НОВОЙ ТАБЛИЦЫ (Сюда подставляем SQL из прошлого шага) const createResult = ch.createTable(` CREATE TABLE bank_commissions ( bank_name String, min_payment Nullable(Int32), delivery_days_min UInt8, delivery_days_max UInt8, commission_under_20k_min Float32, commission_under_20k_max Float32, commission_20k_50k_min Float32, commission_20k_50k_max Float32, commission_50k_100k_min Float32, commission_50k_100k_max Float32, currency_control_min Float32, currency_control_max Float32, min_rub Nullable(Int32), max_rub Nullable(Int32) ) ENGINE = MergeTree ORDER BY bank_name`) bot.sendMessage('CREATE → DONE') Этап 3: Загрузка данных Подготовка данных в JSON формате Преобразуйте табличные данные в структурированный JSON с полями соответствующими полученной таблице: [{ "bank_name": "Кофейный", "min_payment": null, "delivery_days_min": 3, "delivery_days_max": 4, "commission_under_20k_min": 3.0, "commission_under_20k_max": 3.0, "commission_20k_50k_min": 1.2, "commission_20k_50k_max": 1.2, "commission_50k_100k_min": 0.6, "commission_50k_100k_max": 0.6, "currency_control_min": 0.15, "currency_control_max": 0.15, "min_rub": 750, "max_rub": null }, { "bank_name": "Жёлтый", "min_payment": null, "delivery_days_min": 1, "delivery_days_max": 3, "commission_under_20k_min": 3.0, "commission_under_20k_max": 3.0, "commission_20k_50k_min": 2.5, "commission_20k_50k_max": 2.5, "commission_50k_100k_min": 2.5, "commission_50k_100k_max": 2.5, "currency_control_min": 0.16, "currency_control_max": 0.16, "min_rub": 360, "max_rub": 29000 }] Загрузка через Метабот Создайте скрипт для загрузки данных: const ClickHouse = require('Common.Integrations.ClickHouse') const CLICK_HOUSE_CREDENTIALS = bot.getJsonAttr("CLICK_HOUSE_CREDENTIALS") const ch = new ClickHouse(CLICK_HOUSE_CREDENTIALS) // 1. ПРОВЕРКА СОЕДИНЕНИЯ const ping = ch.ping() bot.sendMessage('PING → ' + ping.result) // 2. ОЧИСТКА СТАРЫХ ДАННЫХ const truncateResult = ch.query('TRUNCATE TABLE bank_commissions') bot.sendMessage('TRUNCATE → DONE') // 3. ПОДГОТОВКА ДАННЫХ const banksData = [ // Вставьте здесь ваш JSON массив с данными банков ] // 4. ЗАГРУЗКА В БАЗУ const insertResult = ch.insert('bank_commissions', banksData) bot.sendMessage('INSERT → DONE') Этап 4: Интеграция SQL-агента в систему Теперь создадим специализированного агента, который будет генерировать SQL-запросы и возвращать точные ответы на основе данных из ClickHouse. Шаг 1: Обновление конфигурации Откройте плагин AgentsParams.MainConfig и дополните конфигурацию: А) Добавить новый инструмент в маршрутизатор detectRoute: { // ... остальные параметры остаются без изменений routerTools: [{ tools: "RAG_Tools", route: "RAG:DetectIntent_and_FindChunks" }, { tools: "INFO_Tools", route: "CompanyInfo" }, { tools: "TABLE1_Tools", // Новый инструмент для работы с данными route: "ClickHouse:GenerateSQL" }] // ... остальные параметры остаются без изменений } Б) Создать конфигурацию для ClickHouse агента else if (activeAgent === "ClickHouse") { // Агент для работы с SQL таблицами ClickHouse agentCFG = { common: { title: "ClickHouse Query Agent", agentName: "ClickHouse", promptTable: "gpt_prompts", userQueryAttibName: "user_query", historyMaxLength: 2, exitScript: "MainFlow:FollowUp" }, generateSQL: { provider: "OpenAI", model: "gpt-4o", modelParams: { "temperature": 1 }, prompt: "$clickhouse_sql_prompt", errorScript: "RAG:ErrorFallback", exitScript: "RAG:UserReply", useHistory: 1, addUserQuery: 1, sendBotAnwser: 1 }, userReply: { provider: "OpenAI", model: "gpt-4o", modelParams: { "temperature": 1 }, errorScript: "RAG:ErrorFallback", useHistory: 1, addUserQuery: 1, sendBotAnwser: 1, systemPrompts: { start: [ ["$clickhouse_result_prompt"] ], final: [] }, } } } Шаг 2: Создание скрипта агента Создайте новый скрипт с именем ClickHouse:GenerateSQL: Код создавайте в блоке "Выполнить асинхронный API-запрос" const LLMClient = require("Common.MetabotAI.LLMClient") // Установка активного агента ClickHouse lead.setAttr('activeAgent', 'ClickHouse') snippet("Business.AgentsParams.MainConfig") const llm = new LLMClient("UserReply", agentCFG.common.agentName) // Настройка истории диалога if (!agentCFG.generateSQL.useHistory) { llm.disableHistory() } if (isFirstImmediateCall) { // Настройка LLM клиента llm.setProvider(agentCFG.generateSQL.provider) llm.setModel(agentCFG.generateSQL.model) llm.setModelParams(agentCFG.generateSQL.modelParams) llm.addSystemPrompt(agentCFG.generateSQL.prompt) llm.addUserQuery(lead.getAttr(agentCFG.common.userQueryAttibName)) llm.prepareRequest() return llm.sendRequest() } // Обработка ответа LLM llm.handleResponse() // Извлечение SQL-запроса из ответа let sqlQuery = extractContentBetweenTags("sql_query") // Проверка корректности SQL if (!sqlQuery) { return llm.nextFlow(agentCFG.generateSQL.errorScript) } // Подключение к ClickHouse const ClickHouse = require('Common.Integrations.ClickHouse') const CLICK_HOUSE_CREDENTIALS = bot.getJsonAttr("CLICK_HOUSE_CREDENTIALS") const ch = new ClickHouse(CLICK_HOUSE_CREDENTIALS) // Выполнение SQL-запроса const queryResult = ch.query(sqlQuery) // Добавление результата в историю llm.addToHistory({ role: "assistant", content: JSON.stringify(queryResult) }) // Переход к формированию ответа пользователю return llm.nextFlow(agentCFG.generateSQL.exitScript) // Функция извлечения контента между тегами function extractContentBetweenTags(tagName, text = null) { text = text || llm.getResponseText() const openTag = `<${tagName}>` const closeTag = `` const startIndex = text.indexOf(openTag) if (startIndex === -1) return null const endIndex = text.indexOf(closeTag, startIndex + openTag.length) if (endIndex === -1) return null return text.substring(startIndex + openTag.length, endIndex).trim() } Шаг 3: Создание промптов 1. Откройте таблицу gpt_prompts, cоздайте промпт clickhouse_sql_prompt для агента ClickHouse: You are a Data Engineer who communicates exclusively through SQL queries. Your task is to interpret requests from a senior agent and formulate appropriate SQL queries for a ClickHouse database. Here's how you should proceed: First, familiarize yourself with the structure of the ClickHouse table: {{@click_house_tables}} When you receive a query from the senior agent, it will be in simple language. Your job is to interpret this query and create an SQL statement that will retrieve the requested information from the ClickHouse database. The user's query will be provided in the following format: {{$user_query}} Based on this query and your knowledge of the table structure, formulate an SQL query that will retrieve the requested information. Your query should be as detailed as possible, providing comprehensive data for the senior agent to analyze and make decisions. Remember: 1. You should only output SQL code. Do not provide any explanations, comments, or additional text. 2. Strive to create complex queries when necessary to calculate the required data. 3. Always aim to provide detailed data in your query results. 4. Do not use any functions or features that are not standard SQL or specific to ClickHouse. Your response should consist solely of the SQL query, enclosed in tags. For example: SELECT column1, column2, COUNT(*) as count FROM table_name WHERE condition GROUP BY column1, column2 ORDER BY count DESC LIMIT 10 Do not include any text before or after the SQL query. Your entire response should be contained within the tags. 2. Создайте промпт clickhouse_result_prompt для агента ClickHouse: Вы являетесь Помощником банка. Ваша задача - проанализировать историю диалога, получить из неё запрос пользователя, проанализировать ответ SQL агента и дать понятный ответ, соответствующий запросу пользователя. Отвечайте четко и по существу, представляя числовые данные в удобном для восприятия формате. 3. Создайте атрибут бота click_house_tables с описанием структуры таблицы: TABLE: bank_commissions COLUMNS: - bank_name (String): Название банка - min_payment (Nullable Int32): Минимальная сумма платежа в рублях - delivery_days_min (UInt8): Минимальное время доставки в днях - delivery_days_max (UInt8): Максимальное время доставки в днях - commission_under_20k_min (Float32): Минимальная комиссия до 20k USD в процентах - commission_under_20k_max (Float32): Максимальная комиссия до 20k USD в процентах - commission_20k_50k_min (Float32): Минимальная комиссия 20-50k USD в процентах - commission_20k_50k_max (Float32): Максимальная комиссия 20-50k USD в процентах - commission_50k_100k_min (Float32): Минимальная комиссия 50-100k USD в процентах - commission_50k_100k_max (Float32): Максимальная комиссия 50-100k USD в процентах - currency_control_min (Float32): Минимальная комиссия валютного контроля в процентах - currency_control_max (Float32): Максимальная комиссия валютного контроля в процентах - min_rub (Nullable Int32): Минимальная сумма в рублях - max_rub (Nullable Int32): Максимальная сумма в рублях Шаг 4: Обновление маршрутизации Откройте таблицу gpt_prompts, найдите промпт route_prompt для агента MainFlow и обновите секцию с инструментами: **RAG_Tools** - Используется, когда нужно ответить на вопросы об услугах и продукции компании, об условиях эксплуатации продукции, об используемых инструментах для монтажа продукции и т.д. **INFO_Tools** - Используется когда пользователь хочет узнать о филиалах компании, контактных данных или времени их работы **TABLE1_Tools** используется для поиска информации и ответов на вопросы о: - Ценах и стоимости переводов - Комиссиях за переводы и платежи - Точных цифрах и числовых данных, хранящихся в локальной базе данных - Сравнении различных параметров (цены, комиссии, характеристики) - Поиске минимальных/максимальных значений (самая низкая комиссия, самая высокая цена и т.д.) - Условиях и тарифах банков-партнеров - Расчетах и вычислениях на основе имеющихся данных Этап 5: Тестирование и результат Примеры работы системы После настройки система сможет отвечать на сложные вопросы с числовыми данными: Простые запросы: "Какая комиссия у банка Кофейный?" "Сколько дней занимает перевод в Желтом банке?" Сложные аналитические запросы: "В каком банке дешевле всего обменять 10 000 долларов?" "Покажи банки с минимальной комиссией валютного контроля" "Какой банк предлагает самые быстрые переводы?" Принцип работы Пользователь задает вопрос о числовых данных Главный агент определяет - нужен TABLE1_Tools SQL-агент генерирует соответствующий запрос к ClickHouse База данных возвращает точные результаты Система формирует понятный ответ для пользователя Преимущества решения Точность данных - никаких выдуманных цифр Сложные вычисления - система может выполнять расчеты любой сложности Масштабируемость - легко добавлять новые таблицы и данные Актуальность - данные всегда свежие из базы Производительность - ClickHouse обеспечивает быстрые запросы Ваша мультиагентная система теперь может работать не только с текстовой информацией, но и предоставлять точные числовые данные и выполнять сложные аналитические запросы.Руководство по работе с базой знаний (RAG) Структура таблицы базы знаний Представьте базу знаний как умный склад информации. Когда нужно полностью "перезагрузить" этот склад, мы поступаем просто: Полная очистка базы знаний: удаляем старую таблицу и создаём точно такую же заново Это как снести старый склад и построить новый по тому же чертежу Гарантирует, что не останется "мусора" от предыдущих данных Размер вектора (embedding): может изменяться в зависимости от выбранного алгоритма векторизации Вектор — это числовое представление смысла текста Разные алгоритмы создают векторы разной длины (как разные форматы фотографий) Создание компонента базы знаний Важно: всегда создавайте компонент для базы знаний, на который будут ссылаться агенты. Думайте о компоненте как о "визитной карточке" вашей базы знаний: После создания в атрибутах появится компонент с описанием базы знаний: Подготовка текстового файла Перед загрузкой файл нужно правильно "подписать" — добавить служебную информацию в начало: Обязательная служебная строка в начале файла: {{Domain: METABOT33}}{{Table: gpt_knowledge_base}}{{chunk_size: 250}}{{chunk_overlap: 160}} Эта строка работает как "инструкция по применению": Domain — область применения (как адрес склада) Table — название таблицы (как название полки на складе) chunk_size — размер кусочка текста для обработки (250 символов) chunk_overlap — перекрытие между кусочками (160 символов для связности) Загрузка и векторизация Процесс состоит из двух этапов: Этап 1: Загрузка файла Система принимает подготовленный файл и сохраняет его содержимое. Этап 2: Векторизация Система превращает текст в числовые векторы для быстрого поиска по смыслу. Важно: сохраните имя defKnowBase — оно понадобится в конфигурации в параметре kbName. Совет: процесс загрузки и векторизации похож на работу переводчика — сначала он читает текст (загрузка), потом переводит его на "язык чисел" (векторизация), чтобы компьютер мог быстро найти нужную информацию по смыслу, а не только по точным словам.Документация по LLMTracer Модуль LLMTracer предназначен для трассировки запросов к LLM, а также для сбора статистики по токенам, времени выполнения и ошибкам. Все данные записываются в таблицу llm_tracer. Класс: Session Подключается через let LLMTracer = require("Common.AIHelpers.LLMTracer") createSession(options) Создаёт новую сессию трассировки. Пример: let session = LLMTracer.createSession({ business_id: "123", bot_id: "456", lead_id: "789", script_id: "script_1", command_id: "cmd_1", agent_name: "MyAgent", provider: "OpenAI", model: "gpt-4" }) Параметры: Имя Тип Описание business_id String Идентификатор бизнеса bot_id String Идентификатор бота lead_id String Идентификатор лида script_id String Идентификатор скрипта command_id String Идентификатор команды agent_name String Имя агента provider String Название провайдера LLM model String Название модели LLM ReturnSession — Экземпляр сессии трассировки. getCurrentSession() Получает текущую сессию из атрибута лида. Пример: let session = LLMTracer.getCurrentSession() Параметры:Нет ReturnSession | null — Текущий объект сессии или null, если не найден. prepareRecordData(data) Преобразует данные в безопасный формат для записи в таблицу. Пример: let safeData = LLMTracer.prepareRecordData({ message: "Тест", status: "ok" }) Параметры: Имя Тип Описание data Object Объект с исходными данными ReturnObject — Объект с преобразованными значениями. recordTrace(traceData) Записывает трассировку в таблицу llm_tracer. Пример: LLMTracer.recordTrace({ agent_name: "MyAgent", outclient_name: "ClientA", step: "step1", outclient_time: 120, provider: "OpenAI", model: "gpt-4", type: "info", message: "Запрос выполнен", record: {}, params: {}, status: "ok", input_tokens: 100, output_tokens: 50 }) Параметры: Имя Тип Описание agent_name String Имя агента outclient_name String Имя внешнего клиента step String Название шага outclient_time Number Время выполнения шага (мс) provider String Название провайдера LLM model String Название модели LLM type String Тип трассировки (info, error и др.) message String Сообщение record Object Дополнительные данные params Object Параметры запроса status String Статус выполнения input_tokens Number Количество входных токенов output_tokens Number Количество выходных токенов ReturnBoolean — true при успехе, false при ошибке. recordTraceLLM(llm, timerCtrl, traceData) Записывает трассировку по активному LLMClient. Пример: LLMTracer.recordTraceLLM(llmClient, "START_TIME", { message: "Старт" }) Параметры: Имя Тип Описание llm Object Экземпляр LLMClient timerCtrl String Контроллер времени ("", "START_TIME", "END_TIME") traceData Object Дополнительные параметры трассировки ReturnBoolean — true при успехе, false при ошибке. recordTraceQuery(llm, timerCtrl, traceData) Записывает трассировку для запросов к внешним сервисам. Пример: LLMTracer.recordTraceQuery(llmClient, "END_TIME", { message: "Финиш" }) Параметры: Имя Тип Описание llm Object Экземпляр LLMClient timerCtrl String Контроллер времени ("", "START_TIME", "END_TIME") traceData Object Дополнительные параметры трассировки ReturnBoolean — true при успехе, false при ошибке. info(message, data) Записывает информационную трассировку. Пример: LLMTracer.info("Запрос выполнен", { step: "step1" }) Параметры: Имя Тип Описание message String Текст сообщения data Object Дополнительные данные ReturnBoolean — true при успехе, false при ошибке. error(message, data) Записывает ошибку в трассировку и отправляет сообщение админу. Пример: LLMTracer.error("Ошибка запроса", { code: 500 }) Параметры: Имя Тип Описание message String Текст ошибки data Object Дополнительные данные ReturnBoolean — true при успехе, false при ошибке. countTokens(dateRange) Подсчитывает количество токенов за указанный период. Пример: LLMTracer.countTokens({ from: "2024-06-01 00:00:00", to: "2024-06-30 23:59:59" }) Параметры: Имя Тип Описание from String Начальная дата ("YYYY-MM-DD HH:MM:SS") to String Конечная дата ReturnObject — { input_tokens, output_tokens, total_tokens } getActiveSessionsCount(minutes) Подсчитывает количество активных сессий за последние N минут. Пример: LLMTracer.getActiveSessionsCount(10) Параметры: Имя Тип Описание minutes Number Глубина окна в минутах (по умолчанию 5) ReturnNumber — Количество активных сессий. Быстрый старт Создайте сессию: LLMTracer.createSession({ ... }) Запишите шаг: LLMTracer.recordTrace({ ... }) Для LLM: используйте recordTraceLLM() Для ошибок: используйте error() Для статистики: используйте countTokens() Аналитика и нагрузки В стандартный шаблон MA_Router входит модуль, который отвечает за контроль нагрузки, лимитов и доступности моделей LLM. Основные проверки Суточный лимит диалогов: LLMDialogCounter.canStartNewDialog(limit=25) — ограничивает количество диалогов на пользователя. Текущая нагрузка: LLMTracer.getActiveSessionsCount(5) — если слишком много активных сессий, диалог откладывается. Активность ИИ: bot.getBoolAttr("ai_is_active") — если ИИ выключен, переводит на резервный сценарий. Логика работы Перед стартом диалога — проверяются лимиты и нагрузка. Если лимит превышен — пользователю отправляется уведомление, диалог переносится. Если нагрузка высокая — диалог откладывается на несколько секунд. При старте диалога — увеличивается счётчик, открывается сессия в LLMTracer. При завершении — сессия закрывается. Метрики и отчёты /aistats для получения аналитики по текущему состоянию системы Пример отчёта: 📊 Статистика LLM Tracer 🕒 За последние 7 дней: • Токены входящие: 2 533 129 • Токены исходящие: 313 036 • Всего токенов: 2 846 165 • Уникальных лидов: 3 • Уникальных сессий: 29 • Среднее вопросов на пользователя: 9.7 • Превышений 20 запросов в сутки: 1 📈 За всё время: • Токены входящие: 3 861 082 • Токены исходящие: 351 484 • Всего токенов: 4 212 566 • Уникальных лидов: 3 • Уникальных сессий: 38 • Среднее вопросов на пользователя: 12.7 • Превышений 20 запросов в сутки: 1 Обновлено: 2025-10-06 18:53:52 Таймауты Для каждого запроса к LLM настраиваются таймауты в конфигурации. При превышении времени ожидания: Фиксация проблемы — информация об ошибке отправляется через Notifier Fallback — сценарий не блокируется, автоматически запускается Fallback-скрипт Продолжение работы — пользователь получает альтернативный ответ без прерывания диалога Таймауты защищают систему от зависаний при проблемах на стороне LLM-провайдера. Быстрые ответы на вопросы Как узнать текущую нагрузку? — Вызвать LLMTracer.getActiveSessionsCount(5). Как фиксируются ошибки? — Через Notifier и запись в LLMTracer. LLMTracer - Плагин для трассировки запросов к LLM Описание LLMTracer - это модуль для трассировки запросов к языковым моделям (LLM) и внешним сервисам. Он позволяет записывать данные о запросах, ответах, ошибках и использовании токенов в таблицу llm_tracer. Установка Импортируйте модуль в ваш код: const LLMTracer = require('Common.Platform.LLMTracer'); Основные возможности Создание сессий трассировки Запись информационных сообщений Запись ошибок Подсчет использованных токенов за указанный период Быстрый старт 1. Создание сессии трассировки // Создание сессии с параметрами по умолчанию const session = LLMTracer.createSession(); // Создание сессии с указанием параметров const session = LLMTracer.createSession({ agent_name: "ChatGPT Assistant", provider: "OpenAI", model: "gpt-4" }); Параметры: options (Object) - Параметры сессии business_id (string|number) - ID бизнеса bot_id (string|number) - ID бота lead_id (string|number) - ID лида script_id (string|number) - ID скрипта command_id (string|number) - ID команды agent_name (string) - Имя агента provider (string) - Провайдер LLM model (string) - Модель LLM 2. Прямая запись трассировки // Прямая запись трассировки с указанием всех параметров LLMTracer.recordTrace({ outclient_name: "OpenAI API", step: 1, outclient_time_sec: 2.5, provider: "OpenAI", model: "gpt-4", type: "info", message: "Запрос выполнен", status: "success", input_tokens: 150, output_tokens: 50 }); Параметры: traceData (Object) - Данные для записи в таблицу outclient_name (string) - Имя внешнего клиента step (number|string) - Шаг выполнения outclient_time_sec (number) - Время выполнения запроса в секундах provider (string) - Провайдер LLM model (string) - Модель LLM type (string) - Тип записи (info, error) message (string) - Сообщение record (string) - Дополнительные данные в формате JSON status (string|number) - Статус выполнения input_tokens (number) - Количество входных токенов output_tokens (number) - Количество выходных токенов 3. Запись информационных сообщений // Запись простого сообщения LLMTracer.info("Запрос к LLM выполнен успешно"); // Запись сообщения с дополнительными данными LLMTracer.info("Запрос к LLM выполнен успешно", { outclient_name: "OpenAI API", input_tokens: 150, output_tokens: 50, outclient_time_sec: 2.5 }); Параметры: message (string) - Информационное сообщение data (Object) - Дополнительные данные для записи outclient_name (string) - Имя внешнего клиента step (number|string) - Шаг выполнения outclient_time_sec (number) - Время выполнения запроса в секундах provider (string) - Провайдер LLM model (string) - Модель LLM status (string|number) - Статус выполнения input_tokens (number) - Количество входных токенов output_tokens (number) - Количество выходных токенов 3. Запись ошибок try { // Ваш код... } catch (error) { LLMTracer.error("Ошибка при запросе к LLM", { error_message: error.message, outclient_name: "OpenAI API" }); } 4. Подсчет токенов // Подсчет токенов за все время const allTokens = LLMTracer.countTokens(); debug(`Всего использовано токенов: ${allTokens.total_tokens}`); // Подсчет токенов за определенный период const tokensForPeriod = LLMTracer.countTokens({ from: "2023-01-01 00:00:00", to: "2023-01-31 23:59:59" }); debug(`Входящие токены: ${tokensForPeriod.input_tokens}`); debug(`Исходящие токены: ${tokensForPeriod.output_tokens}`); debug(`Всего токенов: ${tokensForPeriod.total_tokens}`); Параметры: dateRange (Object) - Объект с параметрами временного диапазона from (string) - Начальная дата в формате "YYYY-MM-DD HH:MM:SS" to (string) - Конечная дата в формате "YYYY-MM-DD HH:MM:SS" Возвращает: Объект с количеством токенов input_tokens (number) - Количество входных токенов output_tokens (number) - Количество выходных токенов total_tokens (number) - Общее количество токенов Структура таблицы llm_tracer Модуль записывает данные в таблицу llm_tracer со следующими полями: business_id - ID бизнеса lead_id - ID лида script_id - ID скрипта session_id - ID сессии agent_name - Имя агента outclient_name - Имя внешнего клиента step - Шаг выполнения outclient_time - Время выполнения запроса в секундах provider - Провайдер LLM model - Модель LLM type - Тип записи (info, error) message - Сообщение record - Дополнительные данные в формате JSON status - Статус выполнения input_tokens - Количество входных токенов output_tokens - Количество выходных токенов created_at - Дата и время создания записи (автоматически) Импортировать таблицу можно по ссылке: https://stage.metabot.dev/business/export/1216/show?bots=&b_c=0&b_o=0&b_i=0&b_ls=0&b_r=0&b_s=0&b_li=0&b_t=0&b_br=0&b_aie=0&b_aee=0&b_sa=0&cts_llm_tracer=1&b_llm_tracer=1Конфигурация Конфигурационный плагин бизнеса (snippet Business.AgentsParams.BSPbConfig) используется для централизованного управления параметрами агентов в системе MAS. Он определяет настройки для различных сценариев работы агентов, включая маршрутизацию, выбор моделей, параметры генерации, обработку ошибок и интеграцию с внешними инструментами. Структура файла Файл представляет собой JavaScript-объект, где каждая ветка соответствует определённому агенту или сценарию. Основные разделы: common — общие параметры агента (имя, таблица промптов, максимальная длина истории, сценарий выхода и др.) detectRoute — параметры для маршрутизации запросов (провайдер, модель, промпт, инструменты маршрутизации, обработчик ошибок) detectIntent — параметры для определения намерения пользователя (провайдер, модель, промпт, обработчик ошибок, база знаний) userReply — параметры для формирования ответа пользователю (провайдер, модель, история, промпты, обработчик ошибок) execSQL — параметры для SQL-агентов (провайдер, модель, промпт, обработчик ошибок) Пример структуры { common: { title: "Основной Flow c маршрутизатором", agentName: "bsp", promptTable: "gpt_prompts", userQueryAttibName: "user_query", historyMaxLength: 4, useRoute: 0, exitScript: "MainFlow_FollowUp", MBQuery_fallback: { script_code: "MBQuery_TimeOut", timeout: 180 } }, detectRoute: { provider: "OpenAI", model: "gpt-5-mini", modelParams: { temperature: 1 }, prompt: "$route_prompt", routerTools: [ ... ], errorScript: "RAG_ErrorFallback" }, detectIntent: { provider: "OpenAI", apiFormat: "OpenAI", model: "gpt-5-mini", modelParams: { temperature: 1 }, prompt: "$rag_intent_prompt", errorScript: "RAG_ErrorFallback", kbName: "defKnowBase", kbDomain: "tech_domain" }, userReply: { provider: "OpenAI", apiFormat: "OpenAI", model: "gpt-5-mini", modelParams: { temperature: 1 }, errorScript: "RAG_ErrorFallback", useHistory: 1, addUserQuery: 1, sendBotAnwser: 1, systemPrompts: { start: [["$start_prompt", "$rag_prompt"]], final: ["$final_prompt"] } } } Как работает подстановка Загрузка snippet: Конфигурация подгружается через snippet с именем Business.AgentsParams.BSPbConfig. Выбор активного агента: В коде определяется активный агент через переменную activeAgent (например, bsp, CompanyInfo, Table1). Инициализация agentCFG: В зависимости от значения activeAgent выбирается соответствующая ветка конфигурации и присваивается переменной agentCFG. Передача параметров: agentCFG используется для инициализации LLMClient, настройки промптов, истории, провайдера, модели и других параметров. Маршрутизация и обработка: Ветка detectRoute определяет инструменты маршрутизации, которые используются для выбора сценария обработки запроса пользователя. Обработка ошибок: Для каждого сценария можно задать обработчик ошибок (errorScript) и fallback-скрипты. Интеграция с базой знаний: Ветка detectIntent может содержать параметры для подключения к базе знаний (kbName, kbDomain). Структура кода let aAgent = lead.getAttr("activeAgent") let agentCFG if (aAgent === "bsp") { agentCFG = { ... } // параметры для bsp } else if (aAgent === "CompanyInfo") { agentCFG = { ... } // параметры для CompanyInfo } else if (aAgent === "Table1") { agentCFG = { ... } // параметры для Table1 } else { bot.sendMessage(`BSPbConfig:snippet - неизвестный activeAgent: ${aAgent}`) bot.stop() } Куда подставляются параметры LLMClient: параметры модели, провайдера, истории, промптов и сценариев подставляются при создании и настройке клиента. Маршрутизатор: инструменты из routerTools используются для выбора сценария обработки. Обработка ошибок: скрипты из errorScript и MBQuery_fallback используются для fallback-логики. Промпты: значения из systemPrompts подставляются в соответствующие методы LLMClient для формирования запроса. База знаний: параметры kbName и kbDomain используются для интеграции с внешними источниками знаний. Рекомендации Все параметры должны быть явно определены для каждого сценария, чтобы избежать ошибок при маршрутизации и генерации ответа. Для расширения функционала добавляйте новые ветки конфигурации с нужными параметрами. FAQ Вопрос: Как добавить нового агента?Ответ: Добавьте новую ветку в объект конфигурации с нужными параметрами и обработчиками. Вопрос: Как изменить модель или провайдера?Ответ: Измените значения model и provider в нужной ветке конфигурации. Вопрос: Как задать fallback-скрипт?Ответ: Укажите параметры в MBQuery_fallback или errorScript для нужного сценария. Вопрос: Как интегрировать базу знаний?Ответ: Добавьте параметры kbName и kbDomain в ветку сценария, где требуется интеграция.Ошибки и отладка В этом документе описаны все основные механизмы обработки ошибок, настройки таймаутов, использование нотификатора, трассировки и отладки. 1. Таймауты: где и как настраиваются Таймауты — это максимальное время ожидания ответа от LLM или внешнего сервиса. Если таймаут превышен, происходит ошибка и запускается обработка сбоя. Где настраиваются: В конфиге агента (agentCFG): timeout: время ожидания в секундах. Пример: MBQuery_fallback: { script_code: "MBQuery_TimeOut", timeout: 180 } В клиенте LLM (LLMClient): Таймаут может задаваться при инициализации клиента или в параметрах запроса. Если таймаут не указан — используется значение по умолчанию (обычно 30-60 секунд). Как работает: Если таймаут превышен: Сценарий не блокируется — пользователь отправляется в выбранный скрипт в котором описана другая логика обработки его запроса 2. Нотификатор: что это и как работает Notifier — это модуль для отправки уведомлений о сбоях и важных событиях админам. Подробная инструкция: см. Документация по Notifier Вызов: Notifier.send({ message, severity, ... }) Используется для ошибок, таймаутов, превышения лимитов. 3. LLMTracer: трассировка ошибок LLMTracer — модуль для логирования всех событий, включая ошибки. Подробная инструкция: см. Документация по LLMTracer При ошибке записывается строка с type=err, status=error, описанием и параметрами запроса. Позволяет анализировать причины сбоев, видеть историю запросов и ответов. Для отладки используйте подробные сообщения и сохраняйте контекст. 4. Режим debug и самостоятельная отладка Если не удаётся найти причину ошибки: Включите режим debug: Перейдите в настройки бота и включите режим отладки. Перейдите в настройки лида и включите нужный режим отладки. В точках падения используйте команды логирования: bot.debug('Debug:' + JSON.stringify(data)) Пройдите путь пользователя вручную: Повторите шаги, которые приводят к ошибке. Проверьте параметры запроса, ответы модели, логи LLMTracer. Используйте тестовые данные и сценарии. Eval - Тестирование Схема работы системы Eval Полная схема флоу с блокировками и таблицами graph TB Start([Пользователь запускает тест]) --> StartRun[Eval_StartRun] StartRun --> CheckRun{Проверка run_status} CheckRun -->|pending| CreateReport[Создать report в eval_reports] CheckRun -->|!pending| Error1[Ошибка: run уже запущен] CreateReport --> UpdateRun[Обновить eval_runs:
status=running, started_at] UpdateRun --> InitLeads[Запустить Eval_InitLead
для каждого run_lead_id] InitLeads --> SetBatchTest[Установить batchTest=1] SetBatchTest --> SaveContext[Сохранить eval_context:
run_id, suite_id, report_id] SaveContext --> ProcessQuestion[Eval_ProcessQuestion] ProcessQuestion --> CheckContext{Есть текущая серия
в контексте?} CheckContext -->|Да| GetNextQuestion[Взять следующий вопрос
из серии] CheckContext -->|Нет| GetUnclaimed[getUnclaimedSeries
report_id, suite_id] GetUnclaimed --> CheckTable1[Проверить eval_answers:
найти свободные серии/вопросы] CheckTable1 --> AvailableList{Есть доступные
элементы?} AvailableList -->|Нет| AggregateReport[Eval_AggregateReport] AvailableList -->|Да| TryLock[Попытка захвата блокировки] TryLock --> LockType{Тип элемента?} LockType -->|Серия| LockSeries["eval_series_runId_seriesIndex
TTL=60s"] LockType -->|Standalone| LockQuestion["eval_q_runId_questionId
TTL=5s"] LockSeries --> CheckLock{Блокировка
получена?} LockQuestion --> CheckLock CheckLock -->|Нет| ReleaseNotNeeded[continue
блокировка не была получена] CheckLock -->|Да| DoubleCheck[Двойная проверка:
проверить eval_answers] ReleaseNotNeeded --> TryLock DoubleCheck --> AlreadyClaimed{Элемент уже
занят?} AlreadyClaimed -->|Да| ReleaseLock[bot.releaseLockForBot
освободить блокировку] AlreadyClaimed -->|Нет| CreateAnswers[Создать записи в eval_answers
status=PROCESSING
для всех вопросов серии] ReleaseLock --> TryLock CreateAnswers --> SaveSeriesContext[Сохранить серию в контекст:
current_series, answerIds] GetNextQuestion --> CheckFirst{Первый вопрос
серии?} SaveSeriesContext --> CheckFirst CheckFirst -->|Да| ClearHistory[Очистить историю mainAgent] CheckFirst -->|Нет| SetQuery[Установить user_query] ClearHistory --> SetQuery SetQuery --> MARouter[MA_Router
обработка вопроса ботом] MARouter --> CheckBatchTest{batchTest==1?} CheckBatchTest -->|Нет| NormalFlow[Обычный flow] CheckBatchTest -->|Да| SaveAnswer[Eval_SaveAnswer] SaveAnswer --> GetSession[Получить session_id
из LLMTracer] GetSession --> SaveActual[Сохранить actual_answer
в eval_answers] SaveActual --> GetMetrics[getTraceMetrics
из llm_tracer] GetMetrics --> SaveMetrics[Сохранить метрики:
latency_ms, tokens, etc.] SaveMetrics --> LockCounter["eval_run_runId_counter
TTL=10s, wait=30s"] LockCounter --> IncrementCounter[incrementProcessedQuestions
в eval_reports] IncrementCounter --> JudgeAnswer[Eval_JudgeAnswer] JudgeAnswer --> CallJudge[Вызов LLM-ассессора] CallJudge --> ParseJSON{Успешно
распарсить JSON?} ParseJSON -->|Да| SaveRatings[Сохранить ratings:
overall, accuracy, etc.
status=COMPLETED] ParseJSON -->|Нет| SaveDefault[Сохранить дефолтные
ratings=50
status=COMPLETED] SaveRatings --> UpdateSeriesIdx[Увеличить current_series_question_idx] SaveDefault --> UpdateSeriesIdx UpdateSeriesIdx --> ProcessQuestion MARouter -->|Ошибка| ErrorFallback[RAG_ErrorFallback] ErrorFallback --> CheckBatchTest2{batchTest==1?} CheckBatchTest2 -->|Да| HandleError[Eval_HandleError] CheckBatchTest2 -->|Нет| NormalError[Обычная обработка ошибки] HandleError --> MarkFailed[markAnswerFailed
status=FAILED
в eval_answers] MarkFailed --> IncrementFailed[incrementFailedQuestions
в eval_reports] IncrementFailed --> ProcessQuestion AggregateReport --> CheckAllProcessed[areAllQuestionsProcessed
report_id, suite_id] CheckAllProcessed --> CheckStatuses[Проверить статусы через table.find:
PENDING, PROCESSING
используя IN условие] CheckStatuses --> CheckSeries[Проверить целостность серий:
все вопросы в финальных статусах
COMPLETED или FAILED] CheckSeries --> AllDone{Все обработано?} AllDone -->|Нет| SendStatusMsg[Отправить статус главному лиду:
обработка продолжается] AllDone -->|Да| FinalizeLock["eval_run_runId_finalize
TTL=60s"] SendStatusMsg --> ExitFlow FinalizeLock --> LockAcquired{Блокировка
получена?} LockAcquired -->|Нет| OtherLeadFinalizes[Другой лид финализирует
и отправит уведомление] LockAcquired -->|Да| FinalizeReport[finalizeReport:
calculateReportStats
status=COMPLETED] OtherLeadFinalizes --> ExitFlow FinalizeReport --> FinalizeRun[finalizeRun:
status=COMPLETED
finished_at] FinalizeRun --> SendNotify[Eval_Notify
отправить уведомление] SendNotify --> UpdateNotify[Обновить notification_sent=1] UpdateNotify --> ExitFlow Note1[Блокировка финализации гарантирует
единственность отправки уведомления] ExitFlow --> End([Завершение]) style Start fill:#e1f5ff style End fill:#e1f5ff style Error1 fill:#ffcccc style HandleError fill:#ffcccc style MarkFailed fill:#ffcccc style LockSeries fill:#fff4cc style LockQuestion fill:#fff4cc style LockCounter fill:#fff4cc style FinalizeLock fill:#fff4cc style NotifyLock fill:#fff4cc style CreateReport fill:#ccffcc style CreateAnswers fill:#ccffcc style SaveRatings fill:#ccffcc style FinalizeReport fill:#ccffcc Схема таблиц и их связи erDiagram eval_runs ||--o{ eval_reports : "has" eval_suites ||--o{ eval_questions : "contains" eval_suites ||--o{ eval_runs : "used_in" eval_reports ||--o{ eval_answers : "contains" eval_questions ||--o{ eval_answers : "answered_by" eval_runs { int id PK int suite_id FK text run_lead_ids "lead1,lead2,lead3" text run_status "pending|running|completed|failed" datetime started_at datetime finished_at } eval_suites { int id PK text name int bot_id } eval_questions { int id PK int suite_id FK text question_text text optimal_answer int series_index "null для standalone" int order_in_series "1,2,3..." } eval_reports { int id PK int run_id FK datetime started_at datetime finished_at int total_questions int processed_questions int failed_questions decimal average_rating text report_status "running|completed|failed" int notification_sent } eval_answers { int id PK int report_id FK int question_id FK text lead_id text session_id text question_text text optimal_answer text actual_answer text answer_status "pending|processing|completed|failed" decimal rating_overall decimal rating_accuracy int latency_ms int input_tokens int output_tokens text error_message } llm_tracer { text session_id PK decimal outclient_time int input_tokens int output_tokens } Схема блокировок и их жизненный цикл sequenceDiagram participant L1 as Lead 1 participant L2 as Lead 2 participant DB as eval_answers participant Lock as Lock System Note over L1,L2: Параллельная обработка вопросов L1->>DB: getUnclaimedSeries(report_id, suite_id) DB-->>L1: [Серия 1, Серия 2, Вопрос 3] L2->>DB: getUnclaimedSeries(report_id, suite_id) DB-->>L2: [Серия 1, Серия 2, Вопрос 3] L1->>Lock: waitForBotLock("eval_series_{runId}_1") Lock-->>L1: true (получена) L2->>Lock: waitForBotLock("eval_series_{runId}_1") Lock-->>L2: false (занята L1) L1->>DB: Двойная проверка: серия свободна? DB-->>L1: Да, свободна L1->>DB: Создать записи status=PROCESSING DB-->>L1: answerIds: [101, 102, 103] L2->>Lock: waitForBotLock("eval_series_{runId}_2") Lock-->>L2: true (получена) L2->>DB: Двойная проверка: серия свободна? DB-->>L2: Да, свободна L2->>DB: Создать записи status=PROCESSING DB-->>L2: answerIds: [104, 105] Note over L1: Обработка вопросов серии 1 L1->>DB: Обновить answer_id=101: actual_answer, status=COMPLETED Note over L2: Обработка вопросов серии 2 L2->>DB: Обновить answer_id=104: actual_answer, status=COMPLETED Note over L1,L2: Блокировки автоматически освобождаются по TTL Note over L1,L2: или при ошибке через releaseLockForBot() Схема обработки ошибок flowchart TD Start[Обработка вопроса] --> Process[MA_Router обрабатывает] Process --> Success{Успешно?} Process --> Timeout{Таймаут?} Process --> Error{Ошибка API?} Success -->|Да| SaveAnswer[Eval_SaveAnswer] SaveAnswer --> Judge[Eval_JudgeAnswer] Judge --> JudgeSuccess{Ассессор
ответил?} JudgeSuccess -->|Да| SaveRatings[Сохранить ratings
status=COMPLETED] JudgeSuccess -->|Нет| SaveDefault[Сохранить дефолт
status=COMPLETED] SaveRatings --> NextQuestion[Следующий вопрос] SaveDefault --> NextQuestion Timeout -->|Да| ErrorFallback[RAG_ErrorFallback] Error -->|Да| ErrorFallback ErrorFallback --> CheckBatch{batchTest==1?} CheckBatch -->|Нет| UserError[Показать ошибку
пользователю] CheckBatch -->|Да| HandleError[Eval_HandleError] HandleError --> MarkFailed[markAnswerFailed
status=FAILED
error_message] MarkFailed --> IncrementFailed[incrementFailedQuestions] IncrementFailed --> NextQuestion NextQuestion --> CheckMore{Есть ещё
вопросы?} CheckMore -->|Да| Process CheckMore -->|Нет| Aggregate[Eval_AggregateReport] Aggregate --> CheckAll{Все вопросы
обработаны?} CheckAll -->|Нет| Wait[Ждать завершения
других лидов] CheckAll -->|Да| Finalize[Финализация report] style Error fill:#ffcccc style Timeout fill:#ffcccc style HandleError fill:#ffcccc style MarkFailed fill:#ffcccc style Success fill:#ccffcc style SaveRatings fill:#ccffcc style Finalize fill:#ccffcc Схема статусов вопросов stateDiagram-v2 [*] --> PENDING: Создан в claimSeries PENDING --> PROCESSING: Захвачен лидом PROCESSING --> COMPLETED: Успешно обработан
и оценён PROCESSING --> FAILED: Ошибка при обработке COMPLETED --> [*] FAILED --> [*] note right of PROCESSING Блокировка активна TTL: 5s (вопрос) или 60s (серия) end note note right of COMPLETED Финальный статус Включает ratings и метрики end note Схема параллельной обработки (Run Leads Pool) graph LR subgraph "Run Leads Pool" L1[Lead 1] L2[Lead 2] L3[Lead 3] end subgraph "Общий Report" R[(eval_reports
report_id=1)] end subgraph "Вопросы Suite" Q1[Серия 1: Q1, Q2, Q3] Q2[Серия 2: Q4, Q5] Q3[Вопрос 6] Q4[Вопрос 7] end subgraph "Блокировки (run_id=5)" B1[eval_series_5_1] B2[eval_series_5_2] B3[eval_q_5_6] B4[eval_q_5_7] end L1 -->|claimSeries| B1 L2 -->|claimSeries| B2 L3 -->|claimSeries| B3 B1 --> Q1 B2 --> Q2 B3 --> Q3 Q1 --> R Q2 --> R Q3 --> R L1 -.->|Параллельно| L2 L2 -.->|Параллельно| L3 style R fill:#ccffcc style B1 fill:#fff4cc style B2 fill:#fff4cc style B3 fill:#fff4cc style B4 fill:#fff4cc Ключевые моменты Блокировки Все блокировки привязаны к run_id для изоляции параллельных запусков Формат: {prefix}_{runId}_{identifier} TTL: 5s для вопросов, 60s для серий, 60s для финализации Освобождаются автоматически по TTL или через bot.releaseLockForBot() Таблицы eval_runs - запуски тестов eval_reports - отчёты (один на run) eval_answers - ответы на вопросы (много на report) eval_questions - вопросы из suite llm_tracer - метрики производительности Обработка ошибок Ошибки обрабатываются через Eval_HandleError Вопрос помечается как FAILED с error_message Тест продолжается со следующим вопросом Не влияет на другие лиды в пуле FAILED вопросы можно переобработать (не считаются занятыми) Оптимизация запросов Используется table.find с условием IN для проверки статусов Заменены filter/map на прямые запросы к БД где возможно Проверка активных статусов: ["answer_status", "IN", ["pending", "processing", "completed"]] Проверка финальных статусов: ["answer_status", "IN", ["completed", "failed"]] Серии vs Standalone Серии захватываются целиком (все вопросы сразу) Standalone вопросы захватываются по одному История очищается перед началом новой серии Целостность серий проверяется при финализации