awesome-everything EN
↑ Обратно к восхождению

AI / LLM

LLM-evals: регрессионный тест для недетерминированной фичи

Суть LLM-фичу нельзя выкатывать без evals: один и тот же ввод даёт разный вывод, а смена модели или промпта тихо роняет качество. Golden-набор, программные проверки и откалиброванный judge — то, чем ловят регрессию раньше пользователей.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на junior-высоте — поверхность
◷ 17 min

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

Почему «я попробовал, и работало» — это не тестирование

Обычный unit-тест утверждает f(x) === y. LLM такого контракта не даёт: один и тот же промпт при той же temperature может вернуть разный текст на каждый вызов, и даже при temperature: 0 идентичный вывод между версиями модели или даже между запросами не гарантирован — провайдеры батчат и роутят недетерминированно. Поэтому утверждение, которое тебе на самом деле нужно, — не «вывод равен этой точной строке», а «вывод достаточно хорош по тем измерениям, которые меня волнуют» — корректен, в нужном формате, в рамках политики, основан на полученном контексте.

Этот сдвиг ломает все привычки детерминированного тестирования. Нельзя зафиксировать одно ожидаемое значение — ты оцениваешь распределение поведения по множеству примеров. Нельзя доверять одному зелёному прогону, потому что следующий может отличаться. И режим отказа тихий: ничего не падает. Смена модели, правка промпта, новый system message, изменившийся индекс retrieval — любое из этого может тихо уронить качество ответов на 15% без единого сигнала об ошибке. Evals — единственный механизм, который превращает «тихо стало хуже» в число, проваливающее CI.

Golden-набор: реальный трафик, а не happy path

Eval честен ровно настолько, насколько честен его датасет. Golden-набор — это курируемая коллекция вводов в паре с заведомо верными выводами (или с рубрикой, когда единственно верного ответа нет). Ошибка сеньора — наполнить его примерами, которые он использовал при разработке: лёгкими, чистыми, на распределении. Это ровно те случаи, что уже работают. Полезный golden-набор строится из продакшена: реальные пользовательские запросы с осознанным переотбором крайних случаев, прошлых провалов и ценных сценариев. Дисциплина, которая окупается: каждый продакшен-провал в тот же день становится golden-кейсом, чтобы фикс был доказуем, а тот же баг уже никогда не регрессировал тихо.

Размер — это вопрос суждения, а не фиксированное число. Команды часто становятся полезны на 50–200 хорошо подобранных кейсах и дорастают до тысяч по мере накопления категорий. Покрытие важнее голого количества: 80 кейсов, охватывающих твои реальные категории запросов, ловят больше, чем 2000 почти одинаковых лёгких. Число, которое реально важно, — не размер датасета, а то, какую часть твоего живого распределения вводов набор представляет; это и есть режим отказа, к которому мы вернёмся ниже.

Точные проверки vs LLM-as-judge

Оценивай каждый кейс самым дешёвым методом, который работает. Два семейства:

СкорерЦена / скоростьФлакает?Когда
Точная / программная (regex, JSON-match, схема, исполнение кода)~бесплатно, мсНет — детерминированаВывод имеет структуру: валидный JSON, число, метка класса, парсимый формат
LLM-as-judge (модель оценивает вывод по рубрике)1 доп. вызов API/кейс, секундыДа — шумит, предвзятОткрытое качество: полезность, тон, faithfulness, «ответил ли»

Предпочитай программные проверки везде, где у вывода есть хоть какая-то структура — они бесплатны, мгновенны и не врут. Тянись к judge только для по-настоящему субъективных измерений. Judge означает один дополнительный вызов модели на кейс, чтобы его оценить: дай judge ввод, вывод и рубрику, и пусть он вернёт парсимый вердикт (yes/no или multiple-choice оценку) — ровно так, как предписывает шаблон model-graded eval от OpenAI.

Judge сам по себе — шумный инструмент, его надо калибровать

Вот ловушка, которая жжёт команды: LLM-judge — это не ground truth, это ещё одна стохастическая модель с задокументированными смещениями. Хорошо построенный judge может достигать примерно 80% согласия с людьми-оценщиками — около уровня, на котором два человека согласны друг с другом, — но только откалиброванный; неоткалиброванный уходит заметно ниже. Известные режимы отказа конкретны и воспроизводимы:

  • Position bias. В попарном сравнении смена того, какой ответ идёт первым, может перевернуть вердикт. Исследования GPT-4 как judge показывают, что его предпочтение разворачивается при смене позиций ответов; сама модель-judge — крупнейший драйвер этого смещения, больше, чем сложность задачи или длина вывода. Митигируй прогоном обоих порядков с усреднением.
  • Self-preference. Модель склонна оценивать свои генерации выше, с измеренной линейной корреляцией между тем, насколько хорошо она узнаёт собственный текст, и тем, насколько его предпочитает. Не оценивай вывод GPT-4 judge-ем на GPT-4, если можешь этого избежать.
  • Verbosity bias. Judge систематически предпочитает более длинные ответы независимо от корректности.

Непреложный механизм: проверь judge против человеческих меток, прежде чем ему доверять. Собственное руководство OpenAI — добавить meta-eval с человеческими метками, чтобы проверить model-graded eval. Разметь выборку руками, измерь согласие judge с этими метками и выкатывай judge только когда он проходит твою планку (команды целятся в ~75–90% согласия). Judge, который ты ни разу не измерил, — это генератор чисел, который ты принял за тест.

Почему это работает

«Judge соглашался сам с собой между прогонами» — это не калибровка, это просто judge, стабильно ошибающийся в одном направлении. Консистентность (низкая дисперсия) и точность (согласие с людьми) — разные оси. Уверенно предвзятый judge опаснее шумного, потому что его стабильность читается как надёжность, пока он методично пропускает регрессии, которые люди бы поймали.

Offline-гейты vs online-eval

Два места, где гоняют evals, и нужны оба:

  • Offline — eval-набор гоняется в CI против golden-набора на каждой правке промпта, смене модели или изменении retrieval. Он выдаёт число; regression gate проваливает сборку, если число падает ниже baseline (или ниже прошлого релиза). Именно это заблокировало бы пятничный деплой. Добавляй новые продакшен-провалы в golden-набор, чтобы гейт со временем расширялся.
  • Online — ты семплируешь срез реального продакшен-трафика (скажем, 1–5%), оцениваешь его теми же автоматическими методами и следишь за трендом. Online ловит то, что offline структурно не может: тихое обновление модели провайдером, сдвиг в том, что пользователи реально спрашивают, дрейф индекса retrieval. A/B-тесты сравнивают кандидата с живой версией на реальных пользователях и привязывают качество к бизнес-метрикам.
Расставь шаги по порядку

Расставь жизненный цикл поимки LLM-регрессии раньше пользователей:

  1. 1 Построй golden-набор из реального продакшен-трафика, переотбирая крайние случаи и прошлые провалы
  2. 2 Оцени каждый кейс: программная проверка, где есть структура, LLM-judge для открытого качества
  3. 3 Провалидируй judge против человеческих меток; доверяй ему только когда согласие проходит планку
  4. 4 Подключи набор как CI regression gate, проваливающий сборку при падении числа ниже baseline
  5. 5 Семплируй 1-5% продакшена online, чтобы ловить дрейф провайдера и сдвиг распределения, мимо golden-набора

Провал, который переживает зелёный набор

Худший исход — не упавший eval, а eval-набор, который зелёный, пока реальные пользователи натыкаются на провалы. Это случается двумя путями, и оба про доверие к числу, которому доверять не стоило.

Первый: golden-набор не покрывает живое распределение. Твой набор проходит на 95%, потому что полон запросов, которые ты предвидел, а продакшен-трафик дрейфанул к категории, которую ты ни разу не семплировал — новый язык, новый тип вопроса, новый формат документа. Eval измеряет мир, который больше не совпадает с тем, в котором живут пользователи. Защита — online-мониторинг: отслеживай распределение эмбеддингов реальных вводов и алертируй, когда продакшен-запросы ложатся заметно далеко от всего в golden-наборе, затем затягивай их внутрь.

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

Викторина

Провайдер тихо обновил снапшот твоей модели. CI eval-набор зелёный. Что вероятнее всего поймало — или упустило — регрессию?

Викторина

Ты добавил LLM-judge, и его оценки выглядят отлично. Прежде чем доверять ему как гейту, ход сеньора:

Выбери лучший вариант

Твоя фича возвращает структурированный JSON-объект с обязательным полем status и свободнотекстовым rationale. Выбери стратегию оценки для eval.

Вспомните перед уходом
  1. 01
    Коллега говорит: «eval-набор зелёный, значит новый промпт можно выкатывать». Назови два разных способа, которыми зелёный набор всё ещё может прятать реальную регрессию, на которую напорются пользователи.
  2. 02
    Почему LLM-as-judge дешевле и быстрее в постройке, чем человеческое ревью, но рискованнее программной проверки, и какой один шаг делает его надёжным?
Итог

LLM-фича без eval-набора — это непротестированный код, потому что недетерминизм означает: один и тот же промпт может вернуть разный вывод, а смена модели или промпта может тихо уронить качество без ошибки, без упавшего теста и без строки в логе — только клиенты, с опозданием на дни. Evals превращают эту тихую регрессию в число, которое CI может провалить. Честная версия начинается с golden-набора, построенного из реального продакшен-трафика, с переотбором крайних случаев и превращением каждого продакшен-провала в golden-кейс в тот же день; покрытие живого распределения важнее голого размера. Оценивай каждый кейс самым дешёвым методом, который работает: программные проверки (regex, JSON-match, схема, исполнение кода) везде, где у вывода есть структура, ведь они бесплатны и не флакают, и LLM-as-judge только для открытого качества. Но judge сам по себе шумный, предвзятый инструмент — position bias, self-preference, verbosity bias — поэтому валидируй его против человеческих меток и доверяй только когда согласие проходит планку (~75-90%, около согласия человек-человек). Гоняй набор offline как CI regression gate, блокирующий деплой при падении числа, и семплируй 1-5% продакшена online, чтобы ловить тихое обновление провайдера и дрейф распределения вводов, который offline структурно не видит. Два способа, которыми зелёный набор всё ещё врёт: golden-набор, больше не совпадающий с живым распределением, и шумный judge, которому ты доверился без калибровки — защищайся от обоих, иначе выкатываешь регрессии с проходящим тестом.

Продолжить восхождение ↑LLM-evals: тест с множественным выбором
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources4
expand
  1. 01
  2. 02
  3. 03
  4. 04

Trademarks belong to their respective owners. Editorial reference only.