Как приручить LLM. Ai agents.. Ai agents. conversational ai.. Ai agents. conversational ai. github.. Ai agents. conversational ai. github. llm.. Ai agents. conversational ai. github. llm. Natural Language Processing.. Ai agents. conversational ai. github. llm. Natural Language Processing. Open source.. Ai agents. conversational ai. github. llm. Natural Language Processing. Open source. python.. Ai agents. conversational ai. github. llm. Natural Language Processing. Open source. python. responses api.. Ai agents. conversational ai. github. llm. Natural Language Processing. Open source. python. responses api. software architecture.. Ai agents. conversational ai. github. llm. Natural Language Processing. Open source. python. responses api. software architecture. Structured Output.. Ai agents. conversational ai. github. llm. Natural Language Processing. Open source. python. responses api. software architecture. Structured Output. Развитие стартапа.
  • Пробовали сделать цифрового сотрудника на LLM?

  • У вас получилось?

  • Долго старались?

  • Насколько он качественный?

  • Сколько он стоит в обслуживании?

Очень много вопросов возникает к технологии ведения диалогов нейросетями.

- Ты всегда следуешь скрипту и не импровизируешь.

– Ты всегда следуешь скрипту и не импровизируешь.

ТыжИИ! Сделай хорошо, быстро, дешево!

Сейчас технология LLM переживает бум. Тот случай, когда предложение порождает спрос само на себя. У бизнеса много запросов на создание ботов для общения с людьми: боты-консультанты, боты-продажники, боты-психологи, боты-планировщики, боты-астрологи и т.д. При всём многообразии запросов и многообразии LLM я не смог найти достойного решения для простой задачи: как заставить бота следовать скрипту? Даже самый недалекий человек легко справляется с задачей, когда у него есть четко прописанная инструкция. Но даже самая умная на сегодняшний день LLM не следует инструкции. И чем длиннее скрипт для сотрудника, тем сложнее заставить нейросеть его соблюдать.

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

При разработке своего бота я столкнулся с узкими рамками борьбы между стоимостью и качеством диалога. Я не мог позволить себе строить сложную агентскую сеть для решения довольно простой задачи – следовать скрипту. И тогда я решил «приземлить» LLM к скрипту более дешевым и эффективным способом, не сжигая лишние токены, а задав структуру сценария жестко в логике бота.

Приземляем LLM

Каких-то вменяемых готовых решений беглый обзор GitHub не выявил. Тогда я решил сделать своего агента «с блэкджеком и дешевыми токенами», который будет следовать четко установленной инструкции. И, поскольку решаемая проблема следования инструкциям типовая для самых разных применений, решать задачу я решил в общем виде. Идею сформулировал так: “Нужна библиотека для построения чат-ботов, которые смогут вести диалог по заранее определенному сценарию. При этом сценарий должен храниться отдельно от кода и быть легко заменяемым.” Движок – отдельно, предметная – область отдельно. Главная идея: Граф ведёт, модель исполняет.

Код можете найти на github: https://github.com/chechestor/tg-statemachine-bot. В репозитории открыт раздел с обсуждениями, добро пожаловать.

В основу были заложены следующие принципы:

  1. Весь диалог разбивается на этапы, нет общения вне этапа диалога.

  2. Этапы объединены в граф с направленными переходами. Из этапа может быть несколько выходов в зависимости от результатов этапа.

  3. У каждого этапа есть определенная цель. Как правило, это получение некоторой информации из ответов собеседника.

  4. Входная и выходная информация каждого этапа организована в именованные переменные. Выходные переменные одних этапов могут быть входными переменными других этапов.

  5. Общение на каждом этапе ведет LLM. Она же принимает решение о необходимости перехода на следующий этап, формируя соответствующий сигнал перехода.

Граф общения бота.

Граф общения бота.

Так в основу архитектуры легли три модуля:

  • fsm – (Finite State Machine) машина состояний пользователя. В ней хранится граф состояний диалога и текущее состояние пользователя.

  • vars_memory память переменных диалога.

  • conversation_core – собственно LLM-болталка. Оркестратор для fsm и vars_memory.

Conversation_core. Особенности оркестрации.

Деление инструкции по этапам – это основной механизм, который позволяет LLM работать по скрипту любого объема. За счет того, что в конкретный момент времени модели передается только инструкция текущего этапа.

Инструкция для вызова LLM собирается как композиция:

  • общая роль и правила (common.md);

  • инструкция текущего этапа;

  • только те входные переменные, которые для этапа явно прописаны (stage_input);

  • прогресс этапа: что уже заполнено, чего ещё нет;

  • доступные сигналы перехода.

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

  • response_message – что сказать пользователю;

  • fsm_signal– какой переход совершить (или null, если ещё рано);

  • stage_result– структурированные данные этапа;

  • stage_summary – саммари при завершении этапа.

Как известно, LLM умеют нарушать инструкции, а иногда и врать. Даже если в инструкции четко описаны все сигналы, допустимые для текущего состояния, модель может выдать несуществующий (я называю это «на основании собственного опыта»). Поэтому в conversation_core вокруг вызова LLM дополнительно введена обвязка, которая при обнаружении нарушений контракта делает перезапросы в модель от роли developer, указывая на проблему и требуя исправить её. К таким ошибкам относятся, например: нарушение JSON-схемы ответа, несуществующие сигналы перехода, отсутствие результатов этапа при попытке перехода. Для связанности диалога я решил не «изобретать велосипед», а воспользоваться готовым решением – ведением цепочки Responses API через previous_response_id. Так даже при переходе между этапами сохраняется адекватность общения без резких смен темы, переспрашиваний и т.п. Одновременно такое решение уменьшает расходы за счет cache-read с более дешевой ставкой. В ходе работы над кодом обнаружилась потребность применять LLM не только для общения, но и для агрегации ранее полученных знаний. Поэтому пришлось выделить отдельный вид этапов – так называемые технические этапы, на которых модель без видимой для собеседника активности «что-то обдумывает внутри себя». Например, когда нужно составить отчет по этапу и сохранить его в переменные.

vars_memory

С переменными всё просто – это обычное хранение значений по ключу, где имя переменной является ключом.

Можно было воспользоваться готовыми БД, но было желание сделать ещё и историю изменений переменных, поэтому сразу заложился на отдельный модуль. Кроме того, не хотелось тащить в проект ещё одну БД.

fsm. Описание инструкции

Основное назначение модуля – ориентироваться по состояниям общего скрипта и предоставлять данные только актуального этапа. Общая схема диалога описана в виде YAML-файла. Объемные инструкции этапов вынесены в отдельную папку /instructions/. YAML и инструкции этапов – этого достаточно для того, чтобы сменить прикладную область бота – сам движок менять не нужно.

Как с этим работать

Немного о практиках, которые я для себя выработал, фтыкая в проект.

Писать YAML своими руками оказалось максимально скучно и опасно для психики разработчика, а иногда и для физического здоровья окружающих. Поэтому разработку самого YAML сразу стоит поручить вашей любимой LLM. Она с этим справляется отлично.

Но вам надо будет как-то контролировать результат же. Но даже читать YAML своими глазами не советую, утомляет. Чтобы ориентироваться в нейрослопе, пришлось разработал небольшой скрипт /tools/generate_fsm_drawio.py. Скрипт генерирует из YAML диаграмму в формате draw.io, вполне удобную для анализа человеком и контроля результата работы нейросети.

Для тестового периода необходим сбор логов диалогов тестировщиков, чтобы оценивать качество ответов и адекватность поведения бота. Для этого логи собираются в папку /data/chat_logs. Просматривать голый текст глазами оказалось вредно для зрения. Поэтому решил немного «облагородить» логи и разработал небольшой вьюер /tools/view_log.html. Он отображает переписку в виде, похожем на привычный чат, а также выводит спойлеры с системным логом. Удобно смотреть переходы между состояниями. При отладке на локальном ПК можно также включить автообновление, чтобы наблюдать лог в реальном времени.

Пример применения

В репозитории выложен код бота-аналитика. Цель бота – помочь разработчику пет-проекта с постановкой задачи на разработку. Скрипт проводит пользователя по этапам разбора требований, задавая вопросы, которыми начинающие соло-фаундеры часто не имеют привычки задаваться. Этот бот-аналитик не претендует на звание «бота №1» среди аналогичных решений, а приведен лишь как пример применения библиотеки conversation_core.

Итог применения conversation_core получился довольно приятным: на каждое сообщение пользователя приходится примерно 1,03 вызова LLM, что довольно недорого. Бот держит линию диалога, следует скрипту и собирает информацию именно так, как я того и хотел. Он не идеален, есть известные косяки, в том числе для демобота я забил промт инжениринг. Проект есть куда развивать, и, я уверен, обязательно найдется читатель, который лучше меня ориентируется в ботостроении. Буду рад вашим комментариям, отзывам и предложениям.

Автор: chekz

Источник