Открыл бету AI-Мастера для D&D. Главная проблема оказалась не в кубиках, а в памяти

от автора

Что значит «открыть ОБТ» для пет-проекта

Чтобы тестеры реально играли, а не упёрлись в платный барьер на втором ходу, я раздал всем стартовый бонус внутренней валюты — маны. Хватает примерно на сотню ходов. Логика простая: дайте человеку пройти достаточно, чтобы он наткнулся на настоящие проблемы игры, а не на «закончились бесплатные попытки, платите».

Цифры первых дней

Вот что показал дашборд OpenRouter с момента запуска:

  • 32 тысячи запросов к моделям

  • 91,4 миллиона токенов

Статистика запросов 13.06-18.06

Статистика запросов 13.06-18.06

Оговорюсь сразу, это важно. Это не «аудитория» и не доказательство успеха. Это техническая нагрузка от людей, которые зашли пощупать сырой проект. Интересны цифры другим: один ход игрока — это не один запрос к нейросети, под капотом целая цепочка вызовов. И вот эти 91 миллион токенов за несколько дней очень доходчиво объясняют, почему я нервно смотрю на счёт и почему добрая половина работы — резать лишние вызовы, а не добавлять новые.

Почему наивная нейросеть — плохой Мастер

Если просто посадить языковую модель водить D&D, выйдет беда. И беда предсказуемая.

Во-первых, модель не знает правил — она их имитирует. Просишь бросить кубик — «бросает» удобное число. Атака, урон, спасбросок: всё на глаз, лишь бы складно.

Во-вторых, нейросеть патологически добрая. Она с удовольствием выдаст тебе тысячу золота за то, что ты храбро посмотрел на гоблина. Похвалит за всё, наградит за ничто, баланс снесёт за пару сцен.

Это я лечил ещё до ОБТ, и на старте оно уже работало. Рядом с прозой стоит детерминированный движок D&D 5e. Кости, проверки навыков, инициатива, урон, слоты заклинаний, спасброски от смерти — это считает код по правилам, а не выдумывает нейросеть. Модель отвечает за художественную часть, движок — за физическую правду. Ошибся в бою — получил по щам по-настоящему, а не по настроению Мастера.

За эту часть я был спокоен. И зря решил, что она и окажется главной болью.

Главная боль ОБТ — память

Настоящее узкое место вылезло там, где я не ждал. Мир у нейросети не держится.

Запоминай всё дурацкий ИИ!

Запоминай всё дурацкий ИИ!

Самый показательный баг первых дней — убитый враг. Ты честно завалил бандита, движок отметил его мёртвым, а через две реплики нарратор как ни в чём не бывало пишет: «бандит снова заносит меч». Воскресил. Потому что ему так связнее писать.

Это не разовый глюк, это симптом. Бот забывал NPC, путал, кто кому что должен, переписывал собственные факты из прошлой сцены. Назвал трактирщика добряком — а через десять ходов тот вдруг злодей, и без всякой причины.

Один из тестеров — он специально вёл партию медленно и миролюбиво — сформулировал боль точнее, чем я сам:

Забывчивость ИИ о состоянии мира удручает. Теряется ощущение целостности мира, который каждые несколько сообщений постепенно стирается, а затем неправильно воссоздаётся — с ошибками, огрехами, потерянными деталями. Как комната кривых зеркал.

«Комната кривых зеркал» — это его формулировка, и она бьёт точно в цель. Корень сидел в самой архитектуре. У меня проза была первична: нейросеть сначала писала красивый текст и попутно сама решала, что в мире изменилось. А отдельный кусок кода потом выскребал из готового текста имена, факты, квесты — и пытался сложить из этого память. То есть память собиралась задним числом, из того, что модель уже насочиняла. Нарратор свободно переписывал то, что сам же минуту назад установил, а «память» покорно ехала следом.

Как я это чиню прямо сейчас

Лечение — это перестройка пайплайна, над которой я сижу как раз сейчас. Назвал её «Директор состояния».

Смысл — развести две роли, которые раньше тянула одна нейросеть. Пусть канон мира (что произошло, кто жив, какие факты в силе) решает отдельный шаг ещё до прозы. А нарратор пишет уже под готовое решение и сам в мире ничего не меняет.

Один ход теперь идёт так. Лёгкая модель разбирает намерение игрока — атака, проверка, разговор. Движок считает механику. Дальше новый шаг — директор, единственный, кому позволено трогать канон. Он берёт намерение, результат движка и срез памяти мира и делает три вещи: отбирает из памяти только то, что относится к этому ходу (заодно режет лишние токены), сверяет ход с уже установленным каноном и отклоняет противоречия, фиксирует, что в мире изменилось. И лишь потом нарратор пишет прозу — но под жёсткие ограничения, как под техзадание, а не как автор, которому можно всё.

Из схемы выпали два прежних звена. Нарратор больше не решает изменения мира сам. И я убрал тот самый код, что выскребал факты из готового текста. Переписывать стало нечего — канон решён до прозы.

Заодно завёл настройку строгости. В строгом режиме (по умолчанию) канон незыблем: поменять что-то можно только по явной внутрисюжетной причине. В лояльном директор мягче — мир живее, но иногда дрейф просочится. Кому-то важнее железная логика, кому-то — живость, пусть сами выбирают.

И да, пайплайн обвешан страховкой. Если вызов директора упал по таймауту — ход не теряется, бот деградирует в прежний режим. Рабочее ядро важнее красивой архитектуры.

Что ещё ломалось и как я об этом узнаю

Память — главная история, но не единственная. По горячим следам ОБТ ловились вещи помельче: криво считался лут с трупов, классовые способности не всегда долетали до движка, проза изредка оживляла убитых врагов, нашёлся неприятный момент с проверкой платёжного вебхука. Часть уже закрыта, часть в очереди.

Узнаю я об этом двумя путями. Первый — живой фидбек. Я не прячусь за формой обратной связи: тестеры пишут напрямую, я читаю всё. Куча багов прилетела одной фразой «слушай, а почему вот это так». Второй — регулярные прогоны. После каждого деплоя я гоняю смоук-сценарии, потому что на живом мире постоянно вылезает то, что не словил ни один тест.

Не претендую на лучшее техническое решение — я его и не искал. Я ищу рабочее. И нахожу через грабли.

Зачем я всё это пишу

Затем, что мне нравится возиться с этой штукой. И хочется довести её до состояния, когда соло-партию в D&D можно отыграть вечером — без живого Мастера и без чувства, что мир разваливается под ногами. Впереди много: нормальная долгая память по главам, чтобы кампания помнила себя через десятки сцен, а не последнюю пару ходов. Мир, у которого есть собственные планы, а не только реакция на игрока. И длинный хвост мелких правок, который у пет-проектов не кончается никогда.

Проект живой, я его пилю и буду пилить. Если хочется зайти, поиграть и от души поломать — велкам, критику и баг-репорты собираю и реально по ним чиню. Про процесс пишу в блоге бота таверны Мокрый Тортл. Сам бот доступен тут — https://t.me/dnd5char_bot

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

Один раз на меня напал кузнец, я его оглушил, привёл в чувства (предварительно связав), перевоспитал — и теперь там любящая семья, ячейка общества.

Другой тестер забил на основной квест и сам придумал себе цель:

Забил на основной квест и двигаю историю сам. Нашёл бойцовскую яму, придумал себе цель — стать чемпионом. Дерусь, общаюсь с неписями, пытаюсь то подружиться с ними, то перехитрить распорядителя боёв. Кайф.

Люди пришли тестировать сырого бота, а в итоге сочинили себе квесты, которых нет ни в одном сценарии. Вот ровно поэтому я и копаю память: чтобы мир, в котором игрок выдумал собственную историю, не забывал, что эта история вообще была.

А вывод такой. На запуске я больше всего боялся за кубики. Оказалось, кубики — самая решённая часть. Настоящая инженерия начинается там, где нейросети нужно не сочинять, а помнить.

И вывод номер два — я откладывал релиз каждый раз, думая что «вот это поправить ещё нужно и вот это». Но так в релиз со своим пет проектом можно никогда и не выйти. Так что делайте релизы, дамы и господа!

ссылка на оригинал статьи https://habr.com/ru/articles/1049238/