What Is the ReAct Pattern? A Deep Dive into Agent Reasoning and Action
The ReAct pattern is an iterative Reason → Act → Observe loop that enables Large Language Models to solve complex tasks by combining internal reasoning with external tool calls, as implemented throughout the bojieli/ai-agent-book repository.
The ReAct pattern (Reason, Act, Observe) has emerged as the foundational architecture for building autonomous AI agents that can interact with the real world. In the bojieli/ai-agent-book repository, this pattern is implemented across multiple chapters to demonstrate how Large Language Models (LLMs) can move beyond simple text generation to perform multi-step problem solving. This article examines how the ReAct pattern structures agent reasoning and action, with concrete code examples from the open-source implementation.
How the ReAct Pattern Structures Agent Workflows
The ReAct pattern divides agent execution into three distinct phases that form a repeating cycle. This architectural separation keeps reasoning explicit and debuggable while enabling dynamic tool use.
Phase 1: Reason
The LLM generates a natural-language "thought" that explicitly states what it plans to do or which tool it needs. This phase keeps the model’s reasoning transparent, making the process interpretable and easier to debug. By externalizing the thought process, developers can inspect why an agent chose a specific action before it executes.
Phase 2: Act
Based on the generated thought, the agent invokes an external tool—such as a web search, code executor, or phone API—using either the OpenAI function-calling specification or a custom RPC format. This step empowers the agent with capabilities beyond pure text generation, transforming it into a system that can interact with external data sources and services.
Phase 3: Observe
The tool's output (search results, execution logs, or API responses) is appended to the conversation history as new context. The LLM then updates its reasoning based on this observation, deciding whether to invoke another tool or deliver a final answer. This closes the feedback loop and enables multi-step adaptation to complex problems.
Core Implementation: The ReAct Loop in Code
According to chapter2/local_llm_serving/agent.py, the generic ReAct driver implements this exact skeleton, iterating until the LLM signals completion or hits a safety limit:
def react_loop(messages, tools, max_iters=10):
for i in range(max_iters):
response = llm.chat(messages) # Reason
if tool_call := extract_tool_call(response): # Act
tool_result = call_tool(tool_call) # Observe
messages.append(format_observation(tool_result))
else:
return response["content"] # Final answer
raise RuntimeError("ReAct loop exceeded max_iterations")
This implementation caps the loop at max_iters (default 10) to prevent infinite recursion, logging each iteration as ReAct iteration X for debugging purposes.
Concrete Implementations in the ai-agent-book Repository
Web-Search Agent (Chapter 1)
The file chapter1/web-search-agent/agent.py implements a classic ReAct loop for a web-search assistant. Here, the LLM emits a "Thought" and optionally a web_search tool call, continuing until it synthesizes a final answer:
from chapter1.web_search_agent.agent import ReActWebSearchAgent
agent = ReActWebSearchAgent(
llm_name="gpt-4o",
max_iterations=7,
dry_run=False # set True for offline deterministic demo
)
result = agent.run("Who won the 2023 Nobel Prize in Chemistry?")
print(result)
Agentic RAG System (Chapter 3)
The chapter3/agentic-rag/agent.py file demonstrates a ReAct-based Retrieval-Augmented Generation (RAG) system. The model first reasons about which knowledge source to query, acts by invoking a retrieval tool, observes the retrieved passages, and then continues reasoning:
from chapter3.agentic_rag.agent import ReActRAGAgent
rag = ReActRAGAgent(
llm_name="gpt-4o-mini",
retriever="faiss", # any vector store works
max_iterations=6
)
answer = rag.run("Explain the concept of “self‑consistency” in chain‑of‑thought prompting.")
print(answer)
High-Level ChatReActAgent Wrapper (Chapter 2)
For production use, chapter2/prompt-engineering/tau_bench/agents/chat_react_agent.py provides the ChatReActAgent class, which encapsulates the ReAct logic with a clean run() API:
from chapter2.prompt_engineering.tau_bench.agents.chat_react_agent import ChatReActAgent
# Initialise the ReAct agent (uses OpenAI function calling under the hood)
agent = ChatReActAgent(
model="gpt-4o-mini",
max_iterations=5, # safety cap
verbose=True # prints each Reason/Act/Observe step
)
query = "What are the latest research papers on Retrieval‑Augmented Generation?"
answer = agent.run(query) # triggers the ReAct loop automatically
print("Final answer:", answer)
Safety Mechanisms and Production Considerations
Production-grade ReAct implementations require safeguards against runaway execution. The repository enforces this through the max_iterations parameter, which appears consistently across chapter1/web-search-agent/agent.py, chapter2/local_llm_serving/agent.py, and chapter3/agentic-rag/agent.py.
When the iteration limit is exceeded without reaching a final answer, the system raises a RuntimeError, preventing resource exhaustion. Additionally, setting verbose=True in ChatReActAgent logs each Reason/Act/Observe step, enabling developers to trace decision trees for debugging or compliance auditing.
Summary
- The ReAct pattern structures agents into Reason → Act → Observe cycles that repeat until task completion.
- Interpretability comes from explicit natural-language reasoning steps generated by the LLM before each action.
- Extensibility allows swapping tools (search, RAG, voice) without modifying the core reasoning engine, as demonstrated across
chapter1/web-search-agent/agent.py,chapter3/agentic-rag/agent.py, andchapter9/phone-agent/agent.py. - Safety mechanisms like
max_iterationsprevent infinite loops by hard-capping the number of tool invocations. - The bojieli/ai-agent-book repository provides reusable implementations ranging from low-level drivers in
chapter2/local_llm_serving/agent.pyto high-level wrappers likeChatReActAgent.
Frequently Asked Questions
How does the ReAct pattern differ from chain-of-thought prompting?
Chain-of-thought prompting generates intermediate reasoning steps but remains a single-pass text generation process. The ReAct pattern introduces an action layer where the agent pauses execution to invoke external tools, observes the results, and continues reasoning. This external feedback loop enables the agent to interact with dynamic environments and retrieve information not present in its training data.
What types of tools work best with the ReAct pattern?
The pattern is tool-agnostic. The repository demonstrates implementations with web search (chapter1/web-search-agent/agent.py), vector database retrieval (chapter3/agentic-rag/agent.py), and voice call APIs (chapter9/phone-agent/agent.py). Any tool that accepts structured input and returns observable output can integrate into the ReAct loop, including code executors and robotics controllers.
How does the ReAct pattern prevent infinite loops?
The implementations enforce a maximum iteration limit through the max_iters parameter, typically defaulting to 10 iterations. After reaching this limit without producing a final answer, the agent raises a RuntimeError. This safety mechanism appears in chapter2/local_llm_serving/agent.py and the ChatReActAgent class to ensure resource boundaries.
Can the ReAct pattern work with open-source LLMs?
Yes. The chapter2/local_llm_serving/agent.py implementation specifically provides a generic ReAct driver that works with any LLM supporting function-calling capabilities, not just proprietary APIs. The pattern relies on standard tool-calling formats rather than model-specific features, making it compatible with locally hosted models.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →