AnyLearn
All lessons
AIintermediate

Loop engineering in production: state, errors, and budgets

Once an agent loop runs past a few iterations the failure surface shifts: state bloats, tool calls fail in three distinct ways, retries multiply if you stack them wrong, and unbounded budgets rack up four-figure bills overnight. The state, errors, and budgets you need to make the loop survive contact with reality.

Updated · AI-authored, review-gated · how lessons are made

Not signed in: your progress and quiz score won't be saved.
Progress1 / 8

Three ways to carry state

Once your loop runs past a few iterations, the prompt is mostly prior turns. Three ways to manage that:

  • Full history — keep every turn verbatim. Highest fidelity, fastest to bloat. Fine for short loops (≤5 turns).
  • Sliding window — keep the last K turns plus the system prompt. Loses early context. Use when the task is local (debugging one file).
  • Scratchpad — keep one mutable summary the model rewrites each turn. Best for long multi-step work; trades fidelity for focus.

Most production loops use a hybrid: system prompt + user request + last K turns + a scratchpad of decisions. Don't pick one philosophy; pick what each piece of state earns its keep at.

Full lesson text

All 8 steps on one page, for reading, reference, and search.

Show

1. Three ways to carry state

Once your loop runs past a few iterations, the prompt is mostly prior turns. Three ways to manage that:

  • Full history — keep every turn verbatim. Highest fidelity, fastest to bloat. Fine for short loops (≤5 turns).
  • Sliding window — keep the last K turns plus the system prompt. Loses early context. Use when the task is local (debugging one file).
  • Scratchpad — keep one mutable summary the model rewrites each turn. Best for long multi-step work; trades fidelity for focus.

Most production loops use a hybrid: system prompt + user request + last K turns + a scratchpad of decisions. Don't pick one philosophy; pick what each piece of state earns its keep at.

2. Compaction in practice

Compaction is the act of replacing old turns with a shorter representation that preserves what later iterations actually need. The bare minimum to keep:

  • The user's original request.
  • Decisions the model has made ("chose Python over Bash").
  • Tool results that are still being referenced.

What to drop or summarize first:

  • Verbose tool output — a directory listing from turn 2 doesn't matter on turn 12.
  • Failed attempts — "tried X, got error Y" collapses to "X failed (Y)".
  • Repeated reasoning — three turns of "let me think" → one summary line.

A simple rule: when prompt size crosses 50% of the model's context window, summarize the oldest third. Re-run that rule each turn.

3. A compaction sweep

Old turns become one summary; recent turns stay verbatim; new turn appends.

flowchart LR
  A["Old turns 1-6"] --> B["Summarizer"]
  B --> C["1 summary line"]
  C --> D["Compacted history"]
  E["Recent turns 7-12"] --> D
  D --> F["Next prompt"]
  G["New observation"] --> F

4. Three kinds of tool failure

Tool calls fail in three distinguishable ways. The dispatcher should classify and respond, not just try/except: pass.

def dispatch(call):
    if not validate_args(call):
        return ToolError("malformed_args", "missing 'path'")
    try:
        return TOOLS[call.name](**call.args)
    except TransientError as e:
        return ToolError("transient", str(e), retry=True)
    except ToolFailure as e:
        return ToolError("unrecoverable", str(e))
  • Malformed args — feed the validator's message back so the model fixes the call.
  • Transient — 429s, network blips. Retry inside the dispatcher with backoff; the model doesn't need to see it.
  • Unrecoverable — "file does not exist." Surface to the model so it replans.

Hiding all three behind a generic "tool failed" string is how loops thrash for ten iterations on the same fixable typo.

5. Retries: pick one layer, not both

Retries can live in two places: inside the dispatcher (around one tool call), or around the whole loop (re-run the agent on failure). Pick one, not both blindly. Combining them silently multiplies attempts — three dispatcher retries × three loop retries = nine calls per failed tool, and the model still sees nothing useful.

Good layering:

  • Dispatcher retries — only for transient errors (429, 5xx, timeout). Cap at three with exponential backoff.
  • Model-visible retries — let the model see the unrecoverable error and try a different approach. This is the loop's job, not the dispatcher's.
  • Outer retries — only at the very edge, around end-to-end runs that hit a fatal harness bug. Rare.

If you can't draw the retry pyramid for your loop on a napkin, you have a bug waiting to happen on the next outage.

6. Four budgets, not one

Iteration cap alone isn't a budget. Stack four caps; the loop exits on whichever hits first:

CapWhy it existsTypical value
IterationsBounds the agent's number of decisions10–50
TokensBounds the prompt + completion bill500K–2M per run
WallclockBounds user-facing latency60–600s
DollarsFinal stop-loss when other caps lie5–50 per run

The dollar cap is the one teams forget — and it's the only one that survives a tokenizer change, a model price hike, or a misconfigured cap. Track cumulative usage * price on every API response. Exit immediately on cross. Log which cap fired; that telemetry is how you tune the other three.

7. Plan-act-reflect (and when it's noise)

Bare ReAct decides one action at a time. Plan-act-reflect adds two extra moves: an opening plan turn (the model lists steps before calling any tool), and a reflect turn after each action ("did that get me closer? what's next?").

When it pays off:

  • Multi-step branching tasks (debug → fix → re-test → refactor). The plan keeps the loop coherent across ten iterations.
  • Tasks the model misjudges in one shot. Reflection catches "I thought the test passed but I read the wrong output."

When it's pure noise:

  • Single-tool answers — the plan is one bullet, the reflection is empty.
  • Tasks under three iterations — overhead outweighs benefit.

Reach for plan-act-reflect when your bare-ReAct loops average more than five iterations; otherwise stay simple.

8. Self-correction loops

When a tool reports an unrecoverable error ("test failed: AssertionError on line 42"), feed the failure back to the model and let it retry. This is the self-correction loop — the agent's superpower for code, math, and structured-output tasks where you can mechanically check the answer.

Three rules:

  • Bound it. Cap self-corrections at two or three. If the model can't fix it in three tries, the next try won't help either.
  • Give the model the actual error. Stack traces, validator messages, type-check output — verbatim, not paraphrased.
  • Don't conflate with dispatcher retries. A 429 isn't a self-correction opportunity; an AssertionError is. Route accordingly.

Self-correction is what turns a 70% pass rate into a 90% pass rate on coding benchmarks. It's also where unbounded loops most often hide.

Check your understanding

The lesson ends with a 5-question quiz. Take it in the player above to see your score.

  1. Your loop just crossed 60% of its token budget on iteration 8 of an expected 20. What's the right move?
    • Truncate the user's original request to free room.
    • Summarize the oldest third of the history into one line and continue.
    • Switch to a model with a larger context window mid-run.
    • Disable the budget so the loop can finish.
  2. A tool call fails with a 503 from an upstream API. Where does the retry belong?
    • The dispatcher, with exponential backoff.
    • The model — surface the 503 and let it pick a different approach.
    • The outer loop — re-run the agent from scratch.
    • Skip the retry; the model will figure it out.
  3. Which cap is most often missing from production agent loops?
    • Iteration cap.
    • Token cap.
    • Dollar cap.
    • Wallclock cap.
  4. When does plan-act-reflect typically hurt more than it helps?
    • Debugging tasks that span ten iterations.
    • A one-step lookup that returns a single value.
    • Long-horizon multi-tool tasks.
    • Tasks where the model often misjudges intermediate results.
  5. Your code-fix agent has been self-correcting on the same test failure for six iterations. The cleanest fix is to:
    • Increase the self-correction cap to twelve.
    • Cap self-corrections at two or three and surface the failure to the user when hit.
    • Hide future errors from the model so it doesn't keep trying.
    • Switch the model to a smaller one to reduce cost per iteration.

Related lessons

AI
intermediate

Memory, Identity, and Seeing What the Agent Did

Three services decide whether an agent survives contact with production: what it remembers between sessions, whose authority it acts with when it calls your systems, and whether you can reconstruct what it did after the fact. This lesson covers AgentCore Memory, Identity and Observability, and the delegation problem that makes agent authentication genuinely different.

7 steps·~11 min
AI
intermediate

Running an Agent: Runtime, Harness, and Session Isolation

An agent is a loop that runs for minutes, holds state, executes code it just wrote, and must not leak anything into the next user's session. This lesson covers what AgentCore Runtime provides that a container does not, why session isolation is the load-bearing guarantee, and where the managed Harness sits against bringing your own loop.

7 steps·~11 min
AI
intermediate

Bedrock: One Door to Many Models

Amazon Bedrock's pitch is that model choice becomes a configuration value instead of a rewrite. This lesson takes that claim apart: the four API dialects Bedrock exposes over the same models, what the unified Converse API actually normalises, what it cannot normalise, and the inference and governance machinery that decides cost and blast radius.

7 steps·~11 min
AI
advanced

End to End: What the Cascade Throws Away

Speech in, text, model, text, speech out is the standard architecture and it discards everything not in the words: emphasis, emotion, hesitation, overlap. End-to-end models keep it by never routing through text, and pay with a token rate roughly 185 times higher and far less training data. This lesson covers the trade, and why interleaving is the pragmatic answer.

9 steps·~14 min