Инструкция

Оценка AI-агентов: как построить evals и измерять надёжность, а не вайб

Обновлено: · Skillaria.Top

Оценка AI-агентов — это регулярный прогон фиксированного набора реальных задач с автоматической проверкой результата и подсчётом метрик, а не впечатление от пары удачных сессий. Главное — мерить не только pass@k (хотя бы одна из k попыток успешна), но и pass^k (успешны все k попыток), потому что именно стабильность определяет, можно ли доверить агенту работу без присмотра.

Зачем нужна оценка AI-агентов, если и так видно, что он работает

Видно как раз плохо. Агент за неделю ни разу не застрял после правки промпта — это починка или просто неделя простых задач? Один инженер уверен, что новый шаблон всё изменил, второй смотрел тот же лог и разницы не заметил. Оба правы ровно настолько, насколько ничего не посчитали.

Оценка AI-агентов (evals) заменяет ощущение числом. Вы берёте фиксированный набор задач, прогоняете агента, автоматически проверяете результат и сравниваете метрики до и после изменения. Тогда спор «стало ли лучше» решается таблицей, а не авторитетом.

Без evals любое изменение харнеса — промпта, AGENTS.md, набора инструментов, модели — это ставка вслепую. С ними — эксперимент с измеримым результатом.

Почему «вайб» обманывает

У впечатления от работы агента три систематические ошибки, и все они толкают к ложной уверенности.

  • Ошибка выжившего. Удачные прогоны запоминаются и показываются коллегам, неудачные — перезапускаются и забываются. Надёжность, посчитанная по успешным прогонам, ничего не говорит о том, где агент реально ломается.
  • Маленькая выборка. Три удачных задачи подряд — нормальное событие даже для агента, который справляется в половине случаев. Вероятность этого 0,5³ = 12,5%, то есть примерно каждая восьмая серия.
  • Уверенный тон. Агент пишет «готово, все тесты проходят» одинаково уверенно и когда это правда, и когда нет. Уверенность модели не откалибрована: тон ответа — не сигнал корректности.

Отсюда правило: всё, что не записано и не пересчитано, считается неизмеренным.

pass@k и pass^k: две метрики, которые путают

Агент недетерминирован: одна и та же задача при повторе может пройти, а может провалиться. Поэтому одну задачу прогоняют несколько раз и считают одну из двух метрик.

pass@k — хотя бы одна попытка из k успешна

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

pass^k — все k попыток успешны

Метрика отвечает на другой вопрос: «насколько стабильно агент решает задачу». Она описывает работу без присмотра — когда агент запускается много раз и каждый провал стоит денег или времени.

Разница между ними огромная. Пусть агент решает задачу с вероятностью 70% на одну попытку и попытки независимы:

kpass@k = 1 − 0,3^kpass^k = 0,7^k
170%70%
397,3%34,3%
599,8%16,8%
10~100%2,8%

По pass@5 агент выглядит почти идеальным, по pass^5 — ненадёжным. Обе цифры верны, просто описывают разные вещи. Если вы собираетесь отпустить агента работать автономно, смотрите на pass^k: он ближе к тому, что вы увидите в реальной работе.

Как посчитать на практике

Прогоните каждую задачу n раз (например, 5) и запишите число успехов c. Для задачи pass^k приближённо равен доле запусков, где успешны все k подряд, а проще — оцените вероятность успеха p = c / n и возведите в степень. Для набора задач усредните по задачам.

import json
from statistics import mean

# results.jsonl: {"task": "add-pagination", "runs": [true, true, false, true, true]}
rows = [json.loads(line) for line in open("results.jsonl")]

def pass_at_k(runs, k):
    p = sum(runs) / len(runs)
    return 1 - (1 - p) ** k

def pass_pow_k(runs, k):
    p = sum(runs) / len(runs)
    return p ** k

for k in (1, 3, 5):
    print(k,
          round(mean(pass_at_k(r["runs"], k) for r in rows), 3),
          round(mean(pass_pow_k(r["runs"], k) for r in rows), 3))

Оценка через p в степени k грубая при малом n, но для сравнения версий харнеса между собой её обычно достаточно. Важнее, чтобы n и набор задач не менялись между сравнениями.

Как собрать набор задач для evals

Набор задач — главный актив. Хорошая метрика на плохих задачах измеряет не то.

Берите задачи из своей реальности

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

Состав набора

  • 20–50 задач для начала. Меньше — шум съест разницу между версиями. Больше — прогон станет дорогим, и его перестанут запускать.
  • Разные типы: новая фича, исправление бага, рефакторинг, задача на чужой модуль, задача с ловушкой (где правильный ответ — «так делать нельзя» или «нужно уточнение»).
  • Каждая провалившаяся в работе задача становится тестом. Так набор растёт вместе с пониманием, где агент слаб, и регрессии не возвращаются незамеченными.
  • Фиксированное начальное состояние: конкретный коммит, зафиксированные зависимости, одинаковое окружение. Иначе вы мерите не агента, а дрейф среды.

Формат задачи

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

id: add-pagination
repo_ref: 3f2c1ab
prompt: |
  Добавь пагинацию в GET /payments: параметры limit (по умолчанию 20, максимум 100)
  и cursor. Ответ содержит next_cursor.
check:
  - pytest tests/test_payments_pagination.py
  - mypy app/
limits:
  max_changed_files: 6

Обратите внимание: критерий успеха — это Definition of Done, записанный командами. Если вы не можете записать критерий для задачи, это сигнал, что и агенту она поставлена неоднозначно.

Автопроверки или LLM-судья

Проверять результат можно кодом или другой моделью. У каждого способа своя зона.

Автопроверки (код)LLM-судья
Что проверяетТесты, типы, линтер, E2E, размер diff, запрещённые файлыСоответствие требованиям, читаемость, стиль, качество объяснения
ДетерминизмПолныйНет: оценка плавает от запуска к запуску
СтоимостьПочти бесплатноЕщё один вызов модели на каждую задачу
Главный рискПроверяет не всё: тесты зелёные, а фича не таСудья соглашается с уверенным, но неверным решением

Правило: сначала код, судья — поверх

Всё, что можно проверить детерминированно, проверяйте детерминированно. LLM-судью добавляйте только для свойств, которые кодом не выразить, и никогда — вместо тестов.

Как сделать LLM-судью полезным

  • Разный контекст с генератором. Судья не должен видеть рассуждения агента — только задачу, критерии и итоговый diff. Иначе он повторит те же ошибки: это и есть N-версионность, два независимых взгляда вместо одного.
  • Рубрика вместо «оцени по десятибалльной шкале». Конкретные вопросы с ответом да/нет: «есть ли валидация limit > 100», «изменены ли файлы вне app/payments».
  • Калибровка на ручной разметке. Разметьте вручную 20–30 результатов и сравните с вердиктами судьи. Если совпадение низкое, менять нужно рубрику, а не доверять судье больше.
  • Асимметрия ошибок. Ложное «готово» дороже ложного «не готово»: первое уходит в прод, второе стоит одного перезапуска. Настраивайте судью так, чтобы при сомнении он отклонял.

Какие метрики считать кроме доли успехов

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

  • MTBF — сколько шагов или задач агент проходит до застревания. Показывает, как редко он ломается.
  • MTTR — сколько времени уходит на возврат в рабочее состояние после сбоя. Снижать его почти всегда дешевле, чем повышать MTBF: хороший файл прогресса и воспроизводимая среда сокращают восстановление в разы.
  • Радиус поражения — сколько кода портит один неудачный шаг. Ограничивается лимитом на diff и изоляцией рабочей копии.
  • Доля ложных «готово» — задачи, где агент заявил успех, а проверка упала. Самая опасная метрика: именно она показывает, можно ли верить отчёту агента.
  • Стоимость и время — токены и минуты на задачу. Харнес, который поднял успех на 5%, но удвоил стоимость, не всегда выигрывает.

Журнал провалов: evals из повседневной работы

Не каждая команда готова сразу строить прогонщик. Минимальная версия оценки — журнал провалов из трёх колонок.

| Задача                  | Результат                          | Слой          |
|-------------------------|------------------------------------|---------------|
| пагинация /payments     | «готово», 2 теста красные          | верификация   |
| фикс таймаута webhook   | 30 мин на pip install              | среда         |
| рефакторинг refunds     | старый синтаксис ORM               | контекст      |

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

Почему мощная модель не спасает

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

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

Evals позволяют проверить это честно. Прогоните набор с текущей моделью и с моделью дороже, затем — с текущей моделью и добавленным AGENTS.md с командами проверки. Часто второе изменение даёт больше прироста, чем первое, при нулевой цене. Но не верьте этому на слово: именно для таких сравнений набор и нужен.

Пошаговый план: оценка AI-агентов за неделю

  1. День 1. Заведите журнал провалов и пишите в него каждый сбой агента с указанием слоя.
  2. День 2. Отберите 20 задач из закрытых тикетов и журнала. Для каждой зафиксируйте коммит и запишите критерий успеха командами.
  3. День 3. Напишите прогонщик: чистая рабочая копия, запуск агента с промптом задачи, запуск проверок, запись результата в JSONL.
  4. День 4. Прогоните каждую задачу 3–5 раз. Посчитайте pass@1, pass^3, долю ложных «готово», среднюю стоимость.
  5. День 5. Поменяйте одну вещь в харнесе и прогоните заново. Сравнивайте только при одинаковом наборе и числе повторов.

Меняйте по одной переменной за раз. Если в одном эксперименте сменить модель, промпт и инструменты, вы не узнаете, что сработало.

Типичные ошибки при оценке агентов

  • Один прогон на задачу. Недетерминизм агента делает такой результат лотереей. Минимум три повтора.
  • Набор меняется между сравнениями. Добавили новые задачи и одновременно поменяли промпт — цифры несравнимы.
  • Агент видит проверочные тесты. Если тесты лежат в репозитории, агент может подогнать под них код или просто их изменить. Храните скрытые проверки вне рабочей копии и проверяйте, что агент не трогал тестовые файлы.
  • Отчёт агента вместо проверки. «Все тесты прошли» в ответе модели — не результат. Результат — код возврата команды, запущенной прогонщиком.
  • Только pass@k. Красивая цифра для презентации и плохой прогноз для автономной работы.

Итог

Оценка AI-агентов — это фиксированный набор реальных задач, автоматические проверки и метрики, которые пересчитываются после каждого изменения харнеса. pass@k показывает, на что агент способен, pass^k — можно ли ему доверять без присмотра. Автопроверки дают правду, LLM-судья с рубрикой и отдельным контекстом дополняет их там, где код бессилен. А журнал провалов по пяти слоям показывает, что чинить в первую очередь, и чаще всего это не модель. Метрики надёжности и диагностическая петля разобраны на практике в курсе по harness engineering.

Частые вопросы

Сколько задач нужно для evals агента?

Для начала хватает 20–50 реальных задач с автоматическим критерием успеха и 3–5 повторами каждой. Меньший набор не отличит улучшение от шума, больший станет дорогим и его перестанут запускать.

Можно ли оценивать агента только по публичным бенчмаркам?

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

Чем pass@1 отличается от pass^1?

Ничем: при одной попытке обе метрики равны доле успешных прогонов. Различаться они начинают с k больше единицы.

Может ли LLM-судья быть той же моделью, что и агент?

Может, если у него отдельный контекст: он видит только задачу, рубрику и итоговый diff, без рассуждений агента. Но его вердикты всё равно нужно сверить с ручной разметкой.

Как часто прогонять evals?

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

Разберите тему на видео

Эта тема подробно разобрана с практикой в курсе «Harness Engineering: инженерия надёжности AI-агентов».

Перейти к курсу