ReAct = Reason + Act. The model thinks about what to do, takes an action, sees what happened, thinks again. It's how every working agent in 2025 is built — Claude Code, Cursor, AutoGPT's descendants, LangChain agents, CrewAI workers. Master this 30-line loop and you understand 80% of agent engineering.
Learning Objectives
After this lesson, you will be able to:
Explain why ReAct (interleaving Thought → Action → Observation) is the most battle-tested agent pattern — and when it beats both pure chain-of-thought and pure tool-calling
Write a ReAct loop in 30 lines that ingests a user query, lets the LLM think aloud, dispatches tool calls, and feeds observations back
Tune the ReAct loop's stopping criteria (max iterations, confidence thresholds, fallback heuristics) for production reliability
Recognize ReAct's failure modes — runaway loops, tool selection thrashing, hallucinated observations — and apply the standard fixes
Yao et al. 2022 used few-shot prompting with examples like:
Question: What's the population of the city where Albert Einstein was born?
Thought: I need to find Einstein's birth city, then look up its population.
Action: search[Albert Einstein birthplace]
Observation: Albert Einstein was born in Ulm, Germany.
Thought: Now I need Ulm's population.
Action: search[Ulm population]
Observation: Ulm has a population of approximately 126,000.
Thought: I have the answer.
Final Answer: Approximately 126,000.
Modern implementations replace the text-format Action with native tool calling (OpenAI tools, Anthropic tools), but the structure is identical: model emits thought + tool call, system runs tool, observation fed back as a tool message, repeat.
Here is a more detailed worked trace on a calculator-plus-search task, showing how thoughts shape successive actions:
Question: If a Tesla Model 3 starts at $39,990 and a Toyota Camry starts at $26,420, what's
the percentage difference relative to the Camry?
Thought 1: Both prices appear in the question, but I should verify them before doing math —
prices change frequently. I'll search for the current MSRP of each.
Action 1: search[Tesla Model 3 2026 starting MSRP]
Observation 1: Tesla Model 3 starts at $42,490 as of Q2 2026.
Thought 2: The question stated $39,990 but the current MSRP is $42,490. I'll use the
current MSRP because the user likely wants up-to-date info. Now Camry.
Action 2: search[Toyota Camry 2026 starting MSRP]
Observation 2: Toyota Camry starts at $28,400 as of Q2 2026.
Thought 3: Diff = (42490 - 28400) / 28400. I'll compute that.
Action 3: calculator[(42490 - 28400) / 28400 * 100]
Observation 3: 49.61
Thought 4: I have enough to answer, and I should note that I corrected the user's stale numbers.
Final Answer: Using current 2026 MSRPs ($42,490 vs $28,400), the Model 3 is about 49.6% more
expensive than the Camry. Note: the prices you cited are from a previous model year.
Three things to notice: (1) the thought before each action explicitly justifies WHY that tool is needed; (2) thoughts can override information in the prompt when observations contradict it; (3) the final answer surfaces the discrepancy rather than silently using stale numbers. Take away the thoughts and the agent would either trust the prompt verbatim (wrong) or chain blind tool calls (no error recovery).
What Do You Think?
In the trace above, the agent saw the prompt say '$39,990' but search returned '$42,490'. Which line in the ReAct loop made the agent correct the user instead of trusting the prompt?
ReAct is often confused with chain-of-thought (CoT) prompting because both interleave reasoning with the model's response. The crucial difference is grounding. Pure CoT writes plausible-sounding reasoning from training-time knowledge; ReAct's reasoning is grounded in tool observations from the live world.
Setting
CoT
ReAct
Pure arithmetic ("what is 23 * 47 - 14?")
Strong — model can compute internally
Equivalent + slower (adds tool call)
Stale-knowledge facts ("current Bitcoin price")
Hallucinates last-seen value
Strong — search/calculator grounds answer
Multi-hop QA ("president of country with largest GDP in Africa")
Compounds errors across hops
Strong — each hop verifies via tool
Long arithmetic chains
Drifts after ~5 steps
Strong — calculator removes drift
Codegen with imports/APIs
Hallucinates function signatures
Strong — doc search grounds API surface
Pure creative writing
Strong
Equivalent — no tools to ground in
Latency < 500ms
Strong (one model call)
Weak — each tool adds 200-2000ms
The rule of thumb: if the answer requires fresh facts, computation that exceeds 3-4 steps, or API/tool grounding, ReAct wins. If the answer is entirely deducible from training data and latency is critical, CoT wins. Many production systems use both: CoT for fast paths, ReAct for grounded paths, with a router that classifies queries upfront.
Quick check
A user asks a finance copilot: 'What was Apple's revenue in their most recent quarter, and what's that as a multiple of their R&D spending?' Pure CoT or ReAct?
The best way to internalize ReAct's control flow is to run a tiny simulation. Below, we model the loop in plain Python with a deterministic policy stand-in instead of an LLM, so you can see how the message log grows and how stopping criteria fire.
Loading visualization...
Once that runs, try editing the policy function so it also handles the Curie query (search Curie -> search Warsaw -> answer). You will discover a subtle truth: in real ReAct, the LLM IS the policy. Every fix you make in code is a fix you would otherwise make by prompt-engineering the system message. The loop infrastructure stays identical; only the policy gets smarter.
If you're hand-writing a ReAct system prompt (instead of relying on a framework's defaults), the canonical shape looks like the snippet below. The framing matters: it tells the model that observations come from a real environment, not the model's imagination.
text
You are a research assistant with access to the following tools.
Use them in a Thought/Action/Observation loop until you can answer the user's question.
Tools:
- search(query: str) -> string. Returns top result from Wikipedia.
- calculator(expression: str) -> string. Evaluates math expressions.
- finish(answer: str). Use this to return the final answer to the user.
Format every step exactly as:
Thought: <one sentence of reasoning about what to do next>
Action: <tool_name>(<json args>)
After each Action you will receive:
Observation: <tool output>
When you have enough information, emit:
Thought: I have enough to answer.
Action: finish({"answer": "..."})
Hard rules:
- Never invent Observation lines yourself; only the system emits them.
- If a search returns no useful result, try a different query before giving up.
- Stop after 10 Thought/Action pairs; emit finish() with your best partial answer.
In production with native tool-calling APIs, you drop the textual format and let the model emit tool calls natively — but the framing rules (no hallucinated observations, retry-then-give-up, hard iteration cap) belong in the system prompt either way.
What Do You Think?
Your ReAct prompt does NOT include the rule 'Never invent Observation lines yourself; only the system emits them.' What's the most likely failure mode?
ReAct interleaves Thought → Action → Observation. The most battle-tested agent pattern, default in every major framework
Tool calling APIs structurally enforce ReAct. The model can emit thoughts (assistant content) interleaved with tool calls, and tool results come back as tool messages
Production needs stopping criteria. Max iterations, token budget, no-progress detection, confidence thresholds; without them, loops can run forever
Failure modes: runaway loops, tool thrashing, hallucinated observations — all have standard fixes
ReAct is the right default. Switch to Plan-then-Execute / Reflexion / LATS only when you have evidence ReAct fails on your task