Нескінченний цикл агента: коли AI-агент не зупиняється

Infinite loop виникає, коли агент продовжує генерувати нові кроки без реального прогресу. Чому це стається і як це зупиняють у production.
На цій сторінці
  1. Проблема
  2. Чому це стається
  3. Які збої трапляються найчастіше
  4. Жорсткий цикл (Hard loop)
  5. М'який цикл (Soft loop)
  6. Цикл ретраїв (Retry storm)
  7. Семантичний цикл (Semantic loop)
  8. Як виявляти ці проблеми
  9. Як відрізнити збій від справді складної задачі
  10. Як зупиняти такі збої
  11. Де це реалізується в архітектурі
  12. Самоперевірка
  13. FAQ
  14. Пов'язані сторінки

Проблема

Запит виглядає простим: знайти статус замовлення і повернути коротку відповідь.

У логах видно, що агент постійно повторює один і той самий цикл:

plan → call_tool → analyze → plan → call_tool → analyze

Тиждень тому така задача закривалась за 3-4 кроки. Тепер той самий тип запиту може крутитись 20+ кроків і завершуватись timeout. За 15 хвилин агент може зробити 60+ кроків і витратити близько $12 на задачу, яка зазвичай коштує ~$0.08.

Система не падає одразу.

Вона просто повільно спалює час, токени і гроші.

Аналогія: уяви навігатор, який на кожному перехресті каже "розверніться", навіть коли ти вже розвернувся. Машина їде, але ти не наближаєшся до цілі. Нескінченний цикл в агентах працює так само: дії є, прогресу немає.

Чому це стається

LLM-агенти — це стохастичні системи. Навіть невелика зміна prompt, tool output або контексту може змістити порядок кроків. Якщо runtime не перевіряє реальний прогрес, цикл легко застрягає.

У production зазвичай так:

  1. LLM пропонує наступну дію;
  2. агент викликає tool;
  3. отримує спостереження, але без нового сигналу;
  4. знову повертається в той самий reasoning loop.

Infinite loop виникає не тоді, коли агент "занадто довго думає", а тоді, коли runtime не відрізняє корисну роботу від повторення без прогресу.

Які збої трапляються найчастіше

Щоб не ускладнювати, у сценарії infinite loop найчастіше бачать чотири патерни.

Жорсткий цикл (Hard loop)

Агент викликає той самий tool з тими самими аргументами багато разів.

Типова причина: немає dedupe за tool+args або повтори дозволені без ліміту.

М'який цикл (Soft loop)

Агент виконує ту саму дію з мінімальними змінами аргументів: наприклад, додає одне слово в пошук і пробує знову.

Типова причина: немає перевірки "чи з'явилось щось нове".

Цикл ретраїв (Retry storm)

Інструмент падає, і одночасно ретраї роблять і gateway, і сам агент. У результаті кількість викликів множиться.

Типова причина: retry-логіка розкидана по кількох шарах без єдиної policy.

Семантичний цикл (Semantic loop)

Агент виглядає активним, але реально не рухається: переформульовує план, пересумовує ті самі дані або знову запитує те, що вже відомо.

Типова причина: немає чіткого критерію прогресу в runtime.

Як виявляти ці проблеми

Нескінченний цикл краще видно не по одній метриці, а по комбінації сигналів.

МетрикаСигнал зацикленняЩо робити
steps_per_taskрізкий ріст кроків без завершеннядодати жорсткий max_steps і stop reason
repeated_tool_signature_rateповтори tool+args у межах одного runувімкнути dedupe і ліміт повторів
no_progress_stepsкілька кроків без нових фактів/артефактівзупиняти run за правилом no-progress window
stop_reason_distributionбагато timeout і max_steps_reachedперевірити retry policy і runtime-gates
tokens_per_taskвитрати ростуть, а якість стоїтьобмежити context/tool output і ввести progress check

Як відрізнити збій від справді складної задачі

Довгий run не завжди означає loop. Ключове питання: чи з'являється новий корисний сигнал.

Нормально, якщо:

  • кожен 1-2 крок додає нові факти або артефакти;
  • tool виклики змінюються змістовно, а не косметично;
  • агент поступово наближається до final_answer.

Небезпечно, якщо:

  • 3-5 кроків поспіль не додають нічого нового;
  • повторюється той самий tool (або той самий намір);
  • витрати ростуть, а якість відповіді не покращується.

Як зупиняти такі збої

Мета проста: не продовжувати run за будь-яку ціну, а завершувати його керовано.

Практично це виглядає так:

  1. ставиш жорсткі runtime-ліміти: max_steps, timeout, max_tool_calls, max_tokens;
  2. додаєш dedupe за tool+args і ліміт повторів;
  3. зупиняєш run, якщо немає прогресу впродовж N кроків;
  4. повертаєш керований stop reason і частковий результат, а не "тиху" помилку.

Мінімальний loop-guard у runtime:

PYTHON
class LoopGuard:
    def __init__(self):
        self.max_steps = 12
        self.max_repeat = 3
        self.max_flat_steps = 4
        self.steps = 0
        self.flat_steps = 0
        self.seen = {}

    def on_step(self):
        self.steps += 1
        if self.steps > self.max_steps:
            return "max_steps_reached"
        return None

    def on_tool_call(self, signature: str):
        self.seen[signature] = self.seen.get(signature, 0) + 1
        if self.seen[signature] >= self.max_repeat:
            return "loop_detected:repeated_tool_signature"
        return None

    def on_progress(self, has_new_signal: bool):
        self.flat_steps = 0 if has_new_signal else self.flat_steps + 1
        if self.flat_steps >= self.max_flat_steps:
            return "loop_detected:no_progress"
        return None

Важливо: у кожній ітерації спочатку викликай on_step(), потім on_tool_call(...), а після аналізу результату — on_progress(...).

Цей guard не "лікує" агента. Він не дає циклу стати production-інцидентом.

Де це реалізується в архітектурі

У production системах контроль loop зазвичай знаходиться не в самому агенті, а в окремих архітектурних шарах.

Agent Runtime відповідає за execution loop агента: ліміти (max_steps, timeout, max_tokens), stop reasons і примусове завершення run. Саме тут зазвичай реалізують LoopGuard і перевірку прогресу.

Tool Execution Layer відповідає за безпечне виконання tool_call: dedupe викликів, retry policy і нормалізацію помилок. Багато циклів — retry storm, repeated tool calls і tool spam — виникають саме тут, коли немає єдиної retry policy або дедуплікації.

Самоперевірка

Швидка перевірка перед релізом: відмічайте пункти і дивіться статус нижче.
Це короткий sanity-check, а не формальний аудит.

Прогрес: 0/8

⚠ Є сигнали ризику

Бракує базових контролів. Закрийте ключові пункти цього чекліста перед релізом.

FAQ

Q: Чи вирішує проблему infinite loop перехід на сильнішу модель?
A: Частково інколи допомагає, але не вирішує корінь проблеми. Без runtime-gates навіть сильна модель може зациклитись.

Q: Як підбирати max_steps на старті?
A: Стартуй з малого консервативного ліміту і піднімай його лише там, де бачиш підтверджений приріст якості.

Q: Чи потрібно завжди робити retries?
A: Ні. Для 401/403 і стабільних валідаційних помилок retries зазвичай лише погіршують loop.

Q: Що показувати користувачу, коли run зупинено?
A: Причину зупинки, що вже спробували, і частковий результат. Це знижує повторні запуски без змін.


Infinite loop майже ніколи не виглядає як велика аварія. Це повільна деградація, яка з'їдає бюджет і час. Тому production-агенту потрібна не лише "розумна" модель, а й жорсткий runtime-контроль.

Пов'язані сторінки

Щоб глибше закрити цю проблему, подивись:

⏱️ 6 хв читанняОновлено 12 березня 2026 р.Складність: ★★☆
Реалізувати в OnceOnly
Guardrails for loops, retries, and spend escalation.
Використати в OnceOnly
# onceonly guardrails (concept)
version: 1
budgets:
  max_steps: 25
  max_tool_calls: 12
  max_seconds: 60
  max_usd: 1.00
policy:
  tool_allowlist:
    - search.read
    - http.get
controls:
  loop_detection:
    enabled: true
    dedupe_by: [tool, args_hash]
  retries:
    max: 2
    backoff_ms: [200, 800]
stop_reasons:
  enabled: true
logging:
  tool_calls: { enabled: true, store_args: false, store_args_hash: true }
Інтегровано: продакшен-контрольOnceOnly
Додай guardrails до агентів з tool-calling
Зашип цей патерн з governance:
  • Бюджетами (кроки / ліміти витрат)
  • Kill switch та аварійна зупинка
  • Audit logs та трасування
  • Ідемпотентність і dedupe
  • Дозволами на інструменти (allowlist / blocklist)
Інтегрована згадка: OnceOnly — контрольний шар для продакшен агент-систем.
Приклад policy (концепт)
# Example (Python — conceptual)
policy = {
  "budgets": {"steps": 20, "seconds": 60, "usd": 1.0},
  "controls": {"kill_switch": True, "audit": True},
}

Автор

Микола — інженер, який будує інфраструктуру для продакшн AI-агентів.

Фокус: патерни агентів, режими відмов, контроль рантайму та надійність систем.

🔗 GitHub: https://github.com/mykolademyanov


Редакційна примітка

Ця документація підготовлена з допомогою AI, із людською редакторською відповідальністю за точність, ясність і продакшн-релевантність.

Контент базується на реальних відмовах, постмортемах та операційних інцидентах у розгорнутих AI-агентних системах.