Как всё сломалось из-за одного абзаца
Понедельник, утро. Приходит сообщение: бот снова отдаёт заявки на ручную обработку. Вчера работал нормально, сегодня — нет. Смотрю логи и понимаю: за выходные кто-то добавил в системный промпт пару строк про работу с физлицами. Само по себе нормально, но модель начала перестраховываться и помечать «требует менеджера» всё, где сумма больше полумиллиона.
Два дня агент работал вполсилы, пока не накопилось жалоб. После этой истории я решил сделать обычные регрессионные тесты, только не для кода, а для промптов. За следующие 11 месяцев они поймали 23 поломки до того, как их увидел клиент.
Почему обычные assert здесь не работают
В обычном коде пишешь assert calculate(2, 2) == 4. С LLM так не получается — модель может ответить «4», «четыре» или «два плюс два равно четырём». Строковое сравнение сразу отваливается.
Плюс недетерминированность. Даже с temperature=0 иногда вылезает лишнее слово. Если тест падает раз в десять запусков, через неделю его просто начинают игнорировать.
И ещё цена. Тысяча вызовов GigaChat Pro уже не бесплатная история.
Золотой датасет из 47 кейсов
Я взял реальные логи за два месяца и отобрал 47 примеров, где поведение должно оставаться предсказуемым:
- 12 кейсов на квалификацию лида;
- 8 на извлечение сущностей;
- 9 «тонких» сценариев, где уже были баги;
- 18 на безопасность и промпт-инъекции.
Всё лежит в YAML, который спокойно правят и продакт, и я.
Три уровня проверок
- Жёсткие — для JSON-ответов: сравниваю поля, числа с допуском, списки без учёта порядка.
- Семантические — беру эмбеддинги и считаю косинусную близость. Порог подобрал 0.78.
- Инвариантные — обычный regex или мини-промпт, чтобы проверить запреты.
Чтобы уменьшить флуктуации, делаю три прогона и беру медиану. Структурные проверки должны проходить все три раза.
Как это работает в CI
Тесты запускаются только при изменениях в prompts/ и agents/. Полный прогон занимает около четырёх минут и 60–70 рублей на токенах. Каждый запуск сохраняет JSON с ответами — потом видно, как меняется тон или длина ответов.
Что изменилось
До тестов было в среднем 2.3 хотфикса в месяц по жалобам клиентов. Среднее время от поломки до фикса — 31 час.
После: 0.4 хотфикса в месяц, а обнаружение занимает 4 минуты. 23 регресса пойманы до прода, из них семь были критичными.
Цена внедрения — пять дней на сборку датасета. Дальше поддержка занимает час в месяц.
Где не работает
На креативных задачах семантическая близость не поможет отличить «хорошо» от «отлично». В быстро меняющейся доменной области датасет устаревает слишком быстро. С многошаговыми агентами тоже отдельная история — там нужны моки.
Главный вывод
Промпты — это тоже код. Их правят чаще, чем функции, а ломаются они так же легко. Если у тебя есть хотя бы один платящий клиент, 30–50 кейсов окупятся уже на первом предотвращённом откате.
