almcreate Авторский IT-блог

Когда стоит остановить агента и самому разобраться

Иногда своевременная остановка — это и есть правильное инженерное решение. Не потому, что агент провалился, а потому, что растёт только diff, а не понимание.

Александр Морозов · 18 авг 2026 · 17 мин чтения · 5 просмотров
Рука останавливает робота перед растущей стопкой diff — агент ещё занят, но уже пора сказать stop
Сгенерированная обложка · AI · stopalmcreate

Чем больше задач я отдаю coding agents, тем важнее для меня становится один довольно простой навык. Не запустить агента. А остановить его.

В начале всё выглядит логично. Есть задача. Агент исследует проект. Предлагает решение. Начинает менять код. Запускает тесты. Пытается исправить ошибки. И в какой-то момент возникает развилка.

Можно сказать: продолжай. А можно: stop. Дальше я сначала сам разберусь.

Раньше мне казалось, что второе — почти признание неудачи. Если уж отдал задачу AI, хочется довести эксперимент до конца. Сейчас я думаю иначе. Иногда своевременная остановка агента — это и есть правильное инженерное решение.

Самая опасная стадия — когда агент всё ещё выглядит занятым

Если AI совсем застрял, всё понятно. Ошибка. Ничего не запускается. Он не может найти файл. Работа остановилась.

Гораздо сложнее ситуация, когда агент активно что-то делает. Открывает файлы. Меняет код. Запускает тесты. Получает ошибку. Исправляет. Появляется новая ошибка. Он снова исправляет. Внешне процесс живёт. Но если посмотреть внимательнее, задача уже может не приближаться к решению.

движениене обязательно прогресс
ошибка
    ↓
изменение
    ↓
новая ошибка
    ↓
ещё изменение
    ↓
новая гипотеза
    ↓
ещё больше diff

И чем дольше это продолжается, тем сложнее потом понять, где агент вообще свернул не туда.

Первый сигнал — он ходит по кругу

Это, наверное, самый очевидный паттерн. Агент делает изменение. Тест падает. Он возвращает предыдущий вариант. Потом снова приходит почти к тому же решению немного другим путём.

вариациибез нового знания
вариант A
    ↓
не работает
    ↓
вариант B
    ↓
не работает
    ↓
вариант A с ещё одним условием
    ↓
не работает
    ↓
вариант B с новым helper

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

Это важный момент. Ошибка сама по себе не проблема. Хорошее исследование тоже состоит из неудачных гипотез. Для меня вопрос другой: после неудачной попытки агент узнал что-то новое о системе? Если нет и он просто генерирует следующую вариацию — пора вмешиваться.

Я стал различать «исследует» и «мечется»

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

исследованиекартина яснее
гипотеза A
    ↓
проверка
    ↓
A исключена

гипотеза B
    ↓
проверка
    ↓
найдена конкретная зависимость

То есть после каждого шага картина становится яснее. Когда агент мечется, происходит другое:

метаниемодель проблемы не растёт
может быть A
    ↓
изменим

не помогло
    ↓
может быть B
    ↓
изменим

не помогло
    ↓
может быть C

Он экспериментирует непосредственно на коде, не улучшая модель проблемы. Вот здесь я всё чаще говорю: остановись. Не меняй больше код. Сначала объясни, что мы уже точно знаем.

Иногда этого хватает, чтобы вернуть задачу в нормальный режим. Иногда нет. Тогда я забираю исследование себе.

Второй сигнал — появляются странные abstractions

Это один из моих любимых индикаторов. Начинается всё с маленькой проблемы. Например: нужно поправить обработку одного состояния заказа. Через некоторое время в diff появляются:

чуть утрируюне сильно
OrderStateResolver
OrderStateStrategy
OrderStateContext
OrderStateHandlerInterface
AbstractOrderStateHandler

Я немного утрирую. Но не сильно. Иногда abstraction действительно нужна. Проблема в том, что неожиданное усложнение часто является не решением задачи, а способом обойти непонимание существующего кода. Агент не смог разобраться, почему текущая модель ведёт себя так. И вместо этого начинает строить новую модель рядом.

Новая abstraction иногда маскирует отсутствие понимания

Мне нравится задавать очень простой вопрос: какую конкретную проблему решает этот новый слой? Если ответ «улучшает расширяемость» — этого недостаточно. Расширяемость для чего? Какая текущая задача её требует? Какое существующее ограничение мы снимаем?

Если аргументы становятся всё более абстрактными — separation of concerns, maintainability, future extensibility — я начинаю подозревать, что агент потерял связь с исходной задачей.

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

Третий сигнал — diff постоянно растёт

Это вообще очень наглядный показатель. Исходно задача выглядит как: исправить неправильный переход между двумя состояниями. А потом:

масштабне из исследования
3 files changed
    ↓
7 files changed
    ↓
14 files changed
    ↓
23 files changed

Причём новые файлы появляются не потому, что исследование обнаружило реальный масштаб задачи. А потому что каждое предыдущее изменение породило следующую проблему. Например: чтобы исправить это, я изменил интерфейс. Теперь нужно обновить все реализации. Потом mocks. Потом fixtures. Потом соседний module. Потом compatibility layer.

В какой-то момент полезно спросить: мы раскрываем реальную связанность системы или сами создаём её по ходу решения? Это очень разные ситуации.

Иногда правильный diff должен сначала уменьшиться

Я заметил интересный паттерн. Когда агент действительно понимает проблему, после research решение часто становится компактнее. Сначала кажется, что нужно изменить десять файлов. Потом находится существующий extension point. И оказывается, что достаточно трёх.

пониманиесжимает изменение
непонимание
    ↓
широкий предполагаемый diff
    ↓
research
    ↓
точка изменения найдена
    ↓
меньший diff

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

Четвёртый сигнал — агент чинит симптомы

Это, пожалуй, самый опасный случай. Есть падающий тест. Агент меняет код. Тест начинает проходить. Кажется, отлично. Но затем падает другой. Он добавляет ещё одно условие. Потом ещё одно. В итоге получается что-то вроде:

компенсациине причина
if scenario A
    do X

if scenario B
    special case

if scenario C
    another special case

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

Зелёные тесты здесь особенно опасны

Потому что в какой-то момент он действительно может сделать их зелёными. Добавить достаточно условий. Обновить достаточно mocks. Скорректировать несколько ожиданий. Получается:

формально готовопричина не найдена
root cause
    ↓
не найден

symptoms
    ↓
обойдены

tests
    ↓
✓ green

И технически задача будто завершена. Именно поэтому я теперь смотрю не только на результат тестов. Мне важно понимать: какая была причина проблемы? Если агент не способен сформулировать её в одном-двух понятных предложениях, а уже изменил пятнадцать файлов, я скорее остановлю работу. Про зелёный suite, который сам по себе меня уже меньше успокаивает, я писал отдельно.

Пятый сигнал — он не понимает domain

Это сложнее всего обнаружить по коду. Технически всё может выглядеть нормально. Но в объяснениях начинает появляться что-то странное.

Например, агент говорит: после отмены заказа нужно освободить все связанные ресурсы. Я читаю и понимаю: нет. Не после любой отмены. Или: после успешной оплаты процесс считается завершённым. Нет. Оплата — только один из этапов. Или: пользователь с ролью admin может выполнить операцию независимо от состояния. Тоже нет.

Это уже не проблема PHP. Агент неправильно построил модель предметной области. Продолжать implementation после этого почти бессмысленно.

Domain misunderstanding очень дорого чинить в конце

Потому что на неверной модели начинает строиться всё остальное.

ранняя ошибкадорогая разборка
wrong domain model
    ↓
plan
    ↓
classes
    ↓
conditions
    ↓
tests
    ↓
UI

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

Это важная часть: иногда я тоже не знаю ответ

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

Например, существует три разных пути изменения одного состояния. Два legacy handler. Часть поведения спрятана в database trigger. Документация устарела. В этот момент моя роль не в том, чтобы показать AI, кто здесь senior. Мне самому нужно исследовать систему. И это нормальный исход.

Иногда агент полезно приводит меня к границе моего собственного понимания

Это одна из вещей, которые мне особенно нравятся в работе с ним. Я отдаю задачу, которая кажется простой. AI начинает задавать вопросы. Доходит до странного места. Не может уверенно выбрать решение. И я сначала думаю: почему ты не понимаешь очевидное?

Потом открываю код. И оказывается, что очевидного решения нет. Я просто давно не смотрел на этот участок достаточно внимательно. То есть остановка агента иногда означает не «здесь AI недостаточно умный». А: здесь сама система требует человеческого исследования. Это полезное открытие.

Шестой сигнал — он начинает менять соседние системы

Очень характерная история. Задача касается notifications. Через некоторое время агент пишет: для более корректной реализации я также обновил общий event dispatcher. Стоп. Почему?

Или: я обнаружил, что существующий repository API неудобен, поэтому изменил его. Стоп. Или: для единообразия я переработал соседний module. Особенно люблю «для единообразия». Это почти всегда повод посмотреть внимательнее.

Расширение scope должно быть осознанным

Во время задачи действительно можно обнаружить проблему за её границами. Это нормально. Например: невозможно безопасно реализовать feature без изменения общего контракта. Хорошо. Но тогда для меня правильная последовательность такая:

осознанноне сразу переписал
обнаружена необходимость расширить scope
    ↓
stop
    ↓
объяснить причину
    ↓
оценить последствия
    ↓
принять решение
    ↓
только потом менять соседнюю систему

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

Агент не всегда знает границы задачи так же хорошо, как я

Для него repository — доступное пространство решений. Если изменение общего интерфейса упростит текущую feature, это может выглядеть разумно. Я же могу знать: этот interface использует другой проект. Или: через неделю команда B выпускает изменение в этом module. Или: мы вообще договорились сейчас туда не заходить.

Это ещё один пример контекста, который редко виден только из кода. Поэтому внезапное расширение scope — хороший момент остановиться.

Есть ещё один менее очевидный сигнал: объяснения становятся длиннее, а ясности меньше

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

Текст становится сложнее. А я всё хуже понимаю: так в чём конкретно проблема? Длинное объяснение само по себе не проблема. Но если после пяти абзацев невозможно сформулировать root cause, скорее всего, его пока нет. Тогда лучше остановить кодирование и вернуться к исследованию.

Я стал периодически задавать контрольный вопрос

Он очень простой: объясни текущую гипотезу причины проблемы без предложения решения. Это хорошо отделяет понимание от генерации кода.

Если ответ выглядит конкретно — при смене статуса событие публикуется до сохранения transaction, поэтому asynchronous handler читает старое состояние — отлично. Это можно проверить. Если «проблема, вероятно, связана с взаимодействием нескольких компонентов lifecycle...» — пока слишком туманно. Не пишем дальше. Исследуем.

Ещё один вопрос: что изменилось в твоём понимании после последней попытки?

Мне он очень нравится, когда агент ходит по кругу. Если ответ: я выяснил, что repository здесь не виноват; проблема возникает только при async path — есть прогресс. Если ответ: предыдущий вариант не прошёл тест, поэтому попробую другой подход — это не новое знание. Это просто следующая попытка. И здесь я скорее остановлю autonomous loop.

«Stop» не всегда означает «я теперь всё сделаю сам»

Это тоже важное изменение моего мышления. Раньше было бинарно: AI делает или я делаю. Теперь вариантов больше.

смена режимане отказ от AI
Stop.
    ↓
Я сам исследую root cause.
    ↓
Потом снова отдаю implementation AI.

Stop.
    ↓
Другой agent проводит независимый research.

Stop.
    ↓
Я уточняю domain.
    ↓
Первый agent продолжает.

То есть остановить агента — не значит отказаться от AI. Это может быть просто смена режима работы. В диспетчерской это как раз дешёвый human checkpoint.

Иногда я оставляю себе только самый дорогой кусок

Допустим, агент не понимает, почему существует определённое бизнес-правило. Я разбираюсь сам. Нахожу ответ. Формулирую: вот настоящий invariant. После этого снова отдаю: теперь обнови план и реализуй с учётом этого правила.

разделениене всё или ничего
AI
    ↓
дошёл до границы понимания

я
    ↓
разобрал сложную часть

AI
    ↓
продолжил механическую и техническую работу

Мне нравится такой вариант гораздо больше идеи «либо полная автономность, либо всё руками».

Иногда лучший вклад разработчика — уменьшить пространство поиска

Агент исследует десять файлов. Я смотрю и понимаю: проблема точно не в этих восьми. Можно просто сказать: не трогай notification layer. Причина находится между transaction и asynchronous handler. Исследуй только этот путь.

Это уже огромная помощь. Я не написал ни строчки кода. Но сделал задачу значительно проще. И это опять возвращает меня к изменению роли. Опыт разработчика всё чаще используется не для того, чтобы самому реализовать решение. А чтобы быстрее определить, где вообще имеет смысл искать.

Чем автономнее агент, тем важнее навык вмешательства

Это немного парадоксально. Можно подумать: чем лучше AI, тем меньше нужно за ним следить. В каком-то смысле да. Но сильный агент способен за неправильные двадцать минут сделать гораздо больше изменений, чем слабый.

Он не просто выдаст неправильный snippet. Он может изменить architecture, обновить migrations, переписать тесты, поменять API, «починить» соседние modules. То есть цена поздней остановки растёт вместе с автономностью.

Поэтому хороший agentic workflow должен отвечать не только на вопрос «что агент может делать сам?», но и подсказывать, в какой момент он обязан остановиться.

Я бы сейчас выделил несколько своих красных флагов

Не как универсальный checklist. Просто вещи, после которых я начинаю внимательно смотреть на процесс.

красные флагинесколько сразу — stop
агент несколько раз возвращается к одной гипотезе
появляются abstractions, которых не требовала задача
diff растёт после каждой попытки
новые условия маскируют симптомы
root cause остаётся неясным
агент неправильно описывает domain
scope начинает расширяться
появляются изменения соседних систем
тесты исправляются под реализацию слишком часто
объяснения становятся сложнее, но не конкретнее

Один такой признак ничего не доказывает. Но несколько сразу — хороший повод сказать: stop.

Самая полезная остановка происходит до большого diff

Это тоже навык, который я пока учусь развивать. Легко остановиться, когда уже 37 files changed, +4281, −1730. Тут тревога очевидна. Гораздо полезнее заметить проблему на 5 files changed, +180, −40 и спросить: почему мы вообще пошли этим путём?

Чем раньше остановка, тем дешевле смена направления. Это тот же принцип, что с research и plan. Ошибки предположений дешевле исправлять до того, как они превратились в код.

Я перестал считать время агента бесплатным

Это тоже помогло. Да, пока AI работает, я физически могу заниматься чем-то другим. Поэтому легко подумать: пусть ещё попробует. Но результат работы агента создаёт стоимость. Нужно посмотреть diff. Разобрать лишние изменения. Понять новые abstractions. Откатить неправильное. Перезапустить проверки.

То есть пять дополнительных автономных попыток — не обязательно бесплатно сэкономленные пять минут моего внимания. Иногда они создают двадцать минут будущего review. Поэтому «пусть попробует ещё что-нибудь» не всегда хороший default.

Но и останавливать слишком рано не стоит

Это обратная крайность. Если агент открыл три непривычных файла, не значит, что он потерялся. Если первая гипотеза не сработала, это нормально. Если diff временно вырос во время рефакторинга — тоже.

Я стараюсь смотреть не на отдельное действие. А на динамику. Появляется ли новое знание? Уменьшается ли неопределённость? Становится ли решение проще? Сходится ли агент к понятной причине? Если да — пусть работает. Если нет — вмешиваюсь.

Получается, что я слежу не за кодом, а за траекторией

Это, пожалуй, новое для меня. Раньше review происходил в конце. Код написан. Смотрим результат. Теперь при длинной agentic-задаче иногда полезно оценивать сам путь. Не каждую команду. Не каждый файл. А направление.

Куда агент думает, что идёт? Какое предположение проверяет? Что уже исключил? Что изменилось в его понимании?

В каком-то смысле это похоже на работу с разработчиком, который пришёл обсудить сложный bug. Не нужно сидеть рядом и диктовать каждую строку. Но иногда по ходу рассказа понятно: стоп. Ты сейчас копаешь не туда.

«Самому разобраться» тоже изменило смысл

Раньше для меня это почти автоматически означало: открыть IDE и самому написать решение. Сейчас чаще: самому восстановить правильную модель проблемы. Понять domain. Найти root cause. Определить границы изменения. А после этого код всё равно может написать агент.

То есть моя ручная работа постепенно смещается выше. От implementation к пониманию. Это, наверное, одна из главных перемен всей этой серии.

Поэтому я всё меньше горжусь полностью автономными задачами

Сначала очень приятно сказать: я дал AI задачу, и он полностью сделал её сам. Это выглядит как показатель зрелости workflow. Теперь меня больше интересует другое: сколько раз система вовремя поняла, что ей не хватает информации?

Если агент остановился и сказал: я нашёл два противоречащих друг другу бизнес-правила. Нужен human input — для меня это иногда более сильный результат, чем «feature implemented successfully». Потому что хорошая автономность — это ещё и способность не продолжать уверенно там, где нет основания для решения.

В идеале агент однажды будет сам понимать эти моменты

Например:

checkpointsпока часто остаются у меня
confidence low
    ↓
stop

scope expansion required
    ↓
stop

domain contradiction
    ↓
stop

destructive change
    ↓
stop

architecture decision required
    ↓
stop

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

Моя работа иногда действительно сводится к одному слову

Агент что-то делает. Объясняет. Добавляет ещё один слой. Расширяет diff. И в какой-то момент я пишу: stop. Пока ничего больше не меняй. Расскажи, что мы точно знаем. Или: stop. Я сначала сам разберусь в этой части.

После этого я могу потратить двадцать минут на чтение кода. Найти один старый handler. Понять историческое бизнес-правило. Вернуться и сказать: вот причина. Теперь продолжай отсюда. Ни одной строки production-кода я при этом мог не написать. Но без этого вмешательства агент ещё долго решал бы неправильную задачу.

Наверное, это и есть одна из новых обязанностей разработчика

Не просто писать. Не просто review. Не только ставить задачи. А понимать, когда автоматизированное движение вперёд перестало быть прогрессом.

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

Моя текущая формула примерно такая:

формулаупрощённо, но направление верное
пока растёт понимание
    ↓
пусть агент работает

если растёт только diff
    ↓
пора остановиться

Конечно, слишком упрощённо. Но мне нравится направление.

Поэтому иногда лучшая команда AI — не «продолжай»

А: stop. Дальше я сначала сам разберусь. Не потому, что я обязательно лучше напишу код. И не потому, что агент провалил задачу. А потому, что в этот момент главным bottleneck стал уже не implementation. Им стало понимание.

А это та часть работы, ответственность за которую я пока не готов передавать только потому, что агент способен продолжать генерировать изменения. Иногда самое полезное, что я могу сделать как разработчик, — не добавить ещё одну строку. А вовремя остановить появление следующих пятисот.

#ai #coding agents #workflow #debug #root cause #human checkpoint

Соседние рубрики