Прямой вызов LLM для обработки сложных пользовательских запросов быстро упирается в три стены: экспоненциальный рост стоимости токенов, неконтролируемые галлюцинации и потеря связности при многокомпонентных инструкциях. Решение - архитектурный пайплайн, который разбивает свободный текст на атомарные действия, маршрутизирует их через специализированных агентов и выстраивает граф зависимостей с каскадной обработкой ошибок. На примере D&D-бота разберем, как этот подход превращает реплику «беру зелье, пью и атакую орка топором» в строго детерминированный сценарий с проверкой инвентаря, состояния мира и автоматическим прерыванием цепочки при невозможности любого шага.
Почему простого вызова LLM недостаточно: три ключевые проблемы
Наивный подход - отправлять всю историю игры и состояние мира в каждом запросе - работает на прототипах и ломается на реальных сценариях. Три проблемы проявляются системно, и каждая по отдельности способна сделать продукт непригодным к использованию.
Стоимость токенов: почему контекст дорожает экспоненциально
Предположим, D&D-бот обрабатывает сессию из 50 ходов. Каждый ход игрок получает полный дамп состояния: описание локации, инвентарь, характеристики персонажа, историю взаимодействий. При средней длине контекста в 4000 токенов на запрос и стоимости GPT-4o $2.50/1M входных токенов одна сессия обходится в $0.50 только на обработку ввода. Для 1000 активных игроков в месяц это $500 прямых затрат на API - без учета выходных токенов и накладных расходов.
Пайплайн с распределенным контекстом решает проблему иначе. Агент инвентаря получает только слоты рюкзака, агент боя - характеристики оружия и противника, агент перемещения - граф локаций. Каждый запрос содержит ровно тот объем данных, который нужен для выполнения одной атомарной операции. Суммарный расход токенов снижается в 3-5 раз по сравнению с монолитным подходом.
Галлюцинации и потеря контроля: когда модель «забывает» правила
Игрок пишет: «Достаю из сумки зелье невидимости и крадусь мимо стражи». В инвентаре зелья нет - персонаж использовал его три хода назад. Монолитная LLM, получив длинный промпт с правилами игры, историей и текущим состоянием, с вероятностью 15-20% проигнорирует проверку и сгенерирует сцену успешного прохождения. Причина известна: модели трудно удерживать жесткие ограничения в длинном контексте, особенно когда нарративная инерция подталкивает к «интересному» продолжению.
Пайплайн устраняет этот класс ошибок через атомизацию и валидацию. Запрос разбивается на два действия: «использовать(зелье невидимости)» и «переместиться(мимо стражи, скрытно)». Агент инвентаря перед выполнением проверяет фактическое наличие предмета. Зелья нет - агент возвращает ошибку, и второй шаг не выполняется. Игрок получает сообщение: «Вы шарите в сумке, но зелья невидимости там нет. Стражник замечает ваше замешательство». Никакой галлюцинации, никакого нарушения правил.
Подобный подход к проектированию предсказуемых систем мы разбирали в статье о самостоятельной разработке AI-агентов, где оркестрация и разделение ответственности дают контроль над каждым этапом обработки.
Архитектура LLM-пайплайна: три этапа превращения текста в действия
Пайплайн строится как конвейер с тремя последовательными стадиями. Каждая стадия - независимый модуль, который можно тестировать, заменять и масштабировать отдельно. Общая схема: свободный текст → атомизированные действия → маршрутизация по агентам → граф зависимостей → исполнение с валидацией.
Атомизация запроса: разбиваем реплику на неделимые действия
Первый этап получает на вход реплику игрока и возвращает список атомарных операций. Для этого используется легковесная LLM (например, GPT-4o-mini или локальная модель) со строгим промптом, который запрещает интерпретацию и требует только структурного разбора.
Пример промпта для атомизатора:
Разбей реплику игрока на атомарные действия в формате JSON.
Каждое действие должно содержать тип, цель и параметры.
Не добавляй действия, не упомянутые в реплике явно.
Не проверяй возможность выполнения.
Реплика: "Я беру меч из сундука и атакую гоблина"
Ответ:
[
{"action": "take", "target": "sword", "source": "chest"},
{"action": "attack", "target": "goblin", "weapon": "sword"}
]
Результат - структурированный список, который можно программно валидировать до передачи следующим этапам. Никакой нарративной обработки на этом шаге не происходит, что исключает ранние галлюцинации.
Роутинг специализированных LLM-агентов: каждый агент - узкий эксперт
После атомизации каждое действие направляется своему агенту. Роутер - детерминированный классификатор, который по типу действия выбирает обработчика: take → InventoryAgent, attack → CombatAgent, move → MovementAgent, use → ConsumableAgent.
Каждый агент работает с ограниченным контекстом. CombatAgent знает характеристики оружия, брони и модификаторы урона, но не имеет доступа к содержимому рюкзака. InventoryAgent оперирует слотами и весами предметов, но не рассчитывает боевые сцены. Такое разделение дает три преимущества:
- Меньше токенов. Контекст каждого агента в 5-10 раз короче полного состояния мира.
- Меньше галлюцинаций. Узкая специализация снижает вероятность пересечения несвязанных правил.
- Независимая замена. Можно обновить CombatAgent на более мощную модель, не трогая остальные.
Механизм роутинга может быть реализован как простой словарь соответствий или как еще один вызов LLM для нестандартных действий. Практика показывает, что для 95% игровых сценариев хватает жесткого маппинга, а оставшиеся 5% обрабатываются fallback-агентом с расширенным контекстом.
Граф зависимостей действий: определяем порядок выполнения
Атомизированные действия не всегда независимы. Реплика «беру меч и атакую гоблина» подразумевает, что атака возможна только после успешного получения оружия. Граф зависимостей формализует эти отношения: каждый узел - действие, каждое ребро - предусловие.
Построение графа выполняется после атомизации. Для каждой пары последовательных действий проверяется: использует ли действие N+1 результат действия N? Если да - создается зависимость. Параллельные действия (например, «беру меч и поднимаю щит») могут выполняться одновременно, если не конфликтуют за ресурсы.
Каскадная обработка ошибок встроена в граф на уровне исполнения. Если действие «взять(меч, сундук)» возвращает ошибку (сундук пуст), все зависимые узлы автоматически отменяются. Игрок получает сообщение о точке сбоя и причине, а не нарратив с выдуманным мечом. Этот подход перекликается с идеями из нашего разбора четырех этапов RAG-пайплайна, где каждый шаг верификации предотвращает каскадное размножение ошибок.
D&D-бот в действии: пошаговый разбор обработки реплики
Возьмем реплику игрока: «Я беру зелье из рюкзака, пью его и затем атакую орка топором». Проследим полный путь через пайплайн.
Шаг 1. Атомизация. Атомизатор возвращает три действия:
{"action": "take", "target": "health_potion", "source": "backpack"}{"action": "use", "target": "health_potion"}{"action": "attack", "target": "orc", "weapon": "axe"}
Шаг 2. Роутинг. Роутер направляет действие 1 агенту инвентаря, действие 2 - агенту расходников, действие 3 - боевому агенту.
Шаг 3. Построение графа. Анализатор зависимостей выстраивает цепочку: 1 → 2 → 3. Действие 2 требует зелье в активной руке (результат действия 1). Действие 3 требует, чтобы персонаж был жив и имел топор (проверка состояния, не зависящая от первых двух шагов, но выполняемая после них для сохранения порядка).
Шаг 4. Исполнение с валидацией. Агент инвентаря проверяет наличие health_potion в рюкзаке. Предмет найден - перемещается в слот активной руки, генерируется сообщение «Вы достаете пузырек с красной жидкостью». Агент расходников применяет эффект: +15 HP, зелье удаляется из инвентаря. Боевой агент проверяет состояние орка (жив, в радиусе атаки), рассчитывает бросок d20 с модификаторами и генерирует исход: «Топор обрушивается на плечо орка, нанося 8 единиц урона».
Обработка ошибок: что происходит, если действие невозможно
Модифицируем сценарий: игрок пытается достать зелье, которого нет в рюкзаке. Агент инвентаря на шаге валидации обнаруживает отсутствие health_potion в слотах. Возвращается ошибка с кодом ITEM_NOT_FOUND и сообщением «Вы не находите зелья в рюкзаке». Граф зависимостей помечает действия 2 и 3 как отмененные. Игрок получает: «Вы шарите в рюкзаке, но зелья там нет. Орк тем временем замахивается дубиной».
Система не пытается «додумать» альтернативу. Это принципиальное решение: детерминированное прерывание надежнее, чем креативная галлюцинация. Для задач, где допустима вариативность в рамках правил, можно добавить recovery-агента, который предложит легальные альтернативы (например, «использовать свиток лечения»), но это отдельный модуль, включаемый осознанно.
Когда применять такой пайплайн: границы применимости и альтернативы
Описанная архитектура оправдана при сочетании трех условий: многокомпонентные запросы пользователя, жесткие правила валидации и ограниченный бюджет на токены. Типичные сценарии - игровые AI-мастера, симуляторы с инвентарем и крафтом, образовательные тренажеры с проверкой шагов, корпоративные ассистенты с multi-step инструкциями.
Для простых диалоговых систем (FAQ-бот, генератор идей) пайплайн избыточен. Монолитный вызов LLM с хорошо составленным промптом справляется быстрее и дешевле. Агентные фреймворки вроде LangChain занимают промежуточную позицию: дают гибкость, но добавляют накладные расходы на сериализацию состояний и не всегда обеспечивают детерминированность на уровне графа зависимостей. Наш анализ пайплайна верификации AI-агентов для багхантинга подтверждает: чем сложнее цепочка решений, тем важнее архитектурное разделение этапов, а не надежда на «умную» модель.
Накладные расходы на разработку значительны: нужно спроектировать агентов, написать валидаторы, отладить граф зависимостей. Но после внедрения поддержка обходится дешевле, чем постоянная борьба с галлюцинациями монолита и перерасходом токенов. Для команды из двух разработчиков прототип пайплайна на 5 агентов реализуется за 2-3 недели.
Ключевые выводы: что мы получаем на практике
Архитектура LLM-пайплайна с атомизацией, роутингом и графом зависимостей дает три измеримых результата. Снижение стоимости токенов в 3-5 раз за счет распределенного контекста - каждый агент получает только релевантные данные. Радикальное сокращение галлюцинаций благодаря специализации: узкий агент с ограниченным контекстом ошибается в валидации предметов менее чем в 2% случаев против 15-20% у монолитной модели. Детерминированное выполнение сложных сценариев с автоматическим прерыванием при ошибке - игрок всегда получает сообщение о точке сбоя, а не выдуманное продолжение.
D&D-бот - проверенный пример, но архитектура универсальна. Любая система, где пользователь подает многокомпонентные инструкции, а правила требуют строгой проверки, выигрывает от перехода к пайплайну. Первый шаг к внедрению - атомизация запросов и один специализированный агент для самого проблемного этапа. Дальше граф зависимостей и каскадная обработка ошибок достраиваются итеративно, по мере роста сложности сценариев.