chapter 17 · part 3
Agents & tool use
the hook
Give a model a calculator, a search box and a notepad. Watch it think in loops and get things done.
the idea
An agent is a model wrapped in a loop: think, pick a tool, observe what happened, repeat — until it decides it's done. No new model, no new magic. Same next-token prediction, just given permission to act between guesses.
The 'tools' are just functions — a calculator, a search function, a notepad. The model doesn't run them itself; it asks for one by name (and arguments), your code actually runs it, and the result gets fed back in as new context.
Real APIs (OpenAI, Gemini, Claude) formalize this with a strict JSON contract: you describe each tool's name, description, and expected arguments up front, and the model's 'I want to call a tool' response comes back in a matching structured format — never free text, always parseable JSON.
Below: 3 real local tools (calculator, search, notepad) and an agent loop that actually calls them. With a Gemini key, the model itself drives the loop. Without one, a scripted replay shows you the exact same loop shape.
playground — your hands now
what: watch an agent loop through think → tool → observe using 3 real local tools, either live (Gemini) or scripted.
why: 'agent' sounds mystical until you see the loop — it's just a model, 3 functions, and a while loop feeding results back in.
how: with a Gemini key: type a request and watch it drive the loop live. without one: step through a scripted example.
start here → step through the scripted replay — or add a gemini key via ⚙ to drive it live.
scripted replay (no Gemini key needed)
"what's 15% of 240, and what does RAG stand for? save both to my notes."
no Gemini key set, so this is a fixed script — but every step actually runs the real local tools (the calculator genuinely computes 240 × 0.15, the search genuinely looks up "RAG"). add a key via the ⚙ icon to let a real model drive the loop instead.
bonus · the structured tool-calling contract
how a real API describes a tool:
{
"name": "calculator",
"description": "Evaluates a basic arithmetic expression.",
"parameters": {
"type": "object",
"properties": {
"expression": { "type": "string" }
},
"required": ["expression"]
}
}how the model asks to call it:
{
"tool_calls": [
{
"name": "calculator",
"arguments": { "expression": "240 * 0.15" }
}
]
}what: write the tool-picker if/else logic in python.
why: this exact decision — which tool does this request need? — is what the JSON contract above formalizes for real APIs.
how: check for math trigger words first, then lookup words, and fall back to notepad.
predict first: what should pick_tool("what's 12 times 8?") return?
finish pick_tool() so it returns 'calculator', 'search', or 'notepad' for each request. stuck? there's a hint button.
try this
Ask (or read, in scripted mode) for something that needs 2 different tools in sequence — a calculation AND a lookup. Notice the model has to decide the ORDER itself, and has to correctly read the observation from tool #1 before deciding what tool #2 needs.
checkpoint
1. In an agent loop, who actually executes the tool the model asks for?
2. Why do real tool-calling APIs demand strict JSON instead of letting the model just describe what it wants in plain English?
recap card — keep this
agent = LLM in a loop: think → pick tool → observe → repeat until done.