What Is the ReAct Pattern
ReAct (Reasoning + Acting) is an agent architecture pattern that interleaves natural language reasoning traces with concrete tool actions. Instead of jumping directly from a task description to a sequence of API calls, a ReAct agent first reasons aloud about what it needs to do, then takes an action, then observes the result, then reasons again about what to do next. This interleaving produces a verbalized thought-action-observation chain that is simultaneously the agent's reasoning process and its execution trace.
The insight behind ReAct is deceptively simple: language models are dramatically better at tasks when they can externalize their reasoning rather than trying to solve everything in a single forward pass. The reasoning traces serve as working memory, each thought can build on the previous observation, incorporate new information, and correct earlier misconceptions without needing to hold all of this in the model's limited attention.
Why ReAct Emerged
Early agent architectures that used pure action-taking (input → sequence of tool calls → output) suffered from compounding errors. Without explicit reasoning, the agent had no mechanism to notice when its assumptions were wrong, when tool results contradicted its expectations, or when a different approach was needed. ReAct was introduced in the Yao et al. (2022) paper as a way to bring the error-correction benefits of chain-of-thought into interactive, tool-using agents.
The Thought-Action-Observation Cycle
The ReAct cycle has three distinct phases, each serving a specific function. Understanding what each phase is responsible for helps you design prompts that elicit high-quality behavior in each phase.
The Thought Phase
The thought phase is where the agent reasons about the current state of the task. A well-formed thought includes: what is known so far, what is still unknown, what the next logical step is, and why this step is the right one. The thought phase is not just narration of what the agent is about to do, it's genuine reasoning that can change the plan based on what was observed in the previous iteration.
The Action Phase
The action phase translates the thought into a concrete, executable operation. In a tool-calling framework, this means selecting the right tool and constructing the exact parameters. The quality of the action depends heavily on the quality of the preceding thought, a vague thought produces imprecise tool calls; a specific thought produces targeted, efficient calls.
The Observation Phase
The observation phase processes the result of the action and integrates it into the agent's understanding. Observations can confirm, contradict, or enrich what the thought expected. The agent's next thought must account for what was actually observed, this is the self-correction mechanism that makes ReAct robust. If the observation reveals an error, the agent can correct course in the next thought without needing an external intervention.
ReAct vs Direct Action Models
Comparing ReAct to direct action models highlights exactly what explicit reasoning contributes to agent reliability.
Reliability Improvement Mechanism
- Error detection: The thought phase before each action can catch logical errors that would be invisible in direct action models. 'Wait, I already retrieved this data in step 1, I don't need to call the tool again.'
- Plan adaptation: When an observation reveals unexpected information, the thought phase can adapt the plan before the next action. Direct action models committed to a sequence that may no longer be appropriate.
- Hallucination prevention: Explicit observations force the agent to ground its answers in actual tool results. Without observations, language models tend to generate plausible-sounding but unverified answers.
- Early termination: The thought phase can detect when enough information is available to answer, preventing unnecessary tool calls that waste latency and cost.
Implementing ReAct in Practice
ReAct requires careful prompt engineering to elicit the right structure from the model. The system prompt must establish the Thought/Action/Observation format, explain what each phase is for, and provide examples of the desired behavior.
System Prompt Structure for ReAct
You are an AI assistant that uses a Thought-Action-Observation cycle to answer questions.
FORMAT:
Thought: [Reason about what you know and what you need to find out next]
Action: [Call a tool, use one of: search(query), lookup(id), calculate(expr)]
Observation: [Result of the action will be inserted here by the system]
... (repeat Thought/Action/Observation as needed)
Thought: [Reason that you now have enough information to answer]
Answer: [Your final answer, grounded in the observations above]
RULES:
- Each Thought must explain WHY you are taking the next action
- Each Thought after an Observation must explicitly acknowledge what the observation told you
- Never make up information, only use facts from Observations
- Stop when you can answer the question definitivelyParsing the ReAct Loop
The agent runtime must parse the model's output to extract action calls and inject observation results. The parsing loop runs until the model outputs an 'Answer:' prefix, which signals loop termination. Implement a maximum iteration limit (typically 10–20 iterations) as a safety guard against infinite loops.
import re
from typing import Optional
def parse_react_output(text: str) -> tuple[Optional[str], Optional[str]]:
"""Extract action call and answer from a ReAct step.
Returns (action_call, final_answer), one will be None."""
# Check for final answer first
answer_match = re.search(r"Answer:s*(.+?)(?:
|$)", text, re.DOTALL)
if answer_match:
return None, answer_match.group(1).strip()
# Extract action call
action_match = re.search(r"Action:s*(w+)((.+?))", text, re.DOTALL)
if action_match:
tool_name = action_match.group(1)
tool_args = action_match.group(2).strip()
return f"{tool_name}({tool_args})", None
return None, None # No parseable action or answer
async def run_react_loop(
task: str,
system_prompt: str,
tools: dict,
llm_call,
max_iterations: int = 15,
) -> str:
messages = [{"role": "user", "content": task}]
for i in range(max_iterations):
response = await llm_call(system=system_prompt, messages=messages)
text = response.content
action_call, final_answer = parse_react_output(text)
if final_answer:
return final_answer
if action_call:
# Execute the tool and inject observation
observation = await execute_tool(action_call, tools)
messages.append({"role": "assistant", "content": text})
messages.append({
"role": "user",
"content": f"Observation: {observation}"
})
else:
# Model produced neither action nor answer, malformed output
messages.append({"role": "user", "content": "Continue your reasoning."})
return "Max iterations reached without a final answer."Improving Thought Quality
The quality of the thought phase is the biggest driver of overall ReAct agent quality. Poor thoughts lead to unnecessary actions, misinterpreted observations, and hallucinated conclusions. Improving thought quality requires both prompt engineering and architectural choices.
Thought Quality Characteristics
- Specific, not vague: 'I need to find the order status for order #4521' is a good thought. 'I need to get some information' is not. Vague thoughts lead to imprecise tool calls.
- Grounded in observations: After receiving a tool result, the thought should explicitly reference it: 'The previous search returned 0 results, which means I need to broaden my query terms.'
- Hypothesis-driven: The thought should state what it expects the next action to reveal: 'I expect the lookup to return a price above $100, which would confirm my hypothesis about the pricing tier.'
- Self-critical: High-quality thoughts occasionally reconsider the plan: 'Wait, I've now made 3 search calls and still haven't found the answer. My search terms may be wrong. Let me try a different approach.'
Forcing Better Thoughts with Prompt Constraints
You can improve thought quality by adding explicit constraints to the system prompt: 'Each Thought must answer three questions: (1) What do I know from the previous Observation? (2) What am I still missing? (3) Why is my next action the best way to get what I'm missing?' This structured format prevents the shallow thoughts that produce poor actions.
Action Grounding and Hallucination Prevention
One of ReAct's key benefits is preventing hallucination by grounding the final answer in explicit tool results. But this only works if the agent actually uses the observations and doesn't fabricate them.
Grounding Enforcement Techniques
- Require citation in the final answer: 'Your final answer must cite the specific Observation that supports each factual claim.' This forces the model to reference actual tool results rather than general knowledge.
- Verification thought: Add an instruction: 'Before writing your final Answer, write a Verification thought that checks each claim in your answer against the Observations you received.' This surfaces unsupported claims.
- Contradiction detection: Add an instruction: 'If any Observation contradicted a previous assumption, your final Answer must acknowledge this and use the Observation data, not the assumption.'
Processing Observations Effectively
Raw tool results injected as observations can be noisy, overly verbose, or poorly formatted. Pre-processing observations before injecting them improves the quality of the thoughts that follow.
Observation Pre-Processing Pipeline
- Size limiting: Truncate or summarize large tool results (> 500 tokens) before injection. Large observations consume context without proportional benefit and can distract the model.
- Error normalization: Convert raw API errors into consistent natural language descriptions. 'HTTP 429: Rate limit exceeded' becomes 'This tool is temporarily rate-limited. Try a different tool or a modified query.'
- Relevance highlighting: For structured data (JSON, tables), extract the most relevant fields and present them prominently. Include the full result as a secondary appendix.
- Empty result handling: When a tool returns no results, inject an explicit explanation: 'The search returned 0 results. This means either the query was too specific or this information doesn't exist in the database.'
Loop Termination and Completion Detection
A ReAct loop must terminate under two conditions: successful completion (the agent has enough information to answer) and failure (the agent cannot make progress). Without explicit termination logic, agents can loop indefinitely or give up prematurely.
Termination Signals
- Answer prefix: The model outputs 'Answer:' signaling it's ready to provide a final response. This is the normal success case.
- Explicit completion thought: The thought contains 'I now have all the information I need to answer.' Pre-process thoughts to detect this phrase and extract the answer that follows.
- Maximum iterations: After N iterations without resolution, force termination and return whatever partial answer is possible with a caveat.
- Repeated action detection: If the agent calls the same tool with the same parameters twice, it's stuck in a loop. Inject an instruction: 'You already tried this action. Try a different approach.'
- Budget exhaustion: If token budget or time budget is exceeded, force an early termination with the best available partial answer.
Debugging Agents with ReAct Traces
One of ReAct's most underappreciated benefits is debuggability. The thought-action-observation trace is a complete record of how the agent reasoned about the task. When an agent produces a wrong answer, the trace tells you exactly where the reasoning went wrong.
Debugging Workflow
- Find the first wrong thought: Read through the trace and identify the first thought that contains a false assumption, wrong inference, or missed observation.
- Identify the cause: Was the wrong thought caused by a poor observation (tool returned misleading data), a prompt that encouraged the wrong inference, or a model knowledge gap?
- Test the fix: Modify the prompt or observation processing and re-run the specific failing task. Verify the thought trace now takes the right path.
- Check downstream effects: Verify that fixing the first wrong thought doesn't introduce wrong thoughts later in the trace. Cascading effects are common.
ReAct Variants and Extensions
ReAct is a foundational pattern that can be extended in many directions. Several variants address specific limitations of the basic loop.
ReAct + Self-Reflection (Reflexion)
The Reflexion architecture adds an explicit self-reflection step after the ReAct loop completes. The agent reviews its own trace and identifies errors or improvements for the next attempt. In multi-attempt tasks, reflections from previous attempts are included in subsequent prompts, allowing the agent to learn from failures within a session without model fine-tuning.
ReAct + Memory
For long-running tasks, the full thought-action-observation history becomes too long for the context window. Memory-augmented ReAct compresses older portions of the trace into a semantic memory store, retrieving relevant memories at each thought step rather than keeping the full trace in context.
Multi-Agent ReAct
In multi-agent systems, the orchestrator uses ReAct to reason about task delegation. The 'actions' include spawning sub-agents and waiting for their results. Each sub-agent result becomes an observation in the orchestrator's trace. This creates a hierarchical ReAct structure where reasoning operates at multiple levels of abstraction simultaneously.
Frequently Asked Questions
Build secure agentic systems with AgentixForce
We help companies design, build, and secure production-grade AI agent systems. From architecture reviews to full implementation, our team brings deep expertise to every engagement.