Я перестал радоваться моменту, когда AI-агент слишком быстро уходит в код.

Не потому что скорость сама по себе вредна. Скорость полезна, если задача уже стала понятной и проверяемой.

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

Сигнал настоящий.

Вывод - нет.

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

В моем опыте агентная разработка часто ломается не на коде. Она ломается в момент, когда мы даем агенту задачу и не фиксируем, что именно считается правильным результатом.

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

Prompt - это интерфейс, не сама задача

Prompt может быть хорошим интерфейсом к задаче. Но он не обязан быть самой задачей.

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

Можно сказать: "Но это же обычная постановка задачи". Да, во многом так и есть.

Именно в этом, кажется, и проблема. AI-агент не отменяет старую инженерную дисциплину. Он быстрее показывает, где ее не было. Раньше размытая задача превращалась в лишние вопросы, долгий ревью или неправильную ветку решения. Теперь она быстрее превращается в diff.

Я не спорю с prompt.

Я спорю с моментом, когда prompt повышают до постановки задачи.

Когда мы пишем "почини баг", внутри этой фразы прячется много неявных решений:

  • где именно проявляется баг;

  • какое поведение считается правильным;

  • какие модули можно менять;

  • какие сценарии нельзя сломать;

  • какая проверка действительно докажет исправление;

  • где человеку нужно подтвердить план до изменения кода.

Для человека часть этого контекста может быть очевидной. Он помнит прошлые решения, странные edge cases, договоренности из ревью и зоны, куда лучше не лезть без отдельного обсуждения.

Агент этого не знает, если мы не передали ему это явно. Он видит файлы, похожие названия, тесты рядом и историю изменений, если она доступна. Дальше он строит гипотезу и начинает действовать.

Иногда гипотеза правильная. Иногда нет. Неприятная часть в том, что ошибка часто становится видна слишком поздно: уже после diff, после тестов, после спокойного summary.

Мини-кейс: "починить статус заказа"

Пример ниже условный, но собран из типовых ситуаций, которые возникают при работе с AI-агентами в живом репозитории.

Представим задачу:

Починить баг в отображении статуса заказа после отмены.

На первый взгляд это небольшая правка. Статус показан неправильно, значит нужно найти условие и поправить.

На деле контекст может быть таким:

  • статус приходит из нескольких источников;

  • часть логики живет в backend API;

  • часть логики живет во frontend отображении;

  • тесты покрывают только happy path;

  • менять схему данных нельзя;

  • для старых заказов нужно сохранить прежнее поведение;

  • проблема возникает только при отмене после оплаты.

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

Снаружи это выглядит прилично:

  • diff небольшой;

  • тест добавлен;

  • тесты зеленые;

  • summary уверенное.

Сигнал настоящий.

Но он еще не доказывает, что исправлен нужный сценарий.

Внутри могло произойти другое:

  • исправлен симптом, а не исходная проблема;

  • scope расширен без причины;

  • старый edge case сломан;

  • тест проверяет то, что агенту было удобно проверить;

  • ревьюер видит diff, но не видит путь принятия решений.

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

Что именно ломается

У меня этот класс ошибок обычно раскладывается на несколько повторяющихся мест.

Контекст выбран случайно.

Агент берет ближайший похожий файл или функцию. Иногда это правильное место. Иногда это просто место, где совпали слова.

Scope не ограничен.

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

Non-goals не записаны.

Человеку часто понятно, что "не переписывать state machine" или "не менять API response" нельзя. Агенту это не понятно, пока это не сказано.

Тесты проверяют удобный сценарий.

Агент может написать хороший тест на новый код, но этот тест не обязательно доказывает исходную проблему. Зеленые тесты легко начинают выглядеть как proof. Хотя на деле они доказывают только то, что проверял конкретный набор тестов.

Ревью начинается слишком поздно.

Ревьюер смотрит на diff, но главные решения уже приняты: где искать проблему, что считать причиной, какой scope взять, какие проверки запустить.

Summary заменяет evidence.

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

Diff - это гипотеза, а не конец задачи

Когда агент приносит diff, он приносит не только изменение. Он приносит гипотезу:

  • вот где была причина;

  • вот какой scope достаточен;

  • вот какие проверки закрывают риск;

  • вот что можно не трогать;

  • вот почему это изменение решает исходную задачу.

Ревьюеру нужно проверять не только код. Ему нужно проверить эту гипотезу.

Если гипотеза не видна, ревью быстро превращается в проверку формы: diff маленький, тесты зеленые, summary спокойное. Это полезные сигналы, но они не отвечают на главный вопрос: тот ли риск был закрыт?

Минимальная рамка перед запуском агента

Мне сейчас помогает думать о задаче для агента как о коротком пути:

  1. raw request

  2. уточнение контекста

  3. короткий контракт задачи

  4. plan

  5. исполнение в границах задачи

  6. проверки

  7. проверяемый след результата

  8. решение человека

Это не попытка превратить каждую правку в документ на десять страниц.

Для маленькой задачи короткий контракт может быть на 6-10 строк. Но эти строки меняют точку старта: агент перестает просто "делать что-то полезное" и начинает работать внутри заданных границ.

Под коротким контрактом задачи я здесь понимаю не юридический документ, а описание задачи перед execution:

  • цель;

  • scope;

  • ограничения;

  • non-goals;

  • обязательные проверки;

  • критерий готовности;

  • ожидаемый проверяемый след результата.

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

Да, многие инструменты умеют plan mode. Но сам по себе plan mode не решает проблему, если в задаче нет scope, non-goals и проверок. Агент может аккуратно спланировать неправильную работу.

Ключевое слово здесь не "автоматизация", а "границы". Скорость полезна только внутри рамки.

Пример: короткий контракт задачи

Под proof здесь я не имею в виду формальное доказательство корректности.

Речь о проверяемом следе результата: какие проверки запускались, какой риск они закрывают, какие артефакты появились и что осталось непроверенным.

Возьмем задачу со статусом заказа.

До:

Починить баг в отображении статуса заказа после отмены.

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

После:

Task

Fix incorrect order status in the user order card.

Goal

Show the correct status when an order is cancelled after payment.

Scope

backend order status handlerfrontend order status displayexisting tests around order status

Non-goals

do not change the data schemado not rewrite the order state machinedo not change status labels for unrelated scenariosdo not add a new dependency

Context

bug appears only for cancellation after paymentregular cancellation before payment should keep current behaviorold orders must keep backward-compatible display

Checks

test cancellation after paymenttest regular cancellation before paymentmanual UI check for the user order card

Proof / evidence

diff stays inside listed scopetests passsummary names the original broken scenariosummary states what was not changed

Это не делает задачу идеальной. Но агент теперь получает не свободную просьбу, а рабочую рамку.

Ему не нужно угадывать, можно ли менять схему данных. Нельзя.

Ему не нужно решать, можно ли переписать state machine. Нельзя.

Ему не нужно выбирать доказательство после факта. Ожидаемый след результата уже задан.

Что должен вернуть агент

Мне кажется важным не только то, что агент делает, но и то, что он возвращает после работы.

Плохой финальный ответ:

Готово. Исправил баг и добавил тесты.

Лучше:

Changed

updated backend order status handler for cancellation after paymentupdated frontend status display for the affected caseadded regression test for cancellation after paymentkept regular cancellation behavior unchanged

Checks

go test ./apps/server/internal/ordernpm test -- order-status

Proof / evidence

regression test covers the original scenariodiff is limited to the declared scopeno data schema changes

Decision trace

touched backend handler because it owns status normalizationtouched frontend display because the incorrect label appears thereskipped data schema because it is out of scopeskipped state machine rewrite because the bug is isolated to one transition

Limitations

manual UI check still needed in browserold orders were checked through existing fixture only

Такой ответ не отменяет ревью. Но он дает ревьюеру точки опоры.

Можно быстро проверить, совпадает ли diff со scope. Можно увидеть, какие проверки запускались. Можно понять, где доказательство слабое. Можно увидеть короткий след решения, а не только итоговую уверенность агента.

Чек-лист: готова ли задача для агента

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

Вопрос

Хороший сигнал

Плохой сигнал

Сценарий понятен?

Я могу назвать сломанный user или business flow

Есть только "починить баг"

Scope задан?

Перечислены модули, файлы или зоны

Агент сам выбирает, куда идти

Non-goals есть?

Явно сказано, что не менять

"Ну это же очевидно"

Проверка известна?

Есть тест, ручной сценарий или команда

Доказательство заменено словами агента

Нужен plan review?

Агент сначала покажет план

Агент сразу меняет код

Summary проверяемый?

Есть diff, checks, proof, limitations

Есть только "готово"

Если нужен совсем короткий вариант, я бы начинал с такого блока:

  • Task

  • Context

  • Scope

  • Non-goals

  • Plan first

  • Checks

  • Evidence

  • Stop condition

  • Human decision

Stop condition особенно важен. Это место, где агент должен остановиться и вернуться с вопросом, а не продолжать уверенно менять код.

Примеры stop condition:

  • не найден файл или модуль, который явно отвечает за сценарий;

  • scope оказался шире, чем ожидалось;

  • проверка невозможна без ручного шага;

  • контракт противоречит коду;

  • нужный тест отсутствует, а новый тест будет проверять только удобный сценарий.

Пять-шесть строк перед запуском агента часто дешевле, чем полчаса ревью после того, как он ушел не туда.

Где это ломается

У этого подхода есть ограничения.

Во-первых, для совсем маленьких задач он может быть избыточен. Иногда быстрее самому поправить одну строку.

Во-вторых, короткий контракт не гарантирует, что агент выберет правильный контекст. Он только делает ошибку заметнее.

В-третьих, passing tests не равны proof. Зеленые тесты - хороший сигнал, но не доказательство сами по себе. Они доказывают только то, что проверял конкретный набор тестов.

В-четвертых, точка подтверждения человеком легко превращается в bottleneck, если заставлять человека подтверждать каждый шаг.

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

И еще один неприятный пункт: иногда ревью видит diff, но не видит след решения: какие варианты агент рассматривал, какие отбросил и почему. Не длинное эссе, а короткий decision trace: touched / considered / skipped / reason.

Когда не стоит усложнять

Я бы не применял эту рамку ко всему подряд.

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

Если кодовая база маленькая и риск низкий, иногда достаточно одной строки с goal и одной строки с check.

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

И наоборот, чем больше у задачи неясного scope, тем полезнее остановить агента до первого изменения.

Вывод

Для меня главный сдвиг такой: агентная разработка начинает работать не тогда, когда агент становится "умнее", а когда задача становится ограниченной и проверяемой.

Хороший agent workflow не отменяет инженерную дисциплину. Он просто заставляет ее проявиться раньше: до diff, до ревью и до того момента, когда команда уже потратила время на неправильную ветку решения.

Если коротко:

  • Prompt - это сигнал.

  • Plan - это сигнал.

  • Diff - это сигнал.

  • Зеленые тесты - это сигнал.

  • Proof начинается там, где сигнал связан с исходным риском.

Именно здесь, кажется, проходит полезная граница. Не "запретить агенту писать код", а не повышать его первые действия до доказательства результата слишком рано.

Если у вас были похожие провалы с AI-агентами, напишите в комментариях. Интересно собрать отдельный список failure modes и разобрать, какие из них лечатся процессом, а какие нет.