A/B-тесты промптов: как я перестал катать монетку

A/B-тесты промптов: как я перестал катать монетку

Почему «на глаз» всегда подводит

Понедельник, 9:47. Приходит сообщение: агент в письме поставщику назвал клиента поставщиком и наоборот. В пятницу мы выкатили «улучшенную» версию промпта. На стейдже и пяти примерах всё выглядело отлично. На проде через три дня — два испорченных контакта.

После этого случая я отказался от подхода «поменял промпт и проверил десяток выводов вручную». Промпт — это не детерминированная функция. Даже при temperature=0 разброс остаётся: токенизация, кеши провайдера, обновления модели. Два удачных примера — и ты уже уверен, что новая версия лучше. Два неудачных — и откатываешь хорошую.

В одном из кейсов промпт A показывал 87 % на 30 письмах, B — 90 %. На 1200 реальных письмах разница исчезла: 84,1 % против 84,7 %. Без статистики ты просто кидаешь монетку.

Как мы тестировали промпты на реальном трафике

У заказчика — дистрибьютор электротехники. Агент на GigaChat Pro каждое утро резюмирует входящие письма. Менеджеры раньше тратили 35–40 минут на разбор почты, после первой версии агента — около 8 минут. Через три месяца качество начало проседать: агент путал «отгрузку» и «оплату».

Новый промпт написали быстро. Вопрос был в другом — как понять, что он реально лучше, а не просто «звучит приятнее».

Решение простое: одновременно гоняем оба промпта на разных письмах. Конфигурация лежит в Postgres, роутер выбирает вариант по хешу request_id. Каждый вызов пишется в таблицу с моделью, latency, стоимостью и самим ответом.

Метрики без золотого датасета

Правильных ответов на боевых данных у нас нет. Поэтому используем три сигнала:

  • Частота правок менеджером. Считаем расстояние Левенштейна между сгенерированным и финальным текстом.
  • Thumbs-down. Кнопка «резюме плохое» с комментарием (конверсия 4–6 %).
  • LLM-as-a-judge. Раз в сутки отдельный сервис оценивает 200 случайных примеров по шкале 1–5.

После двух недель на 11 400 писем в каждой ветке v3.2 уверенно обогнал v3.1 по всем трём метрикам. Разница по thumbs-down статистически значима.

Три ошибки, которые мы успели совершить

  1. Один клиент давал 60 % трафика. Пришлось хешировать не request_id, а (client_id, день), чтобы каждый видел обе версии равномерно.
  2. Новый промпт был длиннее на 800 токенов. Качество чуть выросло, а latency и стоимость — заметно. В итоге ROI оказался хуже.
  3. Выкатили тест за два дня до закрытия квартала. Метрики «улучшились», потому что менеджеры просто не успевали править. Теперь минимальное окно — 10 рабочих дней.

Что получилось за полгода

Прогнали 23 эксперимента на трёх задачах. 9 версий выкатили на 100 %, 8 откатили, 6 сделали сегментированными. Если бы тестировали «на глаз», по моей оценке выкатили бы 14–15 и половина из них потом бы деградировала.

A/B-тесты промптов — это не лишняя сложность. Это минимум инфраструктуры, без которой любая итерация LLM-системы превращается в рулетку. Кодовая часть — пара дней: таблица вариантов, роутер и дашборд по логам.

Один открытый вопрос остался: как тестировать промпты, которые радикально меняют структуру вывода (текст → JSON). Edit distance и judge здесь работают плохо. Если у тебя есть рабочий подход — напиши, интересно обсудить.