Что именно оптимизируется
Пространство поиска — вся обвязка целиком, а не только промпт: системные и задачные инструкции, описания инструментов, их реализации, хуки middleware и логика самого цикла. Это существенно шире, чем автоматическая оптимизация промптов, и разница в результате измерима (см. ниже про перекос в сторону текстовых правок).
Рамка — обучение по мини-батчам, где привычные части заменены:
| В обучении модели | В оптимизации обвязки |
|---|---|
| градиент по функции потерь | диагностика провала: трасса плюс исходники обвязки |
| шаг оптимизатора | структурный патч по явной таксономии |
| валидационная выборка | отложенный набор случаев, закрытый от диагностики |
| расписание темпа обучения | фазовое расписание патчей |
Три ингредиента и цена отсутствия каждого
Замер на GAIA2, метрика Pass@1 на тестовом наборе, полная конфигурация даёт 62,0:
| Убрали | Стало | Потеря |
|---|---|---|
| глубокую диагностику (заменена одним вызовом модели «объясни провал») | 57,8 | −4,2 п.п. |
| структурное вмешательство (таксономия патчей и фазовое расписание) | 56,9 | −5,1 п.п. |
| отбор по обобщаемости (рефлексия и проверка на отложенном наборе) | 50,6 | −11,4 п.п. |
Самый дорогой ингредиент — последний, и это главный результат работы. Интуиция подсказывает обратное: кажется, что важнее всего хорошо понять причину провала. Измерение говорит, что важнее всего не оставить исправление, которое сломало что-то ещё.
Разложение подтверждает: если убрать только фильтр по отложенному набору, Pass@1 падает с 60,7 до 50,0; если вдобавок убрать рефлексию — до 44,9. У структурного вмешательства то же соотношение мельче: снятие одного фазового расписания даёт 60,7 → 54,8, снятие всей рамки — до 53,3.
Глубокая диагностика стоит конкретных вызовов. Сессия «диагностика плюс патч» тратит в среднем на 6,2 вызова инструментов и 5,8 обращений к файлам больше, чем сессия, которая сразу правит. Окупается числом принятых патчей: к концу первой эпохи (25 итераций) 13 против 5.
Capability против Steering: не смог или не сказали
Разделение патчей на две группы — самое переносимое, что есть в работе.
- Capability — правка исполняемого кода или логики оркестрации: новый инструмент, изменение цикла, изменение инфраструктуры.
- Steering — текстовая правка, оставляющая код прежним: правило в промпте, описание инструмента, текст напоминания в хуке.
Различение отвечает на вопрос, который при разборе провала задают редко: агент не смог или ему не сказали? Ответы требуют разного, а выглядят провалы одинаково.
Без явной рамки правки сваливаются в Steering — 91,5%. Оставленный без границ поиска оптимизатор почти всегда правит текст, потому что это дёшево и всегда выглядит осмысленным. При этом именно непромптовые патчи принимаются чаще всего: новый инструмент — 83%, изменение цикла — 71%, изменение инфраструктуры — 67%. Без рамки на эти три категории приходится 4% сгенерированных патчей, с рамкой — больше 25%.
Capability надёжнее при равной пользе. Доля исправленных случаев у Capability и Steering сопоставима (55% против 58%), а доля сломанных отличается вдвое: 8% против 17%. Текстовая правка чинит не хуже, но ломает вдвое чаще — и это довод чинить сначала возможность, а потом поведение.
Отсюда фазовое расписание: оптимизация начинается с фазы Capability и лишь затем переходит к Steering.
Между «возможностью» и «поведением» есть различимая середина
Деление на две группы отвечает на вопрос «не смог или не сказали» и на этом останавливается. Практически же средств починки пять, и они выстроены по надёжности — тем, насколько исправление переживает следующий запуск:
| Средство | Пример | Надёжность | Цена заведения |
|---|---|---|---|
| поправка в разговоре | «нет, не так, сделай иначе» | никакая: живёт до конца сессии | ноль |
| правка промпта | инструкция в задачном тексте | низкая: действует на эту постановку | минуты |
| правило в файле инструкций | строка в AGENTS.md |
средняя: действует на все запуски, пока читается | минуты |
| проверка | тест, линтер, схема | высокая: срабатывает сама | часы |
| ограничение среды | право, изоляция, гейт в CI | наивысшая: делает ошибку невозможной | часы и дни |
Первые две — Steering в чистом виде, последние две — Capability; правило в файле инструкций стоит посередине и потому чаще всего выбирается неправильно. Оно выглядит как структурная починка, потому что живёт в репозитории и переживает сессию, но принуждается только чтением — то есть остаётся текстовой правкой со всеми её свойствами, включая вдвое большую долю регрессий.
Практическое правило: чинить на самой надёжной ступени, которая закрывает этот класс ошибок, а не на первой попавшейся. Классы отображаются на ступени почти однозначно:
| Класс провала | Слабая починка | Сильная |
|---|---|---|
| известный плохой шаблон | напоминание в промпте | правило линтера |
| не хватило сведений о проекте | длинный разговор | запись в файле инструкций |
| не тот инструмент | поправка в чате | граница прав |
| качество плавает | ревью каждого прогона | автоматический тест |
| потеря состояния | объяснить заново | чекпоинт на диске |
| небезопасное действие | надежда, что не повторится | бюджет возможностей и запрет |
Левая колонка — не ошибки новичка, а то, что выбирается под давлением: она дешевле и срабатывает сразу. Разница видна не в этом запуске, а в следующем.
Ступень ноль: стоит ли править обвязку вообще
У лестницы выше есть предшествующий вопрос, который обычно пропускают: провал случился — но следует ли из него правка. Пропуск обходится дорого именно потому, что незаметен: каждая отдельная правка выглядит разумной, а через полгода файл инструкций разрастается до состояния, в котором важно всё и потому не важно ничто.
Фильтр формулируется контрфактически: стал бы компетентный агент с текущими инструкциями по-прежнему падать так же? Да — значит пробел настоящий. Нет — правка не нужна, что бы ни показывал разбор.
Чтобы фильтр вообще было к чему применять, разбор прогона обязан указывать на обвязку, а не на модель, и это решается формулировкой мерила. Оценивать прогон надо против того, что понадобилось бы компетентному инженеру с теми же инструментами, а не против того, что было достижимо тем, что у агента случайно оказалось под рукой. Тогда ошибка, выглядящая в контексте неизбежной, всё равно засчитывается — при условии, что разбор называет, чем её предотвратили бы: отсутствующим умением, ранней проверкой, более прямым инструментом. Мерило, сформулированное иначе, регулярно ставит хорошую оценку прогону, который был дорогим по причинам, лежащим целиком в обвязке.
Отдельная поправка того же мерила: повторяющиеся накладные расходы стоят дороже своей цены за прогон. Кружной способ сделать рутинный шаг обходится в этом запуске недорого, но повторится в каждом следующем, пока его не закроет умение или правило. Взвешивать его надо по этой повторяемости, иначе разбор всегда предпочтёт разовый громкий провал тихому системному.
Три класса провалов фильтр отсеивает, и все три регулярно принимают за пробел:
- инструкция уже требовала верного поведения, а модель её не исполнила. Это не отсутствие правила, а его непринуждаемость: лечится подъёмом на ступень проверки, а не переписыванием той же строки другими словами;
- разброс модели — тот же запрос, те же инструменты, другой выбор. Инструкцией не чинится в принципе, и попытка чинить даёт правило, которое ничего не меняет, но занимает контекст навсегда;
- настоящая починка лежит вне текста — в продукте, инфраструктуре, коде или в самом мериле, которым провал измерен.
Что требуется от правки, чтобы пройти: названы владеющая поверхность (чья конфигурация, какое умение, какой файл) и одно переиспользуемое правило, причём такое, что при его наличии и исполнении разобранный провал не случился бы. И либо тот же пробел встретился более чем в одном прогоне, либо единственный случай настолько тяжёл, что сам по себе доказывает отсутствующий контракт.
Перед durable-правкой нужен usage receipt и право воздержаться. Разбор должен доказать, что целевой skill или правило действительно участвовали в прогоне; иначе похожий по теме провал легко приписать артефакту, который агент вообще не загрузил. Routine success, разовый случай, временный сбой зависимости, общий совет и секрет — не кандидаты. Полезный кандидат должен убирать хотя бы два будущих шага модели или инструмента; отсутствие такого кандидата — нормальный исход review.
Даже прошедший фильтр кандидат ещё не live-изменение. Для skills он выпускается через proposal, привязанный к ownership и точной base revision, с отдельными RED/GREEN и откатом (Skill Change Control). Это разделяет качество урока и право внедрить его.
Две технические оговорки, каждая со своей ценой:
- заменять существующее руководство, а не дописывать очередной абзац. Дописывание — путь, которым файл инструкций растёт монотонно; замена держит его размер под контролем и заодно заставляет заметить, что старая формулировка была неверной, а не неполной;
- починки выводятся только из проваленных прогонов. Успешный прогон правки не порождает: из него выводятся «хорошие практики вообще», а это ровно тот материал, который наполняет файл текстом, не отвечающим ни на один наблюдавшийся отказ.
И главное следствие, которое стоит записать явно, потому что оно противоречит устройству любого отчёта: не завести ни одной правки — нормальный исход разбора, и его надо уметь предъявлять. Когда ничто не проходит планку, отчёт называет по каждой находке, почему не проходит. Спекулятивная правка хуже отсутствия правки: она стоит контекста на каждом запуске, а работу выполняет только на бумаге. Обратная сторона того же — обратный ход ратчета в Agent First Repository: там сказано, как правило уходит, здесь — при каких условиях оно вообще заводится.
Обвязка под слабую модель — обязательство, а не актив
Ратчет и планка допуска предполагают, что провалы приходят из задачи. Есть отдельный класс, приходящий из времени: обвязка, построенная как компенсация недостатков модели, переживает эти недостатки и превращается в помеху.
Механика простая и оттого неприятная. Модель не умела держать длинную цепочку — построили внешний планировщик, разбивающий задачу на шаги. Модель путалась в инструментах — построили жёсткую маршрутизацию, решающую за неё, что вызывать. Модель не удерживала контекст — построили слой, подкладывающий ровно то, что сочли нужным. Каждое решение на своём месте было верным и измеримо улучшало результат. Через год модель делает всё это лучше слоя, а слой продолжает работать и не даёт ей это показать: планировщик режет задачу хуже, чем модель бы её не резала вовсе, маршрутизация запрещает то, что стоило вызвать, подкладываемый контекст оказывается уже нужного.
Отказ здесь коварнее обычного устаревания. Устаревшее правило можно прочитать и увидеть, что оно неверно; компенсирующий слой выглядит работающим — он делает ровно то, что описано, метрики не падают, ошибок нет. Видно только сравнением с конфигурацией, в которой слоя нет, а такое сравнение никто не ставит: слой писали не зря, и предположение, что теперь без него лучше, звучит как неуважение к работе.
Признаки, по которым класс опознаётся:
- обвязка тратит заметную часть работы на поддержание самой себя — сочиняет себе подзадачи, ведёт внутренние проекты, пересобирает своё состояние; наблюдалась форма, где на это уходило около половины всей активности, а прикладная задача продвигалась на остаток;
- слой знает лучше модели там, где нет объективного критерия: разбиение на шаги, выбор инструмента, объём подаваемого контекста. Слой, принуждающий проверяемое требование, к этому классу не относится — там критерий есть;
- слой писался под конкретную модель и с тех пор не пересматривался при её смене.
Практическое следствие для порядка работ: смена модели — это повод перепроверить обвязку, а не только прогнать набор сценариев. Дешёвая форма проверки — снять компенсирующий слой и прогнать те же сценарии без него; если результат не упал, слой был обязательством. Дорогая часть в том, что делать это надо по каждому слою отдельно.
И тот же довод с другого конца: инфраструктурную часть обвязки выгоднее брать готовой, а вкладываться в семантическую — в описание пространства, в котором агент решает задачу. Инфраструктура развивается снаружи быстрее, чем её успевает догонять одна команда, и собственная версия устаревает вместе с предположениями, под которые писалась.
Обвязку чинит тот, кто с ней работает
Вся дисциплина выше молча предполагает, что правку вносит тот, кто ею и пользуется. Когда это не так, петля не замыкается, и отказ выглядит одинаково независимо от качества правок.
Инструмент, настроенный кем-то со стороны, для команды остаётся магическим предметом. Пока он срабатывает, им пользуются; на первом же случае, когда он не сработал, им перестают пользоваться совсем — потому что чинить его команда не умеет, а понять, почему он промолчал, не может. Никакая правильность настройки этого не меняет: свойство не у инструмента, а у отношений с ним. «Со стороны» здесь не про внешнего подрядчика: коллега из соседней команды, пришедший навести порядок, попадает в тот же класс.
Вторая половина той же проблемы — неявное знание, которого у пришедшего нет. Ограничения предметной области, причины прошлых решений, места, которые трогать нельзя, — всё это живёт в головах, изредка проглядывает в истории изменений и почти никогда не записано в коде. Опросники и созвоны его не извлекают: человек рассказывает не то, что делает, а то, что считает своей работой.
Форма, при которой петля замыкается. Внешний участник не переписывает умения и инструкции — он разбирает журналы сессий и возвращает разбор команде, отделяя две вещи: где ошибся человек и чего не хватило агенту. Правки в обвязку вносит команда. Выигрыш двойной: правка опирается на неявное знание, которого у разбирающего нет, и инструмент перестаёт быть магическим, потому что его последний раз менял тот, кто им пользуется.
Два практических следствия из того же наблюдения:
- сопротивление внедрению не выравнивается нажимом. Часть людей психологически устроена под глубокую работу над одной задачей, и переводить их в режим диспетчера нескольких — терять сильную сторону, а не приобретать новую (Parallel Agent Dispatch);
- вложение в двух-трёх, кто перенимает быстро, окупается лучше, чем равномерное распределение того же времени: они становятся источником неявного знания уже внутри команды, и следующая передача идёт без внешнего участника.
Почему рефлексия по одной траектории не работает
Механизм провала описан конкретно, и он узнаваемый.
Вариант без отбора по обобщаемости на 20-й итерации завёл новый инструмент send_progress_message_to_user и переписал хук у часто используемого send_message_to_user так, чтобы принудительно перенаправлять агента на новый. На вызвавшей траектории патч сработал. Проверить его было нечем, и он остался — после чего поведение агента поехало в множестве несвязанных сценариев: доля сломанных случаев подскочила с 8% до 22%.
Тот же патч сочинила и полная конфигурация, на 4-й итерации. Разница только в том, что там его отвергли по последствиям. То есть дело не в качестве генерации патчей: широкий хук на высокочастотном инструменте придумывается сам собой, и вопрос лишь в том, есть ли чем его остановить.
Наблюдаемое следствие: у полной конфигурации доля сломанных случаев падает по ходу оптимизации (−0,24 п.п. за итерацию), у варианта без отбора — растёт (+0,16 п.п. за итерацию). Доля же исправленных случаев у обоих сопоставима — расходятся они не в способности чинить, а в способности не ломать.
Карантин выборок при подгонке
Дисциплина, которую при настройке промптов нарушают почти всегда: подогнал под эталонный набор — набор перестал измерять.
- Обучающая выборка — единственное, что видит диагностика.
- Отложенная закрыта от диагностики: по ней ранжируют кандидатов, а рефлексии она видна только агрегатом, без разбора отдельных случаев.
- Тестовая не открывается движком вовсе.
Практический смысл разделения — не формальность, а именно та защита от переобучения, которая в замере оказалась самой дорогой при снятии.
Что переносится на ручную работу
Три ингредиента сформулированы про автоматический контур, но читаются как правила для человека или агента, чинящего агентную систему по упавшему прогону:
- Копать по трассе и по коду обвязки, а не просить модель объяснить провал одним вызовом. Поверхностное объяснение звучит убедительно и указывает не туда.
- Держать рамку правки. Без неё правится текст промпта, потому что это самое доступное, а не самое полезное.
- Проверять исправление там, где оно не требовалось. Прогон, вызвавший починку, подтверждает только её локальный эффект; вопрос «что сломалось у того, что работало» задаётся отдельно и стоит дороже всего, если его не задать.
Навигационная траектория как поверхность A/B
Для coding-agent часть провалов видна до финального ответа: он долго ищет точку входа, читает соседние ветки, возвращается к тем же файлам или загружает внутренности skill вместо его интерфейса. Agent Navigation Observability превращает это в отдельную проекцию трассы — последовательность search / read / edit поверх дерева репозитория.
Такая проекция объясняет, почему одна карта репозитория лучше другой, но не определяет победителя сама. Короткий маршрут может означать хорошее routing description, а может — пропущенное доказательство. Поэтому A/B начинается с одинакового набора representative tasks и ожидаемого материала, ведущей метрикой оставляет task completion, а число чтений, время до первого релевантного файла и возвраты между ветками использует для диагноза. Изменение descriptions проверяется и на отложенных формулировках: иначе карта учится словам тестового набора, а не предметной области.
Визуализация полезна как интерфейс расследования, но скриншот не заменяет эксперимент. Без версии модели, ревизии репозитория, одинаковых прав и нескольких повторов разницу маршрутов нельзя приписать структуре harness: это может быть обычный разброс модели.
Связано с
- Agent Harness — устройство обвязки; здесь то, как её улучшать и чем измерять
- Agent Evals — эталонный набор; отсюда дисциплина карантина выборок при подгонке
- Agent Failure Modes — разбор провала; capability против steering отвечает, чем его чинить
- Agent First Repository — репозиторий, устроенный так, чтобы агент чинил себя сам: та же идея на уровне рабочего процесса
- Prompt Engineering — оптимизация промпта как частный и, по замеру, наименее ценный случай оптимизации обвязки
- Parallel Agent Dispatch — что улучшать в обвязке первым, если работа идёт в несколько агентов сразу
- Convention Over Instruction — как убрать требование со средней ступени лестницы, не поднимая его на проверку
- Source Independence — там про независимость подтверждений, здесь про независимость проверки от вызвавшего её случая