Проблема
03:07 ночі.
Черговий інженер on-call бачить, що агент отримав звичайний запит, кілька разів викликав tool, отримував результати, але так і не зміг завершити задачу.
У логах повторюється:
plan → call_tool → analyze → plan → call_tool → analyze
Кроків багато, токенів теж багато, результату немає.
Агент намагається знайти email у CRM. Пошук повертає 404, але замість відповіді "не знайдено" агент починає змінювати запит:
john@example.comJohn@example.comJOHN@example.comjohn@company.com
За 2 хвилини агент зробив 47 API-викликів, витратив близько $5 на токени і все одно не наблизився до відповіді.
Runaway loop може за 30–40 хвилин спалити бюджет, який планувався на тиждень роботи системи.
Аналогія: уяви касира, який безкінечно пробиває один і той самий товар у чек, ігноруючи ліміт картки покупця. Він може виглядати "зайнятим", але кожна нова дія лише збільшує збиток. Для AI-агентів цю роль контролю виконує runtime: stop conditions, бюджети та policy gates.
Чому це стається
У production:
- LLM пропонує наступний крок;
- виклик іде в інструмент;
- результат знову потрапляє в reasoning loop;
- runtime не перевіряє, чи є прогрес, і не зупиняє цикл вчасно.
Проблема не в моделі — проблема в тому, що runtime не знає, коли треба зупинитись.
Які збої трапляються найчастіше
Щоб не ускладнювати розбір, у production зазвичай починають із трьох головних типів збоїв.
Зациклення (Loop failures)
Агент повторює ті самі кроки без нових спостережень. Зовні це може виглядати так, ніби він ще працює, але насправді система просто крутиться по колу і спалює час та гроші.
Типова причина: відсутні max_steps, progress check або чіткий stop reason.
У production це зазвичай виглядає як нескінченний цикл.
Збої інструментів (Tool failures)
Агент занадто часто або неправильно викликає інструменти. Зростають latency і API-навантаження, а збої починають розповзатися по ланцюгу сервісів.
Типова причина: занадто вільний Tool Execution Layer і слабка валідація аргументів.
У результаті легко отримати збій інструмента.
Збої бюджету (Budget failures)
Бюджет токенів і часу зростає без помітного прогресу. У результаті система дорожчає, а суміжні сервіси частіше впираються в timeout.
Типова причина: немає execution budgets на кроки, токени, час і кількість tool викликів.
Без лімітів це часто переростає у вибух бюджету.
Дрейф контексту (Context drift)
Коли агент працює занадто довго, історія повідомлень росте. Нові токени можуть витіснити системний prompt, і агент починає "забувати" свою роль або первинну задачу — це context drift. Зазвичай його виправляють через summarization і обмеження context window; близький за симптомами сценарій — отруєння контексту.
Окремо варто тримати в полі зору ще два класи:
Security failures: prompt injection і несанкціонований доступ до write-інструментів.Data failures: хибні або невалідовані проміжні дані, що ламають фінальну відповідь.
Як детектити ці проблеми
Щоб спіймати такі збої до того, як вони стануть інцидентом, production-системи зазвичай відстежують кілька ключових метрик.
| Метрика | Сигнал | Що робити |
|---|---|---|
steps_per_task | різкий ріст ітерацій | перевірити stop conditions, додати progress check |
tool_calls_per_task | підозріло багато повторів | ввести dedupe tool+args, обмеження на виклики |
tokens_per_task | витрата росте без прогресу | обмежити розмір context window, додати summarization і caps для tool output |
runtime_duration | затримки ростуть, task зависає | timeout і примусове завершення run'а |
Як відрізнити збій від справді складної задачі
Не кожен довгий run означає збій. Ключовий сигнал проблеми — не кількість кроків, а відсутність реального прогресу.
Нормально, якщо:
toolкроки змінюють спостереження;- з'являються нові дані;
- результат стає ближчим до
final_answer.
Небезпечно, якщо:
- повтори без нових спостережень;
- той самий
tool_callбез змін в аргументах; - вартість росте, а результат не поліпшується.
Як зупиняти такі збої
Найпростіший спосіб контролювати execution loop — runtime limits. Зазвичай це ліміти max_steps, max_tool_calls, max_tokens і timeout.
max_steps — перший стоп-кран проти runaway loops. Більш просунутий варіант — semantic progress check: окрема невелика модель (наприклад, Gemini Flash або Claude Haiku) аналізує останні 3 кроки агента і перевіряє, чи з'явився новий сигнал, чи система просто крутиться по колу. Результат може виглядати так:
{
"is_progressing": true,
"is_looping": false
}
Базовий runtime-каркас, який закриває більшість runaway loops:
class RunLimits:
def __init__(self):
self.max_steps = 8
self.max_tool_calls = 12
self.max_tokens = 4000
self.max_seconds = 30
self.steps = 0
self.tool_calls = 0
def check(self, step_tokens: int, elapsed_ms: int) -> str | None:
self.steps += 1
self.max_tokens -= step_tokens
if self.steps > self.max_steps:
return "max_steps_reached"
if self.tool_calls > self.max_tool_calls:
return "max_tool_calls_reached"
if self.max_tokens <= 0:
return "max_tokens_reached"
if elapsed_ms > self.max_seconds * 1000:
return "timeout"
return None
def register_tool(self):
self.tool_calls += 1
У production такі ліміти часто зберігають у Redis, щоб контролювати їх між stateless workers.
Але самі ліміти не гарантують правильну поведінку — вони лише зупиняють runaway loop. Щоб агент працював стабільно, потрібні ще валідація tool output, policy boundaries і контроль write-дій.
Самоперевірка
Швидка перевірка перед релізом. Відмічайте пункти і дивіться статус нижче.
Це короткий sanity-check, а не формальний аудит.
Прогрес: 0/8
⚠ Є сигнали ризику
Бракує базових контролів. Закрийте ключові пункти цього чекліста перед релізом.
FAQ
Q: Чому AI-агенти ламаються частіше за звичайні workflow?
A: У workflow кроки зафіксовані наперед. В агенті LLM пропонує наступний крок динамічно, і без runtime меж цикл швидко виходить з-під контролю.
Q: Чи врятує перехід на сильнішу модель?
A: Частково допоможе, але проблему не вирішить. Без runtime-контролю навіть сильна модель може зациклитися, перевищити бюджет або спамити інструментами.
Якби агент із початку статті мав max_steps = 8 і dedupe для tool+args, інцидент о 03:07 завершився б за кілька секунд.
У production стабільність агента визначається не моделлю, а межами, які runtime ставить навколо execution loop.
Пов'язані сторінки
Щоб краще зрозуміти, як запобігати таким збоям, подивись на шари системи, які контролюють поведінку агента:
- Agent Runtime — керує циклом агента, лімітами і причинами зупинки.
- Tool Execution Layer — безпечно виконує
tool_callчерез валідацію, policy і timeout. - Policy Boundaries — визначає, які дії дозволені, а які блокуються за замовчуванням.
- Memory Layer — допомагає тримати стан чистим, щоб агент не повторював кроки без прогресу.
Також корисно перейти до окремих failure-сценаріїв:
- Infinite loop — як виявляти і зупиняти повтори без прогресу.
- Tool spam — як обмежувати дубльовані виклики інструментів.
- Budget explosion — як контролювати витрати токенів і API-бюджет.