What an Agent Is
An agent is not a model, and it is not a prompt. It is a program that calls a model in a loop, hands it a set of tools it may ask for, executes what it asks for, feeds the result back, and decides when to stop. Four steps of control flow, written by you, wrapped around something that cannot remember or act on its own.
The word gets attached to at least four different products, and only one of them lets the model choose what happens next. That one costs more, fails differently, and is much harder to test than the other three. It is also the only one that handles work nobody could enumerate in advance. That is what makes it worth the trouble, and what makes it the subject of this book.
Four Things Called an Agent
The first is a chat assistant: one model call, no tools, a person reading the answer. The second is a retrieval application — fetch some documents, put them in the prompt, make one call. The third is a workflow with a model step, where your code owns the sequence and the model fills a slot in it: classify this ticket, draft this reply, extract these fields. All three are useful, cheap and predictable, and calling them agents mostly sells consulting.
The fourth is a loop where the model chooses the next action from a set you have given it, sees the result, and chooses again. That choice is the whole difference. In the first three the sequence of steps is fixed before the request arrives; in the fourth it is decided during the request, by a component that is not deterministic and cannot be stepped through in a debugger.
The Definition Used in This Book
An agent is a program that repeatedly sends a growing context to a model and receives either a final answer or a request to run a tool, executes the request, appends the result to the context, and repeats until a stopping condition. That is the definition every later chapter builds on, and it is all there is at the centre.
messages = [system_prompt, user_message] # decide -> act -> observe -> repeat while True: reply = model(messages, tools=TOOLS) messages.append(reply) if reply.stop_reason != "tool_use": return reply.text for call in reply.tool_calls: messages.append(run(call))
Read that in words: build a list of messages, call the model, and look at why it stopped. If it stopped because it wants a tool, run the tool, append what came back as another message, and go around again. If it stopped for any other reason, the loop is over. Everything this book adds — memory, retrieval, planning, limits, evaluation, permissions — is scaffolding bolted onto those few lines, and none of it changes their shape.
Who Holds Control
In a workflow, your code decides what happens next and the model contributes a value. In an agent, the model decides what happens next and your code decides what it is allowed to do. Control flow moves into a probabilistic component, and the guardrails move into the surrounding program.
That inversion is the reason the rest of the book exists. Once the model chooses the sequence, you can no longer enumerate the paths through your own system, so correctness has to be established by measurement over a set of cases rather than by reading the code. Ceilings, permissions and approval gates stop being polish and become the mechanism that bounds what a wrong choice can do.
What Each Half Contributes
The model brings judgement over unstructured language. It reads a rambling ticket that mentions three separate problems, notices that one of them is a billing error nobody classified for, and picks between two tools whose purposes overlap. Written as rules, that behaviour takes years and never quite works; the model does it out of the box, imperfectly, on the first afternoon.
Your code brings everything the model cannot do. It executes. It remembers between turns. It counts, enforces a limit, refuses an action, and writes an audit record. When people say an agent "decided" to refund a customer, what happened is that the model emitted a request and a dispatcher in ordinary code ran it — which is exactly why authorization belongs in that dispatcher and never in the prompt.
Autonomy Is a Dial
The same machinery runs at several settings. At the lowest, the agent drafts and a human sends. In the middle, it acts but pauses for approval before anything consequential. At the top, it acts alone within limits your code enforces. Sundry's support agent ends this book at the third setting for refunds under its $150 ceiling and the second above it, and that split is a product decision revisited properly in Chapter 12.
Nothing about the technology fixes the position on that dial. It is chosen by asking what happens the times the agent is wrong, how quickly a person would notice, and what it costs to undo — three questions worth answering in writing before the first tool that changes anything gets built.
Why the Distinction Is Operational
The moment the model owns sequencing, four things change at once. Cost becomes variable, because an easy ticket takes three model calls and a hard one takes eleven. Latency becomes multi-turn, so the customer waits for a chain rather than a single response. Testing stops being deterministic, because the same input legitimately produces different runs. And the blast radius becomes whatever the tools can reach, rather than whatever the code path allows.
Each of those four is a chapter later in this book: cost in Chapter 13, latency in Chapter 13, evaluation in Chapter 9, and the blast radius in Chapter 12. If a task does not need the model to choose — and most tasks do not — you can have none of those problems by writing a workflow instead, which is the argument Topic 04 makes with numbers.
Workflow — your code calls the model at fixed points and owns the sequence. Cost is predictable, the whole thing is testable with ordinary fixtures, and it fails in ways you can list. It cannot handle a case you did not anticipate.
Agent — the model owns the sequence, inside limits your code sets. It handles the long tail you could never enumerate, at the price of variable cost, multi-turn latency, and a far larger set of possible behaviours.
Choose the workflow whenever the steps are knowable. Most production systems that work well are workflows with one agentic pocket, and naming which shape you are choosing, and why, beats defaulting to either extreme.
- Building a loop for a task with three known steps — you buy multi-turn latency and non-determinism to solve a problem a
matchstatement already solved, and every failure is now harder to reproduce. - Calling the model's text output a decision without executing anything — a system that only produces suggestions is a drafting tool, and grading it on resolution rate or tool accuracy measures nothing real.
- Starting on a framework before writing the loop once by hand — you inherit somebody's opinions about memory, retries and prompt assembly that you cannot see, and the first production incident is exactly where you need to see them.
- Shipping without a turn limit because the demo always finished in three turns — the first genuinely ambiguous ticket runs until the context window or the budget stops it, whichever hurts more.
- Treating "agentic" as a quality grade rather than a control-flow choice — the design conversation turns into a status conversation, and nobody asks the only question that matters: who decides the next step.
- Write the loop by hand once, in the language you ship in, before evaluating any framework — Chapter 14 compares frameworks against something you have actually built.
- Decide explicitly who owns sequencing for each task and write it down: fixed steps go in code, open-ended judgement goes in the loop.
- Put a turn limit and a spend ceiling in the first version rather than the hardening pass — two lines, and they bound every failure mode in Chapter 8.
- Name the autonomy level in the product spec — suggest, approve, or autonomous within limits — so the approval design in Chapter 12 is a decision rather than an afterthought.
Knowledge Check
A support system classifies a ticket with one model call, fetches the order in code, and drafts a reply with a second model call. Is it an agent by this book's definition?
- No — the code owns the sequence, so it is a workflow with two model steps in it
- Yes — it makes more than one model call, which is what makes a system agentic
- Yes — it calls an external system between the two model calls, so tools are in use
- No — it becomes an agent only once it acts without asking a human first
What changes operationally the moment the model, rather than your code, decides the next step?
- Cost becomes variable, latency becomes multi-turn, testing stops being deterministic, and the blast radius becomes whatever the tools can reach
- The system becomes more accurate, because the model sees more of the task context than a fixed pipeline ever gets at any single step
- Costs fall, because the model skips the lookups a fixed pipeline would have run whether or not the ticket actually needed them
- Permissions stop mattering, because the model only ever requests the actions that the task in front of it genuinely requires
Who executes a tool when the model "calls" one?
- Your own code, which receives a structured request and decides whether to run it
- The model provider, which executes the function on its side and returns the result
- The tool schema, which is executable once the model has filled in its parameters
- The model itself, using the network access granted to it by the tool definition
Why does this book insist on a turn limit in the first version rather than the hardening pass?
- A loop with only "the model answered" as a stop condition has no termination guarantee at all
- Limiting turns improves answer quality by forcing the model to be more decisive
- Model providers reject requests from loops that do not declare a maximum turn count
- Prompt caching only applies to conversations with a known, fixed number of turns
You got correct