ReAct vs Tool-Calling Agents
- LLM Systems
- Agents
- MCP
Revised September 13, 2026.
Suppose we ask an assistant: “Which Project X tickets remain blocked, and what do the meeting notes say about why?” A useful answer needs more than a plausible paragraph. The assistant must find the right project, retrieve current ticket states, locate the relevant discussions, and distinguish an old explanation from a blocker that still applies. A search result might reveal a ticket identifier that was absent from the question. The next useful action depends on what the previous action returned.
This is the setting in which discussions of ReAct and tool-calling agents become confusing. Both can involve a language model choosing tools, reading results, and deciding what to do next. Calling them competing architectures hides the design choices that actually matter.
My working distinction is to separate three questions: how the agent decides its next step, how it represents a tool request, and how the application connects to the tool. ReAct, structured tool calling, and Model Context Protocol (MCP) address these questions at different levels. This note develops that distinction, checks it against the literature, and applies it to the ticket-and-meeting example. All project records, traces, and code below are illustrative; they are not results from a deployed system or a new benchmark.
Three Questions Hidden inside One Comparison
First, consider the control flow. Does application code prescribe a sequence of operations, or can the model revise the sequence after seeing evidence? Second, consider the action representation. Does the application extract a command from generated text, or receive a structured tool-call object? Third, consider the connection. Does the application invoke a local function, a custom service adapter, or an MCP server?
Figure 1. Three separate design questions. Original diagram synthesizing the ReAct method, client tool-use documentation, and MCP tools specification.123 The application connects the layers; an MCP server is one possible destination.
This separation changes how I would review an agent proposal. “We use function calling” leaves the stopping condition unanswered. “We use ReAct” leaves argument validation unanswered. “We use MCP” leaves the choice of the next action unanswered. A complete design needs an answer at each level, even when a framework supplies most of the plumbing.
What ReAct Contributes
Yao et al. introduced ReAct as interleaving verbal reasoning with actions and observations. Reasoning can guide or revise an action plan; actions bring external information back into the context. The paper studies HotpotQA, FEVER, ALFWorld, and WebShop.1
For our example, an explanatory sketch would look like this:
Task: Explain the current blockers for Project X.
Decision: Retrieve blocked tickets before looking for explanations.
Action: search_tickets(project_id="PX", status="blocked")
Observation: PX-17 and PX-24 are blocked.
Decision: Search meeting notes using these exact identifiers.
Action: search_meetings(ticket_ids=["PX-17", "PX-24"])
Observation: PX-17 has a recent discussion; PX-24 has none.
Next step: Check the PX-17 discussion and report the PX-24 gap.
The “Decision” lines are authored explanations for the reader, not a claim to reveal a model’s private reasoning. Notice the dependency: the meeting search uses identifiers learned from the ticket search. If the first tool instead returned an ambiguous project name, the appropriate continuation would change.
In the paper’s PaLM-540B prompting comparison, ReAct improves on the action-only baseline on both knowledge tasks, but trails chain-of-thought on HotpotQA. The authors also report repetitive-action failures.1 That is useful evidence for studying feedback and reasoning together, with task-dependent results. It is not a controlled comparison against today’s native tool-calling interfaces.
What Structured Tool Calling Changes
A structured interface gives the application named fields for a requested operation and its arguments. For client tools, the application executes the request and sends the result back to the model. That round trip remains even when an SDK handles it automatically. Some providers offer strict schema conformance, which is stronger than simply asking for JSON.2
Here is a deliberately small, provider-neutral input schema for search_tickets:
{
"type": "object",
"properties": {
"project_id": { "type": "string" },
"status": { "enum": ["open", "blocked", "closed"] }
},
"required": ["project_id", "status"],
"additionalProperties": false
}
And here is an illustrative exchange. These field names describe our example, not a particular vendor’s wire format:
{
"call_id": "c1",
"name": "search_tickets",
"arguments": { "project_id": "PX", "status": "blocked" }
}
{
"call_id": "c1",
"result": {
"tickets": [{ "id": "PX-17" }, { "id": "PX-24" }],
"next_cursor": null
}
}
The practical benefit is a clearer boundary between generated requests and executable operations. A parser can identify the tool name without guessing whether a sentence is commentary or a command. The application can reject an unsupported status before querying its database.
But "project_id": "WRONG-PROJECT" still satisfies this schema. So does a request for closed tickets when the user asked for blockers. A well-formed request is only one condition of a correct action. The example needs separate checks for project identity, access, and whether the retrieved material answers the question.
Toolformer offers another useful distinction. Schick et al. train a model to insert useful API calls into text using self-supervised filtering, starting from a few demonstrations per tool. Its tools include calculation, search, translation, and a calendar.4 Learning when and how to use a tool is a model-training question; representing a request as structured fields is an interface question. Neither alone specifies the complete application loop.
Comparing the Actual Design Choices
The following is a design comparison, not a performance leaderboard. It separates choices that can otherwise get bundled into the word “agent.”
| Choice | What it controls | What remains to solve |
|---|---|---|
| Text actions or structured calls | How the application reads a request | Whether the requested action is appropriate |
| Fixed workflow or adaptive loop | Who chooses the next operation | Evidence quality and stopping conditions |
| Sequential or concurrent tools | When independent work executes | Dependencies and conflicting operations |
| Direct adapter or MCP | How tools are discovered and invoked | Tool semantics and application policy |
For a question such as “Show the status of PX-17,” I would begin with a fixed lookup and a short response. For “Explain why these tickets are still blocked,” I would allow follow-up retrieval because the necessary sources may be discovered along the way. This is a proposed design choice for our example, not evidence that more autonomy necessarily produces a better answer.
Anthropic’s engineering account similarly distinguishes predefined workflows from systems where a model directs its own tool use, recommending that complexity be justified by the task.5 The implication I draw is to evaluate the smallest sufficient amount of model-directed control. A structured interface is compatible with either choice.
Latency Follows Dependencies
Changing a text command into JSON does not make an unknown ticket identifier available earlier. In our example, meeting retrieval still has to wait for ticket discovery. Once PX-17 and PX-24 are known, however, their individual histories can be retrieved concurrently if the tools and application support that execution pattern.
Figure 2. Parallelism follows the task’s dependency graph. Original illustration for the fictional Project X example. Both retrieval branches wait for ticket discovery, and the answer waits for both branches.
For this simple graph, an illustrative latency model is:
Here, is the total time spent in model turns; the other terms describe application work. This is a scheduling sketch, not measured latency. It assumes concurrent history retrieval, no retries, and no overlap between those stages and model inference. Sequential retrieval would replace the maximum with a sum. Changing the call format alone does not justify changing either expression.
A Combined Agent, Step by Step
Let us make the example more concrete. Assume the user has already selected the project with identifier PX. The ticket tool reports PX-17 and PX-24 as blocked at retrieval time. PX-17 links to a meeting where the team discussed a pending access review. PX-24 has no matching meeting record in the searched collection.
The first answer should not generalize the PX-17 explanation to both tickets. Nor should it treat an unsuccessful search as proof that PX-24 was never discussed. A useful response separates current status, located evidence, and the remaining gap.
Figure 3. A combined agent using structured requests and observation-driven follow-up retrieval. Original sequence diagram. The records and decisions are illustrative; the application executes the calls and returns their results.
Preserve the Evidence Boundary
For PX-17, I would keep the ticket identifier, observed status, retrieval time, meeting identifier, and relevant passage together. If the meeting is older than a later ticket update, the answer should make that timing visible. A past statement that “access review is pending” is evidence of an earlier blocker, not automatic proof of the current cause.
For PX-24, I would write “No explanation was found in the meeting notes searched,” then specify the search coverage. That wording leaves room for an unindexed meeting, a missing identifier, or a discussion outside the chosen date range. It also gives the user something concrete to correct.
This is where tool output design becomes consequential. Anthropic’s guidance recommends relevant, concise responses, pagination or truncation for large results, and actionable errors.6 For our tools, that suggests returning enough provenance to inspect the answer, plus a cursor or coverage indicator. Dumping every ticket field into context would make it harder to see the few fields that determine the conclusion.
Keep the Loop Explicit
The following pseudocode sketches a read-only controller. model_turn normalizes provider-specific responses while preserving their required conversation state. observe records a result against its call identifier. Tool schemas, timeouts, and the allowlist belong to the application.
history = start_conversation(question)
attempts = Counter()
for turn in range(8):
reply = model_turn(history, tools=READ_ONLY_TOOLS)
history.append(reply)
if not reply.calls:
return answer_with_evidence_or_gaps(reply, history)
for call in reply.calls:
if call.name not in READ_ONLY_TOOLS:
observe(history, call.id, error="Unknown tool")
continue
if not valid_arguments(call):
observe(history, call.id, error="Invalid arguments")
continue
key = (call.name, canonical_json(call.arguments))
if attempts[key] >= 2:
observe(history, call.id, error="Repeat limit reached")
continue
attempts[key] += 1
try:
result = execute_with_timeout(call, seconds=10)
except ToolTimeout:
result = {"error": "Timed out", "retryable": True}
except ToolError as exc:
result = safe_error_result(exc)
observe(history, call.id, result=result)
return partial_answer_with_gaps(history, reason="Step limit")
The eight-turn limit, two attempts per identical request, and ten-second timeout are illustrative defaults, not paper-derived optima. This sketch executes calls sequentially for clarity. A real controller also needs a total deadline and call budget; allowing multiple calls per turn means a turn limit alone does not bound total work.
The repetition rule is intentionally conservative for read-only retrieval. It permits one retry but can also block a useful later refresh. If the underlying data change during a task, a production design should distinguish a retry from a deliberate new observation. Write operations need a separate design for authorization and duplicate execution; this controller does not cover them.
What the Evidence Establishes
The studies address different pieces of the system. Their results become more useful when we distinguish a comparison of complete agent configurations from an experiment isolating only the action format.
| Source and question | Reported finding | Limit of the inference |
|---|---|---|
| ReAct: does reasoning help action? | HotpotQA exact match: ReAct 27.4%, Act 25.7%, CoT 29.4% with PaLM-540B | A historical prompting comparison, not a native-tool-interface ablation |
| Toolformer: can tool use be learned? | Self-supervised API augmentation improves several downstream tasks | Does not establish reliable completion of an arbitrary workflow |
| τ-bench: can agents complete tasks consistently? | GPT-4o function calling: 61.2% retail, 35.2% airline; 48.2% domain average | Historical models and simulated domains; the average weights domains equally |
| Turpin et al.: are explanations faithful? | Input biases can affect answers without being acknowledged in explanations | Studies CoT faithfulness, not this ticket agent’s performance |
Selected findings from the original studies.1478 The numerical ReAct row reproduces selected entries from Table 1; it should not be read as a ranking of current systems.
τ-bench evaluates conversations with simulated users, policies, and APIs by checking the resulting database state. Its retail comparison also finds native function calling ahead of text-formatted ReAct for the tested models, while ReAct outperforms text action-only prompting.7 That is relevant evidence for interface selection, although the configurations differ in prompting and use of native capabilities; it does not show that feedback-driven reasoning is incompatible with structured calls.
The paper measures consistency with : success across all trials rather than at least one successful attempt.7 That distinction matters when a user expects the same valid request to work repeatedly.
My interpretation is that an agent evaluation should preserve the distance between three outcomes: a call was accepted, the requested information was retrieved, and the user’s task was completed correctly. A dashboard reporting only the first can look healthy while the user receives the wrong explanation.
Readable Traces Are Not a Proof
Turpin et al. show that chain-of-thought explanations can rationalize predictions influenced by input biases without mentioning those influences.8 This does not establish that every explanation is unfaithful. It does undermine the assumption that a convincing explanation is, by itself, a sufficient audit.
For our example, I would inspect the actual request, the retrieved passage, its date, and the resulting claim. A sentence such as “I checked the latest meeting” should be testable against the log. If no meeting was retrieved, eloquent commentary should not rescue the answer. Likewise, the absence of a visible reasoning trace should not prevent an audit when the actions and supporting records are available.
Evaluate the Failure Cases Deliberately
I would build a small fixture collection for this particular application before comparing prompting strategies. It should include two projects with similar names, a ticket with an outdated meeting explanation, a paginated result, a temporary tool error, and a blocker with no supporting meeting. Each case tests a different reason an apparently sensible trajectory can fail.
The evaluator should check whether every reported ticket belongs to the selected project, whether the status matches the fixture, and whether each explanation cites an actually retrieved passage. It should accept an explicit evidence gap when the collection has none. It should reject a confident explanation borrowed from another ticket, even when all calls were valid.
For the same fixtures, record task completion, unsupported claims, tool errors, repeated calls, elapsed time, and token usage. Compare a fixed workflow with an adaptive loop while keeping model and tool access constant. Repeat trials. These are proposed experiments, not results reported by this note. They would tell us whether the additional decisions improve this application enough to justify their cost.
Where MCP Fits
MCP provides a shared protocol for exposing tools: clients can discover definitions through tools/list and invoke them through tools/call. Definitions include input schemas; results can contain structured or unstructured content. The specification also addresses errors and cautions against trusting tool annotations from untrusted servers.3
In our example, a meeting service could expose the same retrieval capability to more than one compatible agent application. The application would map the discovered tool definition into the model-facing interface and route the resulting request back to the server. This mapping is still application work; the model does not become an MCP client merely because it emits a JSON object.
The useful architectural consequence is a reusable connection boundary. It does not mean two meeting servers return equivalent evidence. One might index transcripts and another only summaries; identical-looking searches could have different coverage. I would document that distinction in the tool description and preserve it in the answer’s provenance.
I would also treat retrieved meeting text as evidence to interpret, never as authority to change the task or grant new capabilities. A note containing “ignore the ticket status” is still a note. In this example, keeping the tool allowlist read-only prevents a retrieved passage from creating a legitimate route to modify a ticket. It does not, by itself, prevent misleading text from influencing the answer.
Takeaways
- Separate the loop, the action format, and the tool connection when comparing agent designs.
- Use structured calls to make the execution boundary explicit, then validate the meaning of the request as well as its shape.
- Let follow-up retrieval earn its place through task-level evaluation; parallelize only work whose dependencies permit it.
- Preserve source identity, timing, and search coverage so that an explanation can be checked and an evidence gap can remain visible.
- Measure completed tasks and repeated-trial reliability alongside call validity, latency, and cost.
For the ticket-and-meeting assistant, my starting design would be a bounded, read-only loop with structured tool calls and inspectable evidence. MCP would be a connection choice where shared tool access is useful. The next decision would come from the fixture evaluation: which questions benefit from adaptive retrieval, and which are already answered well by a fixed sequence?
References
- Yao et al. (2023). ReAct: Synergizing Reasoning and Acting in Language Models.
- Schick et al. (2023). Toolformer: Language Models Can Teach Themselves to Use Tools.
- Yao et al. (2024). τ-bench: A Benchmark for Tool-Agent-User Interaction in Real-World Domains.
- Turpin et al. (2023). Language Models Don't Always Say What They Think.
- Anthropic. Tool use with Claude. Living documentation.
- Schluntz and Zhang (2024). Building effective agents.
- Aizawa (2025). Writing effective tools for AI agents—using AI agents.
- Model Context Protocol (2025-11-25). Tools specification.
All three diagrams are original explanatory illustrations; no chart in this note represents a new empirical experiment.
Citation
If you want to reference this note:
Ma'ruf, Muhammad Rifqi. “ReAct vs Tool-Calling Agents.” rifqimaruf.dev (2026), revised September 13, 2026. https://rifqimaruf.dev/writing/react-vs-tool-calling-agents/
Footnotes
-
S. Yao et al., “ReAct: Synergizing Reasoning and Acting in Language Models,” ICLR, 2023 (preprint 2022). Paper. See Sections 2–4 and Table 1. ↩ ↩2 ↩3 ↩4
-
Anthropic, “Tool use with Claude,” developer documentation. Documentation. Accessed September 13, 2026; API capabilities are version-dependent. ↩ ↩2
-
Model Context Protocol, “Tools,” specification revision 2025-11-25. Specification. Accessed September 13, 2026. ↩ ↩2
-
T. Schick et al., “Toolformer: Language Models Can Teach Themselves to Use Tools,” NeurIPS, 2023. Paper. ↩ ↩2
-
E. Schluntz and B. Zhang, “Building effective agents,” Anthropic, December 19, 2024. Engineering article. Practitioner guidance, not a controlled benchmark. ↩
-
K. Aizawa, “Writing effective tools for AI agents—using AI agents,” Anthropic, September 11, 2025. Engineering article. See the sections on evaluation and tool responses. ↩
-
S. Yao, N. Shinn, P. Razavi, and K. Narasimhan, “τ-bench: A Benchmark for Tool-Agent-User Interaction in Real-World Domains,” 2024. Paper. This note refers to the original 2024 study, not a current leaderboard. ↩ ↩2 ↩3
-
M. Turpin, J. Michael, E. Perez, and S. R. Bowman, “Language Models Don't Always Say What They Think: Unfaithful Explanations in Chain-of-Thought Prompting,” NeurIPS, 2023. Paper. ↩ ↩2