

When I started building agents in 2023, I treated every reasoning loop the same way. Throw a system prompt at the model, give it tools, and hope for the best. The agents worked on simple tasks and fell apart the moment a task needed more than three steps. The fix was not a bigger model or a longer context window. The fix was choosing the right reasoning pattern for the job.
In this article I want to walk through the reasoning patterns that I use most often when building production agents: ReAct, Plan-and-Execute, Reflection, Chain of Thoughts, and Tree of Thoughts. I will cover how each pattern works, when I reach for it, what breaks, and how I evaluate one pattern against another. I will keep the pseudo-code minimal and the trade-offs honest.
By the end you should be able to look at a task and pick a pattern rather than copying a template you found on a tutorial. Reasoning patterns are not just academic constructs. They shape latency, cost, reliability, and whether your agent can be debugged on a Tuesday morning when a customer is waiting.
A reasoning pattern is the loop your agent follows to convert a goal into actions. It determines how the model thinks, when it calls tools, when it stops, and when it asks for help. The model weights matter, but the loop around the model often matters more. I have seen weaker models with the right loop beat stronger models with the wrong loop on the same benchmark.
When I evaluate a reasoning pattern, I am really evaluating four things:
The most expensive reasoning pattern is the one that fails silently in production.
Picking a pattern is a trade-off. ReAct is fast and cheap but brittle on long horizons. Plan-and-Execute is more reliable for multi-step work but harder to recover from when a step fails. Reflection improves quality at the cost of doubling or tripling the token bill. There is no free lunch, only informed choices.
Chain of Thoughts, or CoT, is the simplest reasoning pattern. You ask the model to think step by step before producing the answer. There are no tools, no external actions, and no loops. The model produces a single linear trace and a final answer.
I still use CoT for problems that are entirely textual and that fit inside a single context window. Examples include rewriting an email, classifying a customer query, summarising a document, or answering a maths question. It is the cheapest pattern by a wide margin and the easiest to debug because the entire reasoning is in one place.
The downsides are obvious. CoT cannot call tools, cannot fetch data, and cannot recover from mistakes mid-trace. If the first step in the chain is wrong, every later step inherits the error. CoT also has a curious failure mode where models produce confident reasoning that supports the wrong answer, especially on adversarial inputs. I always pair CoT with a separate verification step when the cost of being wrong is high.
CoT is not really an agent pattern in the strict sense because it has no tools and no actions. I include it here because every other pattern in this article builds on top of CoT in some way.
ReAct was introduced in a 2022 paper by Yao and colleagues, and it became the default pattern for tool-using agents in 2023. The idea is to interleave reasoning and acting in a single loop. The model produces a thought, takes an action, observes the result, and produces the next thought. The loop continues until the agent decides it has enough information to answer.
The structure looks like this in practice:
Thought: I need to find the customer's most recent order.
Action: search_orders(customer_id="C-921")
Observation: [{"order_id": "O-44", "date": "2026-05-12"}]
Thought: Now I need the shipping status for O-44.
Action: get_shipping(order_id="O-44")
Observation: "Delivered on 2026-05-15"
Thought: I have what I need.
Final Answer: Your order O-44 was delivered on 2026-05-15.
I reach for ReAct when the task involves a small number of tool calls and the steps are not known in advance. Customer support agents, research lookups, and simple data retrieval tasks are good fits. The pattern is cheap, easy to implement, and works well with most modern models.
ReAct breaks down when the task needs many steps or when the agent needs to maintain state across a long horizon. The model can lose track of what it has already tried and start looping. I have seen ReAct agents call the same tool fifteen times in a row because the observation looked slightly different each time. Adding a step counter and a forced stop condition is a basic hygiene rule.
Plan-and-Execute splits the agent into two phases. First the model produces a full plan as a sequence of steps. Then a separate executor runs each step, often with a different and cheaper model. After all steps are done, the planner reviews the results and decides whether the goal is met.
This pattern shines on long-horizon tasks. If a user asks the agent to research three competitors, summarise their pricing pages, and produce a comparison table, ReAct will struggle. The agent will get lost in the middle of the second competitor and forget what the third was. Plan-and-Execute keeps the plan explicit, so the executor always knows where it is in the sequence.
I find Plan-and-Execute easier to debug because the plan itself is an artefact I can inspect. If the agent gets the wrong answer, I can ask whether the plan was wrong, whether a specific step failed, or whether the synthesis at the end was wrong. With ReAct, all three failure modes look like the same long trace.
The downside is rigidity. Plans made in advance assume the world will cooperate. When step three fails in an unexpected way, the agent has to either skip ahead or replan. Replanning costs tokens and adds latency. For tasks that depend heavily on intermediate results, ReAct or a hybrid pattern often works better.
Reflection adds a self-critique step after the agent produces an answer. The model reviews its own output, identifies weaknesses or errors, and either revises the answer or sends it back through the loop. The critique can be done by the same model with a different prompt, by a separate critic model, or by an external verifier such as a unit test runner.
I use Reflection when correctness matters more than speed. Code generation, legal drafting, and structured data extraction all benefit from a reflection pass. A well-tuned reflector can catch hallucinations, missing edge cases, and formatting errors that the original generator missed.
The pattern is expensive. Each reflection cycle doubles the token cost for that task, and I rarely see meaningful gains beyond two or three cycles. I have also seen reflection make outputs worse when the critic is poorly prompted. A critic that finds problems where none exist will push the generator into worse and worse rewrites.
A good critic is harder to build than a good generator. Spend your prompt engineering budget accordingly.
Reflection works best when paired with an objective signal. If you can run a unit test, hit an API to validate a JSON schema, or compare against a known-good example, the reflection loop has something concrete to optimise against.
Tree of Thoughts, or ToT, generalises Chain of Thoughts into a search tree. At each step, the model proposes several possible thoughts rather than one. A scoring function picks the most promising branch, and the search continues. The pattern is essentially a depth-limited tree search guided by an LLM evaluator.
ToT excels at problems where the optimal next step is not obvious and where backtracking pays off. Puzzles, planning problems, and code synthesis with verification are classic examples. The downside is that ToT is the most expensive pattern in this article. A breadth of three and a depth of five means up to two hundred and forty leaf evaluations, and each one involves an LLM call.
I rarely use ToT in production. The cases where it pays off are narrow, and most product use cases do not justify the cost. I do use ToT internally for hard offline tasks, such as generating challenging eval cases or doing strategic planning for an agent’s roadmap.
If you want a cheaper version of ToT, look at beam search variants. Maintaining the top two or three partial traces at each step gives you much of the benefit at a fraction of the cost.
Here is the comparison I keep on a sticky note next to my desk.
| Pattern | Best for | Cost | Latency | Debuggability |
| Chain of Thoughts | Single-step reasoning | Low | Low | High |
| ReAct | Few-step tool use | Low | Low | Medium |
| Plan-and-Execute | Multi-step workflows | Medium | Medium | High |
| Reflection | Quality-critical output | High | High | Medium |
| Tree of Thoughts | Search-heavy planning | Very high | Very high | Low |
And here is a second table that maps task shapes to pattern recommendations.
| Task shape | First choice | Fallback |
| Classify or rewrite text | CoT | Reflection |
| Look up data with tools | ReAct | Plan-and-Execute |
| Research and synthesise | Plan-and-Execute | ReAct with memory |
| Generate code | Reflection | ReAct with tests |
| Plan a strategy | Tree of Thoughts | Plan-and-Execute |
I treat these tables as starting points, not gospel. The right pattern depends on your specific tools, model, and tolerance for failure.
Here is a minimal ReAct loop in pseudo-code. I have stripped out logging, telemetry, and error handling so the structure is clear.
def react_agent(goal, tools, model, max_steps=10):
trace = []
for step in range(max_steps):
prompt = build_prompt(goal, trace, tools)
output = model.generate(prompt)
if output.is_final_answer:
return output.answer
thought, action = parse(output)
result = tools[action.name](**action.args)
trace.append((thought, action, result))
return fallback_response(goal, trace)
The key design choices are the prompt template and the parser. I keep the prompt template strict so the parser can rely on consistent formatting. I use a structured output format such as JSON or XML tags rather than free text, because free text parsers break the moment the model adds an extra newline.
I also always add a max_steps cap. Without it, a confused agent can run for hundreds of steps and burn through your token budget. Ten is a sensible default for most workflows.
The Plan-and-Execute structure splits into a planner and an executor. Here is the simplest version.
def plan_and_execute(goal, tools, planner, executor):
plan = planner.create_plan(goal, tools)
results = []
for step in plan:
result = executor.run(step, tools)
results.append(result)
if result.failed:
plan = planner.replan(goal, plan, results)
return planner.synthesise(goal, plan, results)
The replan step is what separates a toy implementation from a production one. A good replanner should detect when a step has failed in a way that invalidates the rest of the plan, and produce a new sequence of steps that incorporates what was learned.
I usually use a stronger and more expensive model for the planner and a cheaper model for the executor. The planner runs once at the start and maybe two or three times for replans. The executor might run dozens of times. Splitting the cost this way often produces better results than running a single model across both phases.
Reflection wraps any inner agent with a critique and revision loop.
def reflection_agent(goal, inner_agent, critic, max_revisions=2):
draft = inner_agent.run(goal)
for _ in range(max_revisions):
critique = critic.evaluate(goal, draft)
if critique.is_acceptable:
return draft
draft = inner_agent.revise(goal, draft, critique)
return draft
The inner agent can be any pattern, including ReAct or Plan-and-Execute. The critic is the part you need to design carefully. A critic that always says the draft is acceptable adds cost without value. A critic that always rejects pushes the inner agent into endless revisions.
I find that the best critics are narrow and specific. Instead of asking the model to evaluate overall quality, I ask for specific checks: “Does this response answer the user’s question?”, “Does the code compile?”, “Does the JSON match this schema?”. Narrow critics are easier to align and easier to evaluate themselves.
Every pattern has characteristic failure modes. I keep a running list of the ones I have hit, so I know what to look for when an agent misbehaves.
Most agent failures in production look like obvious bugs in hindsight. Building observability into the loop is the only way to spot them in advance.
When I sit down to design a new agent, I work through a quick checklist before picking a pattern.
The answers point me toward a starting pattern. One or two tool calls with unknown steps points to ReAct. Five or more tool calls with a known sequence points to Plan-and-Execute. High quality requirements with a programmatic check points to Reflection. Most production agents end up using a combination rather than a pure pattern.
I always start with the simplest pattern that could work. It is easier to add complexity than to remove it. If ReAct does the job, ship it. If it does not, escalate to Plan-and-Execute. If that does not, add a Reflection layer.
I do not pick patterns based on vibes. I run evals. Every agent I build has a fixed set of tasks with expected outcomes, and I run each candidate pattern through the same set.
The metrics I track are:
I weight these metrics based on the use case. For a customer-facing agent, latency and success rate dominate. For an internal research agent, cost and final quality matter more. The same pattern can be the right choice in one product and the wrong choice in another.
The trap I want to flag is benchmark overfitting. If you tune your pattern to win on a fixed eval set, you may degrade real-world performance. I keep a holdout set that I evaluate against only quarterly, to catch this.
Real production agents rarely use a single pure pattern. The patterns compose. Here are combinations I use regularly.
The risk with composition is complexity. Each layer adds latency, cost, and surface area for bugs. I try to add a layer only when the eval data shows it pays off. Composing because the patterns sound impressive is a fast way to ship a slow and expensive agent.
Reasoning patterns are getting more dynamic. The latest research focuses on agents that pick their own pattern based on the task at hand. Instead of hard-coding ReAct or Plan-and-Execute, the agent inspects the request and decides whether to think step by step, decompose into a plan, or branch into a search.
I am also watching the move from text-based reasoning to native reasoning models, where the chain of thought happens in latent space rather than as visible tokens. This changes what reasoning patterns look like at the prompt level and may eventually make patterns like Tree of Thoughts much cheaper.
The pattern-level work matters because it is the part of agent design that ships value to users. Better models help, but a well-designed reasoning loop with a mid-tier model usually beats a poorly designed loop with the best available model. That has been true since 2023 and I expect it to stay true through 2026.
Brian Jagger is an AI Architect and Software Engineer with over 15+ years of experience in generative AI, AI-first software development, and digital accessibility. As the Co-founder & CTO of TechA11y and Founder of GuardRailz, he has built innovative AI solutions for businesses, education, and enterprise clients. Brian combines deep technical expertise with a creative background in film and media, helping professionals leverage AI to build impactful, scalable solutions.
QUICK FACTS
Chain of Thoughts is pure reasoning with no tools. ReAct interleaves reasoning with tool calls. If your agent needs to fetch data, look something up, or take an external action, you need ReAct or a similar pattern. CoT alone cannot reach out to the world.