Article

ReAct and the Basic Reasoning Loop

ReAct interleaved reasoning with actions and became the default agent loop. The idea survived; the parsed Thought/Action/Observation format did not.

ReAct comes from one paper: “ReAct: Synergizing Reasoning and Acting in Language Models” by Yao, Zhao, Yu, Du, Shafran, Narasimhan, and Cao (October 2022, ICLR 2023). The idea in one sentence: have the model generate reasoning traces and task actions in an interleaved manner, so reasoning can guide which action comes next and each observation can update the reasoning. The paper evaluated that on four benchmarks — HotpotQA and FEVER for knowledge work, ALFWorld and WebShop for interactive decision-making.

That pattern won. The format it shipped in did not.

The 2022 implementation was a few-shot prompt containing a human-written Thought / Action / Observation trajectory, with your code parsing Action: search[term] out of the model’s text. In 2026 the same loop runs through native tool calling: the model emits a structured tool call, your runtime executes it, and the result goes back as a typed message. The reasoning moved inside the model. If you are reading older ReAct material, that distinction is the thing most likely to mislead you.

TL;DR

ReAct is a loop in which each action is chosen in light of the reasoning so far, and each observation feeds the next reasoning step. It is worth running when the next step depends on what the last step revealed, and wasteful when the path is already known.

The paper’s headline numbers are about decision-making, not question answering: an absolute 34% success-rate gain on ALFWorld and 10% on WebShop over imitation and reinforcement learning baselines, from one or two in-context examples. On HotpotQA, plain ReAct slightly trailed chain-of-thought.

Today you implement it with native tool calling, not a regex. You no longer own the parsing or the reasoning format. You still own the step budget, the tool surface, and how observations are worded.

What the Paper Actually Measured

It is worth being precise here, because ReAct is routinely cited as having beaten everything on all four benchmarks. It did not, and the real result is more interesting.

On the knowledge tasks, with PaLM-540B and a Wikipedia API the model could call:

Prompting methodHotpotQA (EM)FEVER (Acc)
Standard28.757.1
Chain-of-thought29.456.3
CoT with self-consistency33.460.4
Act (actions, no reasoning)25.758.9
ReAct27.460.9
ReAct → CoT-SC35.162.0
CoT-SC → ReAct34.264.6
Supervised state of the art67.589.5

ReAct beat action-only prompting on both tasks, and beat chain-of-thought on FEVER (60.9 vs 56.3), but it came in slightly behind chain-of-thought on HotpotQA (27.4 vs 29.4 EM). The best results on both came from combining the two, switching between internal and retrieved knowledge. The paper’s qualitative finding is the one worth remembering: in a hand-labelled sample, hallucinated reasoning or facts accounted for 56% of chain-of-thought failures and 0% of ReAct failures, while ReAct’s own dominant failure was reasoning error at 47%, often failing to recover from repetitive steps. Grounding fixed hallucination and introduced loops.

On the interactive benchmarks, the gains are large and are where the famous numbers come from:

BenchmarkReActBest baselineTrained on
ALFWorld (success rate, best of 6 prompts)71%BUTLER 37%10⁵ expert trajectories per task type
WebShop (success rate)40.0%IL 29.1%, IL+RL 28.7%1,012 human trajectories; +10,587 instructions

Those are the absolute 34% and 10% improvements the abstract claims, and the comparison is the point: a prompt with one or two examples beat imitation and reinforcement learning agents trained on 10³–10⁵ task instances. ReAct’s average across six ALFWorld prompt sets was 57%, and even its worst set (48%) beat the best Act (45%) and BUTLER (37%) trials. For scale, human experts score 59.6% success on WebShop, so the loop closed much of a gap rather than all of it.

Two numbers deserve an asterisk when you quote them. ALFWorld’s 71% is the best of six prompt permutations, not a single-run result, and WebShop’s 10 points are measured against the previous best success rate (40.0 − 29.1 = 10.9).

The Loop, Stated Carefully

A broad control loop like The Sense-Think-Act Loop tells you that agents observe, reason, and act. ReAct is narrower and more useful: it specifies that the next action is chosen in light of the accumulated reasoning, and that each observation is fed back as text the model reads before choosing again.

In the Berkeley RDI lecture on agent history, Shunyu Yao puts the contribution plainly: acting-only models lack reasoning, and “for ReAct, the idea is to just generate both… reasoning can help acting, and acting can help reasoning” (LLM Agents: History & Overview, 15:23).

The most useful way to read a single turn is as a small test with three parts.

Hypothesis. The agent forms a local theory about what would move the task forward: the billing job probably failed on a dependency timeout; the answer is probably in the account history; one more search is probably needed before recommending anything. This is the Thought. It does not need to be a master plan. It needs to be specific enough to test.

Probe. The agent takes one action chosen to test that theory — query logs, call search, read a record, ask a follow-up, run a validation. This is the Action. The discipline is that the action is picked because it should reduce uncertainty, not because it is next in a script.

Evidence. The environment returns an Observation, and the agent decides whether the theory held, weakened, exposed a different problem, or finished the task. That observation is the input to the next turn.

So ReAct is not “think, then act”. It is: form a local hypothesis, run a probe, absorb the evidence, choose the next move from there. Many systems loop; what makes a loop ReAct-shaped is that the next step depends explicitly on evidence returned by the previous one.

2022 and 2026, Side by Side

The four moves are identical in both eras. What changed is where the reasoning lives and who guarantees the format.

The 2022 text-parsed ReAct loop next to the 2026 native tool-calling loop Two columns of four stacked steps. The 2022 column: the model returns one text completion stopped at the word Observation; that text contains a Thought line and an Action line such as search of a term; a regex parser extracts the verb and argument and breaks when the model writes prose instead; the observation is appended to one growing prompt string, which is fed back to the model. The 2026 column: the model reasons internally, in a thinking block that is usually hidden or encrypted; it emits a structured tool call carrying a name, JSON arguments and a call identifier, validated against your schema; the runtime executes your function with no parsing step; the result is appended as a typed tool-result message keyed by the call identifier, and the message list is fed back to the model. A note underneath states that the step budget, the tool surface and the observation wording are yours in both columns. 2022 — TEXT-PARSED 2026 — NATIVE TOOL CALLING Model Text it wrote Your regex parser Growing prompt string Model (reasoning inside) Structured tool call Your runtime Typed message list one completion, stopped at "Observation:" extracts verb and argument; breaks on prose observation appended as text, then resent thinking block, usually hidden or encrypted executes your function — no parsing step tool result keyed by call_id, then resent Thought: … / Action: search[term] {name, arguments, call_id} Yours in both columns: the step budget, the tool surface, and how each observation is worded.
Four moves, same order, in both eras. The green boxes mark what moved: the parser you used to own is gone, and the reasoning it used to read now happens inside the model.

The 2022 Loop in Code

This is the classic shape, small enough to read in one sitting. The tool is a fake two-page encyclopedia so you can run the loop without a search dependency, and the model is a 2026 model with native reasoning turned off — which is what it now takes to reproduce the original behaviour.

# classic_react.py — the 2022 text-parsed loop. pip install openai==3.29.0
import re

from openai import OpenAI

client = OpenAI()
PAGES = {
    "colorado orogeny": "An episode of mountain building in Colorado and surrounding areas.",
    "eastern sector": "The eastern sector extends into the High Plains and is called the Central Plains orogeny.",
}
ACTION = re.compile(r"Action:\s*(search|finish)\[(.+?)\]")
FEWSHOT = """Answer the question by emitting one Thought line and one Action line, then stopping.
Action is search[term] or finish[answer].

Question: Who wrote the screenplay for the 1982 film Blade Runner?
Thought: I should look up the film, then read off the screenwriters.
Action: search[Blade Runner]
Observation: Blade Runner is a 1982 film with a screenplay by Hampton Fancher and David Peoples.
Thought: The observation names both writers, so I can answer.
Action: finish[Hampton Fancher and David Peoples]
"""


def search(term):  # stands in for the Wikipedia API in the paper
    return PAGES.get(term.lower().strip(), f"No page found for '{term}'.")


transcript = f"{FEWSHOT}\nQuestion: What is the eastern sector of the Colorado orogeny called?\n"
for step in range(6):  # step budget, because the loop cannot stop itself
    reply = client.chat.completions.create(
        model="gpt-5.6-terra",
        reasoning_effort="none",  # native reasoning off: in 2022 the thinking was the text
        stop=["Observation:"],
        messages=[{"role": "user", "content": transcript}],
    ).choices[0].message.content
    match = ACTION.search(reply)
    if match is None:  # the format broke; most 2022 agent code lived here
        transcript += "\nObservation: No Action line found. Emit exactly one Action line.\n"
        continue
    verb, argument = match.groups()
    if verb == "finish":
        print(argument)
        break
    transcript += f"{reply.strip()}\nObservation: {search(argument)}\n"
else:
    print("Step budget exhausted without an answer.")

Five things in that listing are the whole history of the technique.

The prompt carries a hand-written trajectory, because that is what the method was — Yao describes the original as a few-shot prompt containing a human-written thought, action and observation sequence (LLM Agents: History & Overview, 15:55). The stop sequence exists because the model will happily hallucinate its own observations if you let it keep writing. The regex is load-bearing, and the match is None branch is where a surprising amount of 2021–2023 agent code actually lived. The transcript is one growing string, so every turn pays for every earlier turn. And the for loop with a fixed budget is the only thing preventing an unbounded run.

Note what the state of the art has done to the first argument: to get this loop to behave like 2022, you turn reasoning off.

ReAct in 2026

The pattern is now the default way agents are built, and almost nobody calls it ReAct. LangChain’s current agents documentation defines an agent as “a model calling tools in a loop until a given task is complete” and the constructor is create_agent — the word ReAct does not appear on the page. Anthropic’s tool use documentation describes the same round trip in terms of tool_use blocks and tool_result blocks. OpenAI’s function calling guide describes it as function_call items and function_call_output items. Same loop, three vocabularies, none of them the paper’s.

Yao, asked directly whether tool calling in a loop is ReAct, says the idea is “more implicitly used than explicitly” now, and separates the contribution into two halves: acting through tools, and the inner monologue or thinking (Language Agents: From Reasoning to Acting, 10:57). Harrison Chase, in the same conversation, puts the state of play in one line: “it’s the same ideas… but it’s obviously a very different implementation at this point in time” (12:29).

The two halves came apart, and each went somewhere different.

The acting half became an API contract. Your tool is a JSON schema; the model emits arguments against it; the provider validates the shape. There is no Action: line to parse and no format to re-teach.

The reasoning half went inside the model. Reasoning models produce their deliberation as a native thinking block rather than as prose in your transcript. The practical consequence shows up in the SDK rules: OpenAI’s guide notes that for reasoning models, any reasoning items returned alongside tool calls must be passed back with the tool call outputs. You are now custodian of reasoning you often cannot read.

Yao’s framing of why ReAct worked at all survives the change intact: “ReAct doesn’t change the outside… but it does change the inside through the context”, and thinking can be treated as “a[n] extra tool” (4:08). Reasoning was never a separate subsystem. It was a move the model could make in the same action space as everything else — which is exactly how a thinking block behaves today.

The Same Task, Natively

# native_react.py — the same task, 2026 shape. pip install openai==3.29.0
import json

from openai import OpenAI

client = OpenAI()
PAGES = {
    "colorado orogeny": "An episode of mountain building in Colorado and surrounding areas.",
    "eastern sector": "The eastern sector extends into the High Plains and is called the Central Plains orogeny.",
}
TOOLS = [
    {
        "type": "function",
        "name": "search",
        "description": "Look up one encyclopedia page by title. Returns a short summary, "
        "or a not-found message naming no page. Call once per title.",
        "parameters": {
            "type": "object",
            "properties": {
                "term": {"type": "string", "description": "Page title, e.g. 'Colorado orogeny'."}
            },
            "required": ["term"],
            "additionalProperties": False,
        },
        "strict": True,
    }
]


def search(term):
    return PAGES.get(term.lower().strip(), f"No page found for '{term}'.")


conversation = [
    {"role": "user", "content": "What is the eastern sector of the Colorado orogeny called?"}
]
for step in range(6):  # still a step budget; nothing else about the loop is yours
    response = client.responses.create(model="gpt-6-astra", tools=TOOLS, input=conversation)
    conversation += response.output  # reasoning items ride along and must be passed back
    calls = [item for item in response.output if item.type == "function_call"]
    if not calls:
        print(response.output_text)
        break
    for call in calls:  # one turn can return several calls
        term = json.loads(call.arguments)["term"]
        conversation.append(
            {
                "type": "function_call_output",
                "call_id": call.call_id,
                "output": search(term),
            }
        )
else:
    print("Step budget exhausted without an answer.")

Read the two listings against each other and the ledger is clear.

Gone: the few-shot trajectory, the stop sequence, the regex, the unparseable-reply branch, the single growing string, and the fiction that the model’s visible prose is its reasoning. Tool arguments arrive typed. Several calls can come back from one turn, which the text format could not express at all.

Still yours: the for range(6). The provider gave you structure, not judgement. Nothing in either SDK decides when the loop has gone far enough, so the step budget, the cost ceiling, and the stop condition remain your code — and the native version makes it easier to run twelve cheap steps without noticing.

Newly yours: observation wording, which is now a tool-design problem rather than a prompt-formatting one. "No page found for 'eastern sector'." is an observation the model can act on; a bare null or a stack trace is not. See Designing Tools for Agents for the full treatment, since the tool result is the observation in this architecture.

Harder: seeing what happened. In 2022 the trajectory was plain text you could read, diff, and paste into a bug report; the paper leaned on exactly that for its interpretability claim and for the hand-labelled failure analysis. When reasoning is a hidden or encrypted block, that analysis has to come from traces and tool-call sequences instead, which is why Evaluating Agent Trajectories, Not Just Outputs matters more now than it did when the thinking was sitting in your prompt.

A Worked Example

Suppose an operations agent is asked to find out why the nightly billing job failed and take the safest next step. The goal already assumes the boundaries described in Goals, Constraints, and Success Conditions: act toward recovery, stay inside permissions, stop when the evidence is good enough.

TurnHypothesisProbeEvidence
1The job failed on a payment-provider timeoutRead job logs and dependency healthRepeated timeouts from the provider API
2Transient upstream outage, not our codeCheck provider status and recent deploysProvider degraded; no billing-related deploy
3One retry is safe and inside policyRetry the job onceRetry succeeds; backlog clears
4The run can close if recovery is confirmedVerify downstream records; write the summaryRecords healthy; summary logged

Nothing here was knowable in advance. Turn 3 is only reachable because turns 1 and 2 ruled out a code change — which is the shape of exploratory work, and the reason the loop earns its cost. In Yao’s words from the same lecture, the generality came from noticing that “many tasks can be turned into a text game” (20:43).

In a native implementation the turns look the same, but each one is a tool call with typed arguments, and the hypothesis is in a thinking block you may never see.

What ReAct Is Not

Three comparisons do most of the work.

Not chain-of-thought. Chain-of-thought prompting keeps the reasoning inside the model’s own text with no external check. ReAct pushes it into the world and lets the world push back. The paper quantified the difference: no hallucinated facts in its sampled ReAct failures, versus 56% for chain-of-thought.

Not one-shot tool calling. A single function call is a capability. ReAct is a control pattern around repeated calls.

Not every agent that loops. A retry loop and a fixed pipeline both loop. The distinguishing property is that the next action is selected from the last observation.

DimensionOne-shot tool callingReAct-shaped loop
PatternRequest a tool, execute, returnRepeated reason-act-observe cycle
HorizonOne step or a fixed sequenceMulti-step and adaptive
Role of observationsThe result you return to the userInput to the next decision
Best forClear, well-scoped actionsPaths that are unclear upfront
Main costTool interface complexitySerial model calls, latency, context growth

Tool Use: How Agents Take Action explains how the agent can act. ReAct explains how it decides what to do next after acting.

Where It Breaks

The failure modes did not change when the format did. Three of them got harder to see.

Useless loops. The agent re-searches, re-reads, and re-checks without progress. The paper’s own hand-labelled analysis found reasoning errors — frequently a failure to recover from repetitive steps — in 47% of ReAct’s failures. This is the oldest failure in the pattern and it is still the most common. Step budgets, cost ceilings, and progress checks that can tell repetition from movement are not optional.

Context growth. Every turn adds a tool call and a result to the conversation. Native formats are more compact than a re-sent transcript, but the growth is the same shape, and long runs still decay. Short-Term Context, Retrieval, and Long-Term Memory is the follow-on topic for a reason.

Cascading assumptions. A wrong early hypothesis gets inherited. The loop then looks busy while digging deeper into the wrong branch. Harder to spot now: the hypothesis may be in a hidden thinking block, so the only evidence is a sequence of tool calls that each look individually reasonable.

Premature stopping. The agent stops on a plausible answer rather than a verified one. Nothing in a tool-calling API distinguishes the two.

Latency and cost. Serial model calls, one per turn. For predictable work a fixed workflow is faster, cheaper, and easier to reason about. ReAct is powerful for uncertain paths and wasteful for obvious ones; if you can draw the flowchart, write the flowchart.

Where to Go From Here

The honest 2026 summary is that ReAct is table stakes, not an architecture. You get the loop for free from any tool-calling SDK, and the engineering has moved to the parts the loop never solved: budgets and stop conditions, tool and observation design, context management across long runs, trajectory-level evaluation, and reflection on failed attempts — which is what Reflexion added on top of ReAct-style loops in the first place.

What is worth carrying forward is the discipline the paper’s format made unavoidable. When the thought was a line of text you could read, it was obvious whether the next action followed from the last observation. That property is what made the loop work, and it is the thing a hidden thinking block makes easy to stop checking.

FAQ

Is ReAct still relevant in 2026?

The idea is, to the point of invisibility: nearly every tool-calling agent runs a ReAct-shaped loop. The 2022 implementation is not. Writing a Thought/Action/Observation parser against a current model means fighting the native tool-calling and reasoning behaviour you are paying for.

Should I ever still text-parse a ReAct loop?

Two cases. Teaching, where seeing the trajectory as plain text is the point. And models without tool-calling support, mostly small local ones — and even there, constrained decoding to a JSON grammar is usually a better bet than a regex.

Is tool calling in a loop the same thing as ReAct?

Structurally, yes, and that is roughly how the paper’s author describes the situation: the idea is now “more implicitly used than explicitly”. The contribution had two halves — acting via tools, and an inner monologue — and in a modern stack the first is an API and the second is a model feature.

Where did the Thought part go?

Into the model. Reasoning models emit deliberation as a native thinking block, often summarised or encrypted rather than shown. You still have to carry those items back into the next request alongside your tool results, you just cannot always read them.

Is ReAct the same thing as the sense-think-act loop?

No. Sense-think-act is the general control model. ReAct is the specific claim that interleaving reasoning with action beats either alone, which the 2022 paper tested on four benchmarks.

Is ReAct the same thing as chain-of-thought?

No. Chain-of-thought reasons in text with no external feedback. ReAct interleaves reasoning with real actions and observations, which is why it hallucinated far less in the paper’s failure analysis.

Do all agents need ReAct?

No. Predictable work is better served by a fixed workflow or a single tool call. Reach for the loop when the next step depends on what the last step revealed.

How do you stop a ReAct agent from looping forever?

Explicit success conditions, a step budget, time and cost ceilings, escalation rules, and a progress check that can distinguish a new state from a repeated one. Both SDKs will loop as long as you let them; neither one decides when enough is enough.

Why does the loop get expensive?

One model call per turn, serially, with the conversation growing each time. Reasoning tokens add to that, and the compactness of native formats makes it easier not to notice.

Designing Tools for Agents, because the tool result is the observation. Then Evaluating Agent Trajectories, Not Just Outputs, because the reasoning you used to read in the transcript now has to be inferred from traces.

Further watching

All three are by Shunyu Yao, ReAct’s first author. Timestamps were transcript-checked for this guide and link to the moment the claim appears.

Primary Sources

Both listings target the openai 3.29.0 Python SDK; pin that version to reproduce them.