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

Кузница стала магазином: как ДнД-бот задвоил сцену и забыл кузнеца с уговором

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

Кузница стала магазином: как ДнД-бот задвоил сцену и забыл кузнеца с уговором

ДнД-бот из-за точного (побуквенного) сравнения типов сцен - smithy не равно shop - при возврате в старую локацию не узнал её и создал вторую, пустую кузницу. Игрок терял кузнеца и договорённость о наконечниках. Фикс - группы совместимости типов сцен для построек, а не точное совпадение строки; повреждённые данные слили SQL-транзакцией.

Кузница стала магазином: как ДнД-бот задвоил сцену и забыл кузнеца с уговором

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

Почему нейросеть для DnD иногда “забывает” NPC

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

Звучит как мелочь? На практике это ровно тот случай, когда мелочь стирает кусок канона кампании - причём стирает не сразу, а на следующем визите, когда игрок меньше всего этого ждёт.

Как кузница стала магазином

31 августа 2026 года на ходе “Отправиться к кузнецу” директор сцен (модуль, который решает, куда попала партия) вернул тип smithy. А уже существующая сцена - “Кузница через дорогу от таверны” - жила в базе под типом shop: когда-то, ещё на старте кампании, её завели как обычную торговую точку, и с тех пор так и не переименовали.

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

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

Что терял игрок из-за дубля

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

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

Как починили: группы совместимости типов сцен

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

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

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

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

Второй баг той же недели: враг “повержен”, хотя ещё жив

В той же ревизии всплыл соседний баг - детектор ложной смерти не знал слов “повержен” и “предсмертный”. Игрок читал в прозе “повержен” про ещё живого противника - и на следующий ход спокойно “добивал” уже мёртвого, по мнению бота, врага, хотя по факту бой ещё шёл. Добавили лексемы на русском и английском, написали два теста, задеплоили тем же мержем 1 сентября.

Про то, почему ИИ-мастер вообще теряет часть мира между ходами - отдельный разбор в статье “Почему нейросеть для DnD забывает мир”.

Что это значит, если вы играете в ДнД-бота

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

Если вы водите кампанию и вдруг NPC “не помнит” вас, а знакомая локация выглядит подозрительно пустой - вероятно, это тот самый класс бага. Он не всегда безобиден: конкретно эта дыра стирала не описание, а живого кузнеца вместе с игровой договорённостью. Что делать в такой ситуации:

Похожая путаница с дедупликацией сущностей всплывает не только у DnD-ботов - это известная головная боль в архитектурах памяти ИИ-агентов вообще. Разработчики систем вроде OpenViking прямо заводят отдельные задачи на слияние дублирующихся записей о сущностях, потому что LLM без явных правил сравнения регулярно заводит вторую запись там, где должна была узнать первую. ДнД-бот - просто ещё один частный случай общей проблемы, только с кузнецом вместо абстрактной записи в базе.

Разница в том, что для абстрактной базы данных дубль - это лишняя строка, а для кампании - это NPC, который перестал существовать для игрока прямо посреди истории. Чем больше у бота накапливается сцен и NPC, тем выше шанс, что где-то тип записали чуть иначе, чем в первый раз - и тем ценнее становится не точное сравнение, а сравнение по смыслу.

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

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

Может ли ИИ-мастер DnD принять старую локацию за новую?

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

Что делать, если NPC в ДнД-боте вдруг "не помнит" игрока?

Сообщить в поддержку бота - это известный класс бага (дедупликация сцен/NPC по точному совпадению полей), команда чинит такие случаи адресно.

Как в ДнД-боте лечат уже испорченные багом данные кампании?

Иногда только вручную: например, дубль двух одинаковых сцен смержили SQL-транзакцией, перенаправив кампанию на версию с живым NPC и удалив пустую копию.

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