Усі уроки · 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 із назвою випадку — на три тижні раніше, ніж прийшов би лист від клієнта.