From GPT to Production
Agents and tool use
When the LLM calls functions and loops
Give a next-word predictor a loop, a few tools, and a scratchpad - and it starts to plan, act, and check its own work.
Every lesson so far has treated the model as a one-shot function: text in, one continuation out. But ask it "what is 17% of the population of France?" and one shot is not enough - it may not know the population, and it is a shaky calculator. The fix is not a bigger model; it is a loop. Wrap the model so that instead of answering immediately it can emit an action - "search this," "compute that" - let a real tool run, feed the result back into its context, and let it think again. Repeat until it is ready to answer. That loop is what turns a language model into an agent: something that decomposes a goal into steps, reaches out to the world, and adjusts based on what it sees.
The one-line idea
An agent is a language model in a while-loop with an escape hatch to reality. Each pass it writes a Thought (what to do next), emits an Action (a tool call), and reads back an Observation (what the tool returned). The observation is text the model never generated itself - a fact from the world - so the next thought is grounded in evidence instead of guesswork. It keeps looping until it decides to finish.
From one answer to a loop: tool & function calling
The primitive that makes this possible is tool calling (a.k.a. function calling). You describe a set of tools to the model as a menu - each with a name, a text description, and a typed argument schema (say search(query: str) and calculator(expr: str)). The model, instead of replying in prose, can emit a structured request like calculator("0.17 * 68170000"). Your code - not the model - runs that function and hands the return value back as the next piece of context. The model is still only predicting tokens; you have simply taught it that certain token patterns mean "please run this and tell me the result." Tools are how a frozen, text-only model gets fresh facts (search), exact arithmetic (a calculator), side effects (send an email), or state (read a database).
ReAct: Reason → Act → Observe
The dominant recipe for arranging that loop is ReAct - Reasoning + Acting. Each turn the model interleaves a natural-language reasoning trace with a tool action, then consumes the observation before reasoning again. The magic is the interleaving: pure reasoning with no tools drifts into confident hallucination; pure acting with no reasoning flails without a plan. Alternating the two lets the plan guide the actions and the observations correct the plan. Step through a real trace below - and at the first thought, edit it and re-run to watch the agent take a different path through the problem.
The agent's next action is chosen by this thought. A thought that decides to search / look up the population takes the short grounded path; one that skips the lookup and guesses branches into a longer, self-correcting detour - the loop notices the ungrounded number and repairs it.
Step 1/8 - REASON - the agent decides what to do next before touching any tool.
Read the strip above as a graph traversal: each Action is an edge to a new state; each Observation is the node the agent lands on. The amber Thoughts are internal reasoning - they choose which edge to take, which is why they add no node to the path.
The aha: the Observation is the ground truth injection
Switch the first thought to "skip & guess." The agent multiplies 17% by a made-up 70 million and gets a clean, confident, wrong-ish number - pure hallucination, because nothing external ever entered the loop. But the next Observation forces a real 68.17M into its context, the following Thought notices the mismatch, and the loop recomputes. That is the whole point of the Observe step: it is the one moment the outside world writes into the model's context. Reasoning alone cannot catch its own factual errors; an observation can. Take the tool results away and an agent is just a very verbose guesser.
Planning, memory, and the loop as a state graph
Two ingredients turn this simple loop into something that handles genuinely multi-step goals. Planning / task decomposition: for a hard task the first thoughts break the goal into an ordered list of sub-goals ("first get the population, then take a percentage") - sometimes written out explicitly as a plan the later steps tick through. Memory: the growing transcript of thoughts, actions, and observations is the agent's short-term memory - its scratchpad - carried forward in the context window each turn. When that window is too small for a long task, agents add long-term memory: they write facts to an external store and retrieve them later with the same vector search you saw in RAG. The outer machinery that runs the loop - call the model, parse its action, dispatch the tool, append the observation, stop on finish or a step budget - is the orchestrator.
def run_agent(task, tools, model, max_steps=6):
context = [system_prompt(tools), task] # scratchpad = short-term memory
for step in range(max_steps): # the observation loop (bounded)
thought, action = model.decide(context) # REASON: pick the next move
context.append(f"Thought: {thought}")
if action.name == "finish": # terminal node -> stop the recursion
return action.args["answer"]
obs = tools[action.name](**action.args) # ACT: follow an edge to a new state
context.append(f"Action: {action}")
context.append(f"Observation: {obs}") # OBSERVE: fold the world back in
return "stopped: step budget exhausted" # the base case that guarantees haltingNow look at that loop through two lenses you already own. It is a state-graph traversal (Lesson 29): the agent starts at a node (the task), every Action is an edge it chooses, every Observation is the new node it arrives at, and finish is a terminal node. Unlike BFS on a fixed graph, the agent builds the graph as it walks - the reasoning trace decides which edge to create next. And it is recursion (Lesson 10) with the outside world spliced into each call. Writing the policy as , the environment as , and the running context as , one turn is
and the whole agent is a recursive call that keeps extending its own context until the base case fires:
The only reason it halts is the same reason any recursion halts: a base case (the model emits finish) plus a guard against runaway loops (the max_steps budget). Drop both and you get an agent that spins forever - the infinite-recursion bug of Lesson 10, now with an API bill.
Check yourself
In a ReAct loop, what does the Observe step feed back into the context?
In the state-graph view of an agent loop, an Action is best described as:
What are the three repeating roles of a ReAct loop, and which one keeps the agent from hallucinating?
Nail down the three-part structure and its anti-hallucination mechanism. Try to state it, then check.
Lock it in
- An agent is a language model in a while-loop with tool access - it reasons, acts, observes, and repeats until done.
- The Observation step is the ground truth injection: the one moment the outside world writes into context, preventing confident hallucination.
- The loop is a state-graph traversal (Actions are edges, Observations are nodes) and recursion (the agent extends its own context each call, halting on the finish base case or a step budget).
- Planning decomposes goals into sub-steps; memory (the growing transcript) is the scratchpad; the orchestrator runs the outer machinery.
Primary source
The canonical survey is Lilian Weng's "LLM Powered Autonomous Agents" (2023), which lays out planning, memory, and tool use as the three pillars of the agent stack. The interleaved reason-and-act recipe you stepped through is from the ReAct paper, Yao et al., "ReAct: Synergizing Reasoning and Acting in Language Models" (arXiv:2210.03629).
Ask your teacher
Here the two paths of the course fuse in one artifact. An agent loop is a traversal of a state graph (Lesson 29): each Action is an edge, each Observation a new node, and finish a terminal node - except the agent builds the graph as it walks, rather than exploring a fixed one. And the reasoning trace is recursion (Lesson 10) with an external environment spliced into every call, halting only when the base case (finish) fires. Ask me how tree-of-thought turns the single path into an actual search over that graph, how a multi-agent setup is really multiple traversals sharing a memory, or why the max_steps guard is the same safety net you use against infinite recursion.