Flowchart showing different agent architectural patterns

The ReAct Pattern

AGAI 202 · Foundational Agent Patterns

Learn how the ReAct pattern combines reasoning and tool use into a flexible loop that powers many practical agents.

Key terms

ReAct = Reason + Actobservation → next decisiontool result = evidencestep limit prevents runaway loops

Learning objectives

  • Define the ReAct pattern and describe its loop.
  • Implement a minimal ReAct-style agent in pseudocode.
  • Identify tasks where ReAct is an appropriate architecture.
  • Recognize common ReAct failure modes and mitigations.

The ReAct pattern stands for Reason + Act. It is one of the foundational architectures for building AI agents because it gives a language model a simple loop: think about the task, choose an action, observe the result, and continue.

A basic ReAct agent does not create a full plan upfront. Instead, it makes progress step by step. At each step, the model examines the current context and decides whether to call a tool, ask for clarification, or produce a final answer.

The classic ReAct loop looks like this:

User goal
  ↓
Reason about current state
  ↓
Choose an action
  ↓
Call a tool
  ↓
Observe result
  ↓
Reason again
  ↓
Continue or answer

This pattern is powerful because many real tasks are uncertain. The agent may not know what information is available until it searches. It may not know why a test failed until it runs the test. It may not know which document matters until it retrieves search results.

Why ReAct works

Language models are good at interpreting context and choosing plausible next steps. Tools are good at retrieving facts, running code, querying databases, and changing external state. ReAct combines these strengths.

For example, suppose a user asks:

Find the bug causing the login test to fail and suggest a fix.

A ReAct-style coding agent might proceed:

Reason: I need to inspect the failing test first.
Action: read_file("tests/login.test.ts")
Observation: The test expects a 200 response from /login.

Reason: I need to inspect the login handler.
Action: read_file("src/routes/login.ts")
Observation: The handler expects field "email", but the test sends "emailAddress".

Reason: I found a likely mismatch. I should propose a fix and mention the file.
Final answer: The test sends emailAddress, while the route expects email. Update the test or handler so the field names match.

The agent did not need a full plan. It followed evidence.

Minimal ReAct pseudocode

A simple ReAct loop can be implemented with a model, tool registry, and message history:

def run_react_agent(model, tools, user_goal, max_steps=8):
    messages = [
        {"role": "system", "content": "You are a tool-using agent. Use tools when needed."},
        {"role": "user", "content": user_goal}
    ]

    for step in range(max_steps):
        response = model.generate(messages=messages, tools=tools)
        messages.append(response.message)

        if response.final_answer:
            return response.final_answer

        if response.tool_call:
            result = execute_tool(response.tool_call)
            messages.append({
                "role": "tool",
                "tool_call_id": response.tool_call.id,
                "content": serialize(result)
            })
            continue

        return "The agent stopped without a final answer."

    return "The agent reached the maximum step limit."

The key design choice is the step limit. ReAct agents can loop unnecessarily if they keep searching, retrying, or calling tools without a clear stopping condition.

When ReAct is appropriate

Use ReAct when the task is exploratory, evidence-driven, or interactive. Good examples include:

  • Web research
  • Debugging
  • Document question answering
  • Customer support lookup
  • Data inspection
  • Simple workflow automation
  • Tool-assisted troubleshooting

ReAct is especially useful when the next step depends on the previous observation.

When ReAct struggles

ReAct can struggle with long-horizon tasks. Because it chooses locally at each step, it may lose sight of the larger goal. It may repeat tool calls, follow irrelevant leads, or stop too early.

Common failure modes include:

  • Tool overuse: calling tools even when the answer is already known.
  • Tool underuse: answering from memory when fresh data is required.
  • Looping: repeating similar searches or commands.
  • Local optimization: making a reasonable next step that does not advance the overall task.
  • Poor state tracking: forgetting what has already been tried.

These failures can be reduced with clear system prompts, step limits, state summaries, tool-call logs, and evaluation traces.

ReAct in modern frameworks

Many agent frameworks support ReAct-style behavior. LangChain popularized ReAct agents in early LLM application development. LangGraph gives developers more explicit control over stateful loops and branching. AutoGPT-style systems demonstrated more autonomous loops, though early versions often suffered from looping, cost, and reliability problems.

The ReAct pattern remains important because it is simple, flexible, and easy to understand. Even more complex architectures often contain ReAct loops inside larger workflows.

Practical takeaway

ReAct is the basic reflex arc of agentic AI: reason, act, observe, repeat. It is excellent for tasks where the agent needs to discover information step by step. Its weakness is that it can become unfocused without state management, limits, and evaluation.

A good ReAct agent is not just a model with tools. It is a controlled loop with clear tool definitions, useful observations, stopping rules, and enough state to avoid repeating itself.

Sign in to track your progress.

Ask your AI guide

AI Chat· Agent Architectures — The ReAct Pattern
🤖

Ask anything about Agent Architectures — The ReAct Pattern, or choose a suggested question below.

AI responses are educational and may not be perfectly accurate. Press Enter to send, Shift+Enter for new line.