Архитектура ИИ-мастера для настольной RPG: как код спасает баланс от хаоса LLM

Habr AI · оригинал

Материал подготовлен автоматизированной редакционной системой. Факты можно сверить по указанному первоисточнику.

Разработчик браузерной текстовой RPG «Абсурдия» описывает технические решения на стыке вероятностных языковых моделей и детерминированной игровой механики. Ключевым принципом стала строгая разграничение ролей: модель отвечает за нарратив, а серверный код — за точность расчетов, что позволило устранить ошибки баланса и оптимизировать задержку ответа.

Материал демонстрирует практический подход к интеграции LLM в сложные интерактивные системы, где критически важна предсказуемость. Опыт автора показывает, как избежать типичных проблем галлюцинаций в числовых данных и улучшить UX за счет архитектурных решений, таких как предварительный рандомизация и строгая валидация JSON-ответов.

Создание браузерной текстовой ролевой игры, где ведущим выступает языковая модель, кажется простой задачей: достаточно передать модели историю и лист персонажа. Однако на практике самые сложные проблемы возникают не в генерации текста, а на стыке вероятностной природы LLM и детерминированной игровой механики. Разработчик проекта «Абсурдия» описывает четыре ключевых узла, требующих особого внимания, и способы их решения с использованием стека Node.js 24, Express и встроенного SQLite.

Первая и фундаментальная проблема — попытка доверить модели управление игровым состоянием. Изначальная версия, где LLM должна была сама обновлять здоровье, инвентарь и деньги, быстро давала сбои: модель забывала предметы или выдавала нереалистичные бонусы. Решение заключается в строгом разделении ответственности. Модель возвращает структурированный JSON, содержащий только нарратив и описание изменений (дельты), а не итоговые значения. Серверный движок применяет эти изменения, проверяя их на соответствие жестким игровым ограничениям: броня не может снизить урон более чем вдвое, а характеристики имеют верхние пределы. Таким образом, модель отвечает за то, что произошло, а код решает, сколько это стоит в игровых единицах.

Вторая оптимизация касается экономии ресурсов и снижения задержки. Вместо двух запросов к модели (один для определения необходимости проверки, второй для рассказа с учетом броска кубика), разработчик внедрил механизм предварительного рандомизации. Сервер бросает d20 до обращения к LLM и передает результат в промпт. Модель сразу формирует ответ с учетом исхода, а сервер «запечатывает» его. Игрок видит анимацию броска, но текст рассказа открывается без нового сетевого запроса. Это требует аккуратной работы с потоковой выдачей, чтобы не раскрыть исход до момента нажатия кнопки игроком.

Третья проблема связана с логическими ошибками в интерпретации числовых полей. Тестировщики обнаружили баг, при котором максимальное здоровье персонажа удваивалось после лечения. Причина крылась в неоднозначности промпта: модель воспринимала итоговое значение как дельту. Исправление потребовало двухуровневого подхода: уточнения инструкций для модели и добавления защитной логики в коде, которая ограничивает изменение max_hp диапазоном ±25% от текущего значения. Любое число вне этого диапазона автоматически интерпретируется как абсолютное значение и конвертируется в корректную разницу.

Наконец, автор описывает борьбу за сохранение уникального стиля ведущего (например, «Хам» или «Эпос»). Изначально стили звучали одинаково, так как блок описания тона находился в середине длинного системного промпта и терялся. Перенос инструкции о стиле в самый конец промпта и добавление короткого напоминания прямо перед действием игрока («Стиль ведущего: Хам») радикально улучшили результат. Это подтверждает, что для LLM критически важна позиция важных инструкций в контексте.

Итоговый опыт разработки показывает, что успешная интеграция ИИ в игры требует не просто написания промптов, а построения надежной архитектуры, где код выступает арбитром правил, а модель — лишь источником творческого контента. Явные типы данных (дельта или абсолют) и серверная валидация являются обязательными элементами для стабильной работы.