Самое важное из мира AI — в канале MAX AgentLabОтдельные разборы, инструменты и практические схемы Читайте Agent Lab в Telegram Разборы, кейсы и новости о практических AI-агентах без лишней воды.

Слишком добрый ИИ-судья: измеряем ложные успехи компьютерного агента

Слишком добрый ИИ-судья: измеряем ложные успехи компьютерного агента
Temporary fallback cover; replace in editorial pass.

Уровень: продвинутый · Время чтения: до 12 минут · Опубликовано: 10 октября 2026

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

Зачем считать именно ложные успехи

Обычно в автоматической оценке смотрят на общую согласованность судьи с человеком. Но ошибки судьи не равноценны. Если модель-судья (LLM-as-a-judge или VLM-as-a-judge: модель, которая по скриншотам и логам выносит вердикт «успех/неуспех») отклоняет хорошую траекторию, вы потеряете один полезный пример. Если же она засчитывает плохую, будет хуже:

Поэтому главной метрикой здесь будет частота ложных положительных решений (false positive rate, FPR): какую долю на самом деле проваленных траекторий судья пометил как успешные.

Кого сравниваем

Методика рассчитана на три типа оценщиков. Конкретные модели выбирайте сами. В статье нет результатов замеров, только порядок их проведения.

  1. Универсальный VLM-судья. Мультимодальная модель общего назначения получает описание задачи, финальный скриншот (или несколько последних) и отвечает «SUCCESS/FAIL» с обоснованием.
  2. Специализированная reward-модель. Модель, обученная оценивать траектории агентов. Она возвращает скалярную оценку, которую вы превращаете в бинарный вердикт по порогу.
  3. Проверяемый ground truth. Программная проверка состояния среды после эпизода: запрос к базе данных, чтение файла, проверка DOM или API. Это эталон, с которым сравниваются первые два.

Важно: ground truth здесь тоже оценщик, только детерминированный. У него свои ограничения, о них ниже.

Шаг 1. Соберите задачи с проверяемым финальным состоянием

Подходят только задачи, итог которых можно проверить кодом. Хорошие примеры:

Неудачные примеры: «найди интересную статью», «сделай письмо вежливее». У них нет однозначного финального состояния.

Для каждой задачи сохраните запись в JSONL. Вот пример формата, а не реальные данные:

{"task_id": "t001", "instruction": "Измени e-mail в профиле на test@example.org и сохрани", "checker": "profile_email_equals", "expected": "test@example.org"}

Шаг 2. Получите траектории, включая «почти успешные»

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

Помимо естественных прогонов агента, полезно намеренно собрать контрольный набор «ловушек»: возьмите успешные траектории и обрежьте их перед последним значимым действием. Такая траектория по построению провалена, но визуально очень похожа на успешную. Помечайте эти случаи отдельно ("source": "truncated"), чтобы потом посчитать метрики по ним отдельно.

Шаг 3. Зафиксируйте ground truth до запуска судей

Сразу после эпизода, пока среда не сброшена, запустите программную проверку и запишите результат. Порядок важен: если проверять позже, можно получить состояние следующего эпизода.

{"task_id": "t001", "run_id": "r17", "source": "natural", "gt_success": false, "gt_detail": "email не изменился: форма не отправлена"}

Судьи не должны видеть gt_success и gt_detail. Иначе это утечка ответа.

Шаг 4. Прогоните судей на одинаковых входах

Чтобы сравнение было честным, все судьи получают одно и то же: инструкцию, одинаковый набор скриншотов и одинаковый текстовый лог действий. Финальное сообщение агента («Задача выполнена») стоит прогнать в двух вариантах, с ним и без него. Так видно, насколько судья доверяет самоотчёту агента.

Шаблон промпта для VLM-судьи (пример):

Ты проверяешь работу компьютерного агента.
Задача: {instruction}
Ниже — последние скриншоты и список действий.
Оцени ТОЛЬКО по видимому состоянию интерфейса, а не по словам агента.
Если нет прямого визуального подтверждения, что изменение сохранено, ответь FAIL.
Ответ строго в формате: VERDICT: SUCCESS|FAIL; REASON: <одно предложение>

Для reward-модели запишите сырой скор. Порог подберите на отдельной калибровочной выборке, а не на тестовой. Иначе FPR получится заниженным.

Итоговая запись на одну траекторию (пример):

{"run_id": "r17", "source": "natural", "gt_success": false, "vlm_verdict": "SUCCESS", "rm_score": 0.41}

Шаг 5. Посчитайте FPR и сопутствующие метрики

Скрипт ниже использует только стандартную библиотеку Python, ничего не устанавливает и не обращается к сети. Он читает локальный файл verdicts.jsonl и печатает матрицу ошибок для каждого судьи.

python3 -m venv .venv
. .venv/bin/activate
python3 score_judges.py verdicts.jsonl --rm-threshold 0.5
# score_judges.py
import argparse, json
from collections import defaultdict

def load(path):
    with open(path, encoding="utf-8") as f:
        return [json.loads(line) for line in f if line.strip()]

def confusion(rows, pred):
    c = defaultdict(int)
    for r in rows:
        gt, p = r["gt_success"], pred(r)
        c[("TP" if p else "FN") if gt else ("FP" if p else "TN")] += 1
    return c

def report(name, c):
    neg = c["FP"] + c["TN"]
    pos = c["TP"] + c["FN"]
    fpr = c["FP"] / neg if neg else float("nan")
    tpr = c["TP"] / pos if pos else float("nan")
    judged = c["TP"] + c["FP"]
    prec = c["TP"] / judged if judged else float("nan")
    print(f"{name:12} FP={c['FP']:4} TN={c['TN']:4} TP={c['TP']:4} FN={c['FN']:4} "
          f"FPR={fpr:.3f} TPR={tpr:.3f} precision={prec:.3f}")

ap = argparse.ArgumentParser()
ap.add_argument("path")
ap.add_argument("--rm-threshold", type=float, default=0.5)
a = ap.parse_args()
rows = load(a.path)

judges = {
    "vlm": lambda r: r["vlm_verdict"] == "SUCCESS",
    "reward_model": lambda r: r["rm_score"] >= a.rm_threshold,
}
for source in sorted({r.get("source", "all") for r in rows}) + ["ALL"]:
    subset = rows if source == "ALL" else [r for r in rows if r.get("source") == source]
    print(f"\n== source: {source} (n={len(subset)}) ==")
    for name, pred in judges.items():
        report(name, confusion(subset, pred))

Что смотреть в выводе:

Шаг 6. Проверьте устойчивость результата

Как проверить, что замер корректен

  1. Вручную просмотрите случайную выборку траекторий, где ground truth и судья не согласны. Иногда ошибается проверка: например, она читает не ту запись.
  2. Убедитесь, что все «ловушки» действительно получили gt_success: false. Если какая-то обрезанная траектория прошла проверку, значит, последнее действие не было значимым и ловушка некорректна.
  3. Сверьте число строк: у каждой траектории должны быть вердикты всех судей. Пропуски (таймаут API, неразобранный ответ) учитывайте отдельно и не превращайте молча в FAIL или SUCCESS.
  4. Проверьте, что калибровочная и тестовая выборки не пересекаются по task_id.

Типовые ошибки

Ограничения методики

Что делать с результатом

Если у судьи высокий FPR, не обязательно сразу от него отказываться. Практичные варианты: сделать ground truth основным сигналом везде, где он доступен, а судью использовать только для непроверяемых задач; ужесточить промпт и запретить опираться на самоотчёт агента; для фильтрации обучающих данных требовать согласия двух независимых оценщиков. После любого такого изменения прогоните замер заново на тех же траекториях. Тогда сравнение «до/после» будет честным.

Что почитать дальше

Другие практические методики оценки и тестирования агентов собраны в разделе руководств. Термины из статьи (reward-модель, ground truth, FPR, reward hacking) объяснены в глоссарии.