Amiga
Оглавление курса · урок 20 из 24

Модуль 5 · Оценка и управление · урок 20 из 24

Свои evals для кодинг-агентов

Публичный бенчмарк отвечает на вопрос «как модель решает чужие задачи в чужом harness». Вам нужен другой ответ: станет ли агенту лучше или хуже в вашем репозитории после смены модели, правки AGENTS.md или нового навыка. Без своего набора задач (evals) любое изменение обвязки агента (harness) — это вкусовщина и пара удачных сессий. В этом уроке — как собрать такой набор за несколько дней и встроить его в работу.

Что именно вы оцениваете

Anthropic в статье Demystifying evals for AI agents вводит словарь, которым удобно пользоваться и нам:

  • задача (task) — постановка плюс исходное состояние репозитория;
  • прогон (trial) — одна попытка агента решить задачу;
  • оракул, или грейдер (grader) — то, что выносит вердикт;
  • транскрипт — полная запись действий агента;
  • результат (outcome) — итоговое состояние среды, а не то, что агент сказал о своей работе.

Главное следствие из той же статьи: оценивая «агента», вы оцениваете связку harness и модели. Поменяли AGENTS.md, набор MCP-серверов или версию Codex CLI — это уже другой испытуемый, даже если модель та же.

Второе различие — назначение набора. Capability evals проверяют то, что агент пока делает плохо, и начинаются с низкой доли успеха: это холм, на который вы взбираетесь. Regression evals проверяют то, что уже работает, и должны держаться около 100%. Задачи, которые стабильно проходят, со временем переезжают из первой группы во вторую.

Откуда брать задачи

Не придумывайте задачи с нуля. Anthropic советует начинать с 20–50 простых задач из реальных провалов. В агентстве их источник очевиден: MR, которые ревьюер переписал; баги, пойманные QA после агентского коммита; задачи из Kaiten, где агент трижды не попал в макет или сломал e2e.

Каждая задача должна быть однозначной: два инженера, глядя на результат, выносят одинаковый вердикт. Если для этого нужен разговор с автором задачи, постановку надо дописать. И у каждой задачи должно быть эталонное решение — хотя бы коммит, которым человек закрыл её на самом деле.

Структура набора, которая хорошо живёт рядом с кодом:

text
evals/
  run.sh
  tasks/
    form-phone-validation/
      task.json        # базовый коммит, тип, таймаут
      prompt.md        # постановка, как её получил бы агент
      setup.sh         # подготовка worktree: composer install, npm ci
      check.sh         # оракул: выносит вердикт по итоговому состоянию
      oracle/          # скрытые тесты, агент их не видит
  results/
json · evals/tasks/form-phone-validation/task.json
{
  "id": "form-phone-validation",
  "base": "a1b2c3d",
  "kind": "regression",
  "source": "MR !412, правка ревьюера: валидация телефона на сервере"
}

Базовый коммит — состояние репозитория до того, как человек решил задачу. Промпт — формулировка из трекера, а не пересказ решения.

Оракулы: от дешёвых к дорогим

Anthropic делит грейдеры на три вида: код (быстро и воспроизводимо, но хрупко), модель (гибко, но требует калибровки) и человек (эталон, но дорого и медленно). Совет статьи — детерминированные проверки везде, где возможно, LLM-судья там, где без него никак.

Тесты. Основной оракул для кода. Принципиально, чтобы тесты оракула были скрыты от агента: если он их видит, он решает «пройти тесты», а не задачу. Тесты кладутся в worktree только после того, как codex exec закончил работу.

Проверки поведения. Playwright-сценарий на поднятом стенде, состояние базы после миграции, HTTP-ответ формы. Это ближе к тому, что проверит QA. Почему проверка поведения — самое слабое место harness, разобрано в уроке о проверке поведения.

Проверки отсутствия. Агент не правил существующие тесты, не добавил зависимость, не тронул чужой модуль. Anthropic отдельно советует проверять и наличие нужного поведения, и отсутствие нежелательного.

bash · evals/tasks/form-phone-validation/check.sh
#!/usr/bin/env bash
# Запускается в worktree после агента; $1 — каталог oracle/
set -euo pipefail
ORACLE="$1"
# Агент не должен был править существующие тесты
if ! git diff --quiet HEAD -- tests/; then
  echo "FAIL: изменены существующие тесты"; exit 1
fi
# Агент не должен был добавлять зависимости
if ! git diff --quiet HEAD -- composer.json composer.lock; then
  echo "FAIL: изменены зависимости"; exit 1
fi
# Скрытые тесты оракула
cp "$ORACLE"/PhoneValidationTest.php tests/Feature/
vendor/bin/phpunit tests/Feature/PhoneValidationTest.php

LLM-судья. Нужен для того, что не формализуется: понятно ли описание MR, соблюдены ли соглашения из docs/, не размазана ли логика по слоям. Рекомендации Anthropic: калибровать судью по оценкам людей, давать ему вариант ответа «не знаю», а каждое измерение оценивать отдельным судьёй, а не одним на всё. На практике: два человека размечают 20–30 результатов, судья размечает те же, и вы смотрите, где он расходится с людьми. Пока не совпадает — правьте рубрику, а не доверяйте цифре. Вердикт удобно получать по схеме через --output-schema (см. урок об ответе по схеме).

И последнее правило оракулов: оценивайте результат, а не путь. Проверка «агент сначала прочитал README, потом запустил тесты» ломается на первом же разумном отклонении.

Скрипт прогона на codex exec

Каждый прогон — в чистом окружении: Anthropic прямо предупреждает, что общее состояние между прогонами даёт коррелированные провалы или завышает результат. Отдельный git worktree на прогон — самый дешёвый способ.

bash · evals/run.sh
#!/usr/bin/env bash
# Использование: ./evals/run.sh <прогонов на задачу> <метка> [модель]
set -euo pipefail
K="${1:-3}"; LABEL="${2:-baseline}"; MODEL="${3:-}"
ROOT="$(git rev-parse --show-toplevel)"
OUT="$ROOT/evals/results/$LABEL-$(date +%Y%m%d-%H%M)"
mkdir -p "$OUT"
codex --version > "$OUT/codex-version.txt"
MODEL_ARGS=(); [ -n "$MODEL" ] && MODEL_ARGS=(-m "$MODEL")

for dir in "$ROOT"/evals/tasks/*/; do
  id="$(basename "$dir")"
  base="$(jq -r .base "$dir/task.json")"
  for i in $(seq 1 "$K"); do
    wt="$(mktemp -d)/wt"
    git -C "$ROOT" worktree add --detach "$wt" "$base" >/dev/null 2>&1
    [ -f "$dir/setup.sh" ] && (cd "$wt" && bash "$dir/setup.sh") >/dev/null 2>&1
    codex exec --ephemeral --ignore-user-config -C "$wt" \
      --sandbox workspace-write ${MODEL_ARGS[@]+"${MODEL_ARGS[@]}"} --json \
      -o "$OUT/$id.$i.last.md" - < "$dir/prompt.md" \
      > "$OUT/$id.$i.jsonl" 2> "$OUT/$id.$i.stderr" || true
    if (cd "$wt" && bash "$dir/check.sh" "$dir/oracle") > "$OUT/$id.$i.check.log" 2>&1
    then r=1; else r=0; fi
    echo "$id,$i,$r" >> "$OUT/results.csv"
    git -C "$ROOT" worktree remove --force "$wt"
  done
done
echo "Результаты: $OUT"

Что здесь важно. --ignore-user-config убирает влияние личного ~/.codex/config.toml, иначе результат зависит от того, чей это ноутбук. --json сохраняет транскрипт событий для разбора. Промпт подаётся через stdin (-). Версия Codex CLI записывается рядом с результатами: без неё сравнение двух прогонов бессмысленно.

Оговорка о скрытности оракула: песочница по умолчанию даёт агенту читать почти всю файловую систему, так что каталог evals/ в соседнем checkout формально ему доступен. Для строгого режима гоняйте набор в контейнере или CI-раннере, куда оракул попадает только после завершения агента. В примере OpenAI Cookbook для того же используют профиль прав, запрещающий чтение эталонных ответов.

Повторяемость: pass@k и pass^k

Агент недетерминирован, поэтому один прогон на задачу ничего не доказывает. В том же примере Cookbook три повторных прогона дали почти одинаковую общую долю успеха — разница в 3 пункта, — но 23 вопроса из 108 переключались между «прошёл» и «не прошёл». Средняя цифра скрывает нестабильность.

Две метрики из статьи Anthropic:

  • pass@k — вероятность, что хотя бы одна из k попыток успешна;
  • pass^k — вероятность, что успешны все k попыток.

При 75% успеха на попытку все три попытки проходят примерно в 42% случаев. Если результат агента всё равно смотрит человек и можно выбрать лучший из нескольких вариантов, ориентируйтесь на pass@k. Если агент работает без присмотра — автопочинка CI, фоновая уборка, — важна pass^k.

bash
# Доля задач, решённых хотя бы раз и во всех прогонах
awk -F, '{n[$1]++; s[$1]+=$3}
  END {for (t in n) {c++; any+=(s[t]>0); all+=(s[t]==n[t])}
  printf "задач=%d pass@k=%.2f pass^k=%.2f\n", c, any/c, all/c}' results.csv

Задача с нулём из многих прогонов — по наблюдению Anthropic, чаще сломанная задача, чем неспособный агент. Перечитайте постановку и оракул.

Регресс harness

Набор нужен в момент, когда вы что-то меняете:

  • смена модели — линейка моделей в Codex регулярно обновляется, а старые модели выводятся;
  • правка AGENTS.md, docs/ или навыка;
  • новый MCP-сервер или обновление Codex CLI.

Порядок простой: прогон с меткой baseline до изменения, прогон с меткой кандидата после, сравнение по задачам, а не только по итоговой цифре. И обязательно читайте транскрипты. Anthropic приводит пример с CORE-Bench: результат Opus 4.5 вырос с 42% примерно до 95% после того, как исправили оценку и постановки задач, — дефекты были в самом наборе. Ваши evals — такой же код, и в них тоже бывают баги.

Задачи из вашего репозитория приватны, а значит, защищены от главной болезни публичных бенчмарков — попадания в обучающие данные. Почему это важно, разберём в следующем уроке, о бенчмарках.

Попробуйте сами

10–15 мин на рабочем месте
  1. Пролистайте последние 20 MR пилотного проекта и выпишите 5 задач, где агентский результат пришлось заметно переделывать. Для каждой запишите базовый коммит и коммит человека.
  2. Оформите одну задачу по структуре выше: task.json, prompt.md, check.sh с проверкой отсутствия изменений в тестах. Прогоните ./evals/run.sh 3 baseline и посчитайте pass@k и pass^k.
  3. Измените одну строку в AGENTS.md, которая касается этой задачи, и прогоните набор с другой меткой. Сравните не только цифры, но и два транскрипта.

Коротко

  • Оценивается связка harness и модели: любая правка обвязки — новый испытуемый.
  • Задачи берите из реальных провалов, начните с 20–50; каждой нужен однозначный критерий и эталонное решение.
  • Детерминированные оракулы везде, где можно; LLM-судья — только откалиброванный по людям, по одному на измерение.
  • Чистый worktree на прогон, скрытый оракул, записанная версия Codex CLI.
  • Смотрите pass^k для задач без присмотра; ноль на многих прогонах — повод проверить саму задачу.
Отметка хранится только в вашем браузере
Хотите связаться с владельцем
компании напрямую?
Дмитрий Тарасов
Дмитрий Тарасов
СЕО

НАПИСАТЬ

Написать в MAX