Главная / Статьи

Семь шаблонов циклов агентов и ситуации, когда каждый из них терпит неудачу: 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.
  • Проблемы с политикой и тоном текста предполагают этапы «анализ и корректировка» или «критика и разработка».
  • Нестабильная среда требует повторной попытки с учетом предыдущих данных.
  • Высокий риск означает необходимость включения механизма человеческого вмешательства с самого начала.

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