Architectureagent looptoolsstep limitdefault choiceReAct

Single Agent

One model, one loop, a small set of tools, a hard step limit — the default architecture until measurements prove it insufficient.

Interview question
Progress

The shape

A single agent is one LLM running the loop from The Agent Loop: it receives a goal, reasons about the next action, calls a tool, observes the result, and repeats until it decides the task is done or a limit stops it. There is exactly one context window, one system prompt, one tool list. Everything the agent knows is in that window.

That is the entire architecture. No routing, no delegation, no shared state store. The user talks to the agent; the agent talks to tools; tool results come back into the same context. Most production "agents" that actually work are this shape with 3–8 tools and a step cap around 10–25.

Its simplicity is the point. Every other architecture in this module adds a moving part to fix a specific, measured problem with the single agent: context that is too large, tools that are too many, or tasks that decompose into independent sub-goals. Start here and add parts only when a trace shows the problem.

Single agent
toolunder budgetexceededanswerUserAgent (LLM + loop)Tool call or final answer?Tools (search, db, http)Tool result → contextStep / token budgetFinal answer
UserLLMAgentToolDataDecisionHumanGuardrail

The loop and its limits

The loop is a while with three exits: the model returns a message without a tool call, the step counter hits max_steps, or the cumulative token/cost budget is exceeded. Each iteration appends the assistant message and the tool result to the message list, so context grows monotonically — after 20 steps with verbose tools you can easily be at 60k tokens.

Step limits are not an optimisation; they are the only thing standing between you and an infinite loop when a tool keeps returning something the model does not understand. Set them low (10–15) and raise them per task type when traces justify it. Pair the step cap with a wall-clock timeout and a cost ceiling, as described in Budgets, Limits and Termination.

Tool results should be truncated or summarised before entering context. A 200 KB HTTP response pasted verbatim is the most common way a single agent silently degrades: the relevant sentence lands in the middle of the window and the model stops attending to it.

A minimal single-agent loop with the three exits made explicit.
1def run_agent(goal: str, tools: dict, max_steps: int = 12, max_tokens: int = 80_000) -> str:
2 messages = [{"role": "system", "content": SYSTEM}, {"role": "user", "content": goal}]
3 used = 0
4 for step in range(max_steps):
5 resp = llm(messages, tools=list(tools.values()))
6 used += resp.usage.total_tokens
7 if used > max_tokens:
8 return "Stopped: token budget exceeded"
9 if not resp.tool_calls: # exit 1: model is done
10 return resp.content
11 for call in resp.tool_calls:
12 out = tools[call.name].run(**call.args)
13 messages.append({"role": "tool", "id": call.id, "content": truncate(out, 4000)})
14 return "Stopped: step limit reached" # exit 2: step cap

Why it is the default

One context means one place to look when something goes wrong. A trace of a single agent is a linear list of (thought, tool call, result) triples; you can read it top to bottom and point at the step where it went wrong. Compare that with a supervisor whose sub-agents each have their own hidden context.

One model call per step is also the latency floor. Every architecture that adds a router, a planner, or a verifier adds at least one more LLM round trip. If a single agent hits p95 latency targets, no multi-agent variant will beat it on speed.

Cost is bounded by max_steps × average context size. That is a number you can compute before launch, which is not true of recursive delegation schemes.

  • Complexity: low — a loop, a tool registry, three exit conditions.
  • Latency: one model call per step; total = steps × (model latency + tool latency).
  • Cost: grows quadratically with steps because the whole (growing) context is re-sent each turn.
  • Reliability: good on tasks with ≤ 10 steps; degrades as context fills with stale tool output.
  • Debuggability: best of all architectures — one linear trace.

Where it breaks

The single agent fails in three predictable ways. First, tool overload: past roughly 15–20 tools the model starts choosing wrong tools or hallucinating arguments, because the tool descriptions crowd the context and look alike. Second, context saturation: long multi-step tasks fill the window with intermediate results, and the goal from turn one gets lost in the middle. Third, no isolation: a prompt injection in one tool result contaminates every later step.

Each failure has a specific successor architecture. Too many tools → Router Architecture or Supervisor Architecture to partition them. Context saturation on a fixed task shape → Workflow State Graph with explicit state instead of a growing transcript. Contamination → separate agents with separate contexts and an approval gate.

Before reaching for any of those, check whether the task is agentic at all. A fixed sequence of three tool calls does not need a loop; it needs three lines of code and one LLM call for the fuzzy part, as Choosing the Right Abstraction argues.

Key points

  • One LLM, one context, one loop, a small tool set — everything else is added to fix a measured problem.
  • Three exits: no tool call, step cap, token/cost cap. All three must exist.
  • Cost is roughly quadratic in steps because the growing context is re-sent every turn.
  • Truncate tool results before they enter context; verbatim payloads are the top cause of silent degradation.
  • Best debuggability of any architecture: the trace is a single linear list.
  • Breaks at ~15–20 tools, at long horizons that saturate context, and whenever tool output is untrusted.

When to use — and when not to

Use it when
  • Tasks that finish in ≤ 10–15 tool calls with a tool set you can list on one screen.
  • Prototyping any agentic product — get the single agent measured before adding parts.
  • Interactive assistants where latency matters and one context is enough (coding helpers, ops chatbots).
  • When the team is small and needs to debug by reading one trace.
Avoid it when
  • The task is a fixed pipeline — use plain code plus one or two LLM calls instead.
  • More than ~20 tools, or tools with overlapping descriptions — partition them first.
  • Long-running jobs (hundreds of steps) where a growing transcript blows the context budget.
  • Untrusted inputs (web pages, emails) feed directly into an agent with write-capable tools.

Failure modes

  • Infinite loop: a tool returns the same error each step and the model retries forever — the step cap is the only defence.
  • Wrong tool selection once the tool list grows past what the model can discriminate.
  • Goal drift: after many steps the original instruction is far from the end of context and gets ignored.
  • Verbose tool results fill the window; later reasoning quality drops without any explicit error.
  • Cost surprise: 30 steps at 50k tokens each is 1.5M tokens for one request.

Tradeoffs

Complexity
low → high
Latency
low → high
Cost
low → high
Reliability
poor → strong
Debuggability
hard → easy

Reliability is high on short tasks and falls with step count and tool count.