An agent loop is how a language model becomes an AI agent: the model reads its context, writes text that may contain an action, ordinary software carries that action out, and the result is added back to the context before the model runs again. Every capability an agent has, and every way it fails, traces back to four parts of that loop: what goes into the context, which actions exist, what software runs them, and what makes the loop stop.
Each turn of the agent loop has four steps:
- Perceive. The model reads its whole context: instructions, the task, and everything that has happened so far.
- Reason. The model writes text. Some of that text may be a structured request to do something.
- Act. Ordinary software, called the harness, carries out the request.
- Observe. The result is appended to the context, and the model is called again.
To see why that loop has to exist at all, start one step earlier, with what a language model can do on its own.
Table of Contents
A language model can only produce text
Start with the model by itself. A language model reads a sequence of tokens and writes a continuation. That is the whole job. It has no hands, no network connection, and no memory beyond the tokens it is given in that call.
Called once, a model can only answer. Ask it the price of a laptop and it will produce a plausible sentence, but it cannot look the price up, because looking something up is an action, and the model cannot act.
How an AI agent differs from a chatbot
A chatbot and an agent can use the very same model. The difference is what happens after the model writes its reply.
- In a chatbot, the model answers once and stops. A person reads the answer and decides what to ask next.
- In an agent, the reply can be a request to do something. Software carries it out, feeds the result back, and calls the model again, with no person in the middle, until the task is done or a limit is hit.
The real difference is control flow, not the number of calls. A chatbot can also call tools or look up documents, and many systems chain several model calls along a path a developer fixed in advance; Anthropic’s guide calls those workflows. In an agent, the model chooses each next action based on what the last one returned, and keeps going until the task is done. That is what lets an agent finish multi-step work on its own, and it is also why an agent needs limits a chatbot never did.
In September 2025, Simon Willison argued that “agent” had finally become usable jargon and proposed a one-line definition: “An LLM agent runs tools in a loop to achieve a goal.” He noted that the goal matters because it implies a stopping condition, so these are not infinite loops. Anthropic’s engineering guide from December 2024 describes agents the same way, as “LLMs using tools based on environmental feedback in a loop.” Both definitions put the loop at the center.
That gives a useful test for anything called an agent: does the model choose the next step, or does code written in advance? The pipelines I build in n8n are workflows by this test. Code decides every next step, and the model fills in one step at a time. Often that is the right design.
What is an agent loop?
An agent loop is a model called repeatedly, where each call can request an action, ordinary software performs it, and the result becomes part of what the model reads next. Here is each step in plain terms.
Perceive
Perception in an agent loop means reading the context. The word comes from the classic textbook definition of an agent as something that perceives its environment and acts on it (Russell and Norvig); for a language model, the environment it perceives is the text in front of it. At each step, the model reads every token it is given: the system instructions, the descriptions of the tools it can use, the user’s task, and every earlier action and result. Whatever is in that context shapes the decision. Whatever is missing from it does not exist for the model.
Reason
The model writes text. With most model APIs today, a tool request comes back as a structured tool-call object rather than prose, but the principle is the same: the model only asks, and other software acts. Usually some of it is reasoning about what to do next, and some of it may be a structured request to use a tool. If the task needs planning, the planning happens here too, written out in the model’s text.
Act
Text cannot change anything in the world, so something outside the model has to read the request and carry it out. That something is the harness: ordinary code that parses the model’s text, checks it, calls a real function, and captures the result. The model proposes. The harness acts. Every real effect an agent has passes through code that a person wrote and can control.
Observe
The model needs the result to decide what to do next, and it can only learn something by reading it. So the harness appends the action and the result to the context and calls the model again. Then the agent loop starts over at perceive.
This think, act, observe shape is often called ReAct, after the 2022 paper by Yao et al. that showed language models do better when they interleave reasoning with actions and observations than when they only reason or only act. Some guides split the loop into five stages by adding a separate plan step. It is the same loop with more of the reasoning written down.
An employee who only works by message
Think of a capable new employee who works entirely by message. You send a request. They think, then send back either an answer or a request to a colleague: “please look up order 1182.” The colleague does it and replies. The employee reads the reply, thinks again, and sends another request, until they can answer you.
The employee never touches anything directly. Every effect on the world goes through a colleague, and everything they learn about the result comes back as a message. In this picture, the employee is the model, the colleagues are the tools, and the message thread is the context.
The analogy breaks in one important place. A human employee remembers yesterday. The model remembers nothing between calls except what is in the thread in front of it. If a fact is not in the context at this step, the model does not know it.
Why the loop is the whole agent
Here is the mechanism, one step at a time.
Start with the action itself. Suppose the model’s output contains a structured request like this:
{"tool": "get_price", "args": {"item": "laptop"}}
The harness can parse that, call a real get_price function, and capture what it returns. The model has proposed an action and the harness has executed it.
Next, the result must go back in, so the call must repeat. The model cannot learn the price by any route other than reading it. So the harness appends the result to the context and calls the model again. A single call becomes an agent loop.
Written as an equation, with context , action , and observation at step :
What each symbol means:
- is everything the model sees at step : instructions, the task, and all earlier actions and observations.
- is the model, viewed as a rule for choosing an action given the context.
- means “is sampled from.” The model’s output is drawn from a probability distribution, so the same context can produce different actions on different runs.
- is the world outside the model: tools, files, websites, and people.
- means append. The new context is the old context plus the action plus its result.
That recurrence is the agent. Everything else people build on top, such as planning, memory, and teams of agents, is a variation on three things: what goes into , which actions exist, and how many loops run. Every agent framework wraps this same recurrence, which is why the best way to judge a framework is by how clearly it lets you see and control each piece.
Agent loop vs harness: who decides when to stop
The agent loop and the harness are easy to confuse because they are so tightly coupled. The loop is the cycle: perceive, reason, act, observe. The harness is the code that runs the cycle. It builds the context, calls the model, parses and checks the requested action, executes it, appends the result, and decides whether to go around again. “Agent harness” has become the common industry name for this code; Anthropic’s engineering team, for example, used it in a November 2025 post on long-running agents (checked 26 October 2026).
Why the model cannot be trusted to stop itself
An agent loop without a guaranteed exit can run forever. Agents normally stop when the model writes a final answer instead of another action. But nothing forces the model to do that. It may keep searching for something it will never find, or repeat a call that fails the same way every time. Each error is just another observation, and nothing in an observation makes the model stop.
So there are two kinds of stopping. The model can propose that the task is done by writing a final answer. But a guaranteed stop, on steps, time, or spend, has to live in the harness, in code that runs whatever the model writes.
The hard limits every harness needs
A sound harness sets limits the model cannot override:
- Maximum steps: how many times the model can be called in one run.
- Maximum tokens: how much the run can read and write in total.
- Maximum wall-clock time: how long the run can take, start to finish.
- Maximum spend: how much money the run can cost.
When a limit is hit, the harness should stop and tell the user clearly which limit was reached, instead of failing silently. Two more checks are common in practice. One stops the run when the same error repeats, since retrying an identical failure teaches the model nothing new. The other hands the decision to a person when the stakes are high.
What one missing limit cost me
I run a daily research pipeline in n8n that pulls new q-fin and gr-qc papers from arXiv, filters them by keyword score, and asks a local model (qwen3:4b through Ollama) to write a first-principles analysis of each relevant paper. It is a workflow, not an agent, since code decides every step. But it hit exactly this problem.
With the model’s thinking mode turned on (think: true), a single analysis call ran for more than 30 minutes. Nothing capped how much the model could write, and nothing limited the run’s total time. The fix was to turn thinking off and cap the output at 2,000 tokens (num_predict: 2000). Because the model runs locally, the bill was time rather than money. The lesson carries straight over to agent loops: without a hard cap on output and on time, one step can eat the whole run.
Why tokens read grow with the square of the steps
Each step appends an action and an observation, and each new call rereads the whole context from the start. That simple fact has a large effect on cost.
Say the starting context (system instructions, tool descriptions, and the task) is tokens, and each step adds about tokens. Then the model reads tokens at step . Adding that up over steps gives the total tokens read:
where:
- is the tokens in the system instructions, tool descriptions, and task.
- is the average tokens added per step (the action plus the observation).
- is the number of model calls.
The first term grows in step with . The second term grows with the square of , and for long runs it dominates.
Here are the numbers for a starting context of tokens and tokens per step:
| Steps (n) | Tokens read at the last step | Total tokens read |
|---|---|---|
| 5 | 4,000 | 15,000 |
| 10 | 6,500 | 42,500 |
| 20 | 11,500 | 135,000 |
| 40 | 21,500 | 470,000 |
Going from 10 steps to 20 takes the total from 42,500 tokens to 135,000, more than three times as much for twice the steps. The exact ratio depends on where you start: doubling from 2 to 4 steps multiplies tokens read by about 2.4, and the ratio creeps toward 4 only for long runs.
Treat this as a baseline model of input tokens, not a law of agent cost. It assumes every call rereads the full context and each step adds about the same amount. Real bills also depend on output tokens, prices, prompt caching (which makes reread tokens cheaper on many APIs), and the size of each observation. And a long context does not just cost more, it also tends to degrade the model’s attention, which is why a long-running agent loop usually compacts its context.
The practical rule: budget an agent with , not with “number of calls times the cost of one call.” With the numbers above, the naive estimate for 20 steps is 20 × 2,000 = 40,000 tokens. Under this model, the real figure is 135,000.
One run, traced step by step
Here is a complete three-step run. The labels show who did what: USER is the request, THINK is the model’s reasoning, ACT is the action it requested, OBSERVE is what the harness returned, and RESULT is the outcome with the arithmetic checked.
USER What do 3 laptops cost including 18% tax?
THINK I do not know the current laptop price; I should look it up, then compute.
ACT
get_price(item="laptop")OBSERVE
{"item": "laptop", "price": 899.0}THINK Three laptops at 899.00 is 2,697.00; with 18% tax multiply by 1.18. Use the calculator rather than doing arithmetic in my head.
ACT
calculator(expression="3 * 899.0 * 1.18")OBSERVE
{"result": 3182.46}RESULT “Total with 18% tax: 3,182.46.” Check: 3 × 899 = 2,697; 2,697 × 1.18 = 2,697 + 485.46 = 3,182.46.
Count the calls. The model was called three times: once to request the price, once to request the calculation, and once to write the answer. The harness ran two tools. The third model call is the one that stops the agent loop, by writing a final answer instead of another action. Every one of those calls reread the growing context, which is the effect from the previous section in miniature.
The whole loop in about 30 lines of Python
The agent loop really is this small. The code below runs offline with only the Python standard library. Instead of calling a hosted model, it uses a scripted stand-in that pattern-matches on the context, so the output is the same every time. The loop, the tools, the stop condition, and the error handling are exactly what you would write around a real model.
import json
# --- Tools: ordinary functions the harness can run ---------------------------
PRICES = {"laptop": 899.00, "monitor": 249.50}
def get_price(item): return {"item": item, "price": PRICES[item]}
def calculator(expression): return {"result": round(eval(expression, {"__builtins__": {}}), 2)}
TOOLS = {"get_price": get_price, "calculator": calculator}
# --- A scripted stand-in for the language model (the policy) ------------------
# A real agent would send `context` to a model API; here we pattern-match on it.
def model(context):
last = context[-1]["content"]
if "price" not in last and "result" not in last:
return {"tool": "get_price", "args": {"item": "laptop"}}
if '"price"' in last:
price = json.loads(last)["price"]
return {"tool": "calculator", "args": {"expression": f"3 * {price} * 1.18"}}
return {"final": f"Total with 18% tax: {json.loads(last)['result']}"}
# --- The loop: perceive -> reason -> act -> observe ----------------------------
def run_agent(task, max_steps=10):
context = [{"role": "user", "content": task}]
for step in range(1, max_steps + 1):
action = model(context) # reason
if "final" in action: # stop condition
return action["final"], step, context
try:
result = TOOLS[action["tool"]](**action["args"]) # act
except Exception as e: # errors are observations too
result = {"error": str(e)}
context.append({"role": "assistant", "content": json.dumps(action)})
context.append({"role": "tool", "content": json.dumps(result)}) # observe
return "stopped: step limit reached", max_steps, context
answer, steps, ctx = run_agent("What do 3 laptops cost including 18% tax?")
print(answer, "| model calls:", steps, "| context messages:", len(ctx))
tokens_read = lambda n, T0=2000, d=500: n * T0 + d * n * (n - 1) // 2
print(tokens_read(10), tokens_read(20)) # 42500 135000
Running it prints:
Total with 18% tax: 3182.46 | model calls: 3 | context messages: 5
42500 135000
Three lines carry most of the lesson:
for step in range(1, max_steps + 1)is the harness owning the stop. Even if the model never writes a final answer, the agent loop ends aftermax_stepscalls with a clear message.- The
tryandexceptturn a tool failure into an observation. A missing item becomes{"error": ...}in the context, which the model can read and react to, instead of an exception that crashes the run. - The two
context.appendlines are the observe step. They are also why the context grows on every turn.
One shortcut to know about: the calculator uses Python’s eval with built-ins removed. That is fine for a demo where the input is scripted, but a real harness should never run model-written expressions with eval. Use a small arithmetic parser that accepts only numbers and the operators you need, and check every tool name and argument before running anything.
Compare that with an agent loop written as while True that only exits when the model says it is done. It works in a demo. But if the model never says it is done, nothing ends the run.
Why agents get stuck in loops
Many agent failures that look mysterious are really agent loop failures: the model got the attention, and the loop was treated as an afterthought. From the outside, the symptoms look like this:
- The agent runs for hours. There is no limit on steps, tokens, or spend, so a confused agent keeps going.
- A tool error crashes the whole run. The harness raises the exception instead of returning it to the model as an observation it could react to.
- Nobody can say what the model saw at step 7. The context, action, and observation were never logged, so a failure cannot be traced to its cause.
- The budget was far too low. It was estimated as steps times the cost of one call, while tokens read grow with the square of the steps.
- The model gets credit or blame it does not deserve. A capability that really comes from a tool is credited to “the model,” or a failure that comes from the harness is blamed on it.
The worst case combines two of these: no step limit, and a tool that returns the same error on every call. The model may keep retrying identical requests, and since each call rereads the growing context, token consumption and cost grow roughly with the square of the steps. A harness limit on steps, repeated errors, or spend is the only guaranteed exit.
To see what this looks like in practice, someone on Reddit recently posted an incident in r/SaaS:

In short: a three-person B2B SaaS team lets customers run agents on its infrastructure and pays the model bill itself. One night, a customer’s agent hit a tool that kept returning an error. The agent decided the fix was to retry with a slightly different prompt, and did so about 31,000 times between 1:12 a.m. and 6:50 a.m., roughly 90 model calls a minute for more than five hours. It spent $4,700 in tokens for a customer on a $400-a-month plan, and the team ended up absorbing most of the cost. This is the team’s own account, which we have not verified independently.
Here is how this could have happened. Every part of that story maps onto the agent loop. Each error went back into the context as an observation, so the model kept proposing new fixes, and because every retry was slightly different, nothing looked like an exact repeat. The harness had no maximum retry count per tool and no step limit per run. The team did have a global rate limit and alerts on total spend, but nothing per customer, so one runaway loop could run all night without being noticed. Their fix is the set of harness limits described above: a per-customer budget checked before every model call, a soft alert at 1x the plan and a hard stop at 2x, and a maximum retry count for each tool call.
What to do when you build one
- Write the agent loop yourself before adopting a framework, or at least read it closely. It is a few dozen lines, and once you know them, every framework becomes easier to read.
- Enforce stopping in the harness. Set a maximum on steps, tokens, time, and spend, and tell the user clearly when a limit is hit.
- Limit what tools can do. Give each tool only the access it needs, require human approval for consequential actions such as sending, deleting, or paying, and treat text that comes back from tools as data, not instructions. A web page or file can contain text written to steer the model.
- Return tool errors to the model as observations. Let the model try to recover instead of crashing the run.
- Log the full context, action, and observation at every step. The trajectory, meaning the full record of a run, is your main debugging tool.
- Budget with , not with “number of calls times cost per call.”
Test yourself
- Conceptual: why can a language model, which only produces text, change things in the world when it is part of an agent?
- Quantitative: an agent’s context starts at tokens and grows by tokens per step. How many tokens does it read over steps?
- What would happen if a harness had no step limit and a tool began returning the same error on every call?
Answers
- Because the harness around the model treats certain structured parts of the model’s text as requests and carries them out with ordinary software, such as API calls, file operations, and database queries, then feeds the results back. The model proposes; the harness acts. Every real-world effect passes through code someone wrote and can control.
- = 15 × 3,000 + 800 × (15 × 14)/2 = 45,000 + 800 × 105 = 45,000 + 84,000 = 129,000 tokens.
- The model could keep retrying the same or similar calls forever, since each error is just another observation. The run would consume tokens and money without bound, with tokens read growing with the square of the steps, and would never return to the user. A harness limit on steps, repeated errors, or spend is the only guaranteed exit.
Sources
- Shunyu Yao et al., “ReAct: Synergizing Reasoning and Acting in Language Models,” arXiv:2210.03629 (2022; ICLR 2023). https://arxiv.org/abs/2210.03629
- Erik Schluntz and Barry Zhang, “Building effective agents,” Anthropic (19 December 2024). https://www.anthropic.com/engineering/building-effective-agents
- Simon Willison, “I think ‘agent’ may finally have a widely enough agreed upon definition to be useful jargon now” (18 September 2025). https://simonwillison.net/2025/Sep/18/agents/
- Justin Young, “Effective harnesses for long-running agents,” Anthropic (26 November 2025; checked 26 October 2026). https://www.anthropic.com/engineering/effective-harnesses-for-long-running-agents
- Stuart Russell and Peter Norvig, Artificial Intelligence: A Modern Approach, 4th ed. (Pearson, 2020).
Written by Kauntey Acharya. More about this site on the About page.
