Строим evals, которые реально ловят регрессии
Большинство eval-наборов выглядят внушительно, но пропускают реальные регрессии. Чтобы построить evals, которые ловят важное, нужны аккуратно собранный датасет, чувствительные метрики, калиброванные судьи и культура доверия. Паттерны команд, у которых это получается.
Вы построили eval-набор. Он зелёный. Вы выкатываете. Пользователи тут же жалуются на регрессии, которых eval не поймал.
Это один из самых частых — и самых деморализующих — паттернов в продакшен-LLM-работе. Eval-наборы, которые выглядят внушительно, но пропускают значимые регрессии. Они дают ложную уверенность. Команда им доверяет, выкатывает изменения, портящие качество, и узнаёт о проблеме только когда её всплытие обеспечивают пользователи.
Построить evals, которые реально ловят регрессии, сложнее, чем кажется. Основы (датасет, ожидаемые выходы, скоринг) просты. Превратить их в надёжный сигнал — вот где работа.
Эта статья — о том, что мы выучили о построении evals, которые держатся, для команд, серьёзно относящихся к качеству продакшен-AI.
Что делают хорошие evals
Хороший eval-набор, прогнанный на кандидатном изменении, даёт высокоуверенный ответ на вопрос: «это изменение лучше, хуже или такое же, как текущая версия?»
Грани:
- Ловит регрессии. Когда качество падает на реальных паттернах — eval-оценка падает.
- Детектирует улучшения. Когда качество растёт — оценка это отражает (не только на вишенках).
- Стабилен при неизменениях. Когда по сути ничего не изменилось — оценка консистентна.
- Достоин доверия в решениях. Решения, принятые по eval-оценкам, коррелируют с реальными исходами для пользователей.
Каждое из этого сложнее, чем звучит.
Проблема датасета
Ваш eval хорош ровно настолько, насколько хорош ваш датасет. Большинство провальных eval-наборов проваливаются здесь.
Типичные провалы датасета
Провал 1: вишенки — лёгкие кейсы. Датасет был собран, когда система работала, часто инженером, который её строил. Он выбирал кейсы, которые «имели смысл», — чёткие примеры каждого поведения. Реальный продакшен-трафик грязнее. Сложные кейсы, неоднозначные кейсы, граничные кейсы доминируют в провалах, но недопредставлены в датасете.
Провал 2: устаревший датасет. Датасет собрали шесть месяцев назад. С тех пор поведение пользователей сместилось, появились новые фичи, новые возможности продукта. Датасет тестирует старую версию мира.
Провал 3: нет покрытия зон, где случаются регрессии. Eval тщательно покрывает «happy path», но не прощупывает границы, где регрессии и случаются.
Провал 4: загрязнение датасета. Примеры из eval-а также появляются в промпте или в данных файнтюнинга. Модель их «помнит». Тестовые оценки завышены; реальная работа хуже.
Провал 5: несбалансированное распределение. 80% датасета — один тип входа; 5% — длинный хвост. Регрессия в длинном хвосте едва двигает оценку, хотя это реальная регрессия.
Как построить сильный датасет
Несколько принципов, дающих сильные датасеты:
Берите из реального продакшен-трафика. Лучшие примеры — реальные пользовательские входы (с убранными PII). В них настоящая грязь, с которой системе нужно справляться.
Практический воркфлоу:
- Снимите выборку продакшен-вызовов (с подходящими privacy-контролями).
- Разметьте ожидаемые выходы руками (или LLM-разметка + проверка человеком).
- Добавьте кейс в eval-датасет.
- Регулярно обновляйте датасет (раз в месяц — хорошая частота).
Включайте разнообразные режимы отказа. Специально включайте кейсы, которые ранее падали в продакшене. Они становятся регрессионными тестами — если вы починили баг, добавьте провальный кейс, чтобы он остался починенным.
Стратифицируйте датасет. Категоризируйте кейсы (лёгкие/средние/сложные, по теме, по типу пользователя, по длине). Обеспечьте осмысленное покрытие каждой категории. Отслеживайте оценки по категориям, а не только общую.
Перемешивайте сложность. Немного лёгких (чтобы детектировать катастрофические регрессии). Немало средних (основная масса реального трафика). Немного сложных (граничные кейсы). Датасет только из сложных дико прыгает при малых изменениях; датасет только из лёгких не сдвинется на реальной регрессии.
Подберите размер. Слишком мало — статистика шумит. Слишком много — прогоны становятся медленными и дорогими. Типичные размеры:
- Классификация: 200-500 кейсов.
- Генерация: 50-200 кейсов.
- Сложные агентные потоки: 20-50 кейсов.
Всегда можно начать с меньшего и расти.
Дисциплина обновления. Запланируйте ежемесячный обзор датасета. Добавляйте новые режимы отказа. Списывайте устаревшие кейсы. Обновляйте ожидаемые выходы, если желаемое поведение изменилось.
Проблема метрики
То, что вы меряете, определяет то, под что вы оптимизируете. Плохой выбор метрик — второй по частоте провал evals.
Типичные провалы метрик
Провал 1: однозначные сводки прячут проблемы. Общая точность 90% может прятать, что важная категория просела с 95% до 70%, пока другие выросли. Среднее выглядит нормально.
Лекарство: разбивки по категориям. Всегда.
Провал 2: метрика меряет не то. «Корректность» в ответах поддержки может пропустить, что ответ корректен, но груб. Метрика не ловит тон.
Лекарство: многомерный скоринг. Корректность + тон + длина + формат — отдельно.
Провал 3: нечувствительна к серьёзности. Неверный ответ оценивается одинаково — и в случае тривиальной ошибки, и в случае опасной галлюцинации.
Лекарство: взвешенный скоринг. Серьёзные ошибки весят больше. Часть ошибок весят 0 (нарушения безопасности); часть — -1 (катастрофические провалы, хуже, чем «ничего»).
Провал 4: бимодальная чувствительность. Оценка либо идёт с 100% на 99% (неразличимо), либо с 100% на 50% (катастрофа). Тонкие регрессии не видны.
Лекарство: градуированный скоринг. Каждый выход оценивается по непрерывной шкале (1-5 или 0-1), не бинарно.
Провал 5: агрегация по популяциям. Среднее по всем пользователям прячет, что у 10%-сегмента всё посыпалось.
Лекарство: разбивки по релевантным срезам (тариф, тип запроса, локаль).
Как построить сильные метрики
Многомерные. Каждый выход получает несколько оценок. Корректность. Тон. Формат. Безопасность. Длина. Что важно — то и меряем.
Взвешенные. Какие-то измерения важнее других. Взвешивайте их в любой композитной метрике.
Калиброванные по серьёзности. Внутри измерения различайте мелкие и крупные ошибки. Фактически неверный ответ хуже, чем слегка неточный.
По категориям. Сообщайте оценки в разрезе релевантных срезов. Лёгкие/средние/сложные. По теме. По типу пользователя.
Тренд во времени. Одна оценка бесполезна; тренд — полезен. Стройте графики оценок во времени. Детектируйте дрейф.
Связанные с пользователем. Метрики должны коррелировать с тем, что реально волнует пользователей. Если пользователи жалуются на грубость — меряете грубость. Если на длину — меряете длину.
Проблема судьи
Когда используете LLM-as-judge (LLM оценивает выход другой LLM), судья — это ваш scorer. Если судья смещён или ошибается — ваши evals бесполезны.
Типичные провалы судей
Провал 1: смещение по длине. LLM-судьи склонны предпочитать более длинные ответы. Они поставят более длинному ответу выше — даже если он раздут.
Провал 2: смещение по формату. Судьи предпочитают структурированные выходы (булеты, заголовки) прозе, независимо от того, что лучше под задачу.
Провал 3: self-preference. Когда модель-судья из того же семейства, что и оцениваемая модель, она ставит выше выходам собственного семейства.
Провал 4: подхалимаж. Судьи соглашаются с любой подачей, которой их кормят. Сказать судье «предыдущая версия была плохая, оцени новую» — оценки новой раздуются.
Провал 5: отсутствие заземления. Судьи оценивают по впечатлениям, а не по конкретным критериям. Тот же промпт, разная оценка на разных прогонах.
Как построить сильных судей
Калибруйте по людям. Возьмите выборку оценок судьи; пусть человек переоценит. Где расходятся — донастройте промпт судьи или примите, что по этому измерению нужен человек.
Используйте разные модели для судьи. По возможности берите судью из семейства, отличного от оцениваемой системы. Снижает self-preference.
Явные критерии. Промпт судьи должен точно специфицировать, как выглядит хорошо и плохо, с примерами. Размытые критерии дают размытый скоринг.
Избегайте наводящих формулировок. Не говорите судье «оцените по шкале, где большинство выходов — хорошие». Опирайтесь на конкретные поведения.
Заякоренные рубрики. Оценивайте по определённой рубрике с примерами для каждого уровня. «5: фактически точно, конкретно, хорошо структурировано. 4: в основном точно, может не хватать одной детали. 3: ...» С якорями судья консистентен. Без них — дрейфует.
Принудительный структурированный выход. Судья выдаёт структурированные оценки (по измерениям, с обоснованием), а не свободный текст. Проще агрегировать и аудировать.
Сильный промпт судьи выглядит примерно так:
You are evaluating an AI assistant's response.
User query: {query}
Assistant response: {response}
Score on the following dimensions, on a scale of 1-5:
1. Factual accuracy: Are all claims correct? (5 = all correct, 4 = mostly correct with minor issues, 3 = some incorrect, 2 = many incorrect, 1 = mostly wrong)
2. Relevance: Does the response address the user's actual question? (5 = perfectly addresses, 1 = doesn't address)
3. Completeness: Does the response contain enough information? (5 = complete, 1 = severely incomplete)
4. Tone: Is the response appropriately professional? (5 = perfect tone, 1 = inappropriate)
For each score, provide:
- The score
- A one-sentence specific reason
- The specific text in the response that supports your score
Output JSON: {"accuracy": {"score": N, "reason": "...", "evidence": "..."}, ...}Прогоните этого судью по калибровочному набору (с человеческими оценками). Подстраивайте, пока судья не согласится с людьми в приемлемых пределах.
Проектирование eval-наборов для продакшена
Несколько паттернов, работающих в продакшене:
Набор 1: регрессионный
Определённый набор тест-кейсов (200-500), который система обязана пройти до любого деплоя. Скурирован из реальных провалов, граничных случаев и known-good паттернов. Меняется нечасто.
Это ваш «не сломать» набор. Интеграция с CI: каждый PR его гоняет. Регрессия блокирует мердж.
Набор 2: smoke test
Малый поднабор (10-30 кейсов), гоняемый часто. Быстрая обратная связь во время разработки. Сразу ловит катастрофические регрессии.
Интеграция: pre-commit hook или быстрый smoke до основного eval.
Набор 3: discovery
Больший, более разнообразный датасет (тысячи кейсов), нарезанный из реального продакшен-трафика. Гоняется реже (раз в неделю?). Ищет паттерны, которые малые наборы могут упустить.
Интеграция: запланированная задача. Результаты ревьюятся на еженедельных встречах по качеству.
Набор 4: онлайн
Выборка реального продакшен-трафика, оцениваемая автоматически (LLM-судья) или по пользовательским сигналам. Ловит дрейф, который офлайн-evals пропускают.
Интеграция: непрерывная, на основе дашбордов.
Набор 5: пользовательские потоки
End-to-end-тесты, гоняющие полные пользовательские потоки, а не одиночные вызовы LLM. Для агентных систем и многошаговых воркфлоу.
Интеграция: предeploy крупных изменений.
Зрелая продакшен-система имеет все пять. Начните с регрессионного; добавляйте остальные по мере роста.
Дисциплина по стоимости и времени
Evals стоят денег (вызовы LLM) и времени (прогонять, ревьюить).
Eval на 500 кейсов с флагманским судьёй может стоить €5-20 за прогон. Гоните его на каждый PR (10 в день) — выйдет €50-200 в день. Управляемо, но реально.
Стратегии:
Гоняйте smoke на PR; полные наборы — на мердже. Экономит на PR, которые не смерджатся.
Кэшируйте результаты. Если ни промпт, ни модель не менялись, заново гонять не надо. Кэшируйте по (prompt_version, model, dataset_version).
Используйте более дешёвых судей, где возможно. Судья подешевле с хорошей калибровкой часто приемлем.
Параллельте. Eval-прогоны постыдно параллельны. Используйте concurrency.
Сэмплируйте, а не гоняйте всё. Для рутинных проверок сэмплируйте 50 кейсов из 500. Полный прогон — на важных изменениях.
По времени бюджет обычно «сколько может ждать PR?» Цельтесь в полный eval за <15 минут. За этим разработчики переключаются и теряют продуктивность.
Операционные паттерны
Несколько практик, отличающих зрелые eval-программы:
Паттерн 1: eval-gated деплои
Продакшен-деплои изменений, влияющих на LLM, привязаны к eval-результатам. Оценка упала ниже порога? Деплой блокируется. Инженер разбирается.
Порог обычно относительный: «оценка должна быть в пределах 2% от baseline». Допускает шум, но ловит материальные регрессии.
Паттерн 2: расследование при движении оценок
Любое осмысленное движение оценки (вверх или вниз) расследуется. Оценка выросла? Почему? Мы улучшились или тест стал легче? Оценка упала? Где именно? Регрессия локализована в одном срезе?
Не радуйтесь и не паникуйте по агрегатным движениям; расследуйте.
Паттерн 3: непрерывная курация датасета
Датасет — не одноразовая сборка. Он курируется непрерывно. Процесс:
- Пользователь пожаловался на ответ → добавили в датасет как регрессионный тест.
- Выкатили новую фичу → добавили кейсы под неё.
- Поведение модели кого-то удивило → если это реальный провал, добавили.
- Устаревшие кейсы (больше не релевантны) — списали.
Хорошо работает ежемесячная встреча на ревью. К датасету относятся как к живому активу.
Паттерн 4: ревью по диффу
Когда ревьюите результат eval, фокусируйтесь на дифф-ах от baseline:
- Кейсы, где новая версия набрала выше baseline (улучшения).
- Кейсы, где новая версия набрала ниже (регрессии).
- Кейсы, где оценка не изменилась (нет сигнала).
Дифф — это сигнал. Ревьюить 500 кейсов линейно непрактично; ревьюить 30 диффов — реально.
Паттерн 5: ревью людей при разногласиях с судьёй
Периодически (раз в неделю?) сэмплируйте кейсы, где судья поставил низкую оценку и где — высокую. Человек проверяет: согласны вы с судьёй?
Разногласия выявляют:
- Смещения судьи (донастройте промпт судьи).
- Реальные проблемы качества (чините систему).
- Проблемы датасета (ожидаемый выход неверен).
Именно так вы поддерживаете качество судьи во времени.
Паттерн 6: квартальное ревью evals
Квартальный ретроспективный обзор самой eval-программы:
- Какие реальные регрессии eval-набор поймал за квартал?
- Какие реальные регрессии пропустил?
- Какие ложные тревоги дал?
- Какие пробелы в покрытии нам известны?
- Как датасет покрывает текущее поведение продакшена?
Это мета-eval: оценка оценки. Без него eval-программа деградирует.
Разобранный пример: eval поддержки
Чтобы стало конкретно, вот продакшен-уровневая eval-настройка для AI-системы ответов на запросы поддержки.
Цель: обеспечить, что ответы AI на запросы клиентов точные, полезные, в бренд-стиле и безопасные.
Датасеты:
- Регрессионный набор (300 кейсов): - 50 лёгких (чёткие политики, простые ответы). - 100 средних (типичная сложность). - 100 сложных (неоднозначные, чувствительные, многосоставные). - 50 известных провалов (ранее срегрессировавшие сценарии).
- Discovery (1000 кейсов): ежемесячно нарезается из реального продакшен-трафика, PII вычищены.
- Адверсариальный (50 кейсов): специально сконструированные промпты, пытающиеся вытащить информацию, добиться возврата для неподходящих кейсов, манипулировать AI.
Метрики:
Для каждого кейса судья оценивает:
- Фактическая точность (1-5).
- Соответствие политикам (1-5).
- Уместность тона (1-5).
- Полнота (1-5).
- Уместность длины (1-5).
- Безопасность (бинарно: pass/fail).
Судьи:
- Основной судья: Claude (другой провайдер, чем у тестируемой системы на GPU — выбор другого провайдера снимает self-preference того же семейства моделей).
- Откалиброван по человеку-ревьюеру на 100 эталонных кейсах.
- Перекалибровка квартально.
Агрегация:
- Среднее по измерению по срезу (срезы: тип тикета, тариф клиента, язык).
- Pass rate по безопасности (должен быть 100%).
- Взвешенная оценка на кейс (используется для диффов).
Операции:
- Smoke (30 кейсов) на каждом PR.
- Полный регрессионный набор (300 кейсов) на мердже PR.
- Discovery (1000 кейсов) еженедельно.
- Адверсариальный (50 кейсов) перед любым изменением промпта или модели.
- Онлайн-сэмплирование 1% продакшен-трафика, оцениваемое в реальном времени.
Ревью:
- Ежемесячная встреча: тренды evals, новые режимы отказа, обновления датасета.
- Ежеквартальная встреча: мета-eval, калибровка судьи, аудит датасета.
Результаты (из реальных деплоев похожих систем):
- ~3 пойманных регрессии в месяц, которые бы уехали в продакшен без evals.
- ~1 ложная тревога в месяц (eval помечает регрессию, которая на самом деле в порядке).
- Дрейф детектируется за дни, а не недели/месяцы.
- Уверенность в выкатке изменений промпта и модели — выросла.
Вот как выглядят продакшен-evals. Не быстрый проект на выходные; постоянная инвестиция с реальным ROI.
Типичные ловушки
Несколько паттернов, которые встречаются раз за разом:
Ловушка 1: строить evals после релиза продукта. «Evals добавим позже.» Позже не наступает. Стройте с первого дня.
Ловушка 2: один инженер-владелец. Один человек построил eval; никто больше не сопровождает. Когда он уходит — eval гниёт. Распределяйте владение.
Ловушка 3: рассматривать evals как статику. Построили один раз, больше не обновляем. Становятся бесполезными по мере эволюции продукта. Относитесь к eval как к живому активу.
Ловушка 4: слепо доверять оценкам evals. Eval сказал, что лучше — катим. Без человеческой выборочной проверки выкатываете то, что eval оценил высоко, но что пользователи ненавидят. Парьте evals с ревью человеком на важных изменениях.
Ловушка 5: оптимизироваться под eval. Тюнить промпты так, чтобы хорошо набрать в eval. Eval улучшается; реальность — нет. Следите за этим — если улучшения eval не сопровождаются улучшениями продакшена, вы оптимизируетесь под тест.
Ловушка 6: игнорировать стоимость инфраструктуры. Evals в масштабе дорогие (вызовы LLM накапливаются). Без учёта стоимости узнаёте в конце месяца.
Ловушка 7: нет чётких критериев pass/fail. «Оценка ушла с 4,2 до 4,0 — это регрессия?» Определяйте пороги заранее. Держитесь их.
Ловушка 8: eval-набор поглощает энергию тестирования. Строите изощрённые evals, пока базовые тесты корректности отсутствуют. Evals — для дрейфа качества; не всё тестирование — это evals.
Культурная часть
Самая трудная часть продакшен-evals — культурная. Инженерам и продакт-людям нужно:
- Доверять evals достаточно, чтобы привязывать к ним деплои. Без этого evals — театр.
- Не доверять evals настолько, чтобы расследовать движения. Слепое доверие ведёт к оптимизации под тест.
- Инвестировать в курацию датасета как в постоянную работу. Не разовый проект.
- Принять, что evals не заменяют человеческое суждение. Они сокращают поверхность, которую людям приходится ревьюить.
- Признавать, когда eval-набор не работает. Когда реальные регрессии проскакивают, проблема не у жалующегося пользователя — проблема в eval-наборе.
Команды с этой культурой выкатывают быстрее и надёжнее. Команды без неё в итоге либо чрезмерно полагаются на сломанные evals, либо парализованы их отсутствием.
Главное
Построить evals, которые реально ловят регрессии, сложнее, чем кажется, но это решаемо.
Ключи:
- Реальные, разнообразные датасеты из продакшен-реальности.
- Многомерные, чувствительные к срезам метрики, согласованные с пользовательским опытом.
- Калиброванные судьи, которых вы реально сверяли с человеческим суждением.
- Несколько eval-наборов под разные заботы (регрессия, smoke, discovery, онлайн, end-to-end).
- Операционная дисциплина: eval-gated деплои, непрерывная курация датасета, расследование движений.
- Культурная приверженность использовать и улучшать evals со временем.
Сделанные хорошо, evals становятся самой ценной инфраструктурой в вашем AI-стеке. Это то, как вы быстро выкатываете, не теряя качества. Без них вы летите вслепую.
Постройте evals. Доверяйте evals. Улучшайте evals. Так удерживается качество продакшен-AI.