vegman.dev
Все статьи

От роя к дисциплине: 129 вызовов, которые научили меня считать

2026-07-20кейс

Я открыла биллинг и увидела ноль. Не «мало осталось», а ровно ноль. Виноват был не сложный сценарий и не наплыв пользователей: один агент на расписании отработал сам с собой около 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 и смотрите, что упирается в границу: часто это не сложность задачи, а болтовня на подступах.
  • Выпишите пять вопросов триажа и прогоните через них три последние задачи задним числом. Особое внимание пятому: был ли записан стоп-критерий или система остановилась потому, что вы ее выключили.
  • Пройдите по артефактам, созданным «на будущее», и посчитайте обращения к каждому. Ноль за месяц - в архив, не в бэклог.
  • Замените схему «несколько кандидатов плюс судья» на один проход скептика с инструкцией искать конкретный отказ. Прогоните на десятке задач и сравните, какая схема ловит больше настоящих ошибок.
  • Заведите ретро на три строки после каждой задачи и положите его под систему контроля версий рядом с кодом.

Как понять, что получилось

Главный критерий один: расход перестал быть сюрпризом. Вы можете назвать верхнюю границу вызовов до запуска, а не узнать ее из биллинга.

Остальные признаки:

  • у каждой задачи есть записанный стоп-критерий
  • со временем растет число правил, а не число агентов
  • разбор инцидента заканчивается изменением правила, а не появлением нового агента
  • в репозитории нет артефактов, к которым за месяц никто не обратился
  • скептик хотя бы иногда говорит «не годится» - и это подтверждается на практике.

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