Hermes Wiki
Developer/AI/AgenticWorkflows/Fundamentals/agentic-loop-patterns-react-plan-and-execute-and-guardrails

Agentic Loop Patterns: ReAct, Plan-and-Execute, and Guardrails

Concept

An "agent" is just an LLM using tools, in a loop, based on feedback from the environment — Anthropic's own framing of the term. What varies between agent architectures is how much planning happens up front versus interleaved with acting, and how tightly the loop is bounded so an unpredictable model can't run away with itself.

ReAct (Reason + Act — Yao, Zhao, Yu, Du, Shafran, Narasimhan, Cao; ICLR 2023) is the foundational pattern: the model generates interleaved reasoning traces and actions in the same loop, one step at a time. The reasoning step lets the model verbalize a plan, track progress, and handle exceptions as they come up; the action step lets it query an external source (a search API, a tool call) and see the real result before deciding what to do next. Crucially, every step sees the actual outcome of the previous action before committing to the next one — the plan adapts continuously as new information arrives. On benchmark tasks like ALFWorld and WebShop, the original paper found that 1-2-shot ReAct prompting beat imitation- and reinforcement-learning baselines trained on 10³–10⁵ task instances by 34% and 10% absolute success rate respectively — a striking result given ReAct needs no task-specific training data at all.

Plan-and-execute takes the opposite bet: a strong (typically more expensive) model produces a full multi-step plan up front, and a separate, often cheaper model executes each step against that fixed plan, only invoking the strong model again to re-plan when a step fails or a re-plan condition triggers (e.g. every K steps, or on low-confidence output). This trades ReAct's continuous adaptability for a more predictable cost shape: one expensive planning call plus N cheap execution calls, instead of a full-context, full-capability call at every single step.

Neither pattern is safe to run unbounded. Anthropic's guidance on building agents explicitly recommends separating guardrail screening into its own model call rather than overloading the primary responder with both "do the task" and "check whether this is safe" at once, and building in human-review checkpoints before costly or high-risk actions. On the mechanical side, LangGraph enforces a hard recursion_limit (default 25) that raises a GraphRecursionError if exceeded — a backstop against a loop that never converges. Because that backstop alone is often too coarse, production guidance also recommends an explicit max_iterations counter checked by the graph's own routing logic, forcing termination regardless of what the model itself wants to do next — the operative principle being that you cannot rely on the LLM to decide when to stop.

Tradeoffs

Pattern Cost shape Adaptability Typical failure mode
ReAct One full-capability LLM call per step, every step High — replans continuously as real results come in Can loop indefinitely on a task that never satisfies its own stopping condition without an external cap
Plan-and-execute One expensive planning call + N cheap execution calls Lower — commits to a plan, only re-plans on failure/low confidence A plan built on a wrong early assumption can execute several wasted steps before the re-plan gate catches it
Single tool call, no loop One call, one tool invocation, done None — can't adapt to what the tool returns Insufficient for any task where the next step genuinely depends on the previous result

ReAct's per-step adaptability is exactly what makes it expensive at scale — every step pays for a full reasoning pass even when the task is straightforward. Plan-and-execute recovers cost efficiency precisely where the task's shape is knowable upfront and steps are largely independent of each other's outcomes; it loses ground fast on tasks where each result genuinely changes what should happen next.

When to use / when not to

  • Use ReAct for exploratory or uncertain tasks — anything where the right next step can't be known until you see the result of the current one (debugging a live system, open-ended research, multi-turn tool use against an API whose responses vary).
  • Use plan-and-execute when the task's shape is largely predictable ahead of time and individual steps don't depend heavily on each other's specific outputs — e.g. "fetch these five reports, then combine them," where the plan itself is unlikely to need revision mid-flight.
  • Use a single bounded tool call (no loop at all) whenever one lookup genuinely finishes the task — reaching for a full agent loop when a single tool call would do just adds latency, cost, and a runaway-loop risk for no benefit.
  • Don't pick ReAct by default purely because it's the best-known pattern — its per-step cost is real, and a task with a predictable shape is strictly cheaper to run as plan-and-execute.

Common pitfall

Trusting the model to know when to stop. A loop with no externally enforced cap can burn an unbounded number of calls chasing a stopping condition the model itself never reaches — retrying a failing tool call slightly differently each time, or "almost" finishing a task indefinitely. The fix has to live outside the model's own judgment: an explicit iteration counter checked by deterministic routing logic (not a prompt instruction asking the model to stop), a sane recursion_limit, and ideally a "no-progress guard" — hashing recent (tool, args, error) tuples to detect a loop that's stuck repeating itself, which a raw step-count cap alone won't catch if the model keeps burning steps without ever repeating the exact same failing call.

Engineering Lens

The core discipline here is identical to Palana's approach to autonomous agent infrastructure at Grab (see the Palana case study): when a component's behavior can't be fully specified or trusted — and an LLM's next action genuinely can't be — you don't try to make the component behave, you constrain the blast radius around it with deterministic guardrails it has no ability to override. A hard iteration cap enforced by code outside the model's control is the loop-level version of the same instinct that puts a kill switch outside a workload's own runtime: never let the thing whose behavior is uncertain be the thing that decides when it's allowed to stop.

Sources

Hermes Wiki