В этой статье
- Где ломается автономия: тихий ремонт и скрытый дрейф
- Пример провала: как pipeline закрыл задачу с расходящимися отчётами
- Решение 1: JSON-контракт между фазами
- Решение 2: независимый VERIFY вне периметра агента
- Решение 3: router и пять моделей под разные фазы
- Принципы и Итог
Где ломается автономия
Технический долг — задачи, на которые всегда нет времени. Идеальная цель для автоматизации: распределить роли (PM, системный аналитик, разработчик, QA) и запустить автономный цикл обработки тикетов.
На бумаге это работает. На практике автономия превращается в тихий ремонт.
Агент сталкивается с проблемой в окружении — и не отчитывается о блоке. Вместо этого начинает править соседний код, лезть в конфиги, “оптимизировать” то, о чём его не просили. На выходе “Done”, но половина окружения уехала со спецификации.
Я называю это скрытым дрейфом. Каждая отдельная правка локально выглядит как улучшение. Накапливаются они в “тихий ремонт”, который никто не запрашивал — и который очень трудно откатить, потому что Git diff давно перестал отражать одну задачу.
Пример провала
Сегодня pipeline закрыл задачу как DONE. Developer честно сделал работу, запустил check_command, получил exit=0, отчитался passed=true.
Независимая параллельная проверка дала exit=1.
Никто не соврал. check_command содержал паттерн test, который ведёт себя по-разному на linux и macOS. Артефакт сборки оказался несовместим со средой проверки. Агент видел “успех” со своей колокольни. С другой колокольни — провал.
Этот один случай задаёт всю архитектуру дальше. Если мы доверяем self-report агента, мы доверяем фрагменту окружения, в котором он находится. А окружение — переменная.
Решение 1: контракт между фазами как JSON
В первых итерациях фазы общались свободным текстом. Аналитик описывал план, разработчик читал и интерпретировал. Звучит как нормальный человеческий процесс. На практике даёт три проблемы:
- модель додумывает поля, которые не запрашивались
- следующая фаза вынуждена парсить свободный текст
- “я подумал и решил сделать ещё” — реальная фраза в логах
Перешли к JSON-схеме между каждой парой фаз. Constrained generation через tool_use заставляет модель заполнить именно те поля, которые ожидает следующая фаза, и не заполнять ничего сверх.
Каждый переход — структурный артефакт по схеме. Никакого “свободного творчества”. Хочешь добавить мысль — нет поля в схеме, мысль не передаётся. Свободный текст остаётся только в одном месте — в комментариях для человека, и они не влияют на следующий шаг.
Что важно: схема — это не “лучший формат” для людей, она для следующей фазы. Если на ревью вы хотите видеть что-то ещё — отдельный человеко-читаемый рендер из той же JSON. Не смешивайте каналы.
Решение 2: независимый VERIFY
Из примера с check_command я вытащил жёсткое правило: проверка должна жить отдельно от агента.
Слева — среда агента. Он работает в ней: знает свои зависимости, локальные конфиги, кеши, переменные окружения. Может что угодно. Главное — отчитывается о результате.
Справа — verify-среда. Свежий клон репозитория, чистый контейнер, никаких артефактов от агента, никаких “уже собранных” бинарников. Запускает тот же check_command из независимой точки. Если результаты расходятся — задача в BLOCKED.
Это не дороже, чем доверять. Один лишний прогон проверки стоит сильно меньше, чем тихое закрытие задачи со скрытым дрейфом. Аудит таких закрытий потом всё равно придётся проводить — просто на месяц позже и с потерянным контекстом.
Решение 3: специализация моделей через router
Один универсальный agent на все задачи — анти-паттерн. У каждой фазы своя нагрузка, и универсальная модель либо переплачивает, либо недоезжает.
Пять ролей под пять типов нагрузки:
- planner — структурные решения, последовательность и точность над JSON
- reasoning specialist — тяжёлое обоснование, разбор архитектурных вопросов
- long-context — суммаризация документов и длинных тикетов
- executor — короткие патчи, рутинные операции
- fast chat — диалоговые реплики, простые ответы
Router смотрит на тип фазы и сложность артефакта, направляет вызов в соответствующую модель. Локально, без привязки к одному провайдеру. Это и про стоимость, и про то, что разные модели сильны в разном — нет смысла делать структурный план моделью, заточенной под длинный диалог.
Принципы
- Дисциплина контракта важнее скорости генерации. Свободный текст между фазами — приглашение к дрейфу.
- Не доверяй self-report. Verify живёт вне периметра агента.
- Останавливайся явно. BLOCKED — это статус, а не fallback. Если что-то не сходится — задача стоит и ждёт человека. Не закрывается с “Done”.
- Специализация важнее универсальности. Pipeline из специализированных моделей дешевле и стабильнее, чем одна большая модель на всё.
Итог
Автономия агентов — это не свобода. Это контракт. Чем плотнее контракт и чем независимее проверка, тем меньше дрейфа и тихих закрытий.
Останавливаться — это умение. Pipeline, который умеет сказать “не знаю”, безопаснее pipeline’а, который всегда говорит “готово”.
Архитектурный вопрос: где в вашем процессе self-report агента сейчас считается за истину, и какой минимальный шаг добавит туда независимую проверку?