Last week you met the idea of an "agent." This week we open the hood on the mechanism that actually lets an LLM do things instead of only say things: tool calling, and the reasoning loop that decides which tool to call, when, and what to do with the result.
The simplest connection is function (tool) calling. You describe a function's name, parameters, and purpose in a schema; the model decides whether to call it and with what arguments; your code executes the real function and returns the result. This is a single round trip: reasoning happens once, execution happens once, and you get an answer. It is fast, cheap, and reliable for simple, well-bounded tasks — "what's the weather in LA?" doesn't need a multi-step plan. ReAct (Yao et al., 2022) is what you reach for when a task needs more than one round trip. ReAct interleaves reasoning traces and actions in a repeating loop:
The loop repeats — Thought → Action → Observation → Thought → ... — until the model decides it has enough information to produce a final answer. Because the model's reasoning is written down at every step, you get a legible trace of why it did what it did, which matters enormously for debugging and for trust. In the original paper, this interleaving reduced hallucination and error propagation compared to chain-of-thought prompting alone on multi-hop QA benchmarks (HotpotQA, FEVER), and it beat imitation- and reinforcement-learning baselines by 34% and 10% absolute success rate on the interactive ALFWorld and WebShop benchmarks, respectively — because the model could course-correct mid-task instead of committing to one reasoning chain blind.
Strip away the framework branding and every ReAct-style agent runs the same loop:
That's it — it's a while loop with a model call and a conditional branch. LangChain's own guidance has shifted accordingly: the legacy AgentExecutor class hard-coded a lot of this loop's behavior and was hard to customize, so LangChain now recommends building ReAct-style agents directly in LangGraph, where you define the loop yourself as an explicit graph of nodes (a "model" node, a "tools" node) and edges (conditional: tool calls → tools node; no tool calls → end). You'll build exactly this graph in this week's lab.
| Dimension | Function/Tool Calling (single-shot) | ReAct (looped) |
|---|---|---|
| Reasoning vs. execution | Separated — model reasons once, then hands off | Fused — reasoning and action alternate |
| Best for | Simple, bounded tasks with one clear tool need | Multi-hop tasks, tasks needing self-correction |
| Latency / cost | Low (one round trip) | Higher (N round trips) |
| Traceability | Minimal — you see the call, not the "why" | High — every step has a Thought you can audit |
| Failure recovery | None built in | Can observe a bad result and try a different action |
Use plain function calling when the task is a single lookup or transformation. Reach for ReAct when the task requires multiple dependent steps, when the right tool to use next depends on what a previous tool returned, or when you need an audit trail of the agent's reasoning.
A tool call is only as good as its arguments. OpenAI's strict: true mode for structured outputs forces the model to produce arguments that exactly match a JSON Schema: every property must appear in required (mark truly optional fields as nullable rather than omitting them), and additionalProperties: false must be set so the model can't invent extra fields. Both the OpenAI SDK and LangChain support defining these schemas natively with Pydantic (Python) or Zod (TypeScript), so you rarely hand-write raw JSON Schema yourself — you define a typed class, and the framework generates the strict schema for you.
Plain ReAct is powerful but not the only planning pattern, and each alternative makes a different trade-off between token cost and reliability:
None of these replace ReAct outright — they're tools for when ReAct's one-step-at-a-time approach is too expensive (use ReWOO) or too failure-prone (use Reflexion) or too narrow (use Tree-of-Thoughts) for your specific task.
"ReAct agents plan the whole task ahead of time." Not so. Classic ReAct is inherently short-term: at each step the model only reasons about the next action given what it has observed so far — it has no holistic view of the entire task graph. This is exactly why it can take an inefficient path through a task with interdependent steps, and exactly why ReWOO exists as an alternative when you need real upfront planning. "A failed tool call just gets retried and fixed automatically." There is no free error handling. If your tool node doesn't explicitly catch and surface errors, an agent can loop on the same failed action indefinitely, or a noisy/malformed observation can get appended to context and quietly poison every reasoning step that follows. Explicit error handling — catching exceptions, returning a clear error message as the observation, and giving the model a chance to try something different — is not optional polish; it's a core part of building the loop. "Give the agent every tool available so it can do anything." More tools is not strictly better. Once an agent has roughly 20–30+ tools bound to it, tool selection itself degrades: overlapping or vaguely-worded tool descriptions cause the model to pick the wrong tool, loop between plausible candidates, or hesitate — and every tool's schema sits in the context window whether it's used or not, silently eating your token budget. Curate a small, well-described toolset for the task at hand rather than exposing everything you have. You now have the conceptual and practical grounding to build a ReAct agent yourself. Let's do it.