Agent Loops

The agent loop is the thing that turns "LLM answers a question" into "LLM gets something done." It's also the thing that turns $0.002 in tokens into $40 in tokens when you look away. Most of agent engineering is designing the loop so it fails gracefully instead of expensively.

This page is a failure-mode catalogue. For the shape of the loop itself and which pattern (ReAct vs graph vs supervisor) to pick, start at AgenticWorkflowDesign.

The minimum loop

A working agent loop is six lines of pseudocode:

state = init(goal)
while not terminal(state):
    action = model(state)
    result = dispatch(action)
    state = append(state, action, result)
return extract_answer(state)

Every production problem comes from one of those six lines doing something slightly different from what you expected.

Failures by layer

The loop spans three layers — model, tools, state. Every failure lives in one of them.

Model-layer failures

Schema drift on tool calls. The model emits {"user_id": "42"} instead of {"user_id": 42}. Frequency: extremely high, especially under context pressure or after summarisation.

Hallucinated tool names. Model calls search_emails when your tool is email_search. Common when the context has been summarised and the tool spec evicted.

Response truncation at max_tokens. The model is mid-way through a tool call when it hits max_tokens and returns incomplete JSON. You get {"action": "update_record", "args": {"id": 42, "na and then nothing.

Rate-limit / 429 responses. The model API throttles you.

Non-determinism at temperature=0. Even at temp 0, outputs can differ between calls — batch size, load, and version drift produce small variances. Your eval comparing "prod output" to "expected output" will fail occasionally for reasons unrelated to your code.

Tool-layer failures

Retry on non-idempotent tools. Agent retries send_email because the first call timed out. Recipient gets two emails.

Slow tool blocking the loop. A fetch_document tool that normally takes 2s takes 40s, and your whole agent stalls. You're also likely blocking other concurrent agents.

Tool returns an implicit error. HTTP 200 with {"status": "failed"} in the body. The agent parses the outer success and proceeds on bad data.

Tool spec drift. Backend team adds a required field to create_ticket; your tool spec still says it's optional. Loop hangs on "missing required field."

State-layer failures

Silent context overflow. The oldest messages — including the original user goal — get truncated. The agent optimises for whatever it thinks the goal is now, which is "whatever the most recent message said."

Infinite replan loop. Plan → attempt → fail → replan → attempt same thing → fail → replan. Cost accrues linearly in steps.

Memory saturation with irrelevant history. A 30-step loop ends up with 80% of its context spent on tool responses from step 3.

Stale working memory. The agent noted "user is an admin" in turn 2; in turn 20 it's still acting on that assumption even though the user role field has actually changed.

Cost failure modes

These don't cause crashes, they cause bills.

Tool-response bloat. A search_docs tool returns 50k tokens of raw HTML on every call.

Verbose model reasoning. Chain-of-thought at every step with no control. You pay for every "Let me think step by step about whether to use tool A or B..." paragraph.

Prompt cache miss from rotating system prompt. Your system prompt includes current_time=2026-04-24T15:22:18Z. Cache hit rate: 0%.

Observability baseline

You cannot debug what you cannot see. Minimum telemetry per loop:

Without this you'll spend half your debugging time re-running the failing task trying to reproduce what happened.

Further reading