ИИ-мастер для настольной RPG: баланс вероятностей, детерминированного кода и строгих границ JSON
Интеграция языковых моделей в механику настольных ролевых игр создает уникальный вызов на стыке вероятностного прогнозирования и строгой логики. Разработчик проекта 'Абсурдия' демонстрирует, как переносить управление состоянием героя и обработку случайных факторов (броски кубика) на бэкенд, чтобы избежать потери данных моделью и обеспечивать честность игрового процесса. Статья раскрывает архитектурные решения, позволяющие ИИ генерировать нарратив, в то время как код гарантирует точность расчётов здоровья, характеристик и инвентаря.
# ИИ-мастер для настольной RPG: когда код управляет реальностью, а нейросеть — сюжетом
Создание браузерной текстовой ролевой игры, где ведущим выступает языковая модель, на первый взгляд кажется простой задачей: отправить историю и лист персонажа и получить ответ. Однако на практике самые сложные вызовы возникают не в промптах вроде «напиши смешно», а на грани между вероятностной природой нейросети и жесткими правилами игровых систем.
В проекте «Абсурдия» используется стек Node.js 24, встроенный node:sqlite и API OpenRouter. Основная цель была достигнута путем четкого разделения ответственности: модель отвечает за повествование и генерацию идей, а детерминированный код контролирует все числовые значения, проверяет границы баланса и обрабатывает броски кубиков.
Разделение прав: код над моделью
Изначальный подход, когда модель получала полный лист персонажа и отвечала свободным текстом, оказался нестабильным. Языковая модель склонна к «галлюцинациям» памяти: она может забыть о найденном предмете, присвоить герою заведомо невозможный уровень защиты или исказить финансовое состояние после нескольких ходов.
Решение заключалось в том, чтобы модель возвращала строгий JSON, содержащий только изменения состояния, а не абсолютные значения. Структура ответа включает: * Narration: Текстовое описание событий. * Check: Блок проверки характеристик (характеристика, сложность, результат). * Данные: Изменения здоровья, инвентаря или фактов сюжета. * Scene: Ключи для визуального оформления хода.
Таким образом, модель придумывает, что произошло в мире, а движок игры решает, сколько это стоит ресурсами. Код реализует жесткие правила: броня снижает урон не более чем в два раза, характеристики имеют лимиты, а предметы из редактора имеют потолок бонусов. Кроме того, важные факты (например, диалоги) хранятся в «хронике» — компактном списке событий, который добавляется в промпт следующего хода, позволяя сохранить контекст без перегрузки контекстного окна.
Оптимизация запросов: бросок кубика до ответа
В ранней версии игры ход состоял из двух шагов: сначала модель решала, нужна ли проверка и какой должна быть сложность, а затем игрок бросал кубик, и только потом модель формировала финальный рассказ с учетом результата. Это означало двойную стоимость API и заметную задержку.
Оптимизированный подход перенял логику ролевой игры на сервер: бросок кубика d20 выполняется заранее, до отправки запроса к нейросети. Результат вместе с бонусами характеристик включается прямо в системный промпт: КУБИК: выпало 14, с бонусом Харизмы итог 16. Модель уже пишет рассказ, основываясь на данном числе, а не на предположениях.
Для сохранения тайны для игрока сервер отдает часть ответа, скрытую от пользователя (например, факт успеха или провала), показывая только требования к проверке и анимацию броска. Итоговое сообщение открывается после анимации, экономя ресурсы и создавая эффект напряжения. Если модель ошибочно пишет «успех» при провале, сервер корректирует сложность проверки постфактум, чтобы арифметика совпала с текстом.
Техническая справка: Детерминизм
В контексте разработки игр важно различать вероятностные модели (нейросети, которые предсказывают наиболее вероятные последующие токены) и детерминированные системы (коп, где один и тот же ввод всегда дает один и тот же выход). В данном случае случайность (бросок кубика) вынесена на предобработку, превращая вероятностный процесс в детерминированный расчет внутри промпта.
Борьба с багом: здоровье, которое умножалось
Тестировщики обнаружили критический баг: при увеличении максимального здоровья героя его значение начинало удваиваться на каждом этапе лечения. Причина кроется в природе языковых моделей, которые часто интерпретируют числовые значения в ответе как итоговые состояния, а не как дельты (разницу).
В промпте было указано, что поля здоровья и денег должны отражать изменения, но отсутствие четкого указания для поля max_hp привело к двусмысленности. Модель, видя запись max_hp: 20 вместо существующих 10, считала это целевым значением и прибавляла разницу. Движок же, следуя логике изменений, применял это как добавление к текущему значению.
Для решения проблемы были внедрены два уровня защиты: 1. Уточнение промпта: В список изменений явно добавлено поле max_hp с правилом менять его редко (не более чем на четверть) и только в контексте лечения или отдыха. 2. Защитный код (Sanitization): На стороне сервера реализована функция maxHpDelta, которая анализирует присланное число. Если оно превышает допустимый шаг изменения (например, ±25% от текущего значения), код интерпретирует его как абсолютную цель и пересчитывает дельту, ограничивая изменение безопасными границами. Дополнительно, если максимум растет, текущее здоровье также увеличивается на ту же величину, чтобы изменения были видимы игроку.
Этот кейс подчеркивает необходимость явного типа данных (дельта или абсолютное значение) для каждого числового поля в ответах модели и обязательной проверки на стороне кода.
Стилизация ведущего: роль контекста
Последним аспектом разработки стало внедрение различных стилей для ИИ-мастера: от классического повествования до «Угара» или «Эпоса». Изначально блок описания стиля, размещенный в середине промпта, игнорировался моделью в пользу правил механики и формата JSON.
Эффективность была достигнута благодаря трем изменениям: 1. Перемещение акцента: Блок стиля перенесен в самый конец системного промпта с явной инструкцией о его приоритете над стандартным тоном. 2. Дублирование в контексте: Прямо перед действием игрока добавлена короткая строка-напоминание, например: (Стиль ведущего: Хам.). 3. Адаптация объема: Для каждого стиля определено ожидаемое количество токенов в ответе, учитывая специфику жанра (например, «Хаму» нужно больше места для шуток, а «Документалке» — для пауз).
Эти простые правки позволили кардинально изменить атмосферу игры при минимальных затратах ресурсов.
Заключение
Проект «Абсурдия» демонстрирует, что успешная интеграция ИИ в сложные механики требует жесткого архитектурного контроля. Модель должна оставаться творцом сюжета, в то время как код выступает арбитром реальности, обеспечивая честность, баланс и стабильность игрового состояния. Разделение ответственности, предварительный расчет случайностей и строгая валидация данных на стороне сервера — ключевые принципы создания качественного гибридного игрового движка.
Для тех, кто хочет увидеть реализацию в действии, проект доступен по ссылке. Авторы открыты для вопросов по архитектуре и промпт-инженерингу.