Agents & Tools

ReAct Agent

By Arpit Tripathi, Founder

A ReAct agent is an LLM-driven loop that interleaves natural-language reasoning (Thought) with tool calls (Action) and tool results (Observation), repeating until it can answer. The pattern comes from the 2022 paper "ReAct: Synergizing Reasoning and Acting in Language Models."

What is a ReAct agent?

A ReAct agent is a language-model agent built on the ReAct pattern, which stands for Reasoning and Acting. Instead of producing a single answer, the model generates an interleaved trace: a Thought that reasons about what to do next, an Action that names a tool and its arguments, and then an Observation that contains the result the tool returns. The agent loops over these three steps, feeding each new Observation back into the context, until a Thought decides it has enough information to emit a final answer.

The pattern was introduced by Shunyu Yao and co-authors in the paper "ReAct: Synergizing Reasoning and Acting in Language Models," first posted to arXiv on 6 October 2022 (arXiv:2210.03629) and presented at ICLR 2023. The central claim is that reasoning and acting reinforce each other: reasoning traces help the model plan, track progress, and decide which action to take, while actions let the model gather external information that grounds the reasoning and corrects mistakes.

In practice a ReAct agent is defined less by a specific library and more by the prompt scaffold and control loop around the model. The same idea underlies the prebuilt ReAct agents shipped in frameworks such as LangChain/LangGraph and LlamaIndex, which wrap an LLM, a set of tools, and a parser that extracts the Action and its arguments from each generation.

  • ReAct = Reasoning + Acting; the loop is Thought, Action, Observation, repeated to a final answer.
  • Each Observation is the verbatim return value of a tool, appended to the running context.
  • Introduced in Yao et al., arXiv:2210.03629 (2022), ICLR 2023.
  • It is a prompting and control pattern, not a single model or API.

The Thought / Action / Observation loop

The loop has a fixed grammar. On each turn the model is asked to emit a Thought followed by an Action of the form tool_name[input]. The runtime parses that Action, calls the named tool, captures its output as an Observation, and appends Thought, Action, and Observation to the transcript before prompting the model again. When the model emits a special finishing Action (often written Finish[answer]), the loop stops and returns the answer.

Two control parameters bound the loop: a maximum iteration count and, in some implementations, a token or time budget. The maximum iteration count is what prevents a misbehaving agent from looping forever. The transcript itself is the agent's working memory; everything the model knows about its progress lives in the accumulated Thought/Action/Observation lines inside the context window.

Because the Observation is real tool output rather than model-generated text, the loop is what lets the model check its own reasoning against the world and revise. A Thought can read an Observation, notice that a search returned nothing useful, and reformulate the next Action. This feedback is the mechanism the paper credits for reducing the error propagation seen in reasoning-only methods.

python
def react_agent(question, tools, llm, max_steps=8):
    scaffold = (
        "Answer the question using these tools: "
        + ", ".join(tools) + ".\n"
        "Use this format on each step:\n"
        "Thought: reason about what to do next\n"
        "Action: tool_name[input]\n"
        "Observation: <tool result>\n"
        "Repeat until you can answer, then output:\n"
        "Action: Finish[answer]\n"
    )
    transcript = scaffold + f"Question: {question}\n"
    for _ in range(max_steps):
        step = llm(transcript + "Thought:")
        thought, action, arg = parse(step)  # extract Action + input
        if action == "Finish":
            return arg
        observation = tools[action](arg)     # call the real tool
        transcript += (
            f"Thought:{thought}\n"
            f"Action: {action}[{arg}]\n"
            f"Observation: {observation}\n"
        )
    return "max steps reached"  # loop guard prevents runaway cost
Minimal ReAct control loop. Real frameworks (LangGraph's create_react_agent, now superseded by LangChain's create_agent; LlamaIndex's ReActAgent) add tool schemas, structured parsing, and retries, but follow this shape.
  • A parser converts each model-emitted Action string into a concrete tool call.
  • The Observation is appended verbatim so later Thoughts can react to it.
  • A max-iterations cap is mandatory to bound cost and stop infinite loops.
  • The growing transcript is the agent's only state between steps.

ReAct vs chain-of-thought vs raw function-calling

Plain chain-of-thought prompting asks the model to write out intermediate reasoning before answering, but it never leaves the model's own context. Every fact it uses is whatever the weights already encode, so chain-of-thought is prone to confidently stating wrong facts. ReAct keeps the chain-of-thought style Thought steps but interleaves them with real Actions, so the reasoning is checked against external Observations from search, calculators, code execution, or APIs.

Raw function-calling is the opposite end. A model with native tool-calling can emit a structured call and receive a result, and a single round of that resembles one ReAct step. The difference is the explicit, multi-turn reasoning scaffold. ReAct names the Thought as a first-class part of the trace and runs many rounds, whereas a bare function-calling request may jump straight to a tool call with no recorded deliberation and no enforced loop structure.

The two views are compatible. Modern ReAct agents are frequently implemented on top of native function-calling: the framework asks the model for a Thought and a tool call together, executes the call, and feeds the result back, repeating the cycle. ReAct supplies the loop and the reasoning discipline; function-calling supplies a reliable transport for the Action and its arguments.

  • Chain-of-thought reasons internally only; ReAct grounds each step in tool Observations.
  • Raw function-calling is one tool round; ReAct is a reasoning-plus-action loop over many rounds.
  • ReAct is commonly built on top of native function-calling rather than text parsing.
  • The reported gain over reasoning-only methods is reduced hallucination and error propagation.

Why it works: results from the original paper

The ReAct paper evaluated the pattern on two task families. On the knowledge-intensive question-answering benchmarks HotpotQA and Fever, the agent acted by querying a simple Wikipedia API, which the authors report overcomes the hallucination and error propagation that affect chain-of-thought reasoning alone. The generated trajectories were also more interpretable, since a human can read the Thoughts and Observations and see why the model reached its answer.

On the interactive decision-making benchmarks ALFWorld (text-based household tasks) and WebShop (simulated online shopping), ReAct outperformed imitation-learning and reinforcement-learning baselines by an absolute success rate of 34% on ALFWorld and 10% on WebShop. These gains were achieved while prompting the model with only one or two in-context examples, which is far less supervision than the learned baselines required.

A useful intuition: the formula below frames a ReAct policy as choosing the next action conditioned not just on the observation history but also on the agent's own generated reasoning, which expands the space of internal states the agent can occupy and makes its decisions more interpretable.

aₜ ~ π(· | cₜ), where cₜ = (o₁, a₁, ..., oₜ) augmented with generated thoughts
ReAct lets the action policy condition on an augmented context cₜ that includes the agent's own reasoning thoughts, not just the raw observation/action history.
  • On ALFWorld, ReAct beat imitation/RL baselines by an absolute 34% success rate.
  • On WebShop, it improved absolute success rate by 10% over those baselines.
  • Gains came with only one or two in-context examples per task.
  • On HotpotQA and Fever, Wikipedia-API actions reduced hallucination versus reasoning-only prompting.

Failure modes and limits

ReAct agents fail in characteristic ways. The most common is looping: the model repeats the same Action and Observation without making progress, which is why a max-iteration cap is required rather than optional. A related failure is the hallucinated tool call, where the model emits an Action that names a tool that does not exist or passes malformed arguments, so the parser cannot dispatch it and the loop stalls or wastes a step.

Long-horizon tasks expose context limits. Every Thought, Action, and Observation accumulates in the transcript, so as the loop runs the context window fills with history, raising cost and risking that important early information gets crowded out. Noisy or truncated Observations can also derail reasoning, since the model treats whatever the tool returns as ground truth even when the tool returned an error string.

Mitigations are mostly engineering. Capping iterations, validating each Action against the real tool schema before executing it, summarizing or trimming old Observations, and retrying or repairing malformed Actions all reduce these failures. None of them remove the underlying fragility, which is that the agent's correctness depends on both the model's reasoning and the reliability of every tool it calls.

  • Looping: the agent repeats actions without progress, requiring a hard iteration cap.
  • Hallucinated tool calls: actions naming nonexistent tools or malformed arguments.
  • Context growth: accumulated Thought/Action/Observation history inflates cost and crowds out early facts.
  • Observation trust: the model treats error strings or noisy output as ground truth.

Key takeaways

  • A ReAct agent interleaves Thought (reasoning), Action (tool call), and Observation (tool result) in a loop until it can answer.
  • The pattern comes from Yao et al., "ReAct: Synergizing Reasoning and Acting in Language Models" (arXiv:2210.03629, 2022; ICLR 2023).
  • Unlike chain-of-thought, ReAct grounds reasoning in real tool Observations, which reduces hallucination and error propagation.
  • It is often implemented on top of native function-calling, which carries the Action and its arguments reliably.
  • On ALFWorld and WebShop it beat learned baselines by 34% and 10% absolute success rate with only one or two examples.
  • Common failure modes are infinite loops, hallucinated tool calls, and context growth, so a max-iteration cap is mandatory.

Frequently asked questions

ReAct stands for Reasoning and Acting. It names a pattern where a language model alternates between reasoning steps (Thoughts) and tool-using steps (Actions), reading each tool result (Observation) before continuing. The name and method come from the 2022 paper by Shunyu Yao and colleagues.
Chain-of-thought reasoning stays entirely inside the model's context and uses only what the weights already know, so it can confidently state wrong facts. A ReAct agent keeps those reasoning steps but interleaves them with real tool calls, so each Thought can be checked against an external Observation. This grounding is what the paper credits for reducing hallucination.
No, but they are related. Function-calling is the mechanism a model uses to emit a structured tool call and receive a result, which is one round. ReAct is a multi-turn loop that wraps reasoning around those calls, and modern ReAct agents are commonly built on top of native function-calling.
Set a maximum iteration count so the loop terminates even if the model never emits a finish action. Adding a token or time budget, validating each Action against the real tool schema, and detecting repeated identical actions all help. A hard iteration cap is the essential guard.
LangChain and its graph library LangGraph ship prebuilt ReAct-style agents through factory functions such as create_react_agent, and LlamaIndex provides a ReActAgent. These wrap an LLM, a set of tools, and a parser, but the underlying Thought/Action/Observation loop is the same idea introduced in the original paper.
It is when the model emits an Action that names a tool that does not exist or passes arguments the tool cannot accept. The runtime parser then cannot dispatch the call, so the step is wasted or the loop stalls. Validating actions against the registered tool schema before executing them prevents most of these.