«Агент завис, повторяет одно и то же, пришлось остановить вручную» — и стандартный совет: ограничьте число шагов. Совет верный и совершенно недостаточный. Лимит шагов прекращает прогон, но не отвечает на вопрос, почему цепочка не сходилась, и на следующем запуске всё повторится, только упрётся в предел чуть раньше.
Механизмов четыре. Они выглядят одинаково снаружи — повторяющиеся действия — и требуют разных исправлений.
#Быстрая проверка
Откройте лог и посмотрите на повторяющиеся вызовы. Два вопроса определяют механизм за полминуты:
-
Аргументы у повторов одинаковые или разные?
- Одинаковые → механизм 1 или 2.
- Разные, но по кругу → механизм 3.
- Разные и не повторяются, но прогресса нет → механизм 4.
-
Результат повтора отличается от предыдущего?
- Нет → модель не поняла результат либо его не видит.
- Да → цепочка реагирует на изменение, но не сходится.
#Механизм 1. Повтор идентичного вызова
Как выглядит. Один и тот же вызов с точно теми же аргументами два-три раза подряд.
Почему. Модель видит свой предыдущий вызов в контексте и продолжает текст по образцу. Это не «забыла» — это ровно то, чем занимается языковая модель: продолжает похожее похожим.
Предохранитель. Дедупликация по точному тексту вызова на стороне кода. Уже выполненные вызовы запоминаются за ход, и повтор не исполняется. В Persona так и сделано: тексты выполненных вызовов складываются в множество, и если в очередном раунде не осталось ни одного нового — ход завершается заготовленным безопасным ответом, а не крутится дальше.
Чего не делать. Просить модель в промпте «не повторяйся». Это пожелание, конкурирующее с механикой продолжения текста, и оно проигрывает.
#Механизм 2. Неинформативный результат
Как выглядит. Повтор того же вызова, но с искренним намерением: модель не поняла, что уже получила ответ.
Почему. Инструмент вернул пустую строку, невнятную ошибку или результат, из которого не следует, что делать дальше. Пустой ответ модель трактует как сбой и пробует снова.
Предохранитель. Каждый инструмент обязан возвращать различимый текст в трёх случаях: успех с данными, успех без данных и ошибка с причиной. «Ничего не найдено по запросу X» и пустая строка — разные вещи для модели, хотя для программиста одинаковые.
Проверка. Прочитайте результат повторяющегося вызова глазами. Если из него непонятно, что делать дальше, — механизм найден.
#Механизм 3. Цикл между двумя состояниями
Как выглядит. A, B, A, B. Прочитать файл, изменить, прочитать, изменить — или переход между двумя каталогами.
Почему. Нет условия завершения, привязанного к результату. Модель после каждого действия видит основание сделать обратное: прочитала — надо поправить, поправила — надо перечитать.
Предохранитель. Явный признак завершения в постановке задачи: «работа закончена, когда в файле есть строка X». Плюс счётчик повторов одной пары действий. Общий лимит шагов здесь помогает только в качестве последней преграды.
Смежная причина. Постоянное перепланирование без предела на число пересмотров. Агент, которому разрешено менять план, может менять его бесконечно — разбор в материале про планирование и декомпозицию задач.
#Механизм 4. Блуждание без прогресса
Как выглядит. Вызовы не повторяются, каждый выглядит осмысленным, но задача не приближается к решению. Самый неприятный механизм, потому что снаружи похож на работу.
Почему. Цель сформулирована непроверяемо. «Разберись с отчётами» — это не задача, у неё нет условия выполнения, и модель может двигаться в любую сторону бесконечно, каждый раз делая локально разумный шаг.
Предохранитель. Проверяемая формулировка цели и признак завершения. Дополнительно — счётчик шагов без изменения состояния: если после трёх вызовов подряд ничего не создано, не изменено и не найдено, цепочку стоит прекращать с частичным результатом.
Отдельно. Компактные модели блуждают заметно чаще, и это свойство размера, а не постановки задачи — подробности в материале про пределы агентов на маленькой локальной модели.
#Таблица «механизм — предохранитель»
| Механизм | Признак в логе | Предохранитель | Общий лимит помогает |
|---|---|---|---|
| Повтор идентичного вызова | Те же аргументы подряд | Дедупликация по тексту вызова | Только как последняя преграда |
| Неинформативный результат | Повтор после пустого ответа | Различимый текст на все исходы | Нет |
| Цикл между двумя состояниями | Чередование A, B, A, B | Признак завершения + счётчик пар | Частично |
| Блуждание без прогресса | Разные вызовы, нет результата | Проверяемая цель + счётчик застоя | Да, но поздно |
Из таблицы видно главное: общий лимит шагов полноценно решает только четвёртый случай, и то с опозданием — вы платите за все шаги до предела.
#Значения лимитов по умолчанию
Пределы, с которых разумно начинать. В скобках — как это устроено в Persona; числа не универсальны, но существовать они обязаны.
Раундов цикла за один ход 6
(в режиме углублённого ответа 8)
Вызовов инструментов за ход 16
Символов на один результат 4 000
Символов суммарно за ход 24 000
Повторов одного вызова 0 — дедупликация по точному тексту
Шагов в фоновой цепочке
размышлений 5 по умолчанию
аварийный предел, если модель
сама решает, когда закончить 50
Таймаут одного внешнего вызова от десятков секунд;
внешний инструментальный сервер 60 с
выполнение команды 30 с
Два замечания к этим числам.
Первое. Предел числа символов важнее предела числа шагов. Цепочка, упершаяся в объём наблюдений, деградирует раньше, чем упрётся в счётчик; механика роста контекста разобрана в материале про паттерн ReAct.
Второе. Аварийный предел в 50 шагов существует не как рабочее значение, а как страховка для режима, где модель сама решает, когда остановиться. Разница между рабочим пределом и аварийным должна быть явной: первый срабатывает регулярно, второй не должен срабатывать никогда.
#Что должно происходить при срабатывании
Половина проблем с лимитами — не в самих лимитах, а в том, что происходит после.
- Возвращать частичный результат, а не молчание. «Успел проверить три файла из семи, вот что нашёл» полезнее, чем пустой ответ.
- Говорить, что сработал предел. Пользователь должен отличать «задача решена» от «закончился бюджет».
- Сохранять промежуточное состояние. Чтобы продолжить можно было с места остановки, а не с начала.
- Писать срабатывание в лог отдельной записью. Иначе при разборе непонятно, оборвалась цепочка или завершилась.
Содержательные ограничения на поведение — что агенту вообще позволено делать по смыслу задачи — это отдельный слой поверх лимитов, разобранный в справке про guardrails.
#Если ничего не помогло
Проверьте, видит ли модель результаты вообще. Бывает, что результат инструмента не дописывается в контекст из-за ошибки в сборке промпта. Симптом — модель повторяет вызовы, как будто ничего не получала, потому что действительно ничего не получала.
Проверьте обрезку. Результат, обрезанный на середине структуры, может быть непонятен модели, и она пробует снова. Признак — длина результата упирается в круглое число.
Проверьте формулировку задачи. Если у цели нет проверяемого условия выполнения, никакой предохранитель не сделает цепочку сходящейся — он только ограничит расход.
Посмотрите, не тот ли это случай, когда агент не нужен. Задача с заранее известной последовательностью шагов должна быть кодом. Агент, которого вы каждый раз ждёте с одной и той же цепочкой действий, — это скрипт, написанный дорогим способом.
Разбор трассировки по шагам, включая поиск точки, где цепочка перестала сходиться, — в материале про чтение трассировки агента.
#Частые вопросы
#Почему агент повторяет один и тот же вызов инструмента?
Потому что видит его в собственном контексте и продолжает текст по образцу. Это свойство механики, а не забывчивость. Единственное надёжное лечение — дедупликация по точному тексту вызова на стороне кода; просьба в промпте не повторяться работает ненадёжно.
#Какой лимит шагов ставить?
Начинать стоит с пяти-шести раундов и увеличивать только тогда, когда логи показывают, что цепочки упираются в предел по делу, а не из-за блуждания. Отдельно нужен предел на объём результатов: цепочка чаще деградирует от переполненного контекста, чем от числа шагов.
#Что делать, если агент чередует два действия?
Добавить в постановку задачи проверяемый признак завершения и счётчик повторов одной пары действий. Чередование почти всегда означает, что у задачи нет условия выполнения, и после каждого шага у модели есть основание сделать обратное.
#Помогает ли просто увеличить лимит?
Обычно нет: если цепочка не сходилась на шести шагах, на двенадцати она не сойдётся, а стоить будет вдвое дороже. Увеличение предела оправдано только когда по логам видно, что цепочка развивалась и ей действительно не хватило бюджета.
#Как отличить зацикливание от долгой работы?
По прогрессу, а не по времени. Долгая работа меняет состояние: появляются новые файлы, находятся новые данные, растёт объём найденного. Зацикливание крутит одни и те же наблюдения. Счётчик шагов без изменения состояния формализует эту разницу.
#Может ли зацикливание стоить денег?
Да, и это самый частый способ неожиданно потратить бюджет: каждый лишний шаг — вызов модели с контекстом, который длиннее предыдущего. Именно поэтому пределы нужны даже там, где зацикливание не портит данные.
#Вывод
Механизмов зацикливания четыре, и общий лимит шагов закрывает по-настоящему только один из них, да и то с опозданием. Дедупликация вызовов, различимые результаты инструментов и проверяемый признак завершения устраняют причины, а лимит остаётся последней преградой.
Определите механизм по логу за полминуты — одинаковые аргументы, чередование или блуждание — и чините соответствующий предохранитель. И проверьте, что при срабатывании предела агент отдаёт частичный результат и честно говорит, что бюджет кончился.