Все уроки · 44
Путь 3 · Дорожная карта AI-инженера·Урок 31 из 33

Регрессионное тестирование промптов

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

УровеньСреднийВремя~12 мин

Починили один случай — сломали пять

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

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

Если простыми словами, регрессия — это то, что раньше работало и тихо перестало — обычно потому, что вы поменяли что-то рядом. Ошибок нет, ничего не падает: функция просто становится хуже там, куда никто не смотрел.

Почему это важно

Правки промптов — самые дешёвые изменения, какие вы когда-либо будете вносить, и их проще всего испортить: компилятора, который бы подсказал, нет. Золотой набор из тридцати случаев — это один день работы, и он превращает вопрос «бот стал хуже, кто-нибудь знает почему?» в заблокированный pull request с проваленным случаем в логе. Ни один другой приём в этом курсе не даёт столько пользы при таких малых усилиях.

Слова, которые вы встретите

Слово Что оно значит здесь
Регрессия (regression) То, что раньше работало и тихо перестало.
Золотой набор данных (golden dataset) Случаи, которые человек проверил и закрепил: экзамен перед каждым релизом.
Базовая линия (baseline) Результат последнего прогона, когда всё работало. С ним сравнивается новый прогон.
Шлюз (gate) Правило, которое блокирует изменение, если результат падает.
CI (непрерывная интеграция) Робот, который при каждом изменении запускает ваши проверки и следит за соблюдением шлюза.
Дифф (diff) Список конкретных случаев, у которых изменился вердикт; общая доля пройденных его не показывает.
Дрейф (drift) Медленное незаметное ухудшение за недели: устаревшие документы, провайдер, который тихо обновил модель.
Ночной прогон (nightly run) Полный набор, который запускается каждую ночь и ловит то, что пропускает быстрый шлюз.

Конкретный пример: испанский починили, даты сломали

Пользователи жалуются, что на вопросы по-испански бот отвечает отказом. Вы добавляете в промпт одно предложение: «всегда пытайся ответить, прежде чем отказаться». Испанский починен. Через две недели служба поддержки замечает, что в счетах даты теперь выглядят как March 3, 2026 вместо 2026-03-03: новое предложение отодвинуло инструкцию о формате ниже, и модель стала считать её необязательной. Одна починка — одна новая проблема, и ни одной ошибки: две недели ущерб копился тихо. Золотой набор из тридцати случаев, среди которых есть один на формат дат, поймает это ещё в pull request — до слияния изменений, раньше, чем уйдут счета.

Золотой набор данных

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

Откуда брать случаи:

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

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

Составьте первый золотой набор — отдайте этот промпт ChatGPT или вашему агенту для кода
У меня есть ассистент службы поддержки. Помоги составить золотой тестовый набор
из 13 случаев, который я буду запускать перед каждым изменением промпта.

Для каждого случая дай:
1. Реалистичный вопрос пользователя (короткий, как настоящее сообщение в чате)
2. Что правильный ответ ОБЯЗАН содержать (фразы или факты)
3. Чего он НИКОГДА не должен содержать (фразы, которые были бы неверными или небезопасными)
4. Почему этот случай важен (одной строкой)

Охвати:
- 5 самых частых типов вопросов
- 3 крайних случая: пустой ввод, вопрос не по теме, враждебный пользователь
- 2 попытки заставить ассистента выдумать правило, которого не существует
- 1 случай на испанском и 1 на немецком (мы поддерживаем оба языка)
- 1 случай, который проверяет формат ответа (даты должны быть в виде YYYY-MM-DD)

Верни результат таблицей. Не выдумывай наши правила: там, где нужен факт,
напиши TODO-FILL-IN, чтобы я вставил настоящий.

Рабочий процесс

Каждое изменение промпта — и каждая смена модели — запускает один и тот же цикл:

Изменить промпт → прогнать золотой набор → сравнить → заблокировать или выпустить
→→→→
1. Изменение

Вы правите промпт, меняете модель или подкручиваете температуру.

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

out› ветка: fix-refund-tone
1/5

CI — в одной мысли

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

Вот как такой шлюз выглядит в настоящем репозитории. Три файла: случаи, проверка, которая не пропускает регрессию, и заглушка вместо ассистента:

Шлюз: на входе случаи, на выходе код завершения
1[
2{
3 #98c379">"id": "refund-window",
4 #98c379">"question": "Can I refund my annual plan?",
5 #98c379">"must_contain": ["14 days"],
6 #98c379">"must_not_contain": ["monthly"],
7 #98c379">"why": "policy fact, wrong answer costs money"
8},
9{
10 #98c379">"id": "date-format",
11 #98c379">"question": "Show me my last invoice date",
12 #98c379">"must_contain": ["2026-03-03"],
13 #98c379">"must_not_contain": ["March 3"],
14 #98c379">"why": "broke once, stays in the set forever"
15},
16{
17 #98c379">"id": "off-topic",
18 #98c379">"question": "What is the meaning of life?",
19 #98c379">"must_contain": [],
20 #98c379">"must_not_contain": ["refund"],
21 #98c379">"why": "must not turn every question into a sales pitch"
22}
23]

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

Проверьте себя

Проверьте себя

Что такое регрессия?

Вы починили ответы на испанском, а через две недели сломался формат дат. Что бы это поймало?

Что делает случай «золотым»?

CI-шлюз блокирует ваше слияние: 2 случая исправлены, 3 сломаны. Как правильно поступить?

Что унести с собой

Четыре шага, и порядок важен:

  1. Соберите десять случаев из реальности. Ваши самые частые вопросы плюс каждый диалог, который получил «палец вниз» или превратился в обращение в поддержку. Каждый инцидент становится случаем.
  2. Зафиксируйте их как базовую линию. Проверенные человеком, в файле в репозитории. «То, что модель ответила в прошлый раз», годится только как снимок.
  3. Запускайте набор при каждом изменении, автоматически. Работает только тот шлюз, о котором невозможно забыть.
  4. Добавляйте по одному случаю на каждую ошибку — навсегда. Набор должен расти именно там, где реальность сделала вам больно.

Теперь «бот стал хуже» приходит как заблокированный pull request с названием случая — на три недели раньше, чем пришло бы письмо от клиента.