Симптом и ошибочный диагноз
Команда выпускает агента, запускает eval-набор и наблюдает, как агрегированная оценка растёт несколько недель, а затем выходит на плато. Иногда она подскакивает, а затем падает при следующем запуске без каких-либо изменений в коде. Инстинктивно хочется взяться за архитектуру: заменить планировщик, добавить агента-критика, расширить окно retrieval, изменить схему вызова инструментов. Недели инженерной работы уходят на проблему, которой в модели никогда не было.
Сам eval-набор дрейфовал. Элементы правились на месте без повышения версии. Шаблон промпта, настроенный на нескольких примерах, незаметно впитал эти примеры в свой few-shot блок. Индекс retrieval, построенный по внутренней документации, случайно содержал eval-вопросы и ответы на них. Оценка менялась потому, что менялся измерительный инструмент, и никто этого не замечал, потому что инструмент никогда не рассматривался как артефакт.
Полезная формулировка такова: eval-набор — это датасет. У него есть авторство, происхождение, лицензионные ограничения, риски приватности, распределение и жизненный цикл. Отношение к нему как к папке с JSON, которую может править кто угодно, — корневая причина большинства загрязнений. Решение — не более умная модель. Решение — та же дисциплина, что применяется к обучающим данным, применённая к тому, чем вы измеряете.
Относитесь к eval-набору как к версионированному артефакту
Eval-набор должен быть неизменяемым после публикации. Не «мы стараемся его не править» — структурно неизменяемым, с каждой ревизией, адресуемой по содержимому, чтобы запуск мог записать, против чего именно он оценивался.
Рабочий механизм — манифест, который хеширует каждый элемент и набор целиком:
set: agent-tool-use-core
revision: 2024-11-07.3
items_hash: sha256:9f2c...
item_count: 412
retired:
- id: tool-0183
reason: saturated
superseded_by: tool-0411

Стенд разрешает revision в хеш содержимого до начала запуска и записывает этот хеш в запись результата. Если хеш не совпадает с манифестом, запуск прерывается. Это единственное ограничение устраняет целый класс багов: оценка, с которой вы сравнивались в прошлом месяце, была получена другим инструментом, и теперь система не даёт вам делать вид, что это не так.
Неизменяемость имеет цену. Когда элемент действительно ошибочен — двусмысленная формулировка, устаревшая сигнатура API в трассировке вызова инструмента, фактический ответ, который с тех пор изменился, — вы не можете его исправить. Вы выводите его из обращения и добавляете замену, а значит, набор обрастает родословной, и ваши исторические сравнения должны учитывать замену. Команды, которые пропускают эту дисциплину, получают более чистые на вид временные ряды, которые тихо бессмысленны. Компромисс реальный, и его стоит назвать: вы обмениваете удобство на способность доверять собственной линии тренда.
Дисциплина holdout
Элемент eval не должен появляться ни в одном промпте, индексе retrieval, корпусе дообучения или few-shot примере, используемом во время разработки. Звучит очевидно и нарушается постоянно, обычно через retrieval.
Когда у агента есть шаг retrieval по внутренней документации, а eval-набор хранится в том же репозитории или в том же векторном хранилище, запрос, семантически близкий к eval-вопросу, вытащит элемент eval. Тогда агент отвечает из eval-набора, а не из способности. В выводе ничего не выглядит неправильным; оценка просто растёт.
Контроль, который это ловит, — канарейка. Засейте eval-индекс элементами, правильные ответы на которые известны и которые помечены как канарейки. Оценивайте их отдельно от основного набора и сообщайте долю попаданий канареек как уровень загрязнения. Если канарейки извлекаются или отвечаются правильно с частотой выше случайной, индекс протекает, и главное число подозрительно.
Канарейки дёшевы и несовершенны. Они обнаруживают утечку через путь retrieval и через построение промпта, но не обнаруживают запоминание, зашитое в веса модели при предобучении. Для этого единственные надёжные сигналы — временные: элементы, созданные после даты отсечки обучения модели, или элементы, хранящиеся в приватном пуле, который никогда не публиковался. И то и другое ограничивает то, что вы можете измерить, потому что приватный пул нельзя сравнить с публичными лидербордами. Вот он, компромисс — внешняя сопостави
Каждый элемент должен нести свой источник и авторство. Не для признания заслуг, а чтобы лицензионные и приватностные ограничения можно было пересмотреть, когда они изменятся. Датасет, который можно было использовать два года назад, может быть недопустим сегодня, а набор, собранный из выскобленных клиентских транскриптов, может содержать персональные данные, которые никогда не были согласованы для оценочного использования. Без происхождения по каждому элементу единственное доступное средство — выбросить весь набор.

Контроль доступа — вторая половина. Eval-набор должен быть читаем стендом и почти ничем больше. Инженерам, итеративно улучшающим промпты, не нужен доступ на чтение к элементам eval; им нужны агрегированные результаты и разбивки по срезам. Предоставление доступа на чтение людям, чья работа — улучшить оценку, создаёт очевидный стимул к переобучению, даже при благих намерениях.
Наряду с контролем доступа логируйте каждый retrieval, который касался eval-индекса во время разработки. Лог retrieval, показывающий всплытие элемента eval в сессии разработки, — это событие загрязнения, независимо от того, изменило ли оно решение. Лог делает событие проверяемым постфактум, а не невидимым.
Честный компромисс здесь — скорость. Ограничение доступа на чтение к eval замедляет цикл отладки, потому что инженер, подозревающий конкретный режим отказа, не может просто открыть элемент и прочитать его. Компенсация — отдельный, открыто читаемый набор для разработки, который явно не используется для отчётности. Два набора, два назначения, один из них заперт.
Практика отчётности
Главное число без ревизии и уровня загрязнения — не измерение. Это утверждение. Любая публикуемая оценка должна нести рядом с собой ревизию набора, хеш содержимого и уровень загрязнения, полученный по канарейкам. Если уровень загрязнения нетривиален, оценку следует сообщать с этой оговоркой, а не одной цифрой.
Агрегаты также скрывают регрессию. Единое среднее по смешанному набору замаскирует способность, которая деградировала, пока другая улучшилась. Сообщайте срезы по способностям — выбор инструмента, построение аргументов, многошаговое восстановление, поведение отказа — и сообщайте их с той же дисциплиной ревизий, что и агрегат. Срез, который сдвигается на небольшую величину на наборе из нескольких десятков элементов, — не сигнал; сообщите количество элементов и дайте читателю судить.
Наконец, выводите насыщенные элементы из обращения по расписанию. Элемент, который проходит каждая текущая модель, не даёт ничего, кроме льстящего базового уровня и размытого среднего. Накопление насыщенных элементов заставляет набор выглядеть всеобъемлющим, делая агрегат всё менее информативным каждый квартал. Выводите их из обращения, фиксируйте вывод в манифесте и заменяйте элементами, которые различают.
Ничто из этого не гламурно. Это data engineering, применённый к измерительному инструменту, и это разница между оценкой, которая что-то значит, и оценкой, которая меняется потому, что изменился пайплайн.