В статье «Почему проверку результата стоит определить до реализации» я писал о том, что критерий готовности лучше сформулировать до того, как появилось решение.
Работа с coding agents добавила к этому ещё одну границу. Недостаточно заранее определить, что считать правильным результатом. Нужно отделить реализацию от решения о том, достаточно ли доказательств её корректности.
Сначала я пытался повышать надёжность работы с агентами прежде всего через промпты: подробнее описывал задачу, ограничения, ожидаемый результат и проверки. Это действительно помогает. Но длинный промпт не решает принципиальную проблему.
Агент всё ещё может реализовать изменение, сам выбрать удобный способ его проверки и затем сам решить, что задача выполнена.
Поэтому со временем я стал переносить определение готовности из промпта во внешний проверяемый контракт.
Подробный промпт не является проверкой
Coding agent может точно выполнить подробное задание и всё равно проверить результат слишком узко.
Допустим, ему поручили исправить ошибку и добавить regression test. Агент изменил код, написал тест для своего решения, запустил его и получил зелёный результат.
Каждый шаг выглядит правильным. Но тест может подтверждать только основной сценарий. Соседнее поведение могло измениться. Публичный контракт — сломаться. В diff могли попасть изменения, которые вообще не относятся к задаче.
Получается, что один исполнитель принимает сразу несколько решений:
как реализовать изменение
→ как его проверить
→ достаточно ли этой проверки
→ можно ли считать задачу завершённой
Проблема здесь не обязательно в модели. Такое совмещение ролей создаёт слепые зоны и при обычной разработке.
С агентом это особенно заметно, потому что фраза done может появиться через несколько минут после большой серии изменений и выглядеть убедительно, даже если доказательства результата слабее самого отчёта.
У меня получилось три слоя до реализации
Сейчас я стараюсь разделять требования к работе агента на три уровня.
Первый — постоянные правила репозитория. В них находятся ограничения, которые не нужно заново пересказывать в каждом промпте: структура проекта, обязательные проверки, допустимые границы изменений, требования к безопасности и процессу работы.
Второй — условия конкретной задачи. Здесь остаётся то, что относится именно к текущему изменению:
что должно измениться
что должно остаться прежним
какие части проекта относятся к задаче
какие свойства результата нужно подтвердить
Третий — исполняемые проверки. Если требование можно превратить в тест, линтер или одну воспроизводимую команду, я предпочитаю это текстовому «убедись, что всё работает».
Например, в ashikov.ru для полной проверки проекта используется канонический make check. Одну и ту же команду может запустить агент, человек локально и CI.
Агенту не нужно каждый раз самостоятельно определять смысл требования:
проверь, что сайт не сломан
Есть более конкретный проверяемый контракт:
make check
При этом сама команда тоже требует проверки. Когда я добавлял проверку окончаний файлов, были нужны не только положительные сценарии, но и случаи, которые она обязана отклонить.
Зелёный gate полезен только тогда, когда известно, какие нарушения способны сделать его красным.
Проверять нужно не только поведение, но и границы задачи
Проходящих тестов недостаточно.
Агент может исправить нужную ошибку и одновременно изменить соседнюю конфигурацию, провести ненужный рефакторинг или оставить временные файлы. Автоматические тесты при этом останутся зелёными.
Поэтому после реализации я смотрю не только на проверку поведения, но и на само изменение:
какие файлы изменились
что находится в diff
нет ли посторонних изменений
сохранились ли заданные ограничения
Для этого часто достаточно обычных git diff, git diff --check и git status вместе с тестами проекта.
Эти проверки отвечают на разные вопросы.
Тест показывает, сохранилось ли определённое свойство системы. Diff показывает, каким изменением этого добились. Состояние рабочего дерева помогает проверить, остался ли агент в границах задачи.
Поэтому ограниченная область изменений для меня тоже стала частью проверки результата, а не просто пожеланием в промпте.
Done — это вывод, а не доказательство
Я всё меньше ценю саму фразу агента о том, что задача выполнена.
Полезнее получить основания этого вывода:
изменено
→ что именно
проверено
→ какими командами
получено
→ какой результат
границы задачи
→ чем подтверждены
не проверено
→ что осталось неподтверждённым
В некоторых workflows моего репозитория это уже закреплено прямо в процессе. Агент должен сообщать фактически выполненные проверки и не заявлять об успехе проверки, которую не запускал.
Это меняет характер итогового отчёта.
Агент не должен убеждать меня, что решение хорошее. Он должен предоставить наблюдаемые факты, из которых можно сделать такой вывод.
Но здесь остаётся ещё одна проблема.
Все эти доказательства всё равно собрал тот же исполнитель, который написал код.
Второй агент проверяет результат с чистым контекстом
Для задач, где цена ошибки этого оправдывает, я добавляю ещё одну проверку: отдаю результат другому агенту в новом контексте.
Это не означает, что проверяющий ничего не должен знать о задаче.
Наоборот, ему нужны:
исходная задача
правила репозитория
границы изменения
критерии готовности
итоговый diff
результаты выполненных проверок
Но ему не нужна вся история того, как первый агент пришёл к решению.
Исполнитель видел свои промежуточные гипотезы, неудачные попытки и объяснения выбранного подхода. Этот контекст полезен при реализации, но при проверке способен стать помехой.
Если второй агент получает тот же длинный диалог, ему проще продолжить логику первого:
это решение выбрано потому что...
эта проверка считается достаточной потому что...
этот компромисс уже обсуждали потому что...
В новом контексте задача другая:
вот требуемый результат
вот ограничения
вот получившийся diff
вот заявленные доказательства
найди причину, по которой это нельзя принимать
Проверяющий начинает не с объяснения реализации, а с контракта задачи.
Это позволяет обнаружить вещи, которые исполнитель мог не заметить именно потому, что слишком хорошо знает собственное решение: пропущенный сценарий, ненужное изменение, неверное предположение или проверку, которая на самом деле не доказывает заявленное свойство.
Такое ревью не обязательно должен выполнять агент на другой модели. Важнее разделить роли и контекст: один запуск решает задачу, другой независимо проверяет результат.
И проверяющий агент не должен автоматически исправлять всё найденное. Сначала полезнее получить отдельный вывод о соответствии исходному контракту. Иначе проверка снова незаметно превращается в продолжение реализации.
В итоге промпты стали не длиннее, а короче
Сначала мне казалось естественным повышать надёжность агента добавлением инструкций в очередной промпт.
Со временем устойчивые требования начали уходить из него.
Общие правила оказались в инструкциях репозитория. Повторяемые процессы — в skills. Воспроизводимые проверки — в командах проекта и CI. Независимая проверка получила отдельный запуск с исходным контрактом и итоговым результатом.
В конкретном промпте остаётся то, чего агент не может достоверно получить из репозитория: цель задачи, существенный контекст и специфические ограничения.
В результате мой рабочий процесс всё больше выглядит так:
задача
→ границы
→ критерии готовности
→ реализация
→ исполняемые проверки
→ проверка diff
→ evidence
→ независимое review
Здесь нет попытки полностью исключить ошибку агента. Проверки тоже могут быть неполными, критерии — неверными, а второй агент способен пропустить дефект.
Но распределение ответственности становится понятнее.
Исполнитель выбирает способ реализации.
Проверки подтверждают заранее определённые свойства результата.
Diff показывает фактическую область изменения.
Второй агент независимо проверяет, достаточно ли этих доказательств для исходной задачи.
Поэтому для меня качество работы coding agent всё меньше определяется тем, насколько подробный промпт я смог написать.
Промпт задаёт работу. Контракт определяет готовность. А независимая проверка не позволяет исполнителю остаться единственным судьёй собственного результата.
