Анти-патерн Single-Step Agents: однокрокові агенти

Anti-pattern, коли агент виконує лише один крок і не використовує ітерації.
На цій сторінці
  1. Ідея за 30 секунд
  2. Приклад анти-патерну
  3. Чому виникає і що йде не так
  4. Правильний підхід
  5. Швидкий тест
  6. Чим відрізняється від інших анти-патернів
  7. Agent Everywhere Problem vs Single-Step Agents
  8. No Stop Conditions vs Single-Step Agents
  9. Tool Calling for Everything vs Single-Step Agents
  10. Самоперевірка: чи немає у вас цього анти-патерну
  11. FAQ
  12. Що далі

Ідея за 30 секунд

Single-Step Agents стає анти-патерном тоді, коли один крок використовують для задач із tools, side effects або неоднозначністю.

У результаті немає місця для перевірки, recovery і контрольованої зупинки. Для задач із tools або побічними ефектами (змінами стану системи) це швидко стає крихким у продакшені.

Для безпечних read-only кейсів single-step може бути нормальним, але для задач із tools або side effects потрібен bounded loop з явними stop_reason.


Приклад анти-патерну

Команда будує агента підтримки, який має шукати дані й виконувати дії в зовнішніх системах.

Але реалізація робить лише один крок: один вибір дії й одне виконання.

PYTHON
decision = agent.decide(user_message)
result = run_tool(decision.tool, decision.args)
return result

У такій схемі немає повторної оцінки після tool-result:

PYTHON
# немає validate_output(...)
# немає no_progress(...)
# немає stop_reason

Для цього кейсу потрібен контрольований цикл із межами:

PYTHON
for step in range(MAX_STEPS):
    decision = agent.next_step(state)
    ...

У цьому випадку single-step підхід додає:

  • ранній ризик помилкової дії
  • відсутність recovery після помилки інструмента
  • слабкий контроль якості фінальної відповіді

Чому виникає і що йде не так

Цей анти-патерн часто з’являється, коли команда оптимізує "щоб було простіше" і зводить агентну систему до одного виклику моделі.

Типові причини:

  • бажання зменшити latency будь-якою ціною
  • змішування понять "single LLM call" і "повноцінний агент"
  • відсутність вимог до stop reasons і валідації output
  • надія, що prompt сам закриє recovery-сценарії

У результаті виникають проблеми:

  • немає recovery-loop — після помилки tool агенту нема куди рухатись
  • ризик передчасного write — side effect може статись до перевірки
  • крихкий output — немає етапу перевірки "чи задачу реально закрито"
  • складний дебаг — run завершується без прозорої причини
  • нестабільність у production — один невдалий крок одразу дає інцидент

На відміну від No Stop Conditions, тут немає навіть керованого циклу: проблема починається раніше, на самому дизайні "один крок і завершення".

Типові production-сигнали, що single-step уже небезпечний:

  • задачі з tools і side effects працюють без max_steps/stop_reason
  • невдалий tool-call одразу завершує run без спроби безпечного recovery
  • одна помилка маршруту призводить до зовнішньої дії без додаткової перевірки
  • команда не може пояснити, чому було обрано саме цю дію в цьому запуску

Важливо, що кожен крок агента — це частина LLM inference. У single-step дизайні ви фактично дозволяєте одному inference прийняти критичне рішення без перевірки.

Правильний підхід

Починайте з мінімального bounded loop для всіх сценаріїв, де є tools або side effects. Single-step залишайте тільки для справді безпечних read-only low-risk кейсів без tool-call.

Практична рамка:

  • розділіть маршрути: read_only_single_step і loop_required
  • для loop-шляху задайте max_steps, timeout, stop_reason
  • додавайте перевірки validate_output і no_progress
  • write-дії виконуйте лише після явних policy-перевірок
PYTHON
MAX_STEPS = 6

def run_support_flow(user_message: str):
    route = classify_intent(user_message)  # simple classifier or rules

    if route == "read_only_faq":
        return run_single_step_answer(user_message)  # no tools, no side effects

    state = init_state(user_message)

    for step in range(MAX_STEPS):  # hard limit for unsafe loops
        decision = agent.next_step(state)

        if decision.type == "final_answer":
            if validate_output(decision.output):  # format and required fields
                return decision.output
            return stop("invalid_output")

        result = run_tool(decision.tool, decision.args)
        if no_progress(state, result):  # repeated pattern or no meaningful state change
            return stop("no_progress")
        state.append(result)

    return stop("max_steps_exceeded")

У такій схемі ризики стають керованими: система або закриває задачу, або зупиняється з прозорою причиною.

Швидкий тест

Якщо на ці питання відповідь "так", у вас є ризик анти-патерну Single-Step Agents:

  • Чи задачі з tools і side effects виконуються через один model call?
  • Чи після невдалого tool-result run завершується без recovery-кроку?
  • Чи немає явного stop_reason, коли сценарій не закрито коректно?

Чим відрізняється від інших анти-патернів

Agent Everywhere Problem vs Single-Step Agents

Agent Everywhere ProblemSingle-Step Agents
Основна проблема: агент використовується навіть для детермінованих задач.Основна проблема: навіть коли агент уже потрібен, його виконують одним кроком без циклу.
Коли виникає: коли простий workflow замінюють агентним reasoning.Коли виникає: коли задачі з tools/write запускають без recovery і stop-логіки.

Якщо коротко: Agent Everywhere Problem — про зайвий вибір агента, а Single-Step Agents — про небезпечний спосіб виконання агента.

No Stop Conditions vs Single-Step Agents

No Stop ConditionsSingle-Step Agents
Основна проблема: цикл є, але немає чітких умов завершення.Основна проблема: циклу як такого немає, тому немає простору для контрольованого recovery.
Коли виникає: коли run заходить у нескінченні або довгі повтори.Коли виникає: коли один помилковий крок одразу завершує сценарій або запускає небажану дію.

Якщо коротко: No Stop Conditions — про неконтрольований цикл, а Single-Step Agents — про відсутність циклу там, де він потрібен.

Tool Calling for Everything vs Single-Step Agents

Tool Calling for EverythingSingle-Step Agents
Основна проблема: зайві tool-calls навіть у простих сценаріях.Основна проблема: критичний tool-call роблять одним кроком без перевірки результату.
Коли виникає: коли tool-call стає дефолтним маршрутом.Коли виникає: коли після tool-result немає жодного циклу для валідації або корекції.

Якщо коротко: Tool Calling for Everything збільшує кількість зайвих викликів, а Single-Step Agents підвищує ризик одного неконтрольованого виклику.

Самоперевірка: чи немає у вас цього анти-патерну

Швидка перевірка на anti-pattern Single-Step Agents.
Відмічайте пункти під вашу систему і дивіться статус нижче.

Перевірте свою систему:

Прогрес: 0/8

⚠ Є ознаки цього anti-pattern

Спробуйте винести прості кроки у workflow і залишити агента лише для складних рішень.

FAQ

Q: Single-step підхід завжди поганий?
A: Ні. Він підходить для безпечних read-only сценаріїв без tools і side effects. Проблема виникає, коли його застосовують для задач, що потребують recovery і контролю.

Q: Як зрозуміти, що треба переходити на loop?
A: Якщо є tool-calls, зовнішні дії, неоднозначний output або ризик помилки з високим впливом — потрібен bounded loop з явними stop_reason.

Q: Чи сильно виросте latency після переходу на loop?
A: Може вирости, але це керується budget-обмеженнями. У production зазвичай важливіше контрольований і безпечний результат, ніж "швидко, але крихко".


Що далі

Схожі anti-patterns:

Що будувати замість цього:

  • Stop Conditions — як задавати умови завершення для керованого run.
  • Routing Agent — як розводити read-only і side-effecting маршрути.
  • Tool Execution Layer — як безпечно виконувати tool-calls через policy і ліміти.
⏱️ 7 хв читанняОновлено 17 березня 2026 р.Складність: ★★★
Реалізувати в OnceOnly
Safe defaults for tool permissions + write gating.
Використати в OnceOnly
# onceonly guardrails (concept)
version: 1
tools:
  default_mode: read_only
  allowlist:
    - search.read
    - kb.read
    - http.get
writes:
  enabled: false
  require_approval: true
  idempotency: true
controls:
  kill_switch: { enabled: true, mode: disable_writes }
audit:
  enabled: true
Інтегровано: продакшен-контрольOnceOnly
Додай guardrails до агентів з tool-calling
Зашип цей патерн з governance:
  • Бюджетами (кроки / ліміти витрат)
  • Дозволами на інструменти (allowlist / blocklist)
  • Kill switch та аварійна зупинка
  • Ідемпотентність і dedupe
  • Audit logs та трасування
Інтегрована згадка: OnceOnly — контрольний шар для продакшен агент-систем.

Автор

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

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

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


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

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

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