К курсу

Цикл агента

Один шаг цикла агентаПрактика: один шаг циклаЦикл в кодеПрактика: цикл в кодеОстановка и повторыПрактика: остановка и повторыЧто решает только кодПрактика: что решает код

Надёжность в проде

Таймаут и ключ идемпотентностиПрактика: таймаут и ключ идемпотентностиСказал «готово», а ничего не произошлоПрактика: ложный успехУстойчивый агент: checkpoint и продолжениеПрактика: устойчивый агент

Устройство агентов

Workflow или агентПрактика: workflow или агентReAct и plan-and-executeПрактика: ReAct и plan-and-executePlan-and-SolveПрактика: Plan-and-SolveReflexionПрактика: ReflexionОдин агент или ройПрактика: один агент или рой

Контекст и стоимость

Почему растёт счёт за агентаПрактика: токены и кэшКонтекст-инженерияПрактика: управление окномПамять агентаПрактика: что агент хранит

Инструменты и протоколы

MCPПрактика: MCPОписания инструментов и инъекцииПрактика: описания инструментов и инъекцииКод вместо набора инструментовПрактика: код вместо набора инструментовНавыки агента и A2AПрактика: навыки агента и A2A

Фреймворки

LangGraph или обычный циклПрактика: LangGraph или обычный циклAgent SDK: что вы покупаетеПрактика: agent SDK

Агенты для кода

Агент для кода по спецификацииПрактика: агент для кода по спецификации
←→ENВойти
Агенты › Цикл агента

Остановка и повторы

Опирается наЦикл в коде

Этот блок про то, как заканчивается цикл и какие сбои стоит повторять.

Агент Northwind вызывает issue_refund, а платёжный сервис лежит. Модель пробует снова, получает ту же ошибку и пробует ещё раз. Ничто не гарантирует, что она остановится.

Кто говорит «хватит»

Вернёмся к телефону. Коллега снова и снова просит позвонить в платёжный отдел, а там не берут трубку. Просить он будет, пока вы отвечаете. Поэтому решение остановиться за вами, и это должно быть правило, которое можно посчитать: пять попыток, потом дело уходит другому.

Из цикла два выхода.

Обычный выход выбирает модель. Принудительный принадлежит вашему коду.
Обычный выход выбирает модель. Принудительный принадлежит вашему коду.

Обычный выход — это ответ без tool call. В API Anthropic он приходит со stop_reason, равным end_turn. Ответ с max_tokens оборван, считать его ответом нельзя.

Принудительный выход — это бюджет, который считает ваш код:

Бюджет

Что ловит

Вызовы модели за прогон

Бесконечные вызовы инструментов

Время прогона

Прогоны, которые затянулись

Токены или деньги за прогон

Прогоны, которые становятся дорогими

Одинаковые сбои

Один вызов падает одинаково раз за разом

Бюджеты считает цикл. Лимит, который есть только в промпте, — это просьба к модели.

Зависший инструмент — это вы на удержании у телефона. Цикл ждёт, и счётчик никто не проверяет. Поэтому таймаут нужен и на каждый вызов инструмента.

Что получает покупатель

Когда срабатывает бюджет, покупатель получает короткое честное сообщение, а дело вместе с историей переходит к человеку:

Не получилось завершить возврат автоматически. Вашим обращением уже занимается сотрудник, он ответит в этом чате.

Никаких stack trace и внутренних текстов ошибок. Если возврат уже прошёл, так и скажите, причём берите этот факт из платёжных записей: текст модели записью не является.

Занято или нет такого номера

Когда вы кому-то звоните, бывает два исхода. Занято, и вы перезваниваете через минуту. Или такого номера не существует, и сколько ни звони, результат будет тот же.

Сбои делятся так же:

Сбой

Что делать

429, лимит запросов

Занято. Подождать, учесть Retry-After, если он есть, повторить несколько раз

5xx при вызове модели, включая 529 у Anthropic

Занято. Retry с backoff

Ошибка соединения или таймаут вызова модели

Занято. Retry с backoff

400, 401, 403

Нет номера. Чинить запрос, ключ, права или лимит расходов

429 из-за лимита расходов или кредитов

Нет номера. Повторы не помогут: поменять лимит или ждать его сброса

Бизнес-правило отклонило возврат

Нет номера. Вернуть модели как ошибку инструмента

По одному статусу два вида 429 не отличить, поэтому смотрите на код ошибки.

Как правильно ждать

Backoff увеличивает паузу после каждой попытки до верхней границы: секунда, две, четыре.

У одного backoff есть изъян. Если тысяча клиентов потеряла связь в один момент, все они и перезвонят в один момент, и линия снова занята. Jitter добавляет в каждую паузу случайность, и звонки расходятся.

Шесть клиентов, у пауз тот же растущий потолок. Jitter распределяет нагрузку по всему интервалу.
Шесть клиентов, у пауз тот же растущий потолок. Jitter распределяет нагрузку по всему интервалу.

Официальные Python SDK от Anthropic и OpenAI по умолчанию сами делают два retry при ошибках соединения, 408, 409, 429 и 5xx. Ваш цикл повторов поверх них умножает число попыток.

С таймаутом или 5xx на записи сложнее: неизвестно, прошёл ли возврат. Об этом следующий блок.

Вывод

Глубже

Exponential backoff and jitter (AWS)Симуляция того, почему jitter снижает нагрузку от повторов.Errors (Anthropic)Коды ошибок и то, что SDK повторяет сам.Error codes (OpenAI)Какие ошибки 429 проходят со временем, а какие нет.Building effective agents (Anthropic)Какое место в агенте занимают условия остановки и точки проверки человеком.
‹ Назад
Предложить улучшениеНашёл ошибку