Мокрый Тортл Мокрый Тортл Wet Tortle Таверна для героев A tavern for heroes
ТавернаTavern ГеймплейGameplay Как игратьHow to play ПутьJourney ВопросыFAQ Блог Роадмап Играть в TelegramPlay on Telegram

ДнД с ИИ: как я нашёл одну архитектурную ошибку за 120 багами с деньгами

· Владислав Новиков

ДнД с ИИ: как я нашёл одну архитектурную ошибку за 120 багами с деньгами

120 багов с деньгами в ИИ-мастере DnD оказались одной архитектурной ошибкой: пять параллельных каналов проведения денег без общей точки решения. Единая касса - дедуп, клэмп и запись в кошелёк в одном месте - заменяет их одной проводкой, а редкий LLM-арбитр разбирает только спорные случаи.

ДнД с ИИ обещает игроку одно: мир помнит, что происходит. А потом ты продаёшь трофей торговцу, и через пару ходов золото на счету не совпадает с тем, что тебе только что описали прозой. Мелочь? У меня в проекте AI-Мастера DnD таких мелочей за месяцы набралось около 120 - и почти все они оказались одним и тем же багом, просто в разных костюмах.

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

Почему в ДнД с ИИ путаются деньги игрока?

Деньги в игре шли через пять разных каналов одновременно: дар от NPC, торговля на суб-золото (медь, серебро), торговля на целое золото, находки в приключении и снова дар - каждый со своей логикой признания сделки. Движок и текст, который видит игрок, обновлялись из разных мест, и рано или поздно расходились: бот описывал сделку, а кошелёк её не фиксировал, или наоборот.

Пять каналов - пять мест, где можно один раз забыть про клэмп или дедуп. Один и тот же символ ошибки кочевал по цепочке “дар NPC → торговля на суб-золото → торговля на целое золото → находки → снова дар”: чинишь дедуп в одном канале - та же логика оказывается дырявой в соседнем, потому что каждый канал считал деньги по-своему. Багрепорты копились по одному, каждый чинили точечно - и снова ловили следующий, потому что причина была не в конкретном канале, а в том, что каналов вообще было пять.

Что такое единая касса для денег в ИИ-мастере DnD?

Касса - это единая точка проводки денег и предметов сделки поверх всех пяти каналов: один дедуп, один клэмп по потолку, одна запись в кошелёк, вместо пяти параллельных подсчётов. Канал по-прежнему решает, что произошло за столом (“NPC подарил зелье”, “ты продал кольчугу”), а вот проводит эту сделку в кошелёк всегда одна и та же логика.

Дедуп в кассе строго попарный, без транзитивности: если сообщение А совпало с Б, а Б - с В, это не значит, что А и В - одно и то же. Это тонкость, но именно на ней раньше залипали автоматические слияния - движок мог схлопнуть две разные сделки в одну просто потому, что обе задели одного персонажа в одном ходу. Запись идёт по event_id, так что повторная попытка провести ту же сделку не задвоит деньги, а сама сделка - либо целиком применяется, либо целиком откатывается, без “денег списали, а предмет не выдали”. Похожая жёсткая логика уже стояла в проверке сделок купли-продажи у NPC - писал об этом в “Плачу 20 золотых” - а зелья нет, теперь эта же дисциплина накрывает вообще все денежные каналы разом.

Когда в дело вступает LLM-арбитр?

LLM-арбитр в кассе - не главный судья, а редкое исключение: его зовут только на двух типах спорных ходов - когда денежный сигнал есть, а кандидата на проводку в кассе нет, и когда в прозе есть акт сделки без указанной суммы. Во всех остальных случаях решают жёсткие регулярки-запретители - они режут заведомо мусорные срабатывания ещё до того, как вопрос вообще доходит до модели.

Звучит как перестраховка, но так и есть - в разработке ПО это называют принципом единого источника истины: чем меньше решений отдано непроверяемому звену, тем меньше шансов, что где-то в системе окажутся две конкурирующие версии одной и той же цифры. Для денег в игре это не абстракция, а разница между “кошелёк совпадает с тем, что тебе только что описали” и очередным багрепортом.

Отдельно досталось квестовым и лутовым наградам - их специально вывели из-под вето арбитра. Квест выдаёт награду по своим правилам, и если зарубить эту проводку общим фильтром “подозрительная сумма”, она просто не дойдёт до игрока. Вето и клэмп в кассе умеют быть избирательными, а не рубить с плеча всё подряд - иначе экономия на ложных срабатываниях обернулась бы новым классом багов вместо старого.

Как спеку и план проверяли на прочность?

План выполнения гейта прошёл через адверсариальное ревью раньше, чем до него добрались руки писать код: спека получила 10 критичных и 11 мелких правок, план реализации - 2 обязательные и 7 желательных, и только после этого превратился в 17 задач по TDD. Дороже по времени на старте, зато меньше шансов упереться в архитектурный тупик через полсотни коммитов.

Похожий принцип “сначала найти дыру, потом чинить” уже проверял себя на живых QA-прогонах бота - про то, как зелёные тесты обманывают и почему нужен ещё и скрипт-аудитор, я писал в “Зелёные тесты врут”. Разница в том, что ревью спеки ловит проблему до того, как она успела стать кодом - это дешевле, чем ловить её потом тестами.

Ревью плана отдельно потребовало честно описать границы дедупа: слияние двух похожих сообщений о деньгах - штука полезная, пока не начинает склеивать то, что склеивать было нельзя. Это и вылилось в правило строгой попарности без транзитивности из предыдущего раздела - не абстрактная забота о качестве, а конкретная обязательная правка, без которой план не ушёл бы в реализацию.

Что уже готово, а что впереди?

Первая сессия реализации - субагентами, с передачей контекста через задачи, а не в одном непрерывном чате - закрыла задачи с 0 по 8b из плана на 17 задач и оставила около 18 коммитов: каркас кассы, врезку в денежные точки пайплайна, дедуп, вето и клэмп, атомарность сделки и арбитра. Гейт стоит за отдельным флагом и на боевых столах пока не включён - впереди офлайн-прогон корпуса старых партий на новой кассе, и только потом переключение.

Что было: пять каналов, каждый со своим представлением о деньгах, и багрепорты, которые множились быстрее, чем закрывались. Что стало: одна точка решения - но она ещё не под нагрузкой живых столов, и это честно стоит сказать прямо, а не как “уже всё готово”. Разбирал похожую экономику хода бота и в “Нейросети для DnD: почему ход ИИ-мастера оказался в 13 раз дороже” - там тоже разница между “выглядит нормально” и “а что на самом деле” оказалась не в мелочи, а в архитектуре.

Перед тем как включать гейт на боевых столах, план такой: прогнать кассу офлайн на корпусе уже сыгранных партий и посмотреть, где она разойдётся со старым поведением пяти каналов - и только после этого щёлкнуть флаг на живых играх. Это медленнее, чем просто включить и смотреть на репорты игроков, зато не превращает тестеров в подопытных для проверки денежной логики.

Что это значит для игроков за столом?

Момент, который стоило заметить раньше: 120 разных багрепортов про деньги - это не 120 разных проблем, а один архитектурный баг, который просто надевал новую маску на каждом новом канале. Пока чинишь по одному репорту за раз, этого не видно - видно только тогда, когда раскладываешь все находки рядом и смотришь на форму, а не на содержание.

Для игрока за столом это должно выглядеть скучно - а скука тут и есть цель: кошелёк совпадает с тем, что описывает мастер, сделка либо прошла целиком, либо не прошла вовсе, и никаких “а куда делись мои тридцать золотых” после перезахода. Похожая тема доверия к решениям бота - не только про деньги, но и про броски навыков - разбиралась в “Игрок перевязывает раны, а бот катит Обман”. Проект в активной стройке, и часть находок этого месяца ещё не долетела до продакшена - но касса уже показывает, что 80% эффекта иногда стоят не полного рефактора, а одной точки, куда сходятся все каналы разом.

Частые вопросы

Почему в играх с ИИ-мастером расходятся деньги и текст?

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

Зачем нужен LLM-арбитр, если деньги можно считать по правилам?

Регулярки закрывают почти все случаи, но не могут разобрать прозу без явной суммы. Арбитра зовут только на спорные ходы - чтобы не отдавать модели решения, которые прекрасно решаются жёсткой логикой.

Что даёт адверсариальное ревью спеки перед реализацией?

Правки в спеке и плане до того, как они стали кодом, дешевле, чем те же правки после багов на проде. Ревью специально ищет дыры в дизайне, а не ждёт, пока их найдут игроки.

Как готовился материал: черновик собирает мой ИИ-конвейер по темам из практики таверны, факты сверяются с первоисточниками и правилами, финальную версию я читаю и правлю руками перед публикацией. Обложку тоже рисует нейросеть. Про кухню — на странице о проекте.