Skip to content
Forward Deployed

Forward Deployed
Lessons and contents
Learn

The ReAct loop in LangGraph; tool calling vs ReAct

Source
From the RAG & Agents Engineering course
By
Sourav Banerjee
Last updated
9 Nov 2026

Report an issue

Reason–act–observe

What you'll learn

  • Explain the reason, act, observe loop and the one graph edge that creates it.
  • Trace a run whose second search depends on what the first one found.
  • Measure what the loop buys on the Larkspur golden questions, and what every extra round costs.
  • Compare native tool calls with text-based ReAct, and diagnose a failure in the transport between them.

Module T7.1 built the agent loop by hand: a model that requests tools, a node that runs them, and an edge back to the model. This lesson gives that loop its name, ReAct, and measures what it buys over a single tool call.

Larkspur's support agent gets How long does a refund take? Its first handbook search returns the refund-window passage and misses the one that says how many days a refund takes. A single tool call ends there, with half the evidence; finding the rest means reading the result and searching again.

ReAct (reason plus act) is an agent that plans one step at a time: it reasons about the next step, calls a tool, observes the result and reasons again, until it replies without asking for a tool (Yao et al., ReAct: Synergizing Reasoning and Acting in Language Models, ICLR 2023).

The message list is the trace

In LangGraph the whole run lives in one state key: a list of messages that only ever grows, so every model call sees everything that came before. Each part of the loop leaves one kind of message:

Message Written by What it holds
Human message The user The question
AI message with a tool call The model The reasoning step turned into an action: which tool, with which arguments
Tool message The tool node The observation: what the tool returned
AI message without a tool call The model The final answer, which ends the run

Table 1: One ReAct round leaves an AI message and a tool message on the list.

The model never runs a tool itself: it returns a request, and the tool node executes it and appends the result.

One edge makes the loop

A single-shot graph and a ReAct graph have the same nodes. They differ in where the tool node sends its result:

Diagram: Single shot; START; agent; tools; END; ReActDiagram: Single shot; START; agent; tools; END; ReAct

Figure 1: Single shot sends the tool result to the end. ReAct sends it back to the model.

With the edge to the end, the user receives the tool message itself, raw search results, and no search can build on another: the raw-result handoff. With the edge back to the agent, a router returns the run to the model after every observation and ends it when the model stops calling tools.

A question that needs two dependent searches

The recorded comparison asks both graphs one question whose second half depends on the first: Who is the current CEO of the company that created the sci-fi movie Dune, and what was the budget for that company's most recent film? Both use the same live web-search tool and the same small model:

Graph Round Search the model wrote What came back to the user
Single shot 1 current CEO of Legendary Entertainment 2023 The tool message: a list of search results naming the CEO, no budget
ReAct 1 current CEO of Legendary Entertainment 2023 (observation, back to the model)
ReAct 2 budget of Legendary Entertainment's most recent film 2023 (observation, back to the model)
ReAct 3 No tool call An answer naming the CEO and the latest film with its budget

Table 2: The multi-hop question on both graphs, one recorded run each.

The ReAct run's answer combines both observations. The loop costs nothing when no tool is needed: Explain AI in 2 bullets went straight to the end in one model call.

Pitfall: the lenient judge. The notebook then asks an LLM judge to score both runs. It gave the raw-result handoff 7 out of 10 for task completion, though the user received only search results, and the ReAct run 10. The judge was the agent's own model. A score that rewards an answer nobody wrote measures the judge, so check its scores against a few runs you grade yourself (lesson 5 of T7.1).

Measuring the loop on Larkspur

The interactive lab runs this loop over the twelve Larkspur handbook chunks from the T5.1 lab, with real TF-IDF retrieval (top two per search) and a scripted model that answers once the evidence is in the message list. On the three T5.1 golden questions:

Question Single shot ReAct ReAct, call cap 3
Can I export my data after I cancel my plan? evidence 1.00, raw tool output 1.00, 2 calls, answered answered
How long does a refund take? 0.50, raw tool output 1.00, 3 calls, answered answered
What happens if my server goes down? 0.00, raw tool output 1.00, 4 calls, answered stopped at the cap, evidence 1.00
Mean, total 0.50, 3 calls, 0 of 3 answered 1.00, 9 calls, 3 of 3 answered 8 calls, 2 of 3 answered

Table 3: Evidence recall, model calls and outcome per golden question in the lab.

Interactive lab: The ReAct loop and its call cap. Open full screen (opens in a new tab)

Read the evidence and completion columns separately:

  • Single shot equals the T5.1 baseline. One top-2 search per question gives the same mean recall, 0.50, and the user receives chunks instead of an answer.
  • The loop recovers vocabulary mismatch by rewording. The refund question's first search misses the refund-timing chunk, which says "Refunds" where the question says "refund". The second search, written after reading the first result, finds it. The outage question needs three searches: its own words and "server outage" both rank the reboot and sizing chunks first, and "what happens during an outage incident" returns the incidents and SLA chunks.
  • A cap set too low cuts off the answer, not the search. At a cap of 3 the outage run holds both evidence chunks when it stops; lesson 2 of T7.2 sizes the cap.

What each round costs

Every model call rereads the whole message list, so a round costs more than the one before it. The lab estimates the context each run reads as characters divided by four:

Question Single shot: calls, tokens read ReAct: calls, tokens read
Export 1, about 11 2, about 99
Refund 1, about 7 3, about 243
Outage 1, about 9 4, about 451

Table 4: Context read per run in the lab (characters divided by four, so approximate).

The outage run reads about 50 times the context of its single search to go from 0.00 to 1.00 evidence. Context grows faster than the call count because each round carries every earlier observation: lesson 1 of T7.1's context creep, measured.

Native tool calls vs text-based ReAct

The ReAct paper predates tool-calling APIs. It drove the loop with text: the prompt listed the tools and asked the model to write Thought, Action and Action Input lines. The framework stopped generation at Observation, parsed the action out of the text, ran the tool and pasted the result back. Native tool calling moves the same loop onto structured tool calls returned by the provider, so nothing is parsed from prose:

Native tool calling Text-based ReAct
How the call travels Structured tool calls from the provider API Free text, parsed with a pattern
Needs a tool-calling model Yes No, any instruction-following model
Parallel calls in one turn Yes No, one action per turn
Visible reasoning Optional Always, the Thought lines
Typical failure Wrong tool or bad arguments Format drift, or arguments polluted by quotes and whitespace

Table 5: The same loop on two transports.

Planted failure: the quoted argument

The recorded comparison runs both on the same two deterministic stubs: a weather lookup that knows New York, London and Tokyo, and a calculator. The question is What's the weather in Tokyo and calculate 25% of 80?

Run What the model wrote What the tool received Outcome
Text ReAct Action Input: 'Tokyo', with the quotes The six characters 'Tokyo', an unknown city "Weather data not available"
Text ReAct Action Input: '0.25 * 80', with the quotes A quoted string, which the calculator returned unchanged Five identical calculator calls, then the run stopped at its limit of 6 steps with no answer
Text ReAct, inputs cleaned The same quoted inputs Quotes and whitespace stripped first Answered in 2 tool steps and 3 model calls
Native tool calls Structured arguments Tokyo and 0.25 * 80 Both tools requested in one turn; answered in 2 model calls

Table 6: One question on four runs, one recorded run each.

The model knew which tool it wanted every time. The failure was in the transport: the tool receives whatever characters the model happened to write. A text-driven agent needs tools that clean their input, and a setting that turns a format break into an observation. Native calls remove the parsing step and let independent calls share a turn, which is why the native run needed one model call fewer. LangChain 1.x builds its agents on them (lesson 2 of T7.2); the ReAct idea is unchanged.

Choosing a driver

ReAct earns its extra calls when the path depends on what the tools return. Two questions settle which loop to build:

Diagram: Steps known in advance?; Fixed workflow T7.3; Model has a tool-calling API?; Native ReAct create_agent; Text ReAct clean every inputDiagram: Steps known in advance?; Fixed workflow T7.3; Model has a tool-calling API?; Native ReAct create_agent; Text ReAct clean every input

Figure 2: Use a workflow when the path is known; otherwise a native loop wherever the model supports it.

Limits of this evidence

  • A scripted model in the lab. The retrieval and counts are computed; a live model may reword differently or stop earlier.
  • One recorded run per comparison. The multi-hop run, the judge scores and the quoted-argument failure are single runs with one small model; the quoted argument is frequent with that model, not certain, and live search results change between runs.

Run the notebooks

The code for this lesson is in these notebooks. Colab runs one in your browser: install the packages its first cell imports and set the API keys it reads. To run every notebook as written, clone the repository and use its uv environment.

Notebook GitHub Colab
React agent LangGraph Open on GitHub Open in Colab
Tool calling vs react Open on GitHub Open in Colab

Key Takeaways

  • A ReAct agent reasons about one step, calls a tool, reads the result and repeats until it replies without a tool call. The edge from the tool node back to the model is what turns a single-shot graph into that loop.
  • On the Larkspur golden questions the loop lifts mean evidence recall from 0.50 to 1.00, for 9 model calls instead of 3. Every round rereads the whole message list, so the outage run reads about 451 tokens against 9 for one search.
  • Prefer native tool calls to text-based ReAct: no parsing, parallel calls in one turn and no quoted-argument failures. Use a fixed workflow when the steps are known.

Check yourself

1. Why does adding one edge from the tools node back to the agent turn a single-shot graph into a ReAct agent?

With the edge from tools to the end, the last message is the tool message, so the user gets raw search results and no search can build on another. With the edge back to the agent, the run returns to the model after every observation, so each search can use what earlier results found. The run ends when the model replies without a tool call.

2. In the lab, the first search for the refund question misses the refund-timing chunk. What does the loop do next, what does the run cost, and what does it gain?

The model reads the first result and rewords its search, and the second search finds the refund-timing chunk, which says "Refunds" where the question says "refund". The run takes 3 model calls and reads about 243 tokens of context, against 1 call and about 7 tokens for the single shot, and lifts evidence recall from 0.50 to 1.00.

3. A text-based ReAct agent picks the weather tool for Tokyo but the tool finds no such city. What failed, and how do you fix it?

The transport failed, not the choice: the model wrote the city with quotes around it, and the tool looked up the quoted string. Clean text inputs before the tool uses them, and turn format breaks into observations the model can read. Native tool calls, which the LangChain 1.x agent uses, remove the parsing step altogether.

Rate your confidence and keep notes on the module page.