Generator Evaluator

Паттерн «генератор + внешний оценщик»: качество обеспечивает не самооценка модели, а отдельный верификатор. Опирается на асимметрию: проверить решение легче и дешевле, чем создать. Для длинных задач разворачивается в трио Planner / Generator / Evaluator (harness-дизайн Anthropic).

Суть

Генератор выдаёт варианты, верификатор отбирает/судит. Самооценке агента доверять нельзя: «агенты уверенно хвалят свою работу, даже посредственную» — особенно на субъективных задачах (дизайн), где нет бинарного теста. Поэтому оценщик выносится наружу.

Зачем это нужно

Одиночная модель в долгой автономной сессии «сходит с рельсов» и переоценивает себя. Внешний оценщик с явными критериями ловит брак, который модель приняла бы «на слово». Важно: если верификатор слабее генератора — система деградирует («слепой ведёт слепого»), поэтому верификатор должен быть сильным, а генератор может быть дешёвым.

Как работает

  • Best-of-N / Search against Verifier — генерируем N вариантов (повышая temperature), строгая модель-судья выбирает лучший. Так внутри работают Claude Code и топовые код-агенты.
  • Trust Gate / Executable Spec Layer — где есть объективная проверка, оценщик = автотесты (Pytest), которые агент не может изменить; при провале агент получает лог ошибки и переписывает решение (см. DoD в Agent Evals).
  • Planner / Generator / Evaluator (harness Anthropic) — трёхагентная архитектура для многочасовых сессий: планировщик декомпозирует, генератор пишет, оценщик критикует по критериям. Цикл генератор↔оценщик соответствует review/QA в обычной разработке.
  • Context resets — против «context anxiety» оценщик/оркестратор сбрасывает контекст и передаёт следующему агенту структурированный handoff-артефакт (отличие от compaction — см. Context Window).

Пример

Best-of-N: генератор выдаёт N вариантов (повышенная температура → разнообразие), отдельный верификатор оценивает каждый (проверить легче, чем сгенерировать), возвращается лучший.

def best_of_n(query, n=3):
    candidates = [think_then_answer(query, temperature=0.7).answer for _ in range(n)]  # N вариантов
    scored = [{"answer": c, **verifier_score(query, c)} for c in candidates]           # внешний судья
    scored.sort(key=lambda x: x["score"], reverse=True)
    return scored[0]                                                                   # лучший по оценке

Проверка взрослеет по месту включения

Один и тот же verifier можно внедрять ступенчато, не начиная с обязательного gate для всей команды:

  1. Standalone — человек отдельно запускает проверку после работы; дёшево проверить полезность критериев.
  2. Embedded — рабочая процедура сама вызывает проверку перед завершением.
  3. Chained — один skill вызывает другой и передаёт ему явный артефакт.
  4. Every PR — стабильная проверка становится общей политикой приёма.

Продвигать проверку вверх стоит по наблюдаемой повторяемости: частый ручной follow-up сначала встраивается в локальную процедуру, и только после стабильного trigger и приемлемого false-positive rate становится командным gate. Иначе сырой evaluator масштабирует шум быстрее, чем качество.

Если исправляющий агент может менять сам критерий, цикл замыкается неправильно: самый короткий путь к GREEN — ослабить тест. На время починки evaluator замораживается либо его изменение требует отдельного review и доказательства, что проверка не стала слабее (AI Native SDLC).

Сколько итераций держать цикл

По длине цикла «генератор ↔ ревьюер» источники расходятся, и разница в них не фактическая, а нормативная.

Как бывает. В разборе CrewAI цикл исполнителя и ревьюера уходил на шесть-семь ретраев: ревьюер раз за разом отклонял текст и удовлетворился только с седьмого прохода. Это наблюдение из отладки — так система действительно себя вела.

Как надо. Продакшен-практика ставит жёсткий потолок в единицы итераций с эскалацией человеку. Аргумент простой: агентный цикл — это while True с привязанной кредиткой, и каждая лишняя итерация стоит денег и латентности, а прирост качества после первых проходов не гарантирован.

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

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

Сколько вариантов и как оценивать невыразимое кодом

Best-of-N. Отдача от N убывающая: разброс качества между вариантами конечен, и после нескольких генераций новые почти не приносят лучшего кандидата, тогда как стоимость растёт строго линейно. Поэтому N подбирают не «побольше», а от того, насколько дороже ошибка, чем лишняя генерация: там, где ошибка стоит одного повторного запроса пользователя, хватает одного прохода; там, где она попадает в необратимое действие, N оправдан вместе с внешним верификатором. Adaptive compute — именно про это: тратить N только на шагах, где нужна надёжность (Agent CostControl).

Субъективные задачи. Отсутствие бинарного теста не означает отсутствия критерия — оно означает, что критерий надо выписать. Рабочая форма — набор отдельных бинарных проверок вместо одной шкалы: не «оцени качество от 1 до 10», а «соответствует ли тону», «есть ли ответ на заданный вопрос», «нет ли утверждений сверх источника» — каждая с PASS/FAIL. Бинарность здесь не упрощение, а условие согласуемости: по шкале 1-10 два человека не сойдутся, по «прошло/не прошло» — сойдутся (LLM as Judge, монадическая оценка и обязательное рассуждение до вердикта).

Выбрать из нескольких — не то же, что переписать своё

Паттерн выше требует, чтобы оценщик был внешним, и опирается на то, что самооценке доверять нельзя. Рядом в базе стоит более жёсткое утверждение: внутренняя самокоррекция без внешнего сигнала на задачах рассуждения не работает и местами ухудшает результат (Chain of Thought, Huang et al.). Из двух вместе получается, что модель не может быть верификатором сама себе.

Это верно для ревизии и неверно для селекции. Различие не в том, кто проверяет, а в том, что делают с проверкой:

Ревизия Селекция
Что происходит модель переписывает свой ответ модель выбирает лучший из N уже готовых
Верхняя граница нет — можно уехать куда угодно лучший кандидат в наборе (оракул)
Нижняя граница нет — результат может стать хуже исходного случайный выбор из N
Чем платит ошибка суждения испорченным ответом невыбранным лучшим кандидатом

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

Это подтверждено на самопроверке, а не выведено умозрительно. В LLM-as-a-Verifier deepseek-v4-flash выступает и генератором, и верификатором на Terminal-Bench 2.1: Best-of-3 поднимает 79.4% → 86.5% при оракуле 92.1%, Best-of-5 — 78.7% → 88.0% при оракуле 96.6%. Та самая модель, которой нельзя доверить переписывание собственного ответа, отбирает свои же траектории с пользой.

Оракул — та величина, которой в паттерне не хватало. Он говорит, сколько вообще можно выиграть отбором: разрыв между Pass@1 и Pass@k — это весь бюджет верификатора, и внутри него измеряется, насколько он хорош. Без оракула прирост «на 8 пунктов» не с чем сравнить. На Terminal-Bench Best-of-5 верификатор забирает около половины доступного разрыва (78.7 → 88.0 при потолке 96.6); на MedAgentBench разрыв узкий изначально (70.2 → 73.3 при потолке 75.0), и там отбор почти исчерпан. Узкий разрыв — сигнал, что тратить на Best-of-N нечего, и считать его надо до того, как строить отбор.

Заголовочный результат той же работы — про разные модели: GPT-5.5 генерирует, gemini-2.5-flash проверяет, 83.1% → 86.5% при оракуле 92.1% на Terminal-Bench V2. Это ровно то, что паттерн и утверждал; новое здесь — вторая установка, где проверяющий и проверяемый совпадают.

Связано с

  • Reflexion — самокритика того же агента между попытками вместо отдельного критика внутри задачи; это ревизия, и разбор выше объясняет, почему к ней предупреждение применимо, а к Best-of-N нет

  • Chain of Thought — предупреждение про самокоррекцию, область которого здесь сужена

  • Benchmarks Agents — Terminal-Bench и рамка «Pass@1 против оракула Pass@k»

  • Agent Architecture — где этот слой встраивается в master loop

  • Agent Evals — Trust Gate / executable spec как форма оценки

  • Plan and Execute — Planner здесь = планировщик из plan-and-execute

  • Reasoning Effort — почему внешняя оценка надёжнее самокоррекции (нюанс риска self-reflection)

  • LLM as Judge — техника судьи (критерии, бинарность, калибровка), на которой стоит этот паттерн

  • Multi Agent Patterns — критик/ревьюер как обязательный паттерн MAS (каскад ошибок 90%→65%)