- 01The three patterns make different bets about when the model thinks, acts and checks.
- 02ReAct decides each step from the last observation: maximally adaptive, and prone to wandering.
- 03Plan-and-execute plans once then runs cheaply: predictable and auditable, and brittle when the plan is wrong.
- 04Reflection adds a critique loop: better quality where errors are recognisable, at the cost of extra calls.
- 05They compose. Production systems usually plan for structure, ReAct where a step needs it, and reflect for quality.
Note. ReAct and reflection are named after specific papers, cited at the end; the patterns have since become general vocabulary. The comparative analysis — the failure each is prone to, and when to prefer which — is ours.
The choice each pattern makes
Framing them this way is more useful than a feature list, because it tells you immediately which fits a task. If the right steps cannot be known until you are in the task, you want thinking distributed across the steps. If they can, you want it concentrated up front where it is cheapest to review. If quality matters more than speed, you want it repeated at the end.
| ReAct | Plan-and-execute | Reflection | |
|---|---|---|---|
| Thinks | Before every action | Once, up front | After producing output |
| Adaptable | Fully | Only within the plan | Adds quality, not adaptability |
| Cost | High — a call per step | Lower — plan once, execute cheap | Extra calls per attempt |
| Auditable | Only after the fact | The plan is inspectable first | The critique is a record |
| Fails by | Wandering | Executing a wrong plan | Approving its own errors |
ReAct: reason and act, interleaved
Thought: I need the customer's current plan before I can answer.
Action: get_subscription(customer_id="c_88")
Observation: { plan: "pro", renews: "2026-08-01" }
Thought: They're on pro. The question was about the team tier, so I
need the team-tier limits to compare.
Action: get_plan_limits(plan="team")
Observation: { seats: 25, ... }
Thought: I now have both. I can answer.
Action: respond(...)The strength is obvious: it handles tasks where you genuinely could not have written the steps in advance, because each step’s result determines the next. Debugging, research, anything exploratory. This is the pattern most agent frameworks implement by default and the one most people mean when they say “agent”.
“ReAct never has a plan you can approve before it starts acting. Its flexibility and its habit of wandering are the same property.”
Plan-and-execute: think once, then run
// 1. Expensive model, ONCE — produces an inspectable plan.
const plan = await planner.create(task);
// [ { step: "fetch order", tool: "get_order" },
// { step: "check policy", tool: "get_policy" },
// { step: "decide refund", tool: null },
// { step: "issue refund", tool: "issue_refund", gate: "human" } ]
// 2. Execute the plan — cheap model or code per step, no re-planning.
for (const step of plan) {
if (step.gate === "human") await requireApproval(step);
await execute(step); // planner is NOT called again here
}Two advantages are easy to undervalue. Cost: the frontier model runs once, not once per step, which for a ten-step task is a large difference. And auditability: the plan exists as an object before execution, so it can be logged, gated, or shown to a human for approval — a property ReAct structurally cannot offer, because in ReAct the plan never exists as a whole.
Re-planning is the pressure valve
Pure plan-and-execute is brittle: if the plan is wrong, it executes the wrong plan efficiently. The practical version adds a re-plan trigger — when a step fails or returns something the plan did not anticipate, hand control back to the planner to revise. That reintroduces some cost and adaptability, and the design question is how readily to re-plan: too eagerly and you have rebuilt ReAct; too reluctantly and you execute nonsense.
Reflection: produce, critique, revise
let draft = await produce(task);
for (let i = 0; i < MAX_REVISIONS; i++) {
const critique = await evaluate(draft, criteria); // a SEPARATE pass
if (critique.passes) break;
draft = await revise(draft, critique.problems); // fix what was named
}
return draft;Reflection works when the gap between producing and recognising quality is real — code that can be run, an argument that can be checked against sources, a plan that can be validated against constraints. It is close to useless when the model cannot tell good from bad in the domain, because then the critique is as unreliable as the output and the loop just costs more.
- The reflection precondition
- Reflection helps only when evaluation is easier than generation. If checking the answer is as hard as producing it, a second pass by the same model adds cost without adding reliability. Ask whether a fresh critique can catch what the first pass missed before you add the loop.
Combining them
// Plan-and-execute on the outside: structure, cost control, an auditable plan.
const plan = await planner.create(task);
for (const step of plan) {
if (step.adaptive) {
// ReAct inside a step whose path genuinely can't be pre-planned.
await runReActLoop(step, { maxSteps: 8 });
} else {
await execute(step);
}
}
// Reflection around the consequential output, not around everything.
let output = await draftFinalResponse();
output = await reflectUntilAcceptable(output, { maxRevisions: 2 });The instinct to pick a single pattern for a whole system is the mistake. Most tasks have a knowable skeleton with one or two genuinely open steps, and a small number of outputs where quality is worth a second pass. Matching the pattern to the part is how you get the adaptability where you need it without paying for it everywhere.
The failure each one is prone to
| Pattern | Characteristic failure | Mitigation |
|---|---|---|
| ReAct | Wanders — local steps fine, global drift | Keep the goal in context; step budget; periodic 'am I on track?' check |
| Plan-and-execute | Executes a wrong plan efficiently | Re-plan trigger on surprise; gate the plan before running |
| Reflection | Approves its own mistakes | Critique against external criteria; a different model or a real check |
ReAct’s wandering is the most common and the most insidious, because the transcript reads as sensible the whole way down — each thought follows from the last observation, and the drift is only visible against the original goal. The cheap, effective mitigation is to re-state the goal in context every few steps and periodically ask the model whether its current direction still serves it, which catches drift while it is still recoverable.
Reflection’s self-approval is the subtle one. A single model producing and critiquing shares its own blind spots — it cannot catch an error it could not see. Where quality genuinely matters, the critique should come from a different model, a different prompt with fresh framing, or an external check like running the code. Self-critique by the same model in the same frame is better than nothing and worse than it looks.
Choosing
| If the task is… | Reach for |
|---|---|
| A knowable sequence with cheap steps | Plan-and-execute |
| Genuinely exploratory, path unknowable | ReAct |
| Mostly knowable, one or two open steps | Plan-and-execute with ReAct inside |
| Quality-critical with checkable output | Reflection over whichever base |
| Fully specifiable, no model judgement needed | Not an agent — a workflow |
When none of them applies
This is worth stating at the end of a patterns article because the existence of elegant patterns is itself a temptation to use them. The question is never “which agent pattern” until you have answered “do I need an agent” — and for a large share of tasks the honest answer is no, as argued in workflow versus agent. Choose the pattern once you have established that the flexibility is actually required.
And whichever pattern you land on, the concerns it does not address are still yours. None of ReAct, plan-and-execute or reflection says anything about what the agent is permitted to do, or what it records — those are the governance and evidence layers, which sit under every pattern equally. See the seven-layer stack for where the patterns fit and what they leave for you to build.
Frequently asked questions
What is the ReAct agent pattern?
ReAct interleaves reasoning and acting: the model produces a thought, takes an action with a tool, observes the result, and repeats. It decides each step based on what the previous step returned, which makes it flexible and adaptive but means it never has a plan you can inspect before it starts acting.
What is the difference between ReAct and plan-and-execute?
ReAct decides the next action at every step, so the plan emerges as it goes. Plan-and-execute makes the model write a full plan first, then execute the steps — usually with cheaper models or fixed code — so the expensive reasoning happens once. ReAct adapts continuously; plan-and-execute commits early and is cheaper and more predictable when the plan holds.
What is the reflection pattern for AI agents?
Reflection adds a critique step: the agent produces output, then a second pass evaluates it against criteria and feeds problems back for revision, looping until the critique passes or a limit is reached. It improves quality on tasks where errors are recognisable after the fact, at the cost of extra model calls per attempt.
Which agent design pattern should I use?
ReAct when the path genuinely cannot be known in advance and each step depends on the last. Plan-and-execute when the task decomposes into a plan you could mostly write yourself, so the model plans once and cheap execution does the rest. Reflection layered on either when output quality matters more than latency and errors are detectable on review.
What is the main weakness of the ReAct pattern?
It can wander. Because it decides one step at a time with no plan to hold it to, a wrong observation leads to a wrong next thought, and it can drift away from the goal while looking locally reasonable at every step. It also has no natural stopping point, so it needs an explicit step budget.
Can you combine agent design patterns?
Yes, and production systems usually do. A common shape is plan-and-execute for structure with ReAct inside any step that turns out to need adaptation, and reflection wrapped around the whole thing for quality. The patterns are composable because each governs a different question — how to choose the next action, whether to plan first, and whether to critique.
Sources
- 01ReAct: Synergizing Reasoning and Acting in Language Models — Yao et al., 2023
- 02Reflexion: Language Agents with Verbal Reinforcement Learning — Shinn et al., 2023
- 03Building effective agents — Anthropic, 2024