What an AI Agent Is: Five Classic Types, Two Rival Definitions
The vacuum world broken four times, each break earning one of the five classic agent types. Then one tool turns a 39-token call into 420.
On this page
Here is the same question, asked twice of the same model, with the same weights and greedy decoding. The only difference is that the second time there was one tool in the catalogue.
no tools in the catalogue
turn 1 prompt= 39 out= 8 finish=stop TEXT "The capital of France is Paris."
=> model calls=1 prompt tokens=39 output=8 wall=974 ms
one tool in the catalogue: get_temperature(city)
turn 1 prompt= 185 out= 20 finish=tool_calls CALL get_temperature({"city": "Paris"})
tool get_temperature -> {"city":"Paris","celsius":11}
turn 2 prompt= 235 out= 18 finish=stop TEXT "The capital of France is Paris. It is
currently at 11 degrees Celsius."
=> model calls=2 prompt tokens=420 output=38 wall=6,685 msOne call became two. Thirty-nine input tokens became 420, a factor of 10.8. Under a second became almost seven. And the answer picked up a fact nobody asked for, from a tool the model chose to call for a question that never mentioned the weather.
The second system is what most of the industry in 2026 calls an agent. Or it is not one, depending on which of the two most widely read definitions you open — and those two do not say the same thing. One does not even agree with itself.
That disagreement is this chapter. It is not a vocabulary quarrel: the two definitions draw the boundary on different axes, and the axis you pick decides what you build and what you are billed. Both stand on an older taxonomy, and the cheapest way to earn it is to build the worst agent in the world.
Show details
What this chapter needs from the earlier ones.
- Chapter 13 measured what a single call costs in time; this chapter multiplies that by the number of turns.
- Chapter 15: the prompt is the model's complete state, because nothing survives the call.
- Chapter 16: input tokens grow with the square of the conversation.
- Chapter 18: the tool catalogue, and the round trip in which the model asks and your code executes.
No tensors here. The chapter is TypeScript, where Chapter 14's language rule puts it, and its loop is the direct ancestor of Chapter 23's.
A robot with two rooms
Link to the section: A robot with two roomsThe oldest example in the field is a vacuum cleaner in a world of two squares, A and B, each either clean or dirty.1 It survives in every textbook because it is the smallest world in which an agent can be right or wrong.
The percept is a pair — where I am, and whether it is dirty here — and the actions are SUCK, LEFT and RIGHT. The whole program is one line.
type Percept = { dirty: boolean; where?: "A" | "B" };
type Action = "SUCK" | "LEFT" | "RIGHT";
const textbook = (p: Percept): Action =>
p.dirty ? "SUCK" : p.where === "A" ? "RIGHT" : "LEFT"; Run it against every starting configuration of the two-square world:
A dirty, B dirty, start A -> steps=3 clean=true
A clean, B dirty, start A -> steps=2 clean=true
A dirty, B clean, start B -> steps=2 clean=trueThat is a simple reflex agent: it acts on the current percept alone, with no memory of anything before it. Not a toy category — a thermostat is one, and so is a single call to a language model with no conversation attached.
Now break it the way reality does. A real vacuum robot has a dirt sensor and a bumper, not a square labelled A under the carpet. Take the location out of the percept and change nothing else:
const dirtOnly = (p: Percept): Action => (p.dirty ? "SUCK" : "RIGHT");A dirty, B dirty, start A -> steps=3 clean=true still dirty=0
t=0 at=A percept={dirty:true} -> SUCK
t=1 at=A percept={dirty:false} -> RIGHT
t=2 at=B percept={dirty:true} -> SUCK
A dirty, B clean, start B -> steps=500 clean=false still dirty=1
t=0 at=B percept={dirty:false} -> RIGHT
t=1 at=B percept={dirty:false} -> RIGHT
t=2 at=B percept={dirty:false} -> RIGHT
t=3 at=B percept={dirty:false} -> RIGHTThe same program, two squares. From one starting state it finishes in three steps; from another it drives into the right-hand wall five hundred times and would keep going until the battery died. It cannot perceive the difference between the two situations, so it cannot act differently in them. Russell and Norvig state the general result in one line: infinite loops are often unavoidable for simple reflex agents in partially observable environments.1
There is a fix that costs one line and no memory, worth measuring before we reach for anything cleverer.
let seed = 12345;
const rnd = () => ((seed = (seed * 1103515245 + 12345) & 0x7fffffff) / 0x7fffffff);
const coin = (p: Percept): Action => (p.dirty ? "SUCK" : rnd() < 0.5 ? "LEFT" : "RIGHT"); Two thousand runs of an all-dirty corridor at three sizes, one seeded generator throughout:
| rooms | mean steps | median | worst of 2,000 | never finished |
|---|---|---|---|---|
| 2 | 4.0 | 4 | 13 | 0 |
| 4 | 16.6 | 14 | 81 | 0 |
| 8 | 68.7 | 52 | 306 | 0 |
Randomisation removes the loop entirely. It also costs: eight rooms need fifteen moves if you know what you are doing, and this agent averages 68.7 and once took 306. That is the whole chapter in miniature. Every capability we add buys correctness in a case the previous agent could not handle, and charges for it in a currency you have to name first.
Naming the parts, now that they are needed
Link to the section: Naming the parts, now that they are neededAn agent perceives its environment through sensors and acts through actuators. The agent program is the function from percepts to actions — every listing above is one. The percept sequence is everything perceived so far, and a simple reflex agent ignores all of it but the last item.
Rationality is the word most articles get wrong, and getting it right makes the rest of this chapter usable. An agent is not rational or irrational in itself. Russell and Norvig define a rational agent as one that, for each possible percept sequence, selects the action expected to maximise its performance measure, given the evidence of that sequence and whatever built-in knowledge it has.1 The performance measure is not inside the agent: it belongs to the designer, and rationality is only defined relative to it.
The specification is conventionally written as four things, PEAS: performance measure, environment, actuators, sensors.
| the vacuum robot | a support agent in production | |
|---|---|---|
| Performance measure | squares clean, per unit of battery | tickets resolved, per dollar, without escalation |
| Environment | the floor, the dirt, the furniture, the carpet | the ticket queue, your database, the customer |
| Actuators | wheels, suction | tool calls |
| Sensors | dirt sensor, bumper | the user's message, tool results |
Notice which row is the odd one out. Almost every team building agents in 2026 writes down E, A and S — the tool schemas, the integrations, the message format — because the code will not run without them. Almost nobody writes down P. Without it, "our agent is doing well" has no meaning anyone can check, and "rational" cannot be applied to the system at all, only to a demonstration. Chapter 29 is about turning P into a number, and this is why it exists.
┌───────────────────────── the environment ─────────────────────────┐
│ │
│ ┌──────────────────────── the agent ─────────────────────┐ │
│ │ │ │
───┼──►│ sensors ──► the agent program ──► actuators ─────┼──────┼──►
percept │ │ action
│ └────────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────────┘
▲
the performance measure lives out here, in the head of
whoever built the thing, and the agent cannot change itTask environments are further classified along seven axes, five of which decide most of the difficulty here: fully or partially observable, deterministic or not, episodic or sequential, static or dynamic, known or unknown.1 An agent talking to real tools over a real network is in the hard corner of all five — non-deterministic even at temperature zero (Chapter 17), and, the underestimated one, unknown, because you have no reliable model of what your own tools do to the world. That is why Chapter 23's loop needs error handling more than planning.
Adding memory, and finding the next wall
Link to the section: Adding memory, and finding the next wallReal floors are not one-dimensional, so promote the world to a plan. Hash marks are walls, asterisks are dirt, and the robot starts in the middle chamber:
col 0 1 2 3 4 5 6
row 0 * . . # . . *
row 1 . # . # . # .
row 2 . # . S . # . S = the robot starts here
row 3 . # . # . # .
row 4 * . . # . . *The obvious upgrade is memory. The agent keeps a map: every square it has stood on and every square where the bumper fired. Its rule is to walk into an adjacent square it has not visited — right, then down, then left, then up — and back off when everything around it is known. This is a model-based reflex agent: it maintains internal state from the percept history, so it can act on what it cannot currently see.
It is a real improvement, and still not enough:
5,000 steps allowed -> steps=5,000 distinct squares visited=13/25 still dirty=2/4Five thousand moves, half the floor never seen. The map is correct and the rules are correct. What the agent cannot do is use the map to go somewhere: its rules only ever answer "which of my four neighbours should I step into", so once it runs out of unvisited squares next to it, it has no way to express the thought there is an unvisited square eight moves away and I would like to be standing on it. It knows where it is. It does not know where it wants to be.
A goal, and then a reason to prefer one route over another
Link to the section: A goal, and then a reason to prefer one route over anotherA goal-based agent holds, on top of its model of the world, a description of the situation it wants to bring about, and chooses actions by searching over sequences of them until it finds one that ends there. Goals turn action selection from a lookup into a search.
The goal is "no dirty square remains". The search is a breadth-first walk to the nearest dirty square, and the path it returns is the plan.
goal-based (fewest moves) -> moves=27 battery=52 still dirty=0
from 2,3 -> 4,6 via 5 moves: 2,3 2,4 3,4 4,4 4,5 4,6
from 4,6 -> 0,6 via 4 moves: 4,6 3,6 2,6 1,6 0,6
from 0,6 -> 4,0 via 10 moves: 0,6 0,5 0,4 1,4 2,4 2,3 2,2 3,2 4,2 4,1 4,0
from 4,0 -> 0,0 via 4 moves: 4,0 3,0 2,0 1,0 0,0Twenty-seven moves, floor clean. But look at the battery column and the last leg of the plan. Column 0 is carpeted: crossing a carpeted square costs six units of battery, a tiled square one. The agent went home up column 0 because that is four moves instead of eight, and those four carpeted moves cost 24 where the eight-move detour would have cost 13.
It cannot do otherwise. A goal is a binary test: the floor is clean or it is not. Every plan that ends with a clean floor satisfies it equally, so when several succeed the agent has nothing to choose between them. Preferring one success over another needs a number over outcomes, and that number is a utility function. An agent that maximises it is a utility-based agent.
The change to the code is one term inside the search. Breadth-first search counts moves; make it count cost instead and you have Dijkstra's algorithm and a different agent:
const nd = dist.get(k)! + (byCost ? cell.cost : 1); // <- the entire differencegoal-based (fewest moves) -> moves=27 battery=52 still dirty=0
utility-based (cheapest route) -> moves=31 battery=41 still dirty=0
from 4,0 -> 0,0 via 8 moves: 4,0 4,1 4,2 3,2 2,2 1,2 0,2 0,1 0,0Four extra moves, eleven fewer units of battery: twenty-one per cent cheaper. Same goal, same map, same code but for one term. The two agents differ only in what they are trying to be good at, and they take different routes home.
This is also the first point where the agent needs something it cannot produce. Someone has to decide what a unit of battery is worth relative to a move. Utility is the performance measure written in a form the agent can compute with, and writing it is the designer's job. When people say an agent "optimised the wrong thing" they almost never mean a bug. They mean this line was written carelessly.
The fifth type, and the way it goes wrong
Link to the section: The fifth type, and the way it goes wrongNow let dirt come back. Four rooms get dirty again at four different rates, and the agent is never told them. It visits one room per tick and sees only that room. The performance measure is room-ticks spent dirty over 4,000 ticks — lower is better.
A learning agent, in the textbook's decomposition, is any of the above plus three parts: a learning element that changes the agent, a critic that tells it how the agent is doing against a fixed performance standard, and a problem generator that proposes actions worth trying for what they would teach.1 Three policies in the same environment. The first does not learn; the second and third learn the same thing and use it differently.
| policy | dirty-room-ticks over 4,000 | versus the patrol |
|---|---|---|
| fixed round-robin patrol, no learning | 2,290 | — |
| learner A: estimate each room's dirt rate, then go where dirt is likeliest | 11,820 | 5.2× worse |
| learner B: same estimates, weighted by how long since the last visit | 1,576 | 31 % better |
The hidden rates were 0.35 for the kitchen, 0.05 for the hall, 0.02 for the study and 0.01 for the attic — and learner A found them. It correctly identified the kitchen as the dirtiest room in the house, then went to the kitchen every tick for the rest of the simulation while the other three sat dirty forever. It is five times worse than not learning at all, and it is not broken.
The lesson is the utility section's. Learner A maximised "probability that the room I am about to visit is dirty". The performance measure was "room-ticks spent dirty". Different numbers; the second is what the critic was scoring, and nobody told the agent. Learner B multiplies the same learned rate by the time since the last visit — the dirt it expects to find rather than the chance of finding any — and beats the patrol it started from.
One implementation detail decided the result. In the first version of learner B, a room where no dirt had turned up in three visits got a rate of exactly zero — and zero times anything is zero, so it was never visited again and the estimate could never be corrected. Smoothing the fraction, successes plus one over trials plus two, turned 11,895 into 1,576. "Not observed yet" and "measured and came out zero" are different claims, and a system that stores them in the same field makes decisions it cannot undo.
The five types, and what they are in 2026
Link to the section: The five types, and what they are in 2026 1 simple reflex percept ────────────────────────────────► rules ────► action
2 model-based percept ──► [state] ──────────────────► rules ────► action
3 goal-based percept ──► [state] ──► [goal] ──────► search ───► action
4 utility-based percept ──► [state] ──► [goal] ──► [U] ──► argmax ► action
5 learning all of the above, plus [critic] ──► changes the parts aboveEvery one of the five is in production today under another name.
| classic type | what it carries between percepts | its 2026 shape | what it cannot do |
|---|---|---|---|
| simple reflex | nothing | one model call with no history: a classifier, an extraction endpoint, a single-turn completion | anything that depends on the previous turn |
| model-based reflex | internal state built from the percept history | a chat: the transcript, resent whole on every call | choose where the conversation should end up |
| goal-based | state plus a description of the wanted situation | a reason-and-act loop with a stopping condition2 | prefer one successful plan over another |
| utility-based | state, goal, and a number over outcomes | evaluator–optimiser loops, and ranking candidate answers by a written criterion (Chapter 25) | invent the criterion |
| learning | all of it, plus a critic and a problem generator | Reflexion, which writes its own lessons into an episodic buffer instead of updating weights;3 persistent user memory (Chapter 24) | choose the standard the critic scores against |
Two rows are closer than an analogy, in a way that costs money.
The chat is a model-based reflex agent whose model is not internal. In the textbook the state is a variable inside the agent program. In a chat it is the transcript: it lives on your side, is re-sent in full on every call, and is rebuilt from scratch inside the model each time. That is Chapter 16's quadratic bill, and it is the same object the textbook drew as a box labelled "state". Here is the difference, measured on one follow-up question with and without the two messages before it:
with the transcript prompt=67 "The current temperature in Lisbon, Portugal is 15°C."
without the transcript prompt=29 "Lisbon is the capital of Portugal, not a city in Portugal."The same model, the same three words of user input, and the second one is the corridor robot driving into the wall. There were no tools in that run, so the 15 is invented — but the state is what makes the follow-up mean anything at all. You rebuild it every time and pay 2.3× the input tokens for it on a two-turn conversation. Chapter 16 measured what that multiplier reaches by turn forty.
Reflexion is a learning agent that changes its input rather than its program. In the textbook decomposition the learning element modifies the performance element. Reflexion leaves the weights alone and writes reflective text into an episodic buffer that the next attempt reads.3 The learning element is a prompt, the memory a database row, the performance element a frozen model — and the diagram is the textbook's, unchanged.
And here is the honest limit of the mapping. The five types classify the agent program. In 2026 that program is split down the middle: some of it is your code, some of it is inside weights you did not train. When a model decides on its own to call a tool, is the goal test in your program or in the model? The taxonomy has no answer, because when it was written there was nowhere else for it to be — and that question is exactly where the two modern definitions part company.
Answering, calling and stopping, in one trace
Link to the section: Answering, calling and stopping, in one traceThe definitions are arguments about behaviour, and much easier to judge with a trace in front of you.
The loop below sends the conversation to a model; if the reply contains a tool call it executes the tool, appends the result and sends the whole thing again. It runs against a local Qwen2.5-0.5B-Instruct behind an OpenAI-shaped endpoint on this machine — the seam from Chapter 14, so the loop neither knows nor cares what is behind the port.
const BASE = process.env.LLM_BASE_URL ?? "http://127.0.0.1:8799/v1";
async function loop(question: string, maxTurns = 6) {
const messages: Msg[] = [
{ role: "system", content: SYSTEM },
{ role: "user", content: question },
];
for (let turn = 1; turn <= maxTurns; turn++) {
const reply = await call(messages, TOOLS);
const calls = reply.choices[0].message.tool_calls ?? [];
messages.push(reply.choices[0].message);
if (!calls.length) return messages;
for (const c of calls) {
const out = runTool(c.function.name, JSON.parse(c.function.arguments));
messages.push({ role: "tool", name: c.function.name, content: out });
}
}
throw new Error("turn cap reached");
}Two lines carry the whole idea, and both are marked; the rest is bookkeeping. All three behaviours are visible in one run. Asked something it can do itself, the model answers. Asked something it cannot, it calls:
=== a question the model cannot answer, one tool available
turn 1 prompt= 187 out= 21 finish=tool_calls CALL get_temperature({"city": "Oslo"})
tool get_temperature -> {"city":"Oslo","celsius":4}
turn 2 prompt= 238 out= 12 finish=stop TEXT "The current temperature in Oslo is 4
degrees Celsius."
=> model calls=2 prompt tokens=425 output=33 wall=6,257 ms
=> stopped by: the model produced text instead of a callAnd it stops — the third behaviour, and the easiest to miss, because it looks like nothing happening. The loop ends because turn 2 came back without a tool call. Nobody decided that; the model did, by emitting prose. The termination condition of this program is the sign of an absence.
Two more runs are worth the space. Asked to compare two cities, the model issues both tool calls in one turn, gets both readings back, and gets the comparison wrong:
turn 1 prompt= 188 out= 43 finish=tool_calls CALL get_temperature({"city": "Oslo"}),
get_temperature({"city": "Lisbon"})
tool get_temperature -> {"city":"Oslo","celsius":4}
tool get_temperature -> {"city":"Lisbon","celsius":19}
turn 2 prompt= 284 out= 13 finish=stop TEXT "Oslo is currently warmer than Lisbon
at 4°C."The tools worked. The parallel call worked. The loop worked. The answer is false, with both correct numbers sitting in the transcript. Wrapping a model in a loop does not make it reason; it gives a model that is wrong the ability to act on being wrong — which is Chapter 30 in advance, and half of Chapter 29.
Now delete the marked return and let the loop run to its cap instead. Same question, same model:
turn 1 prompt= 187 out= 21 CALL get_temperature({"city": "Oslo"})
turn 2 prompt= 238 out= 12 TEXT "The current temperature in Oslo is 4 degrees Celsius."
turn 3 prompt= 261 out= 30 TEXT "Could you please specify the exact location you're..."
turn 4 prompt= 302 out= 14 TEXT "Sure! Could you tell me which city you're interested in?"
turn 5 prompt= 327 out= 35 TEXT "I'm sorry, but I need more details to provide an..."
turn 6 prompt= 373 out= 12 TEXT "Which city would you like to know the temperature for?"
=> model calls=6 prompt tokens=1,688 output=124 wall=25,261 ms stopped by: turn capFour times the input tokens, four times the wall clock, and an ending in which the agent has forgotten what it was asked and is interrogating the user about a question they answered on turn one. The correct answer was on screen at turn 2, and every turn after it made the transcript worse.
So an agent is not a loop. It is a loop plus a rule for leaving it, and this one has exactly one such rule. Chapter 23 finds five, and shows what breaks when each is missing.
The two definitions, side by side
Link to the section: The two definitions, side by sideBoth quoted rather than paraphrased, because the paraphrases are where the confusion is manufactured.
Definition one puts the boundary at who controls the flow. Anthropic's Building effective agents names the ambiguity and rules on it:
"At Anthropic, we categorize all these variations as agentic systems, but draw an important architectural distinction between workflows and agents: Workflows are systems where LLMs and tools are orchestrated through predefined code paths. Agents, on the other hand, are systems where LLMs dynamically direct their own processes and tool usage, maintaining control over how they accomplish tasks."4
The test is a question about your source code: who chose the next step? A switch in your program: workflow. The model: agent. The same document says agents "are typically just LLMs using tools based on environmental feedback in a loop" — which is exactly the listing above.
Definition two puts the boundary at independence from the user. OpenAI's A practical guide to building agents opens its definitional page like this:
"While conventional software enables users to streamline and automate workflows, agents are able to perform the same workflows on the users' behalf with a high degree of independence. Agents are systems that independently accomplish tasks on your behalf."5
Two sentences later, on the same page, it excludes:
"Applications that integrate LLMs but don't use them to control workflow execution—think simple chatbots, single-turn LLMs, or sentiment classifiers—are not agents."5
Read those quotations in order. The opening sentences draw the line at independence: does this thing go off and finish the job without me? The fourth draws it at control of execution, which is Anthropic's line exactly. Different tests, same page, and there are real systems on which they disagree.
There is a vocabulary collision underneath, and it causes arguments in real meetings. In the first document a workflow is an architecture, and it is the thing that is not an agent. In the second a workflow is "a sequence of steps that must be executed to meet the user's goal" — the job itself, which every agent has one of. "We replaced the workflow with an agent" is coherent under the first definition and close to meaningless under the second.
Three systems, classified twice
Link to the section: Three systems, classified twiceThree systems that exist in 2026, under both definitions.
A coding agent in a terminal
Link to the section: A coding agent in a terminalYou describe a task; it reads files, runs the test suite, edits, runs them again, and stops when they pass or when it gives up. Nothing in your code decides that the next step is "run the tests" — the model does, from what the last tool returned.
Definition one: agent, because the model directs its own process. Definition two: agent, because it independently accomplishes the task, recognises completion and hands control back. Both documents cite this shape as their central example.
A nightly ticket-triage pipeline
Link to the section: A nightly ticket-triage pipelineFor each new support ticket, three model calls in a fixed order — classify, extract the fields, draft the reply — and then it sends. No model ever chooses what happens next; a for loop does. It runs at 03:00 and nobody watches it.
Definition one: not an agent. It is prompt chaining, listed by name as a workflow. Definition two: both answers. By the opening sentences it independently accomplishes tasks on your behalf; by the fourth it does not use the model to control workflow execution, and is excluded. This system is why you read the whole page rather than the pull quote.
A chat assistant with a search tool
Link to the section: A chat assistant with a search toolOne user turn. The model decides for itself whether to search before answering, then answers and waits for you.
Definition one: agent, because the model dynamically directs its own tool usage on results from the environment, which is the stated test. Definition two: not an agent, because there is no independence — one turn, then it hands back — and "simple chatbots" are in the exclusion list by name.
Two of the three change sides. That is not a failure of either document. It is a warning about a kind of meeting in which two people who agree completely about what a system does spend an hour disagreeing about what to call it.
The way out is two axes, not one
Link to the section: The way out is two axes, not oneThe definitions collide because each collapses two independent questions into one word. Separate them and the disagreement becomes a table, which is more useful than a verdict.
| your code chooses the next step | the model chooses the next step | |
|---|---|---|
| a person is watching every turn | a form with a model inside it: classifiers, extraction, single-turn completion | a chat with tools — definition one says agent, definition two says no |
| nobody is watching until it is done | a pipeline — definition two's opening says agent, its fourth sentence says no | everyone agrees: an agent |
Each definition disputes a different cell, and the other two are not in dispute at all. So when the label matters — in a contract, a risk review, a postmortem — the two sentences worth writing are not "is it an agent" but who chose the next step and who was watching. Both are answerable by reading code, neither needs anyone's definition, and together they carry every consequence the label was standing in for.
None of this is new. Wooldridge and Jennings surveyed the competing senses of "agent" in 1995;6 Franklin and Graesser asked this chapter's question in 1996, gathered the definitions in circulation and found that they disagreed.7 A 2023 survey still defines agents from first principles — "artificial entities that sense their environment, make decisions, and take actions"8 — because nothing settled existed to cite, and CoALA describes parts rather than drawing a boundary at all.9 Thirty years of declining to agree says the word is doing more than one job.
An agent is N calls, not one
Link to the section: An agent is N calls, not oneNow the consequence that arrives before the philosophy, which is the bill.
Every measurement here has the same shape. The single call cost 39 input tokens; the same question with one tool cost 420 across two calls; the loop with its stopping rule removed cost 1,688 across six. The growth is worse than linear, because turn n carries every previous turn with it: the prompt column of that six-turn run reads 187, 238, 261, 302, 327, 373. Chapter 16 derived that the total is and fitted the curve on a real conversation. An agent turns every task into that conversation, whether or not a human ever sees it.
If those measured token counts had gone to a commercial endpoint at the rates Chapter 16 read on 6 September 2026 — $2.00 per million input tokens and $12.00 per million output — the four runs price out like this:
| run | model calls | input tokens | output tokens | cost |
|---|---|---|---|---|
| the question, no tools | 1 | 39 | 8 | $0.000174 |
| the same question, one tool in the catalogue | 2 | 420 | 38 | $0.001296 |
| a question that needs the tool | 2 | 425 | 33 | $0.001246 |
| the same, with the stopping rule removed | 6 | 1,688 | 124 | $0.004864 |
Row two against row one is the number to keep. Seven and a half times the cost, for a worse answer to a question the model already knew. Nothing was misconfigured: a tool existed, so the model used it — and Chapter 18's finding, that the price of a catalogue and not its accuracy is what hurts, has its cheapest demonstration here with a catalogue of one.
Which is why the useful half of both documents is the half about not building this. Anthropic's is blunt: find the simplest solution possible and add complexity only when needed, which "might mean not building agentic systems at all", since agentic systems "trade latency and cost for better task performance" and "for many applications, optimizing single LLM calls with retrieval and in-context examples is usually enough".4 Its case for an agent is narrow: open-ended problems where you cannot predict the number of steps and cannot hardcode a path, in an environment you trust, accepting "higher costs, and the potential for compounding errors".4 OpenAI's screen is the mirror image — complex judgement, unmaintainable rule sets, unstructured data — and ends the same way: "otherwise, a deterministic solution may suffice".5
So, in this chapter's taxonomy: a fixed number of steps in a fixed order is a pipeline, and calling it an agent will not make it faster. If the number of steps depends on what you find on the way, you want a loop — and you buy that flexibility with N calls, a quadratic transcript, and a system that can be wrong N times instead of once.
Where this goes next
Link to the section: Where this goes nextYou now have the taxonomy, both modern definitions, the two axes that make them compatible, and a short loop that answers, calls and stops.
That loop has one way to end: the model stops asking for tools. Chapter 23 breaks it on purpose, seven times, and each break adds a piece. An impossible task, and it never ends — a turn cap. A night of running, and the bill arrives — a budget in dollars. A tool that fails — an error the model can act on. The same call twice — an idempotency key. A file it should not have touched — a human approval. A restart halfway — session persistence. A tool that takes three minutes in silence — progress and cancellation. What comes out is a harness, the file the rest of this course runs on.
Which leaves the question this chapter's disputed diagonal was really about. A loop that decides its own next step has to decide when to stop, and we have just watched what happens when it cannot: six turns, four times the bill, and an agent interrogating the user about a question it had already answered. Stopping is not one condition. How many are there, and which one fires first?
Sources and method
Link to the section: Sources and methodLilian Weng's LLM Powered Autonomous Agents (2023) is the best-known decomposition of a language agent into planning, memory and tool use, and is the right next read alongside the two vendor documents; its three components are Chapters 23, 24 and 18 of this course in that order.
Every number in this chapter was produced on this machine and nothing was estimated. The corridor, the floor plan, the four agents that walk it and the three patrol policies are the TypeScript above, run on Node 22; the randomised agent's figures are means over 2,000 seeded runs each and the patrol figures are single seeded runs of 4,000 ticks. The model traces come from Qwen2.5-0.5B-Instruct in float32 on CPU with greedy decoding, served over loopback by a small local Python endpoint that loads the weights and speaks the OpenAI chat-completions shape — the seam again, with the tensors on the Python side and the loop on the TypeScript one — so the token counts are that model's tokenizer and the latencies are that machine's. The only figures taken from elsewhere are the two prices in the cost table, which are the rates Chapter 16 read from OpenAI's pricing page on 6 September 2026, applied here to locally measured token counts as an illustration and not as an observed invoice.
References
Link to the section: References-
Russell, S. and Norvig, P. Artificial Intelligence: A Modern Approach, 4th edition, chapter 2, Intelligent Agents. Source of the vacuum world, the PEAS specification, the definition of rationality relative to a performance measure, the seven properties of task environments, the five agent types used here, and the observation that infinite loops are often unavoidable for simple reflex agents in partially observable environments. The book's companion code is
aimacode/aima-pythonon GitHub (8,806 stars, last pushed 30 June 2026, read 7 September 2026) — worth naming precisely for what it is. It is a book's accompanying repository, not a reference implementation that other projects build on the waykarpathy/micrograd(17,412) andkarpathy/nanoGPT(62,852) are. That is why this chapter cites and links it rather than translating it, and why the ecosystem argument that kept Chapter 5 in Python does not apply here: nothing in this chapter touches a tensor, and the loop written above is the direct ancestor of Chapter 23's. ↩ ↩2 ↩3 ↩4 ↩5 -
Yao, S., Zhao, J., Yu, D., Du, N., Shafran, I., Narasimhan, K. and Cao, Y. ReAct: Synergizing Reasoning and Acting in Language Models. arXiv:2210.03629 (2022). The interleaving of reasoning traces and actions that the goal-based row of the mapping table refers to. ↩
-
Shinn, N., Cassano, F., Berman, E., Gopinath, A., Narasimhan, K. and Yao, S. Reflexion: Language Agents with Verbal Reinforcement Learning. arXiv:2303.11366 (2023). The paper's own summary of the mechanism is the reason it maps onto the learning agent: it reinforces agents "not by updating weights, but instead through linguistic feedback", with agents that "verbally reflect on task feedback signals, then maintain their own reflective text in an episodic memory buffer to induce better decision-making in subsequent trials". ↩ ↩2
-
Anthropic, Building effective agents, 19 December 2024,
anthropic.com/engineering/building-effective-agents, read 7 September 2026. Source of the workflow/agent distinction quoted above, of the umbrella term "agentic systems", of the description of agents as "typically just LLMs using tools based on environmental feedback in a loop", of the guidance to find the simplest solution possible and that this "might mean not building agentic systems at all", and of the case for and against agents, including "higher costs, and the potential for compounding errors" and the recommendation of stopping conditions "such as a maximum number of iterations" to maintain control. ↩ ↩2 ↩3 -
OpenAI, A practical guide to building agents, pages 4 to 7, read 7 September 2026. Source of "Agents are systems that independently accomplish tasks on your behalf", of the exclusion of "simple chatbots, single-turn LLMs, or sentiment classifiers", of the definition of a workflow as "a sequence of steps that must be executed to meet the user's goal", of the two core characteristics of an agent, of the three components — model, tools, instructions — and of the screening criteria for when to build one, ending in "otherwise, a deterministic solution may suffice". ↩ ↩2 ↩3
-
Wooldridge, M. and Jennings, N. R. Intelligent Agents: Theory and Practice. The Knowledge Engineering Review, volume 10, issue 2 (1995). The survey that split the field's usage into a weak notion of agency — autonomy, social ability, reactivity, pro-activeness — and stronger notions borrowing mental vocabulary. Read today, it is a record of the same argument this chapter's two documents are still having. ↩
-
Franklin, S. and Graesser, A. Is It an Agent, or Just a Program? A Taxonomy for Autonomous Agents. Proceedings of the Third International Workshop on Agent Theories, Architectures, and Languages, Springer (1996). Cited here for what it is rather than for a quotation: a survey that gathered the definitions of "agent" then in circulation, found that they disagreed, and proposed a taxonomy to replace the argument. Thirty years later the argument is in better-designed documentation and is otherwise unchanged. ↩
-
Xi, Z. et al. The Rise and Potential of Large Language Model Based Agents: A Survey. arXiv:2309.07864 (2023). Quoted above for its opening definition, "AI agents are artificial entities that sense their environment, make decisions, and take actions", which is the textbook definition restated in 2023 because there was no agreed modern one to cite. ↩
-
Sumers, T. R., Yao, S., Narasimhan, K. and Griffiths, T. L. Cognitive Architectures for Language Agents. arXiv:2309.02427 (2023). Organises language agents as "modular memory components, a structured action space to interact with internal memory and external environments, and a generalized decision-making process to choose actions", and situates them explicitly in the history of symbolic AI and cognitive science. The memory taxonomy returns in Chapter 24, where the three-store table is its practical shadow. ↩