ReAct stands for "Reasoning + Acting." It's the canonical agent pattern and, if you build an agent without thinking about it, this is probably what you'll end up with anyway. The model thinks about what to do, takes a single action, looks at the result, thinks again, and loops. That simple alternation between thought and action is what turns a chatbot into an agent. This page is about how it actually works, why it matters, and why it's harder to do well than it sounds.
Here's the entire pattern in four steps:
In code, the whole thing is about six lines:
while not done:
thought = model.reason(context) # what should I do next?
action = model.choose_tool(thought) # which tool, with what args?
result = tool.execute(action) # run it
context += (thought, action, result) # feed it all back in
The genius is the interleaving. The model doesn't produce a big plan and then execute it. It thinks one step, takes one step, sees the result, thinks again. This means the agent can adapt. When a tool returns something surprising, the next thought takes that into account. When a page doesn't have the info the agent expected, it searches somewhere else. Exploratory tasks work with ReAct because the agent is always reacting to what just happened.
Three properties, and they all matter.
Adaptive means the agent responds to reality as it unfolds. The plan doesn't need to be right upfront; the agent can course-correct mid-task. For most real-world work (research, debugging, exploration), the plan you'd have to write upfront is worse than the plan the agent builds incrementally.
Modular means you can add or remove tools without rewriting the agent. The loop stays the same; only the tool list changes. This is why ReAct and MCP are such good partners: MCP adds tools to the available pool and ReAct consumes them transparently.
Inspectable means the reasoning trace is explicit. Every step has a thought, an action, and an observation. When the agent does something you didn't expect, you can scroll back and see exactly why. This is the difference between debugging an agent and guessing at it.
ReAct is the default, but it's not bulletproof. There are five classic failure modes. If you build more than a couple of agents, you'll hit all of them. Here they are with fixes.
Each one is a specific pattern you'll recognize after you've shipped a few agents. The fixes are small and well-understood. But you have to actually put them in place, none of them come free.
A ReAct system prompt has a specific shape that works. Most problems with ReAct agents trace back to one of these five elements missing from the prompt:
ROLE: Research agent. Answer the user's question using web_search and fetch_url.
TOOLS:
- web_search(query) : find relevant URLs
- fetch_url(url) : read a specific page
REASONING (before each tool call, state):
1. What do I still need to know?
2. Is this a broad search or a specific URL fetch?
3. Call the tool.
4. After: did the result help? What's next?
STOP when:
- You can answer the user's question with citations
- You've made 5 tool calls without substantial new info
- The user's question is outside the scope of these tools
ON TOOL ERROR:
- Retry once with reformulated input
- If still erroring, state the failure and what you'd need to proceed
This prompt works because it tells the agent the shape of each step (1-4) AND the exit conditions. When you run it, you'll see the agent narrate its reasoning, call tools, and stop at the right time. That's a ReAct agent.
Two cases argue for switching or layering:
But for the 80% case (exploratory work, unknown depth, adaptive behavior), ReAct is the default and the right choice. Start here; graduate to other patterns only when you have a concrete reason to.
Andrej Karpathy - Intro to Large Language Models (1 hour)