Просишь проверить дифф — получаешь новый дифф. Найденное по дороге исправлено, потому что это выглядит полезным.
Формально помощь. Фактически я теперь ревьюю правки, которые никто не ревьюил, и потерял ровно ту информацию, ради которой запускал проверку: список того, что было не так.
Строка, которая это чинит
В фронтматтере агента есть поле со списком инструментов. У пишущих агентов оно выглядит так:
tools: Read, Edit, Write, Grep, Glob, BashУ проверяющих — так:
tools: Read, Grep, Glob, BashРазница в двух словах, и она не про вежливость. Инструмента записи просто нет, поэтому написать нельзя. Не «нежелательно», не «постарайся не», а нельзя.
Это тот же переход, что и с запретами в постановке задачи: от принципа к механизму. «Ты ревьюер, не пиши код» — просьба, которую легко перешагнуть с добрыми намерениями. Отсутствие инструмента перешагнуть нечем.
Кто у меня без права записи
Из двенадцати агентов блога семь не могут менять файлы.
Ревьюеры. code-reviewer смотрит дифф на регрессии: пропущенная валидация, права, массовое присвоение, тяжёлые запросы, побочные эффекты очередей и уведомлений, экранирование в шаблонах, нарушения политики безопасности содержимого. security-reviewer — граница админки, формы, подписанные ссылки, утечки в выводе и логах. a11y-reviewer — доступность публичных страниц.
Разведка. flow-orchestrator строит карту от маршрута до шаблона и отмечает затронутые конфиги, миграции, сидеры и тесты. ecosystem-orchestrator — карту влияния на соседние проекты.
Проверка результата. qa-runner гоняет тесты и линтер, разбирает падения. visual-qa смотрит публичный интерфейс: темы, адаптив, кроп, переполнение.
Пятеро оставшихся пишут: бэкенд, публичный фронт, общий модуль редактора, контент, тесты.
Соотношение семь к пяти меня самого удивило, когда я посчитал. Больше половины набора занимается тем, что смотрит и рассказывает.
Почему qa-runner может запускать, но не чинить
Самый спорный случай. У него есть Bash, то есть он запускает тесты, линтер, композер. Может выполнить команду, но не может отредактировать файл.
Соблазн дать ему право правки велик: он же видит красный тест и понимает причину, пусть сразу и починит. Один шаг вместо двух.
Не даю по одной причине: починка красного теста — это решение, а не действие. Надо выбрать, кто виноват, код или тест, и от этого выбора зависит всё остальное. Агент, у которого есть право правки, делает этот выбор мимоходом, и выбирает он то, что быстрее приводит к зелёному. Обычно это тест.
С правом только на запуск разговор другой. Он возвращает мне вывод, причину и виновника, а решение принимаю я или отдаю пишущему агенту с явной формулировкой «проблема в коде, чини код».
Отдельно про Bash у ревьюеров. Он у них есть, потому что ревью без возможности посмотреть историю правок и прогнать поиск по проекту — это чтение вслепую. Формально через оболочку файл изменить можно, и это дыра в моей границе. На практике за все эти месяцы не случалось: тело агента говорит «только ревью», а инструмента с явной семантикой записи нет, и обходить границу через перенаправление вывода никто не пытается.
Что происходит, когда границу снять
Я проверил один раз, специально. Дал ревьюеру право записи на том же диффе.
Без права записи: 11 замечаний списком, из них 4 существенных.
Мои решения: 3 принял, 1 отклонил.
С правом записи: 6 замечаний в отчёте, 5 исправлений в коде.
Мои решения: разбирал новый дифф 25 минут.Обратите внимание на первую цифру: замечаний стало меньше. Часть найденного не попала в отчёт, потому что была исправлена по дороге, а исправленное перестаёт выглядеть как замечание.
Это и есть главная потеря. Ревью — это не про то, чтобы код стал лучше. Ревью — про то, чтобы я узнал, что с кодом не так. Исправление без отчёта отбирает у меня знание и оставляет чужие правки.
Вторая потеря — время. Двадцать пять минут на разбор нового диффа против десяти минут на разбор списка замечаний.
Роль как свойство
Общий принцип, к которому я пришёл: роль агента должна быть выражена свойствами, а не описанием.
Свойства — это то, что задано в фронтматтере и работает независимо от того, что написано в теле: имя, описание-условие, список инструментов. Описание в теле — это намерение, и оно проигрывает возможности.
Первый набор агентов у меня был написан вообще без фронтматтера. Тела на сотни строк, роли расписаны подробно, границ нет. Ревьюер правил код, тестировщик правил тесты, и оба были уверены, что помогают. Ни одна строка описания этому не мешала, потому что описание — не ограничение.
Проверка, которой пользуюсь при заведении агента: если убрать тело файла целиком, останется ли роль? У ревьюера останется — по отсутствию инструментов записи видно, что он не пишет. У агента, чья роль держится только на словах в теле, не останется ничего.
Чего этот приём не даёт
Список инструментов ограничивает действия, но не качество.
Ревьюер без права записи всё так же может выдать сорок одно замечание, из которых семь настоящих. Границы инструментов на точность не влияют — на неё влияет постановка задачи, про которую я писал в цикле о промптах.
Не влияет и на выбор исполнителя. Агент с правильным набором инструментов, но размытым описанием будет выбираться не на те задачи. Инструменты — про то, что он сделает, описание — про то, когда его позовут. Обе части нужны, и они не заменяют друг друга.
И не спасает от главного: я всё равно читаю результат. Ревьюер без права записи не делает ревью за меня, он делает первый проход.
Что осталось
Правка на два слова во фронтматтере, эффект — на всё время жизни агента. Это лучшее соотношение из всего, что я делал с набором.
Что бы я хотел иметь: более тонкое разграничение. Сейчас у меня право записи выдаётся целиком, а хочется по каталогам — чтобы агент публичного фронта физически не мог тронуть модели, а не только знал, что не надо. Такая настройка существует не везде, и я её пока не настроил. Живу на честном слове тела агента, и один раз оно меня подвело: правка в шаблоне утащила за собой правку в контроллере, которую я заметил только на ревью.