The ReAct Pattern – Reasoning + Acting
The ReAct pattern (short for Reasoning + Acting) is one of the most powerful and widely used patterns for building AI Agents. It was introduced in a 2022 research paper from Google and has since become the standard architecture for reasoning-capable agents.
ReAct teaches an agent to think out loud before acting — and this single idea dramatically improves agent accuracy, reliability, and transparency.
The Problem ReAct Solves
Without the ReAct pattern, an agent might rush to call a tool without fully thinking through the problem:
User: "Who was the CEO of Twitter before Elon Musk took over,
and when did Elon Musk become CEO?"
Simple Agent (without ReAct):
→ Calls web_search("Twitter CEO Elon Musk")
→ Gets mixed results
→ Gives an incomplete or inaccurate answer
With ReAct, the agent first thinks through the problem:
ReAct Agent:
Thought: "I need two pieces of info — who was CEO before Elon Musk,
and when did Elon Musk become CEO. Let me search for each separately."
Action: web_search("Twitter CEO before Elon Musk")
Observation: "Jack Dorsey was Twitter's co-founder and served as CEO..."
Thought: "Good. Now I need the date Elon Musk became CEO."
Action: web_search("Elon Musk Twitter CEO date")
Observation: "Elon Musk became CEO on October 27, 2022 after completing acquisition..."
Thought: "I now have both answers. I can give a complete response."
Final Answer: "Jack Dorsey was the CEO before Elon Musk. Elon Musk took over
as CEO on October 27, 2022, after completing his acquisition of Twitter."
The ReAct Format
ReAct works by structuring the agent's response in a specific format — alternating between Thought, Action, and Observation:
| Component | What It Is | Written By |
|---|---|---|
| Thought | The agent's reasoning about what to do next | LLM |
| Action | The tool or function to call, with its input | LLM |
| Observation | The result returned by the tool | Agent Framework (injected back) |
| Final Answer | The complete response to the user | LLM |
A Full ReAct Example
Question: "What is the capital of Australia, and what is the current population of that city?"
Thought: The user wants two things — the capital of Australia and that city's
population. Let me start by confirming the capital.
Action: web_search("capital of Australia")
Observation: "Canberra is the capital city of Australia."
Thought: The capital is Canberra. Now I need the current population of Canberra.
Action: web_search("Canberra population 2024")
Observation: "As of 2024, Canberra has an estimated population of approximately
470,000 people."
Thought: I now have both pieces of information. I can give the final answer.
Final Answer: The capital of Australia is Canberra. As of 2024, its population
is approximately 470,000 people.
Implementing ReAct from Scratch
ReAct can be implemented using prompt engineering — the system prompt instructs the LLM to think before acting:
# react_agent.py
import os
import re
import json
from dotenv import load_dotenv
import openai
from tools import TOOL_MAP
load_dotenv()
client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
REACT_SYSTEM_PROMPT = """You are a smart research assistant using the ReAct framework.
For every task, follow this exact loop:
Thought: [Reason about what you know and what you need to find out]
Action: tool_name({"parameter": "value"})
Observation: [This will be filled in by the system after the tool runs]
Repeat Thought/Action/Observation as many times as needed.
When you have enough information to answer, respond with:
Final Answer: [Your complete, clear answer to the user's question]
Available Tools:
- web_search(query): Search the internet for information
- calculate(expression): Evaluate a mathematical expression
IMPORTANT: Always write a Thought before every Action. Never skip the reasoning step."""
def parse_action(text: str):
"""Extract tool name and arguments from the LLM's Action line."""
# Match pattern: tool_name({"key": "value"})
pattern = r'Action:\s*(\w+)\((\{.*?\})\)'
match = re.search(pattern, text, re.DOTALL)
if match:
tool_name = match.group(1)
try:
tool_args = json.loads(match.group(2))
return tool_name, tool_args
except json.JSONDecodeError:
return None, None
return None, None
def run_react_agent(question: str) -> str:
messages = [
{"role": "system", "content": REACT_SYSTEM_PROMPT},
{"role": "user", "content": question}
]
print(f"\nQuestion: {question}\n")
for step in range(8): # Max 8 ReAct steps
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
temperature=0.2,
max_tokens=600,
stop=["Observation:"] # Stop before Observation — we will fill that in
)
llm_output = response.choices[0].message.content
print(llm_output)
# Check if agent has reached Final Answer
if "Final Answer:" in llm_output:
final = llm_output.split("Final Answer:")[-1].strip()
print(f"\n{'='*50}")
print(f"FINAL ANSWER: {final}")
print(f"{'='*50}")
return final
# Parse the Action from LLM output
tool_name, tool_args = parse_action(llm_output)
if tool_name and tool_name in TOOL_MAP:
# Execute the tool
observation = TOOL_MAP[tool_name](**tool_args)
print(f"Observation: {observation}\n")
# Add LLM output + observation to conversation
messages.append({"role": "assistant", "content": llm_output})
messages.append({
"role": "user",
"content": f"Observation: {observation}"
})
else:
# Could not parse an action — ask again
messages.append({"role": "assistant", "content": llm_output})
messages.append({
"role": "user",
"content": "Please provide an Action or a Final Answer."
})
return "Agent could not complete the task within the allowed steps."
# Test the ReAct agent
if __name__ == "__main__":
run_react_agent("What is Python and who created it?")
Sample Console Output
Question: What is Python and who created it?
Thought: The user wants to know what Python is and who created it.
Let me search for this information.
Action: web_search({"query": "Python programming language creator history"})
Observation: {"result": "Python was created by Guido van Rossum and first released in 1991.
It is a high-level, general-purpose language known for its readability."}
Thought: I have enough information to answer both parts of the question.
Final Answer: Python is a high-level, general-purpose programming language known for its
clean syntax and readability. It was created by Guido van Rossum and first
released in 1991. Today it is widely used in data science, AI, web development,
and automation.
==================================================
FINAL ANSWER: Python is a high-level, general-purpose programming language...
==================================================
ReAct with Native Function Calling
Modern LLMs support function calling natively, which is a cleaner way to implement ReAct. The LLM automatically generates a structured tool call instead of outputting text that needs to be parsed:
# ReAct with native tool use (cleaner approach)
# The LLM outputs a structured tool_call object instead of text
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=TOOL_DEFINITIONS,
tool_choice="auto"
)
# The Thought is internal to the model
# The Action is expressed as a tool_call object
# No regex parsing needed
if response.choices[0].message.tool_calls:
# Tool call detected — run it and continue the loop
...
else:
# No tool call — final answer reached
final_answer = response.choices[0].message.content
When to Use Text-Based ReAct vs Native Function Calling
| Approach | Best For | Pros | Cons |
|---|---|---|---|
| Text-based ReAct | Debugging, transparency, older models | Shows full reasoning in text | Requires regex parsing, more fragile |
| Native Function Calling | Production apps, modern LLMs | Reliable, structured, no parsing | Less visible reasoning chain |
Why ReAct Improves Agent Performance
- Reduces errors: Thinking before acting prevents jumping to wrong conclusions
- Improves transparency: The reasoning chain is visible and auditable
- Handles complexity: Multi-step tasks are broken into logical sub-steps
- Easier debugging: When something goes wrong, the thought trail shows exactly where
- Better tool selection: Reasoning helps choose the right tool for each step
Summary
The ReAct pattern combines reasoning and acting into a structured loop: Thought → Action → Observation → repeat until Final Answer. This approach makes agents far more accurate and reliable than those that act without thinking. Whether implemented via text prompts or native function calling, ReAct is the most important architectural pattern in AI Agent development — and the foundation of all advanced agent frameworks covered in later topics.
