The agent loop
How an agent differs from a chatbot: a goal, a loop, tools, and a stopping condition — plus the failure modes of each.
Chatbot versus agent
A chatbot maps one message to one reply. An agent is given a goal and runs a loop: decide the next action, take it, look at the result, repeat until the goal is met or a limit is hit. The model is still the decision-maker; the loop and the tools are what you build.
goal ──▶ [ think ] ──▶ [ act: tool call ] ──▶ [ observe result ]
▲ │
└────────────── not done yet ◀─────────────┘
│
done / limit → final answer| Piece | Your responsibility |
|---|---|
| Goal | Written unambiguously, with the definition of done |
| Planner | Prompt + model choice; usually the least reliable part |
| Tools | Real functions with validated inputs and clear errors |
| Loop control | Max steps, timeouts, budget |
| Termination | How you decide it is finished — and how you fail safely |
💡
The single most valuable design decision is a crisp definition of "done". Agents without one do not stop; they wander until a step limit kills them.
A minimal loop you can reason about
def run_agent(goal, tools, max_steps=8):
messages = [{"role": "user", "content": goal}]
for step in range(max_steps):
reply = model(messages, tools=tools) # model may request a tool
if reply.tool_calls:
for call in reply.tool_calls:
try:
result = tools[call.name](**call.args)
except Exception as e: # give failures back to the model
result = {"error": str(e)}
messages.append(tool_result(call.id, result))
continue # let the model see the result
return reply.content # no tool call = it is answering
return "Stopped: step limit reached without a final answer."- Always cap the loop. Steps, wall-clock time and tokens — all three.
- Feed tool errors back as data. A well-described error often lets the model self-correct; a raised exception just ends the run.
- Log every step with its inputs and outputs. Without a trace, an agent failure is unfixable.
- Make tools idempotent where possible so a retry after a timeout cannot double-charge or double-send.
How agents fail
| Failure | Symptom | Mitigation |
|---|---|---|
| Looping | Same call repeated | Detect repeats, cap steps, vary the prompt |
| Tool misuse | Wrong arguments | Validate inputs; return precise errors |
| Over-broad action | Deletes or sends too much | Dry-run mode, scoped credentials, confirmation |
| Hallucinated success | Claims done, nothing happened | Verify with a real check, then report |
| Context overflow | Forgets the goal | Summarise history, keep the goal pinned |
⚠️
Give an agent the narrowest credentials that can do the job. An agent with production write access and a hallucination is an outage waiting for a trigger.
FAQ
Do I need a framework?
No. A loop, a tool dispatcher and a prompt are ~100 lines and you will understand every failure. Frameworks help when you need tracing, retries and many integrations — bring them in once the manual version works.
How many tools should one agent have?
As few as possible, with distinct names and descriptions. Ten overlapping tools confuse the model more than they extend it.
Related
Tools and function calling Using a model API
Last refreshed 2026-09-18.