§ Agentic systems · Patterns

Three ways to bound an agent loop before it eats your budget.

Every agent programme discovers, usually painfully, that "the loop won't terminate" is the default behaviour of loops. Here are three specific bounding patterns we reach for — each with the failure mode it's actually preventing.

Mark Coleman · · 6-min read

Every agent programme has a Friday afternoon nobody wanted, where a production trajectory used a thousand tool calls, produced a mediocre answer, and cost enough to warrant an incident review. The root-cause write-up is always the same shape: the loop didn’t know when to stop.

Bounding an agent loop is not a nice-to-have. It’s the substrate that makes everything else about agent engineering possible — cost budgets, latency SLAs, safety guarantees, the ability to ship a change without crossing your fingers. Here are three patterns we default to. Use one; compose all three when the workload warrants it.

Pattern 1 — Step budget with a hard stop

The simplest one, and the one people underweight.

MAX_STEPS = 12
step = 0

while step < MAX_STEPS
  step += 1
  result = agent.step(context)
  break if result.terminal?
  context = result.next_context
end

if step == MAX_STEPS && !result.terminal?
  Metrics.increment("agent.hit_step_cap")
  abort_with_diagnostic("hit MAX_STEPS without terminating", context)
end

Two things about this pattern that matter more than the code:

The step cap is a hard stop with a diagnostic, not a soft nudge that degrades. When you hit the cap, you don’t return “here’s my best guess”; you fail loudly with structured logging so an operator can see why. That metric — agent.hit_step_cap — is your leading indicator that something new is happening in production.

The cap should be small enough to hurt. If your normal trajectory takes six steps, MAX_STEPS at fifty means nothing. Set it at twelve; the handful of legitimate long trajectories will show up in your alerting and you’ll deliberately raise it for those cases, not because the number felt polite.

Failure mode this prevents: the runaway loop. The trajectory that starts marginally, spirals gently, and would eventually burn through your month’s inference budget in an afternoon.

Pattern 2 — Tool-scoped budgets

The step cap treats every step as equal. In practice, some tools are cheap (a local database lookup) and some tools are expensive (a wide web search). A step budget that ignores the difference is a step budget that missed the interesting failure.

Give each tool its own budget:

search_web:            ≤ 3 calls / trajectory
retrieve_document:     ≤ 12 calls / trajectory
call_external_api:     ≤ 6 calls / trajectory + ≤ £0.05 / call
run_code_sandbox:      ≤ 2 calls / trajectory

The budget is enforced at the tool boundary, not in the model. The model can ask for the tool a fourteenth time; the tool returns a budget-exceeded observation. The model gets to reason about that, either terminating or choosing a different approach.

Two useful side effects:

  1. The model learns — via the observation history — that budgets exist. Prompting it up-front about the budgets sometimes changes behaviour on its own.
  2. Budget-exceeded observations are excellent training signal for the eval loop. Every one is a data point about a trajectory that the model didn’t shape as expected.

Failure mode this prevents: the “one expensive tool” trap. The trajectory that’s cheap on twelve out of thirteen steps, and catastrophic on the thirteenth because the model hammered one high-cost tool.

Pattern 3 — Self-critique gate at the end

The first two patterns bound how much the agent does. The third one bounds whether it should return the answer at all.

Before returning the final answer to the caller, run a critique step:

Given the goal, the observations, and the draft answer:
  - Is every claim supported by an observation?
  - Are any required sub-goals unaddressed?
  - Is the answer specific enough to be actionable?
Return { pass: bool, reasons: [str] }

If pass: false, feed the critique back to the agent with one more step of budget. If it still fails, return a failure with the critique attached instead of returning a bad answer.

This one is more expensive than the first two — it costs an extra model call per trajectory — but it catches a specific failure the other patterns miss: the confident wrong answer. The trajectory that terminated inside budget with a clean-looking final answer that happens to be nonsense.

You want the critique model to be at least as strong as the agent model. A weaker critique will happily agree with plausible-sounding wrong answers.

Failure mode this prevents: the plausible hallucination. The trajectory that ran clean, didn’t loop, stayed inside budget, and returned something confident and wrong.

Composing them

The three patterns compose freely. Cheap agents use only the step cap. High-stakes agents use all three. The order in production runtime is:

  1. Step + tool budgets enforced at every step (hard runtime caps).
  2. Self-critique gate on the final answer (soft quality gate).
  3. Both surfaces feed observations back into offline eval so tomorrow’s regressions are on today’s fixture set.

What to instrument

None of this is worth doing if you can’t see it. Emit metrics for:

  • Steps consumed per trajectory (histogram, not average).
  • Tool budget hit rate, per tool.
  • Self-critique fail rate.
  • Cost per trajectory, in the currency your finance team cares about.

The first time cost-per-trajectory bends up sharply, you’ll be glad you had the histogram, not the average.

So what?

Bounding is the plumbing that turns an agent from an experiment into a system you can operate. It’s boring engineering, done deliberately, and almost every production incident we’ve reviewed on an agent programme would have been either prevented or contained by one of these three patterns.

Start with the step cap. Add tool budgets when the trajectory shape justifies it. Add the self-critique gate when the stakes justify the extra call. And instrument all three so you’re the first to see when the loop stops behaving.

  • Evals for agents that use tools, not just tokens — the offline side of “the loop stopped behaving”.
  • A senior engineer’s checklist before letting an agent commit — the same discipline, applied to code-generation loops.
Tagged — agents cost guardrails

Want more like this?

Subscribe to the RSS feed, or drop us a line if the piece sparked something you want to talk through.