Примеры кода: code/ Практический проект: Project 05. Let the agent verify its own work
Лекция 09. Предотвращение преждевременных заявлений о завершении
Вы просите агента реализовать функцию «сброс пароля». Он изменяет схему базы данных, пишет API-эндпоинт, добавляет email-шаблон, запускает юнит-тесты (все проходят) и уверенно сообщает: «готово». Когда вы реально пытаетесь это запустить — ссылка сброса пароля не отправляется (отсутствует конфигурация email-сервиса), миграция базы данных падает на середине (несогласованность схемы), а сквозной поток ни разу не выполнялся.
Это чувство не должно быть незнакомым — это как заполнить всю экзаменационную работу, уверенно сдать её первым и затем провалиться при выставлении оценок. То, что работа заполнена, не значит, что ответы правильные.
Это не единичный случай. Классическая статья Guo et al. на ICML 2017 доказала: современные нейронные сети систематически сверх-уверены — уверенность, сообщаемая моделями, значительно выше их фактической точности. То же самое относится и к AI-агентам для кодинга: они «чувствуют», что закончили, но на самом деле до завершения далеко. Ваш harness должен заменить «чувства» агента на экстернализированную, основанную на выполнении верификацию.
Скользкий склон
Преждевременные заявления о завершении почти всегда следуют одному паттерну: код выглядит нормально — синтаксис правильный, логика кажется разумной, статический анализ не показывает очевидных ошибок. Но harness не обеспечивает комплексной верификации выполнения, поэтому агент пропускает реальный запуск или запускает только часть тестов. Он запускает юнит-тесты, но пропускает интеграционные; запускает тесты, но не проверяет покрытие. В итоге «код выглядит нормально» принимается как доказательство того, что «фича завершена». И экзаменационная работа сдаётся.
На каждом шаге теряется информация. От спецификации задачи к реализации кода к runtime-поведению — каждое преобразование может внести искажение, и каждая пропущенная верификация усугубляет информационную асимметрию.
Трёхслойная проверка завершения
Ключевые концепции
- Преждевременное заявление о завершении: Агент утверждает, что задача выполнена, но невыполненные спецификации корректности всё ещё существуют. Главная проблема: агент судит на основе локальной уверенности на уровне кода, тогда как системная корректность требует глобальной верификации.
- Искажение калибровки уверенности: Систематический разрыв между самооценкой уверенности агента в завершении и фактическим качеством завершения. Для сложных мультифайловых задач это смещение значительно положительно — агент всегда увереннее, чем его реальный результат. Как студент, который всегда переоценивает свой балл после экзамена.
- Критерии завершения: Чёткий, выполнимый набор условий, определённый в harness'е. Агент должен удовлетворить все условия перед заявлением о завершении. «Готово» переходит от субъективного суждения к объективному определению.
- Двойной шлюз верификации-валидации: Первый слой верификации проверяет «правильно ли код реализует указанное поведение»; второй слой валидации проверяет «соответствует ли системное поведение сквозным требованиям». Оба должны пройти, чтобы считаться завершёнными.
- Runtime-сигналы обратной связи: Логи, состояния процессов и проверки здоровья из выполнения программы. Это объективная основа для harness'а, чтобы судить о качестве завершения.
- Ограничение приоритета завершения: Сначала верифицировать функциональную корректность, затем производительность, и наконец стиль. Рефакторинг запрещён до верификации основной функциональности.
Юнит-тесты пройдены ≠ Задача завершена
Это самая распространённая ловушка и самая опасная. Агент написал код, запустил юнит-тесты, получил все зелёные и сказал «готово». Но философия дизайна юнит-тестов — изоляция тестируемого модуля и мокирование зависимостей — именно то, что делает их неспособными обнаружить проблемы межкомпонентного взаимодействия:
Несоответствие интерфейсов: Файловый путь, переданный процессом рендеринга в preload-скрипт, является относительным путём, но preload-скрипт ожидает абсолютный путь. Их соответствующие юнит-тесты оба использовали моки и прошли. Проблема обнаруживается только при сквозном тестировании. Как каждый музыкант в группе идеально отыгрывает свою партию, но при совместной игре выясняется, что все в разных тональностях.
Ошибки распространения состояния: Миграция базы данных изменяет схему таблицы, но слой кэширования ORM всё ещё содержит записи кэша для старой схемы. Юнит-тесты предоставляют свежую мок-среду каждый раз, что не выявляет эту кросс-слоевую несогласованность состояния.
Зависимость от окружения: Код ведёт себя корректно в тестовой среде (где всё замокировано), но падает в реальной среде из-за различий в конфигурации, сетевых задержек или недоступности сервисов. Как идеальное пение в репетиционной комнате, но проблемы со звукооборудованием на сцене.
«Заодно отрефакторим» — яд для оценки завершения
У Claude Code есть распространённый паттерн поведения: он начинает рефакторить код, оптимизировать производительность и улучшать стиль до того, как основная функциональность прошла верификацию. Цитата Кнута «Преждевременная оптимизация — корень всех зол» обретает новый смысл в сценарии агента — рефакторинг изменяет границу между верифицированным и неверифицированным кодом, потенциально ломая ранее неявно корректные пути выполнения. Это как переписывать ответы с черновика набело, пока вы ещё не решили задачи — не только трата времени, но можно ещё и переписать с ошибкой.
Систематическое искажение самооценки
Anthropic обнаружила более глубокий паттерн провала в исследовании 2026 года: когда агента просят оценить свою собственную работу, он систематически даёт слишком позитивные оценки — даже когда сторонний наблюдатель счёл бы качество явно неудовлетворительным. Это как попросить студента оценить свой собственный экзамен — он всегда будет особенно снисходителен к своим ответам.
Эта проблема особенно остра в субъективных задачах (таких как эстетика дизайна) — является ли «вёрстка изысканной» — это субъективное суждение, и агент надёжно смещается в положительную сторону. Даже в задачах с проверяемыми результатами производительность агента может быть ограничена плохой оценкой.
Решение не в том, чтобы сделать агента «более объективным» — та же модель, генерирующая и оценивающая, внутренне склонна быть щедрой к себе. Решение — разделить «исполнителя» и «проверяющего». Как студент не должен проверять свой собственный экзамен — нужен независимый проверяющий.
Независимый оценивающий агент, специально настроенный на «придирчивость», значительно эффективнее, чем генерирующий агент, оценивающий сам себя. Экспериментальные данные Anthropic:
| Архитектура | Время | Стоимость | Основные фичи работают? |
|---|---|---|---|
| Одиночный агент (bare run) | 20 мин | $9 | Нет (игровые сущности не реагируют на ввод) |
| Три агента (planner + generator + evaluator) | 6 часов | $200 | Да (игра полностью играбельна) |
Это та же самая модель (Opus 4.5) с тем же самым промптом («создать 2D ретро-игровой редактор»). Единственная разница — harness: от «bare run» к «планировщик разворачивает требования → генератор реализует фича за фичей → оценщик выполняет реальное клик-тестирование через Playwright».
Источник: Anthropic: Harness design for long-running application development
Как предотвратить преждевременные сдачи
1. Экстернализировать суждение о завершении
Суждение о завершении не должно выноситься самим агентом. Harness должен независимо выполнять валидацию завершения, используя runtime-сигналы как входные данные, а не уверенность агента. Запишите это чётко в CLAUDE.md:
## Определение завершения
- Фича завершена = сквозная верификация пройдена, а не «код написан»
- Требуемые уровни верификации:
1. Юнит-тесты пройдены
2. Интеграционные тесты пройдены
3. Сквозная верификация потока пройдена
- Не переходить к уровню 2, если уровень 1 не пройден
- Не переходить к уровню 3, если уровень 2 не пройден2. Построить трёхслойную валидацию завершения
- Слой 1: Синтаксис и статический анализ. Наименьшая стоимость, наименьшая информация, но должен пройти. Это минимальная проверка — сначала надо написать слова правильно, прежде чем рассматривать что-либо ещё.
- Слой 2: Верификация runtime-поведения. Выполнение тестов, проверки запуска приложения, валидация критических путей. Это основное доказательство завершения. Недостаточно просто написать — это должно работать.
- Слой 3: Системное подтверждение. Сквозное тестирование, интеграционная валидация, симуляция пользовательских сценариев. Последняя линия обороны от преждевременных заявлений. Недостаточно работать — должно работать правильно.
3. Разработайте хорошие «красные пометки» для агентов
OpenAI внедрила особенно эффективный паттерн в своей практике Codex: сообщения об ошибках для агентов должны включать инструкции по исправлению. Не просто ставьте большой красный крест как ленивый проверяющий; будьте как хороший учитель и напишите на полях «вот как это нужно изменить». Не используйте "Test failed", а используйте "Test failed: POST /api/reset-password вернул 500. Проверьте, что конфигурация email-сервиса существует в переменных окружения. Файл шаблона должен быть в templates/reset-email.html." Эта конкретная, действенная обратная связь позволяет агенту самокорректироваться без вмешательства человека.
4. Собирайте runtime-сигналы
Эффективные runtime-сигналы включают:
- Успешно ли запустилось приложение и достигло состояния готовности?
- Успешно ли выполнились критические функциональные пути во время выполнения?
- Были ли корректными записи в БД, файловые операции и другие побочные эффекты?
- Были ли очищены временные ресурсы?
Реальный кейс
Задача: Реализовать функциональность сброса пароля пользователя. Включает операции с базой данных, отправку email и модификацию API-эндпоинтов.
Путь преждевременной сдачи: Агент изменяет схему БД, пишет API-эндпоинт, добавляет email-шаблон, запускает юнит-тесты (проходят) и заявляет о завершении. Экзаменационная работа полностью заполнена.
Фактические вычеты баллов: (1) Сквозной поток не протестирован — фактическая отправка и верификация ссылки сброса никогда не подтверждались. (2) Миграция БД упала после частичного выполнения, вызвав несогласованность схемы. (3) Конфигурация email-сервиса отсутствовала в целевом окружении.
Вмешательство harness'а: Принудительная валидация завершения — (1) Запустить полное приложение для проверки доступности эндпоинта сброса; (2) Выполнить полный поток сброса; (3) Верифицировать согласованность состояния БД. Все дефекты были обнаружены в рамках сессии, сэкономив в 5–10 раз стоимость последующих исправлений. Независимый проверяющий нашёл реальные проблемы.
Ключевые выводы
- Агенты систематически сверх-уверены — искажение калибровки уверенности — это объективная реальность. Заполнение экзаменационной работы не означает, что ответы правильные.
- Суждение о завершении должно быть экстернализировано — harness верифицирует независимо; не доверяйте «чувствам» агента. Студенты не могут проверять свои собственные экзамены.
- Все три слоя валидации необходимы — синтаксис пройден, поведение пройдено, система пройдена, прогрессия слой за слоем.
- Сообщения об ошибках должны быть как красные пометки хорошего учителя — включать конкретные шаги исправления, чтобы агент мог самокорректироваться.
- Никакого рефакторинга до верификации основной функциональности — ограничение приоритета завершения — ключ к предотвращению преждевременной оптимизации.
Дополнительное чтение
- On Calibration of Modern Neural Networks - Guo et al. — Доказывает, что современные глубокие сети систематически сверх-уверены
- Building Effective Agents - Anthropic — Критическая роль runtime-доказательств в суждении о завершении
- Harness Engineering - OpenAI — Преждевременное заявление о завершении — один из основных режимов провала агентов
- The Art of Software Testing - Myers — Классический справочник по иерархиям методов тестирования и их эффективности
Упражнения
Дизайн функции валидации завершения: Спроектируйте полную валидацию завершения для задачи, включающей миграцию БД и модификацию API. Перечислите требуемые runtime-сигналы и критерии пройдено/провалено для каждого сигнала. Запустите на реальной задаче и зафиксируйте, какие скрытые проблемы она обнаруживает.
Измерение искажения калибровки: Выберите 10 различных типов задач кодинга и зафиксируйте самооценку уверенности агента в завершении vs. фактическое качество завершения. Вычислите значение смещения и проанализируйте его связь со сложностью задачи.
Эксперимент с многослойной обороной: Запустите три конфигурации на одном наборе задач — (a) только статический анализ, (b) добавить юнит-тестирование, (c) полная трёхслойная валидация. Сравните долю преждевременных заявлений о завершении и количество необнаруженных дефектов.