Vocabulary for this course

The terms the chapters assume, in plain words. You can open this from any chapter.

action space
The full set of moves an agent can choose from, usually the list of tools it is given.
agent
A program that repeats a loop: read the state, choose a move, look at the result, then decide again.
budget
A hard limit on how many steps, seconds or moves a run may spend before it must stop.
delegation
Handing a smaller task to another agent, with its own instructions, tools, budget and required result shape.
guardrail
Code that checks a proposed move against the rules before it runs, and can refuse it or ask a person.
loop
The repeated cycle of choosing a move, carrying it out and reading the result, which makes a program an agent.
model
The trained program that reads text and chooses what to say or do next.
observation
What came back from a tool or a step, added to the state for the next decision.
plan
A written list of steps for the task, which can be revised when a step fails or the facts change.
scratchpad
The working notes for one run: the plan, what was tried and what came back, discarded when the run ends.
state
The record of the question, the plan and the observations so far, passed to the model on every turn.
sub-agent
A separate agent given one bounded job, its own tools and its own budget, whose answer returns to the caller.
tool
A named function an agent may ask to run, with declared inputs and a result the loop can read.
trace
The ordered record of every decision, tool use and result in a run, used to explain what happened.

AI agents from the ground up

The loop and its limits

Every agent loop needs three exits: answered, out of budget, and going nowhere. The third one is the one people forget.

Part 3 of 10

Intermediate15 min readBack to Courses

Three exits, not one

The happy exit is the model returning an answer. The budget exit is the step or token limit. The third is progress: the agent is still acting but the state has stopped changing, which means it will act forever if allowed.

Without the third exit, a model that keeps searching the same query looks busy and burns the budget. Detecting “no progress” is what turns that from a timeout into a decision.

A worked example: the agent searches for “refund policy”, gets no results, and searches again with the same query. The step count rises, the trace looks active, and nothing new enters the state. Hashing the observation and comparing it with the set already seen turns that repetition into an exit on the second identical result, long before the step budget would have fired.

What counts as progress

A new tool call is not progress by itself. Progress is a new observation: a document not seen before, a value that changed, a subtask marked done. Hash the observations and compare them with what is already in the state.

The check is cheap and catches the most common failure of a looping agent, which is repeating an action that already failed. Two identical observations in a row is enough to stop and report.

The comparison should be on the observation, not on the action. Two different queries that return the same empty result are the same lack of progress, and a model that rephrases its search is still stuck. Hash what came back, including the empty case, and let the second identical result end the run. That is the difference between a loop that looks busy and one that is doing work.

The three exits

for step in range(max_steps):
    action = model.decide(state)
    if action.kind == "answer":
        return answer(action)
    observation = run_tool(action)
    if observation in state["seen"]:
        return stopped("no progress", state)
    state["seen"].add(observation)
    state["steps"].append(observation)

return stopped("step limit", state)

Detect a loop that goes nowhere

The agent keeps searching the same thing. Run it and confirm it stops on the repeated observation rather than the step limit; then make the search return something new each time and watch it finish.

Output
Click "Run" to execute your code

Budget the thing you are afraid of

A step limit is a proxy. What you actually care about depends on the agent: tokens for a research run, seconds for an interactive one, effects for anything that writes. An email agent with a ten-step limit can still send ten emails, which is the number that matters. Count the effects directly and set the limit below the point where a mistake becomes expensive.

A common mistake is setting the budget after watching a successful run and choosing a number slightly above it. That budget fits the demo and fails the adversarial input, which is the only input that will test it. Work backwards from the worst acceptable outcome: one refund, two emails, thirty seconds, then make the loop stop before that.

Budgets are more than steps

A step limit bounds the number of model calls. A token budget bounds the cost of those calls, which is what you actually pay. A wall-clock limit bounds the time a user waits. A tool-call limit bounds the side effects.

Pick the ones that match the risk. A read-only research agent needs tokens and time; an agent that can send email needs a count of effects and probably an approval.

Do not use the framework’s recursion limit as your budget. It is a crash guard, not a decision: it tells you the loop was unbounded, not that the agent finished.

A stopped run is still a result

When the loop hits a limit, return the state: what was tried, what was found, why it stopped. A caller can then show the partial answer, ask a human, or retry with a bigger budget.

Throwing an exception instead loses all of that. The user sees an error and the trace is gone, which is the worst combination for something that may have already had the answer in its notes.

Design the return value before the loop: answer, stopped reason, steps taken, and the observations that mattered. Every caller then has the same shape to render, whether the run succeeded or ran out of budget. That consistency is what lets a UI show a partial answer instead of an error page.

Stop on time, not only on steps

The clock is injected so the example is deterministic. Run it and confirm the loop stops on the time budget before the step limit; then slow the tool down and watch the same budget fire earlier.

Output
Click "Run" to execute your code

Check what you learned

One question at a time. A wrong answer explains itself — take another go.

Part 1 of 5

What are the three exits an agent loop needs?