Я открыла биллинг и увидела ноль. Не «мало осталось», а ровно ноль. Виноват был не сложный сценарий и не наплыв пользователей: один агент на расписании отработал сам с собой около 14 часов и сделал 129 вызовов языковой модели. Задача, которую он при этом решал, была детерминированной — её можно было закрыть скриптом с обычным условием.
Это статья о том, почему я перестала лечить ненадёжность агентной системы добавлением новых агентов. Дальше — что именно сломалось, какой слой оказался мёртвым грузом, и правила, которые заменили количество: бюджет вызовов, стоп-критерии, ретро после каждой задачи и память под системой контроля версий. И почему результат надёжнее проверять одним скептиком, чем толпой судей.
Пару терминов сразу.
- Агент — программа, которая в цикле сама решает, какой шаг сделать следующим, и спрашивает об этом языковую модель.
- Вызов — одно обращение к модели, за которое вы платите.
Соблазн роя: почему хочется добавить ещё одного агента
Логика добавления агента всегда выглядит убедительно. Результат вышел кривой — добавим аналитика, который разберёт задачу до начала работы. Аналитик ошибся — добавим скептика, который его проверит. Скептик спорит с исполнителем — добавим оркестратора, который их рассудит. Каждый шаг кажется дешёвой страховкой: ещё одна пара глаз, ещё один слой защиты.
Проблема в том, что пара глаз здесь недетерминированная. Новый агент — это не проверка, а ещё один источник решений, который может ошибиться, зациклиться или уйти не туда. Слои защиты складываются в надёжность только тогда, когда каждый слой надёжнее того, что он проверяет. Если вы ставите вероятностного контролёра над вероятностным исполнителем, вы получаете не гарантию, а вторую вероятность и вдвое больший счёт.
Вторая ловушка — ощущение работы. Рой производит много видимой активности: обсуждения, планы, промежуточные документы. Со стороны кажется, что система думает. На деле она может потратить весь бюджет на разговор о задаче, к которой ещё не приступала.
Инцидент, который всё расставил по местам
Агент с языковой моделью висел на расписании и просыпался каждые 30 минут. За примерно 14 часов он сделал 129 вызовов и обнулил баланс.
Здесь важна арифметика. Пробуждений за это время было около тридцати, а вызовов — 129. То есть одно пробуждение — это не один вызов: внутри каждого запуска агент ещё и рассуждал, что ему делать. Ставя агента на расписание, вы умножаете не число запусков, а число запусков на среднюю длину внутреннего цикла. Вторую величину вы обычно не контролируете и в голове не держите — именно она и превращает «раз в полчаса, это же копейки» в пустой счёт к утру.
Вывод я записала себе большими буквами: детерминированная проверка — это скрипт, а не агент. Если условие выражается как «если A, то B», языковая модель в этом месте не нужна. Она не добавляет ума, она добавляет расход и разброс. Модель нужна там, где вход неструктурирован и заранее неизвестно, какие шаги понадобятся. Проверка состояния по расписанию — не тот случай.
И отдельный урок про предел. У агента на расписании нет естественного конца: человек закрывает ноутбук, а цикл — нет. Всё, что работает без человека в контуре, должно иметь границу, заданную снаружи, а не надежду на то, что оно само остановится.
flowchart LR
subgraph BEFORE["Было — агент на расписании"]
A1["Пробуждение каждые 30 минут"] --> A2["Внутренний цикл рассуждений"]
A2 --> A3["129 вызовов за ~14 часов"]
A3 --> A4["Баланс обнулён"]
end
subgraph AFTER["Стало — скрипт плюс бюджет"]
B1["Проверка условия скриптом"] --> B2["0 вызовов модели"]
B2 --> B3["Модель только там, где вход неструктурирован"]
B3 --> B4["Не более 5 вызовов на задачу"]
endМёртвый слой: 63 файла, которые никто не открыл
Второй симптом той же болезни я нашла не в счетах, а в репозитории. В системе жил доменный слой из 63 файлов-анкет — структурированных описаний предметной области, которые агенты должны были заполнять и потом переиспользовать. Их делали «на будущее»: придёт похожая задача — не начнём с нуля.
За полтора месяца — ноль повторных использований. Ни один файл не понадобился второй раз. Слой я заархивировала.
Это тот же рой, только застывший в файлах. Логика идентичная: раз мы не знаем, что понадобится, сделаем побольше, вдруг пригодится. Разница в том, что лишние агенты жгут бюджет сразу, а мёртвые артефакты жгут внимание постепенно. Они видны в дереве файлов, попадают в контекст, их приходится учитывать при рефакторинге и объяснять новому человеку.
Проверка простая и неприятная: у любого артефакта, созданного «на будущее», должны быть дата появления и счётчик обращений. Если через месяц счётчик на нуле — это не задел, это балласт.
flowchart TD
T["Задача"] --> Q["Триаж: 5 вопросов"]
Q --> S{"Стоп-критерий сформулирован?"}
S -- "нет" --> X["Не начинаем"]
S -- "да" --> B["Бюджет: не более 5 вызовов"]
B --> E["Исполнитель — один, без роя"]
E --> K["Скептик — один проход, ищет отказ"]
K -- "не годится" --> E
K -- "годится" --> R["Обязательное ретро"]
R --> M["Память под контролем версий"]
M -.-> QПравила, которые заменили количество
Вводила я их не в лаборатории, а на живых задачах — там, где система работает на отельную сеть и на северного туроператора, и где неверный результат стоит не абстрактной репутации, а чьего-то рабочего дня.
1) Бюджет вызовов
Не больше 5 вызовов модели на задачу. Один исполнитель вместо роя.
Бюджет полезен не тем, что экономит деньги — хотя экономит, — а тем, что заставляет систему выбирать. Когда вызовов пять, нельзя позволить себе два на «обдумать подход» и один на «уточнить формулировку». Приходится сразу идти в дело. Ограничение работает как проектное решение, а не как бухгалтерия.
2) Триаж из пяти вопросов
Перед запуском задача проходит через пять вопросов:
- что это за задача
- стоит ли её вообще делать
- какая стратегия
- какие ресурсы нужны
- когда остановиться
Второй вопрос отсекает половину работы, которую никто не просил. Пятый — главный.
Стоп-критерий формулируется до начала, а не тогда, когда стало ясно, что не получается. Если сформулировать его не удаётся, это сигнал: задача поставлена плохо, и агент здесь ни при чём.
3) Ретро после каждой задачи
Обязательное, а не по настроению. Что было задачей, что пошло не так, какое правило из этого следует. Именно так система учится: не тем, что в ней стало больше ролей, а тем, что после каждой задачи в наборе правил что-то меняется.
4) Память под системой контроля версий
Организационная память системы — накопленные правила и выводы — лежит там же, где код, под системой контроля версий. Значит, у каждого правила есть автор, дата и причина; видно, когда оно появилось; его можно откатить.
Память, которая живёт в базе без истории, за пару месяцев превращается в свалку утверждений, про которые непонятно, кто их туда положил и верны ли они ещё.
Проверка: один скептик вместо толпы судей
Популярная схема верификации выглядит так: несколько агентов дают варианты ответа, отдельный агент-судья выбирает лучший. В исследовательских задачах, где вы честно не знаете, какая стратегия сработает, у неё есть смысл. В прикладной работе я от неё отказалась.
Причин три:
- Цена: N кандидатов плюс судья — это N+1 вызовов там, где на всю задачу отведено пять.
- Судья не эксперт: он выбирает из того, что ему принесли. Если все кандидаты ошиблись одинаково (а они к этому склонны), судья уверенно выберет ошибку.
- Размытая ответственность: когда ошибку пропустили пятеро, чинить нечего — механизма «виноватого» нет.
Вместо этого — один проход скептика. Скептик получает готовый результат и одну инструкцию: найти место, где это неверно. Не «оцени качество», не «выбери лучший вариант», а покажи конкретное место, где сломается.
Применить у себя
Что проверить на практике
- Посчитайте вызовы модели за сутки и разделите на число решённых задач. Если среднее вас удивило — вы не знаете, куда уходит бюджет, и это первая проблема, а не деньги.
- Найдите всех агентов, которые запускаются по расписанию. По каждому спросите: если бы решение принимал скрипт с обычным условием, изменился бы результат? Там, где ответ «нет», перепишите скриптом.
- Поставьте потолок вызовов на задачу. Начните с 5 и смотрите, что упирается в границу: часто это не сложность задачи, а болтовня на подступах.
- Выпишите пять вопросов триажа и прогоните через них три последние задачи задним числом. Особое внимание пятому: был ли записан стоп-критерий или система остановилась потому, что вы её выключили.
- Пройдите по артефактам, созданным «на будущее», и посчитайте обращения к каждому. Ноль за месяц — в архив, не в бэклог.
- Замените схему «несколько кандидатов плюс судья» на один проход скептика с инструкцией искать конкретный отказ. Прогоните на десятке задач и сравните, какая схема ловит больше настоящих ошибок.
- Заведите ретро на три строки после каждой задачи и положите его под систему контроля версий рядом с кодом.
Как понять, что получилось
Главный критерий один: расход перестал быть сюрпризом. Вы можете назвать верхнюю границу вызовов до запуска, а не узнать её из биллинга.
Остальные признаки:
- у каждой задачи есть записанный стоп-критерий
- со временем растёт число правил, а не число агентов
- разбор инцидента заканчивается изменением правила, а не появлением нового агента
- в репозитории нет артефактов, к которым за месяц никто не обратился
- скептик хотя бы иногда говорит «не годится» — и это подтверждается на практике.
Надёжность агентной системы даёт не количество исполнителей, а дисциплина: стоп-критерии, бюджет вызовов, обучение через ретро и память под версионированием. Рой выглядит как сила, а ведёт себя как расход. Пять правил обходятся дешевле пяти агентов — и, в отличие от них, работают одинаково в любое время суток.