Перейти к основному содержимому

Eval-наборы устаревают: версионируйте харнесс, а не только модель

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

Макрофотография печатной платы с медными дорожками, паяными соединениями и небольшой интегральной схемой при малой глубине резкости.

Режим отказа

Агенты, которые итерируют против фиксированного eval-набора, не сходятся к задаче. Они сходятся к набору. Это не тонкий статистический артефакт; это предсказуемый результат цикла оптимизации, где целевая функция — конечная статическая выборка. Каждая правка промпта, каждая настройка политики вызова инструментов, каждая корректировка порога скоринга — это шаг градиента в сторону идиосинкразий eval-набора, а не лежащей в основе способности, которую набор должен был измерять.

Эта динамика хорошо задокументирована в литературе о самоулучшающихся агентах. Исследователи Google предложили методы, не позволяющие самоулучшающимся агентам запоминать тесты, именно потому, что поведение по умолчанию — запоминание. Когда агент может генерировать собственный обучающий сигнал или уточнять свои промпты, граница между «изучением задачи» и «изучением теста» размывается. Агент не может отличить подлинную способность от паттерна, который случайно удовлетворяет скореру.

Загрязнение обычно обнаруживается после того, как результат уже опубликован. Сообщается оценка бенчмарка, обновляется карточка модели, выходит пост в блоге. Месяцы спустя кто-то замечает, что подмножество eval-элементов появилось дословно в обучающем корпусе, или что выходы агента на определённом срезе подозрительно однородны. Отзыв публикации неловок; ущерб доверию хуже. В пайплайне не было механизма, чтобы поймать проблему до публикации, потому что eval-набор рассматривался как фиксированная точка отсчёта, а не как живой артефакт.

Почему это баг пайплайна

Eval-наборы копируются в контексты обучения и промптинга без происхождения. JSONL-файл коммитится, затем дублируется в задание дообучения, затем вставляется в few-shot промпт, затем встраивается в индекс поиска. Каждая копия — это форк. Ни одна из них не несёт ссылку на оригинал. Когда оригинал обновляется, форки расходятся молча. Когда форк утекает в обучение, нет записи о том, что eval-элемент и обучающий пример имеют общего предка.

Нет дисциплины holdout между набором, используемым для итерации, и набором, используемым для отчётности. Команды итерируют на тех же элементах, о которых отчитываются. Набор для итерации становится набором для настройки, а набор для настройки становится целью запоминания. Настоящий holdout — это не просто «набор, на который мы не смотрим»; это набор, структурно изолированный от цикла итерации, с контролем доступа и журналами аудита.

Close-up of cooling fans inside a server room rack

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

Первопричина — категориальная ошибка. Eval-наборы рассматриваются как данные, а данные предполагаются инертными. Но eval-набор — это зависимость каждого результата, который на него ссылается. У него есть схема, происхождение, набор потребителей и жизненный цикл. Он заслуживает той же дисциплины версионирования, ревью и вывода из эксплуатации, что и любая другая зависимость в стеке.

Правило проектирования: относитесь к eval как к версионируемым зависимостям

Закрепите eval-набор, харнесс и код скоринга как единую версионируемую единицу. Не три отдельные версии; одну составную версию. Версия eval — это кортеж: набор элементов, конфигурация промпта и инструментов, реализация скоринга и идентификатор модели. Любое изменение любого элемента порождает новую версию. Версия — это хеш содержимого, а не назначенная человеком метка, поэтому она не может дрейфовать.

Поддерживайте ротируемый приватный holdout, который никогда не используется для итерации. Holdout создаётся отдельно, хранится в отдельном репозитории с отдельным контролем доступа и ротируется по расписанию. Ротация означает вывод из эксплуатации раскрытых элементов и создание новых. Это дорого, и это честный компромисс: holdout, который никогда не ротируется, становится де-факто набором для итерации, как только его содержимое утекает в знания команды. Стоимость ротации — это цена измерения, которое что-то значит.

Записывайте версию eval рядом с каждой отчётной метрикой. Число без версии eval — это не результат; это слух. Версия должна появляться на дашбордах, в карточках моделей, в трекерах экспериментов и в любом документе, который ссылается на оценку. Когда ревьюер спрашивает «стало ли лучше?», первый вопрос — имеют ли эти два числа одну версию eval.

Конкретный механизм: файл манифеста, который связывает кортеж вместе.

eval_version: sha256:9f2c...
items: s3://evals/holdout-2024-11/items.jsonl
harness:
  prompt_template: sha256:1a4b...
  tools: sha256:7c3d...
  scoring: sha256:e8f1...
model: provider/model-name![Close-up of white woven fabric with small ![Close-up of white woven fabric with small textured holes, a stock photo](/media/woven-carbon-fibre-texture-e8e50d-38b215.jpg)erver-rack-closeup-48ae67-477829.jpg)

Манифест — это единица цитирования. Шлюз релиза проверяет хеш манифеста перед разрешением деплоя. Дашборд отображает хеш рядом с метрикой. Пайплайн обучения отказывается принимать элементы, чей манифест совпадает с манифестом holdout. Хеш — это происхождение.

## Обнаружение

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

Сравнивайте со свежесозданным срезом перед любым решением о релизе. Свежий срез мал, создан вручную и никогда не используется для итерации. Это не бенчмарк; это проверка здравомыслия. Если оценка агента на свежем срезе расходится с его оценкой на наборе для итерации, набор для итерации загрязнён или переобучен. Расхождение — это находка.

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

Более глубокая мысль в том, что самоулучшающиеся агенты делают eval-набор частью цикла обучения. Как только это происходит, eval-набор перестаёт быть нейтральным наблюдателем. Он становится участником. Участникам нужно версионирование, контроль доступа и ротация. Дефект пайплайна не в том, что агенты жульничают; а в том, что пайплайн дал им статическую цель и назвал это измерением.

## Обязательство жизненного цикла

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

Связанное чтение

На какие вопросы это отвечает

What is eval set contamination?

Contamination occurs when eval items leak into training data, prompting contexts, or retrieval indexes, so the agent's score reflects memorisation of the items rather than capability on the task. It is usually discovered after a result has been published because the pipeline lacks lineage between eval items and their copies.

Why version the harness together with the eval set?

A score is produced by a tuple: item set, prompt template, tool definitions, scoring code, and model revision. Changing any element changes the measurement. Pinning the tuple as a single content-hashed version makes historical numbers comparable and makes silent drift detectable.

How often should a private holdout be rotated?

Rotation should be scheduled and triggered by exposure, not by calendar alone. Any time holdout items enter team knowledge, documentation, or iteration discussions, they are candidates for retirement. The cost of authoring new items is the price of a measurement that still means something.

What signals suggest an agent has memorised its eval set?

Per-item tracking reveals suspiciously uniform success, pass rates that jump without a corresponding capability change, and outputs collapsed to a single phrasing. Comparing against a freshly authored slice before a release decision surfaces divergence between iteration-set and holdout performance.