Most people's first attempt at building an agent looks like this: take a user request, have the LLM generate a plan, execute the entire plan, return the result. It works for simple tasks. It falls apart the moment reality doesn't match the plan.
The ReAct pattern (Reasoning + Acting) is the fix. Instead of planning everything upfront and executing blindly, the agent alternates between thinking and doing. Think, do, observe. Think again, do something else, observe again. Repeat until done.
It sounds obvious when you say it out loud. It took a research paper to formalize it, and it changed how every serious agent framework works.
## The Pattern
ReAct interleaves three distinct steps:
**Thought.** The agent reasons about the current situation. What does it know? What does it need to find out? What should it do next? This is explicit reasoning, visible in the trace, not hidden inside the model's weights.
**Action.** The agent does something. Calls a tool, executes code, queries a database, reads a file. A concrete interaction with the environment.
**Observation.** The agent receives the result of its action and incorporates it into its understanding. For a deeper look, see [planning agents that decompose goals](/blog/planning-agents-goal-decomposition).
Then back to Thought. The loop continues until the agent decides it has achieved the goal or can't make further progress.
```
Thought: The user wants to know why the API is returning 500 errors.
I should check the server logs first.
Action: read_file("/var/log/api/error.log", last_lines=50)
Observation: [Log output showing database connection timeouts starting at 14:32]
Thought: The errors started at 14:32 and they're all database connection timeouts.
I should check if the database is running and responsive.
Action: query_database("SELECT 1")
Observation: Error: Connection refused at 10.0.1.5:5432
Thought: The database server isn't responding. I should check if the service is running.
Action: execute_command("systemctl status postgresql")
Observation: postgresql.service - PostgreSQL database server
Active: inactive (dead) since Thu 14:31:47 UTC
Thought: PostgreSQL stopped at 14:31, which explains the 500 errors starting at 14:32.
The database service needs to be restarted. I should inform the user
and ask if they want me to restart it, since that's a service-affecting action.
Action: respond_to_user("Found the issue: PostgreSQL stopped at 14:31...")
```
Each step is grounded in what the agent actually observed, not in what it assumed.
## Why ReAct Beats Plan-Then-Execute
The alternative to ReAct is "plan everything first, then execute." Generate the complete plan in one shot, then run each step sequentially. This works fine when the environment is predictable and each step succeeds as expected.
Real environments are neither.
**Plans break on contact with reality.** The agent plans to read a file that doesn't exist. The API it planned to call requires authentication it doesn't have. The database query returns unexpected schema. A rigid plan can't handle any of these gracefully.
**New information changes the best course of action.** After reading the logs, the agent discovers the problem is different from what it initially assumed. A plan-first agent would keep executing its original plan, wasting time on the wrong investigation. A ReAct agent pivots immediately because it re-reasons after every observation.
**Partial results inform next steps.** Sometimes you don't know what tool to use until you see the results of the previous tool. The log file might point you to the database, which might point you to a configuration file, which might point you to a recent deployment. Each observation narrows the search space in ways that couldn't be predicted upfront.
## Implementing ReAct in Practice
Most modern frameworks implement ReAct natively. LangChain, LangGraph, Mastra, the Claude Agent SDK. They all use the same basic loop. But there are implementation details that make the difference between a ReAct agent that works and one that spins uselessly.
### Structured Thought Prompts
Don't just tell the agent to "think step by step." Give it a structure.
```
Before each action, reason about:
1. What do I know so far?
2. What am I still uncertain about?
3. What is the single most useful thing I can do right now?
4. What would a successful result look like?
```
This forces the agent to evaluate its state before acting. Without structure, the "thought" step often degenerates into restating the problem without actually reasoning about it.
### Observation Parsing
Raw tool outputs can be enormous. A log file might be thousands of lines. An API response might be deeply nested JSON. Feeding all of that raw into the context is wasteful and confusing.
Parse observations before feeding them back. Summarize long outputs. Extract the relevant fields from JSON. Highlight error lines in logs. The agent reasons better with clean, focused observations than with raw data dumps.
### Loop Limits
ReAct agents can and do get stuck in loops. The agent tries something, it doesn't work, it reasons about what to try next, tries the same thing with slightly different parameters, observes the same failure. Without intervention, this continues until the context window fills up or your API budget runs out.
Set hard limits. Maximum iterations (10-20 is usually plenty). Maximum tool calls. Maximum tokens spent. When the limit hits, the agent should summarize what it's tried, what failed, and what it thinks the remaining options are. Then hand it back to a human.
### Thought Visibility
One of ReAct's best properties is that the reasoning is explicit. You can read the agent's thought process in the trace. This is invaluable for debugging and for building trust. It is worth reading about [the anatomy of an agent](/blog/anatomy-of-an-ai-agent) alongside this.
Don't hide the thoughts. Log them. Display them in your UI if appropriate. When an agent makes a bad decision, the thought trace tells you exactly where its reasoning went wrong. Without it, you're debugging a black box.
## ReAct Variants Worth Knowing
### ReAct with Reflection
After completing a task (or failing), the agent adds a reflection step. "Did my approach work? What would I do differently next time? What assumptions did I make that turned out to be wrong?"
This is especially powerful when combined with memory. The reflection gets stored and retrieved in future similar situations. The agent literally learns from experience.
### ReAct with Planning
Some tasks benefit from a lightweight planning step before the ReAct loop starts. "Here's my initial plan: steps 1, 2, 3. But I'll adapt as I go." The plan gives direction without being rigid. The ReAct loop handles the adaptation.
This hybrid works well for complex tasks where completely planless exploration would be inefficient but rigid planning would be too brittle.
### Multi-Agent ReAct
Multiple agents, each running their own ReAct loops, coordinating through shared state. Agent A investigates the frontend while Agent B investigates the backend. Each reports observations to a coordinator that synthesizes findings and redirects efforts.
This is where agent architectures start to get genuinely complex, and genuinely powerful. But that's a topic for another article. This connects directly to [agent loops as state machines](/blog/agent-loop-state-machines).
## When ReAct Is Overkill
Not everything needs iterative reasoning. If the task is a single tool call ("What's the weather in Dubai?"), ReAct adds latency and cost for no benefit. If the task is deterministic ("Format this JSON as a CSV"), a script is better than an agent.
ReAct shines when: the task requires multiple steps, the environment is uncertain, new information changes the approach, or the agent needs to recover from failures gracefully.
For everything else, simpler patterns are simpler. And simpler is almost always better.
## The Key Insight
ReAct's real contribution isn't the specific pattern of thought-action-observation. It's the principle that agents should interleave reasoning and action, making decisions incrementally as they learn about the environment.
That principle applies whether you're using the formal ReAct pattern, a planning agent, a state machine, or a custom loop. The days of "generate the complete answer in one shot" are behind us for any task that requires real work.
Think. Do. Look. Think again. It's not complicated. It's also not optional.