Головна / Статті

Сім шаблонів агентських циклів та ситуації, коли кожен з них не спрацьовує: ReAct, Maker-Checker та інші.

Практичний каталог схем агентських циклів, від моделей типу «планувати-діяти-перевіряти» до ситуацій залучення людини, із рекомендаціями щодо того, коли кожна з них підходить, коли їх слід уникати та як їх обирати.

Видавець: REACTAPP.TOP9 хв читання1958 слів

Джерела: Agentic Loops & Design Patterns

Ніхто не повинен оцінювати агента за тим, наскільки кмітливо він звучить. Важливим є його поведінка під час великого навантаження, коли щось ламається та коли приходить аудитор. Саме в цих ситуаціях шаблони проектування циклів мають перевагу над будь-яким окремим запитом. Цикли працюють найкраще, коли їх розглядають як архітектурні примітиви: кожен з них вирішує певну категорію проблем, має відомі компроміси та повинен обиратися навмисно. Нижче наведені шаблони з прикладами у стилі Claude та ситуаціями, в яких кожен з них слід уникати.

1. Планування, дія, перевірка

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

// Pseudo-code: Node/TypeScript orchestrating Claude as an agent

async function planActVerifyLoop(ticket) {
  let iteration = 0;
  const maxIterations = 5;

  while (iteration < maxIterations) {
    iteration++;

    // 1. PLAN: ask Claude for the next step
    const plan = await claude.chat({
      model: "claude-3-opus",
      messages: [
        {
          role: "user",
          content: `You are a coding agent working on ticket ${ticket.id}.
Goal: Make tests pass for this ticket without changing public APIs.

Current context:
${ticket.description}
${ticket.latestFailureLog}

What is the single most useful next action?`
        }
      ]
    });

    // 2. ACT: execute the suggested action if it's in the allowed action space
    const action = parseAction(plan);
    const result = await executeAction(action); // run tests, edit file, etc.

    // 3. VERIFY: use tests as verification
    const verification = await runTests(ticket.testSuite);

    if (verification.allPassing) {
      return { status: "done", iterations: iteration };
    }

    // Attach the failure output back into ticket context
    ticket.latestFailureLog = verification.failureOutput;
  }

  return { status: "budget_exhausted" };
}

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

Хорошими прикладами є багатокрокові інженерні завдання з вимірюваним прогресом, скрипти розгортання та зміни конфігурації, які мають досягти перевіреного робочого стану, а також внутрішні інструменти, у яких можна вбудувати сильні механізми перевірки, такі як тести чи верифікація схеми.

Поганими прикладами є суто творча робота, така як маркетингові тексти чи довгі текстові твори, суб’єктивні рішення, де перевірка лише відображатиме особисті уподобання, та реальні часові процеси, які не можуть дозволити собі кілька ітерацій на критичному шляху.

2. ReAct (спочатку міркуй, потім дій)

ReAct поєднує короткі імпульси мислення з окремими діями. Замість того, щоб заздалегідь спланувати всю дорогу, агент вивчає найновіший стан, обирає один інструмент, використовує його, а потім знову думає. Це робить його ідеальним вибором для дослідницької чи діагностичної роботи, де кожне нове спостереження може справедливо змінити план.

# Pseudo-code: Python coordinator orchestrating Claude tool calls

def react_loop(incident):
    iteration = 0
    max_iterations = 6

    while iteration < max_iterations:
        iteration += 1

        # REASON: Claude decides what to inspect next
        reasoning = claude.chat(
            model="claude-3-opus",
            messages=[
                {
                    "role": "user",
                    "content": f"""
You are an SRE assistant triaging a payment incident.

Incident summary:
{incident.summary}

Recent metrics:
{incident.latest_metrics}

Logs snippet:
{incident.logs_snippet}

Decide one next diagnostic action from:
- CHECK_METRICS
- CHECK_LOGS
- CHECK_DB_HEALTH
- SUMMARIZE_FINDINGS_AND_RECOMMEND_ACTION

Explain your reasoning briefly and output JSON with 'action' and 'target'.
"""
                }
            ]
        )

        action = parse_json(reasoning)
        if action["action"] == "SUMMARIZE_FINDINGS_AND_RECOMMEND_ACTION":
            return claude.chat(... )  # final summary + recommended steps

        # ACT: run the selected diagnostic
        observation = run_diagnostic(action, incident)

        # Update incident state for the next reasoning step
        incident.update_with_observation(observation)

Кожен крок діагностики має чітку мету, і Claude бачить оновлений контекст після кожної дії.

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

Обійдіться без нього, коли план є стабільним та послідовність дій очевидною, як у обробці документів у стилі ETL; коли пропускна здатність достатньо висока, щоб пошук рішення крок за кроком стає занадто дорогим; або коли можливості для дій настільки обмежені, що додаткове обмірковування нічого не дає.

3. Аналізуйте та коригуйте

Тут спочатку відбуваються дві фази – генерація та критика – після чого йде крок корекції. Це створює розумний стандарт для всього, що потребує перевірки перед тим, як потрапити до клієнта, регулятора чи виробничої системи. Важливим є розділення функцій: функцію критики може виконувати інший запит, дешевша модель чи навіть двигун правил.

async function reflectReviseLoop(draftInput: string) {
  // 1. GENERATE
  const draft = await claude.chat({
    model: "claude-3-opus",
    messages: [
      {
        role: "user",
        content: `
Write a customer-facing email explaining a declined payment due to suspected fraud.
Constraints:
- empathetic but clear
- no admission of fault
- no promises about future approvals

Context:
${draftInput}
`
      }
    ]
  });

  // 2. CRITIQUE (using a cheaper model as checker)
  const critique = await claude.chat({
    model: "claude-3-haiku",
    messages: [
      {
        role: "user",
        content: `
You are a compliance checker.

Review the following email for:
- policy violations
- misleading statements
- over-commitments

Output a JSON with:
- issues: list of strings
- safe: boolean

Email:
${draft.content}
`
      }
    ]
  });

  const review = JSON.parse(critique.content);

  if (review.safe) {
    return draft.content;
  }

  // 3. REVISE
  const revised = await claude.chat({
    model: "claude-3-opus",
    messages: [
      {
        role: "user",
        content: `
You wrote this email:
${draft.content}

Compliance issues:
${review.issues.join("\n")}

Rewrite the email to resolve all issues while preserving intent.
`
      }
    ]
  });

  return revised.content;
}

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

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

4. Розробка, тестування, виправлення

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

async function draftTestFixLoop(issue: Issue) {
  const maxIterations = 4;
  let iteration = 0;

  while (iteration < maxIterations) {
    iteration++;

    // DRAFT: Claude proposes code changes
    const patch = await claude.chat({
      model: "claude-3-opus",
      messages: [
        {
          role: "user",
          content: `
You are an autonomous coding agent.

Ticket:
${issue.title}
${issue.body}

Current failing tests:
${issue.failingTests}

Propose a minimal patch as a diff that makes tests pass
without changing public APIs.`
        }
      ]
    });

    applyPatchToGitRepo(patch.content);

    // TEST: run CI locally or via API
    const testResult = await runCi(issue.branchName);

    if (testResult.success) {
      // FIX_DONE: open a PR with the diff
      await openPullRequest(issue, patch.content);
      return { status: "done" };
    }

    // FEEDBACK: update failingTests for next iteration
    issue.failingTests = testResult.failureSummary;
  }

  return { status: "needs_human_review" };
}

Цей підхід ефективний для завдань низького ризику, які добре ізольовані та позначені як готові до обробки агентом, у внутрішніх інструментах, де скасування змін є простим, а також для некритичних процесів, які можуть толерувати затримки та додаткові витрати.

Уникайте його для будь-яких змін, які безпосередньо впливають на фінансові операції через основні шляхи транзакцій, для змін схеми даних, міграцій та загальних оптимізацій, а також для логіки, яка підлягає регулюванню — автоматизовані зміни можуть порушити встановлені правила.

5. Критик та створювач

Один агент створює зміни, а інший їх перевіряє. У сфері оплат за цим принципом слідує модель «створювач-перевіряючий», яка вже використовується для операцій високого ризику, що полегшує передачу завдань командам з управління ризиками та дотриманням правил.

Цей підхід підходить там, де вже очікуються другі очі для перевірки, де автоматизація впливає на системи, близькі до продакшну, такі як конфігурація, маршрутизація чи сповіщення, а також у випадках важливих звітів чи панелей керування, які читають керівники.

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

6. Перепробувати з пам’яттю

Більшість наївних циклів просто намагаються ще раз. Цикл з повторною спробою та пам’яттю фіксує стани невдач та використовує їх, щоб уникнути повторення тієї ж помилки.

def retry_with_memory_loop(task, max_attempts=3):
    failures = []

    for attempt in range(1, max_attempts + 1):
        # Ask Claude to consider past failures before deciding the next move
        decision = claude.chat(
            model="claude-3-opus",
            messages=[
                {
                    "role": "user",
                    "content": f"""
You are handling a task with a flaky external API.

Task:
{task.description}

Past failures:
{failures}

Decide whether to:
- RETRY_API
- FALLBACK_TO_CACHE
- ESCALATE_TO_HUMAN

Explain briefly and output JSON: {{ "choice": "...", "reason": "..." }}
"""
                }
            ]
        )

        choice = parse_json(decision)

        if choice["choice"] == "RETRY_API":
            result = call_api(task)
        elif choice["choice"] == "FALLBACK_TO_CACHE":
            result = use_cache(task)
        else:
            return {"status": "escalated", "failures": failures}

        if result.success:
            return {"status": "success", "attempts": attempt}

        failures.append(result.error_summary)

    return {"status": "max_attempts_exhausted", "failures": failures}

Підходящими цілями є нестабільні інтеграції, API з обмеженням швидкості та зовнішні системи, якими ви не керуєте, обробка документів із непослідовним форматуванням, а також некритичні робочі процеси, де можливості повторної спроби є прийнятними.

Непідходящими є основні потоки транзакцій, де повторна спроба може призвести до подвоєння ефектів, операції, які не є ідемпотентними, тож безпека повторної спроби невідома, а також сценарії, де збій має виникати негайно та бути помітним, а не повторюватися безслідно.

7. Передача справи людині

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

async function triageLoop(ticket: Ticket) {
  const autoActions = ["LABEL", "ROUTE_TO_QUEUE", "REQUEST_MORE_INFO"];

  const decision = await claude.chat({
    model: "claude-3-opus",
    messages: [
      {
        role: "user",
        content: `
You are a support triage agent in a payments company.

Ticket:
${ticket.body}

Decide one of:
- LABEL (low risk)
- ROUTE_TO_QUEUE (medium risk)
- ESCALATE_TO_HUMAN (high risk / unclear)

Return JSON with:
- choice
- risk_level
- rationale
`
      }
    ]
  });

  const choice = JSON.parse(decision.content);

  if (choice.choice === "ESCALATE_TO_HUMAN") {
    await createHumanTask(ticket, choice.rationale);
    return { status: "escalated" };
  }

  // LABEL or ROUTE_TO_QUEUE are automated but bounded
  await applyAutomatedTriage(ticket, choice);
  return { status: "auto_treated" };
}

Використовуйте його для будь-якої автоматизації, яка може покращити досвід клієнта чи сприйняття справедливості, у процесах, де часткова автоматизація є корисною, але повна автономність несе ризики, а також для початкових впроваджень, які потребують навчання перед тим, як послабити контроль.

Не використовуйте його у суто внутрішніх завданнях з низьким ризиком, де люди лише створюватимуть зайвий шум, у пакетних операціях відділу підтримки, де людський огляд не може бути масштабованим, а також у ситуаціях, де ескалація проблем призведе до перевантаження людей без покращення результатів.

Вибір на практиці

Коли з’являється нова можливість для використання агента, питання «Як мені це ініціювати?» є неправильним першим запитанням. Чотири кращі запитання є такими:

  1. Який сигнал підтверджує результат: тести, схеми, правила, показники чи людське судження?
  2. Скільки кроків реально потрібно для виконання завдання?
  3. Що станеться, якщо система зазнає невдачі?
  4. Хто постраждає, якщо вона прийме неправильне рішення?

Відповіді вказують на певну закономірність:

  • Жорстка, бінарна верифікація свідчить про необхідність створення чернетки, тестування та виправлення помилок.
  • Експлоративний підхід вказує на використання методології ReAct.
  • Заперечення щодо політики та тональності вимагають переосмислення та корекції, або ж застосування підходів критики та розробки.
  • Нестабільне середовище вимагає повторної спроби з використанням механізмів пам’яті.
  • Високий ризик означає необхідність включення механізмів людського втручання з самого початку.

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