Нейросети для DnD: почему ИИ-мастер закрывал квест "Убить и найти" после первой половины

Нейросеть для DnD закрывала составной квест сразу после выполнения первой половины цели, потому что не отличала одну достигнутую цель от полного списка целей. Новая проверка режет название квеста на части и держит его открытым, пока прозой не подтверждена каждая часть - с учётом отрицаний в тексте.
Нейросети для DnD: почему ИИ-мастер закрывал квест “Убить и найти” после первой половины
Ребят, разбираем свежий баг - вернее, свежую дыру в уже почти закрытом баге. Один из тестеров сдавал квест “Убить тварь и найти поставщика” - и бот закрывал его сразу после того, как тварь падала замертво. Поставщика игрок находил ещё часа четыре игрового времени спустя, но плашка “квест выполнен” уже висела. Мелочь? Для механики ИИ-мастера DnD - нет: это четвёртая попытка почистить один и тот же класс багов, и на этот раз всплыла дыра, которую три предыдущих захода даже не видели.
Для тех, кто впервые тут: ИИ-мастер DnD в Telegram сам ведёт квесты, следит за целями и решает, когда сюжетная задача выполнена, а когда нет - без человека за столом, который бы поправил ход рукой. Значит, ошибка “закрыл рано” бьёт не по одному игроку, а по каждому, кто в этот момент сдаёт похожий квест. Отсюда и четыре захода на одну проблему подряд - это не тянущаяся история чужой лени, это механика, от которой честно зависит, поверит ли игрок квестовому логу бота.
Почему ИИ-мастер DnD закрывает составной квест раньше времени
Нейросеть-директор ИИ-мастера DnD закрывала составной квест, как только в прозе хода появлялось упоминание любой из его целей - даже первой из двух. Квест “убить тварь и найти поставщика” директор считал выполненным сразу после гибели твари, хотя вторая половина задания ещё не начиналась: проверка не различала одну достигнутую цель и полный список целей квеста.
Составной квест - это цель, склеенная из двух самостоятельных дел, которые идут одно за другим (“убить тварь и найти поставщика”, а не просто “убить тварь”). Именно на таких квестах и цеплялась старая проверка.
Почему это уже четвёртая попытка починить
Тут не “нашли баг - исправили”, а история из трёх неудачных заходов подряд. Сначала правили промпт директора - не помогло, нейросеть всё равно торопится закрывать. Потом добавили проверку “цель квеста должна реально существовать на сцене” - отловила часть случаев, но не составные. Потом - отдельное вето на квесты с деньгами или предметом, чтобы не засчитывать сдачу без оплаты. Все три фикса целились в свои узкие дыры и честно их закрывали, но ни один не был про то, что цель может состоять из двух частей. Баг с “Убить и найти” - первый прод-кейс, который явно это доказал: тварь есть в бестиарии, значит первая цель формально выполнена, а до второй нейросети как будто и дела нет.
Это тот случай, когда зелёные тесты врали - юнит-тесты на простые квесты были зелёными все три раза, а живой прод всё равно приносил новый вариант той же болезни.
Как эвристика режет квест на клаузы и держит вето
Что было: одна проверка “цель упомянута - квест закрыт” на весь квест целиком, без разбора, простой он или составной.
Что стало: название квеста режется на клаузы - куски по союзам “и” и ”, затем”, у каждой клаузы требуется свой глагол и свой объект (“убить тварь” - глагол “убить”, объект “тварь”; “найти поставщика” - глагол “найти”, объект “поставщика”). Новое вето VETO_PARTIAL_GOAL держит закрытие, пока прозой не подтверждена каждая клауза, а не только первая попавшаяся.
Та же логика в принципе годится для любого составного квеста: назывался бы он, скажем, “собери травы и отнеси травнице” - клаузы “собрать травы” и “отнести травнице” держались бы по отдельности, и вторая - пока в прозе не появится сама травница, а не просто упоминание трав в инвентаре.
У вето есть ограничитель - сработать оно может максимум один раз на квест, и вместе с ним нарратору уходит хинт “Осталось: …”, подсказывающий, что доигрывать. Без этого лимита эвристика против ошибок LLM могла превратиться в новую жалобу - “квест вообще не закрывается”, симметричную старой “закрыл слишком рано”. Мы это уже проходили с ложными срабатываниями других валидаторов - перегнутая палка чинит одну проблему и тут же создаёт другую.
Квесты для DnD: сколько из них на самом деле составные
Прежде чем катить фикс в прод, эвристику откалибровали офлайн на 256 реальных названиях квестов из продовой базы (август 2026). Составными оказались 17 из 256 - 6,6%. Ложных срезок, то есть случаев, когда простой квест ошибочно разрезало на клаузы, не нашлось ни одной. Немного, но именно эти 17 квестов и порождали баг “закрыл рано”: чем реже кейс, тем дольше он прячется в проде, пока не попадётся тестеру.
Разработку этого куска довели до продакшена двумя пул-реквестами: сначала само вето частичной цели, потом - рефикс полярности по вердикту QA (тот самый, что закрыл дыру с отрицанием, о ней ниже). Живой QA 18 августа регрессию раннего закрытия не воспроизвёл: 10 ходов, 4 намеренные провокации, ни одной ложной плашки на частичных ходах, юнит-тесты - 63 из 63, полный сьют - 6642 зелёных.
Как нейросеть обрабатывает отрицания в тексте - и почему сначала не смогла
До рефикса проверка поддержки клаузы искала в прозе только упоминание цели, без учёта отрицания - поэтому фраза “поставщик так и не объявился” формально подтверждала клаузу “найти поставщика” и снимала вето именно в тот момент, когда оно было нужнее всего: слово “поставщик” в тексте есть, а того, что перед ним стоит “так и не”, проверка не видела.
Дыру доказали офлайн-репреем на реальной прозе прод-ходов - взяли настоящие реплики из живых партий и прогнали через старую и новую версию проверки без единого живого игрока за столом. До рефикса - вето снималось. После - держится, а контрольные пары (где отрицания нет и клауза правда выполнена) не задело.
Рефикс простой: поддержка клаузы теперь считается только по неотрицательным сегментам текста - фраза режется по маркерам “не”, “ни”, “нет”, “наполовину”, “безуспешно”, “тщетно”, и в зачёт идёт только то, что осталось после отрицания. Тесты на этом месте выросли с 55 до 63, весь сьют - 6642 зелёных.
И тут, если честно, нейросети для DnD не одиноки в своей беде: обработка отрицаний в тексте - не наша доморощенная проблема, а известный открытый вопрос NLP-исследований. Языковые модели годами путаются именно в отрицании, и научные работы 2025 года прямо называют это нерешённым вызовом для индустрии, а не багом одного бота (ACL TrustNLP, 2025). Приятного мало, но хотя бы понятно, что мы не единственные, кто наступил на эти грабли - и баг-охота на нейросети для DnD вообще регулярно упирается в то, что модель понимает язык не так, как человек за столом.
Что дальше: живой QA, открытый вопрос и баг про пастуха
Приёмку фикса провели по полосе “без живого QA” - то есть офлайн-репреем и юнит-тестами, а не сутками мониторинга реальных партий. Живьём такое совпадение (составной квест + отрицание в прозе на моменте сдачи) - редкое событие, само по себе не спровоцировать в песочнице. Так что суточный мониторинг лог-маркера “квест держится, а не закрылся раньше времени” вынесли отдельной заметкой - и вот тут я, если честно, не могу сказать вам, сработало ли вето на живых игроках за эти сутки: в логах и беклоге фикса записей о результате мониторинга после 18 августа я не нашёл. Спрошу у автора отдельно, не буду гадать.
Это, в общем-то, честная позиция для проекта, который сам себя не называет готовым продуктом - это активная стройка, и часть фиксов проходит приёмку не “поиграли сутки и точно всё ок”, а “доказали детерминированно на реальной прозе и отпустили в прод под присмотром”. Разница между этими двумя способами приёмки для игрока не видна, но именно она отделяет фикс, в который веришь, от фикса, который просто закрыл тикет.
А ещё в процессе всплыл курьёз, который в тикет не поместился как срочный, но с концами не забудется: фаззи-матчер, который сверяет слова клаузы с прозой, приравнивает основу “паст” к “пастух” - то есть фраза “волк, оскалив пасть” теоретически могла засчитаться как поддержка клаузы “найти пастуха”. Волк и пастух - звучит как начало отдельного квеста, а не баг-репорта, но факт остаётся фактом: на это завели отдельную задачу (тоже починим, куда денемся). Такие дела - чиним по-крупному, находим по мелочи.
Частые вопросы
Что такое вето частичной цели у ИИ-мастера DnD?
Это проверка VETO_PARTIAL_GOAL, которая держит составной квест открытым, пока прозой хода не подтверждена каждая его часть (клауза) по отдельности, а не только первая из них.
Почему нейросеть путает отрицание в тексте квеста?
Старая проверка искала в прозе просто упоминание цели без учёта контекста, поэтому фраза с "не" рядом с целью всё равно засчитывалась как подтверждение - это известная слабость языковых моделей, а не только этого бота.
Сколько квестов в DnD бывают составными?
На выборке 256 реальных названий квестов из прода ИИ-мастера DnD составными оказались 17 - 6,6%. Именно на них и проявлялся баг раннего закрытия.
Как готовился материал: черновик собирает мой ИИ-конвейер по темам из практики таверны, факты сверяются с первоисточниками и правилами, финальную версию я читаю и правлю руками перед публикацией. Обложку тоже рисует нейросеть. Про кухню — на странице о проекте.