Skip to main content

09 · Agents and AI engineering

From LLM app to agent

What makes a system an agent — the model decides the next step — and why that freedom needs limits.

12 minCase study: docket (opens in new window)

Most AI features are a single question and answer: a program sends text to a model and uses the reply. An works differently. The model runs in a loop: it looks at a goal, picks an action, sees the result, and picks the next action, until it decides it is done or a limit stops it. That shift moves a decision from your code to the model, and almost everything about building agents follows from it.

This lesson covers four ideas: one test that separates applications, and agents; the loop that makes an agent work; the limits that make that loop safe to run; and why the loop is, above all, a security concern.

One question: who decides the next step?

Picture a cook. One cook follows a recipe step by step. Another is handed a full fridge and told "make dinner", and decides what to do next based on what they find. The same difference sorts AI systems into three kinds.

LLM application: the model answers. The program calls a model at fixed points, and every other step is code the team wrote. Summarizing each support ticket and saving the summary is an example. If the model fails, the damage is bounded: a bad summary gets saved.

Workflow: the model fills slots in a fixed plan. A workflow is a sequence of steps, some done by a model and some by ordinary code. It can branch, run in parallel and retry, but every possible path exists in the code before anything runs; you could draw the whole map by reading it. For example, the model labels a ticket "billing", code fetches the billing help articles, and the model drafts a reply from them.

Agent: the model chooses the action. Now take "fix this failing test in a repository you have never seen". Nobody knows in advance which files to read or how many it will take, so no fixed map works. An agent is a system in which a model, inside a loop, chooses the next action from a goal and what it has seen so far, until it decides it is done or something outside it stops it.

Kind Who picks the next step Map known in advance
LLM application code yes, a straight line
Workflow code yes, with branches
Agent the model, within limits no

Labels like "assistant" or "agentic workflow" blur this line, and that has a cost: call an agent a workflow and you underestimate its risk.

The loop, and why the simple version breaks

An agent acts through tool calls: the model asks for something to be done (read a file, run a command, look up an order) and the program does it; the details are in Tool calling and harnesses. The cycle around those calls is the . Follow the arrows: the model decides, the program acts, the result returns to the model.

  1. Goalwhat the agent must achieve
  2. Model decidesanswer, or ask for an action
  3. Program actsruns the tool the model asked for
  4. Resultgoes back to the model

back to the model, round after round

The agent loop. It ends when the model asks for no action and gives a final answer, or when a limit stops it.

The simplest version is a dozen lines of code: repeat forever, run whatever the model asks, stop when it stops asking. It works in a demo. In production it breaks in predictable ways:

  • Nothing forces it to stop, so a confused model keeps spending.
  • Nothing limits volume or waiting. One reply can request hundreds of actions; one stuck action blocks everything.
  • Nothing checks what runs, whatever inputs the model wrote.
  • It trusts every reply, even a malformed one or one cut off by the length limit.
  • It saves carelessly. A crash loses the work, and saving at the wrong moment can store an action without its result.
  • It leaves no record of what happened.

Limits decided in code

A loop you can operate knows every way it can end. Only one is success: the model gives a final answer and asks for nothing more. Every other exit is a limit or a failure, and each should have a name, be reported, and be enforced by the program, not requested in the .

Three choices show that limits shape the loop rather than decorate it:

  • The tool-call limit is checked before a batch, not during it. If the model asks for five actions and three remain, none run. Running some would leave requests without results, a state the history must never hold.
  • A cut-off reply is never executed. It may contain a half-written action.
  • The overall time limit is checked between rounds, so it cannot interrupt a model call already underway; a separate per-request limit covers that.

Put together, one round of docket's loop looks like this:

In docket

  1. Check limitsrounds, time, tokens, tool calls
  2. Ask the modela final answer ends the turn
  3. Check the batchover the limit, none of it runs
  4. Check each callone checkpoint, then run it
  5. Save as one unitthe request and all its results

next round

Every step can end the turn, and each way out has a name. A reply cut off by length stops at the second step and is never run. Source: core/agent_loop.py

The loop is a security surface

Traditional software guards the entrance: check the input once, then trust your own code. In an agent, the thing choosing the next action is a model that reads everything in its context: the user's request, but also files, web pages, command output and other tools' replies. Any of those can carry text the model takes as an instruction. The diagram compares the two: one checked entrance for traditional software, many unchecked ones for an agent.

  • Traditional softwarechecked once, at the door
    • Input
    • Check
    • Trusted code
    • Action
  • Agentnew inputs every round
    • Request, files, web, tool output
    • Model reads it all and decides
    • Action
Traditional software checks one entrance and then trusts its own code. An agent's next action can be shaped by anything it read, in any round.

Each round brings in new material, often fetched by the model itself, and is a fresh chance for hostile text to get in and for an action to run. So checking only the first request does not protect the agent, and you cannot count on the model always deciding well. Control has to sit where a model's decision becomes a real action, on every round. That point is a policy enforcement point. In docket it is a single function every tool call passes through (Security: Layered & Convention-Based), covered in Tool calling and harnesses; threats such as are in Sandboxing and agent security.

Putting it into practice

  • Ask first whether the task needs autonomy. If you can draw the map before running, build a workflow: cheaper, easier to test, with a predictable worst case.
  • Keep agents for tasks whose path can't be known up front, and plan how to govern them from day one.
  • Set limits on rounds, actions, time and spend in code, and make every stop report its reason.
  • Put checks where actions run, not only at the entrance.

Go deeper

docket's documentation shows these ideas in a working loop:

  • DOCKET Architecture explains why docket runs the loop itself instead of wrapping another program, and how its tasks, retries and timeouts work.
  • Security: layered and convention-based describes the check every tool call passes before it runs, which cannot be turned off, and how an unanswered approval denies itself.
  • ADR 0001: harness mode records how docket runs one agent's loop to completion for another program and reports how it ended, including when an approval had nobody to answer it.

Key takeaways

  • LLM applications, workflows and agents differ in who decides the next step.
  • An agent is a model in a loop choosing actions toward a goal, within limits set by code.
  • If you can draw the map before running, you probably need a workflow.
  • An operable loop names and reports every way it can stop; those limits shape the loop and can't be bolted on later.
  • Every round adds untrusted input, so control belongs where a decision becomes an action.

Check yourself

A system labels a ticket with a model and, depending on the label, calls one of three fixed tools. Is it an agent?

No. Every possible path is written in code before anything runs; the model only fills a slot. It is a workflow with branches.

The model asks for five actions, but only three remain under the limit. Why run none instead of three?

Running only some would leave the history with requests that have no result, a broken state. The batch runs whole or not at all.

Why is checking the user's first request not enough to keep an agent safe?

Each round brings new material (files, web pages, tool results) that the model reads and that can carry hostile instructions. Control has to apply to every action, not just the first input.