LLMAgentsCostPython

Runaway LLM Agent Costs: Budgets, Step Limits and Kill Switches

An agent that loops can burn a month of budget in an afternoon. Seven guards to put around every run: step caps, token caps, dollar budgets, loop detection and a tenant kill switch.

A normal API call has a natural ceiling: one request, one response, one bill line. An agent has no such ceiling. It decides how many more calls to make, and when it decides badly, it keeps deciding. This post is about the guards I would put around every agent run before it touches real traffic, in the order I would add them.

#Why cost grows faster than steps

The usual loop sends the full history back to the model at every step: the system prompt, the task, every earlier reply and every tool result. If each step adds roughly the same number of tokens, then the input at step k is about k times that amount, and the input across n steps adds up to a triangle: the tokens per step times n times n plus one, divided by two.

Illustrative arithmetic, not a measurement: 1,000 tokens added per step, 500 output tokens per step, full history resent each step. Priced at Claude Haiku 4.5 rates ($1.00 input, $5.00 output per 1M tokens, accessed 2026-08-16).
StepsTotal input tokensInput costOutput costRun total
1055,000$0.055$0.025$0.08
501,275,000$1.275$0.125$1.40
1005,050,000$5.05$0.25$5.30

Five times the steps (10 to 50) cost about seventeen times as much here, ten times the steps (10 to 100) about sixty-six times, and a hundred-step run is nearly four times a fifty-step one. A single runaway run is not ruinous. A runaway queue is: the same bug repeated across a thousand jobs overnight. Caching and history summarisation lower these numbers, but they do not change the shape, so the guards below do not depend on them.

#The seven guards

  • Step cap. A maximum number of model calls per run, enforced in the loop itself and not in the prompt. A prompt that says stop after ten steps is a request, not a control.
  • Output cap. Set the maximum output tokens on every call. It bounds the most expensive column in the price table, since output is priced several times higher than input on the models above.
  • Run budget. Before each call, read the run's spend so far from your usage ledger and refuse the call if it would pass the budget. This is the guard that limits what you pay, whatever shape the loop takes.
  • Loop detection. If the same tool is called with the same arguments twice in a row, the agent is stuck. Stop, or force a different strategy.
  • Wall-clock timeout. A run that takes ten times its normal duration is a defect even if each step looks fine.
  • Tenant kill switch. A daily spend ceiling per account that blocks new runs and alerts you, so one bad day stays one bad day.
  • Alert on the tail. Watch the most expensive runs and the share of truncated runs, not the average. The average hides exactly the runs you are worried about.

#A budget guard, sketched

This is a sketch of the idea, not code from a production system. The key design choice is that the guard reads spend from the ledger, so it keeps working however many components share a run.

budget_guard.py (sketch)
class BudgetExceeded(Exception):
    pass

class RunGuard:
    def __init__(self, run_id, ledger, *, max_steps=25, max_usd=0.50, max_repeats=2):
        self.run_id, self.ledger = run_id, ledger
        self.max_steps, self.max_usd, self.max_repeats = max_steps, max_usd, max_repeats
        self.steps, self.last_call, self.repeats = 0, None, 0

    def before_model_call(self, est_next_usd=0.0):
        self.steps += 1
        if self.steps > self.max_steps:
            raise BudgetExceeded("step cap")
        spent = self.ledger.spend_for_run(self.run_id)      # SUM(cost_usd) WHERE run_id = ...
        if spent + est_next_usd > self.max_usd:
            raise BudgetExceeded(f"run budget: {spent:.4f} spent")

    def before_tool_call(self, name, args):
        key = (name, repr(sorted(args.items())))
        self.repeats = self.repeats + 1 if key == self.last_call else 0
        self.last_call = key
        if self.repeats >= self.max_repeats:
            raise BudgetExceeded("repeated tool call")

#Where the ledger comes from

The run budget only works if you record cost per attempt, grouped by a run id. That is the same ledger described in LLM Model Routing to Keep Inference Costs Predictable: every model call goes through one gateway, which writes tokens and computed cost for each attempt. Adding guards later is then a small change to code you already have. If you do not have the ledger yet, build that first. The formula and what to log are in How do I calculate the cost of an LLM request?

#What I would do first

  • Log usage per attempt with a run id before anything else.
  • Add the step cap and the output cap. They are a few lines each and catch the worst cases.
  • Add the run budget and the tenant ceiling once the ledger is trustworthy.
  • Add loop detection and alerts last, after you have seen what your real runs look like.

In the LangChain survey of 1,340 practitioners, quality, not cost, was the main blocker to production for about a third of respondents. Guards are not a substitute for fixing quality. They are what let you run an imperfect agent on real traffic without an unbounded bill.

Sources

  1. Dinesh Solanki, LLM Model Routing to Keep Inference Costs PredictableThe gateway, price tables and per-run ledger this post builds on.
  2. Google, Gemini API Pricing (ai.google.dev)Accessed 2026-08-16. Gemini 2.5 Flash and Flash-Lite rates per 1M tokens, used for the price examples.
  3. Anthropic, Claude Platform Pricing docsAccessed 2026-08-16. Claude Haiku 4.5 rate of $1.00 input and $5.00 output per 1M tokens, used in the worked example.
  4. LangChain, State of Agent EngineeringSurveyed 18 November to 2 December 2025, 1,340 practitioners. About one third named quality as the primary blocker to putting agents in production.

Frequently asked questions

Why do LLM agents cost so much more when they loop?

Most agent loops resend the whole conversation on every step, so input tokens grow with each step instead of staying flat. If every step adds about the same number of tokens, total input tokens across n steps are roughly the tokens per step times n times n plus one, divided by two. Doubling the steps therefore costs about four times as much input, not twice.

What is the single most useful guard against runaway agent costs?

A dollar budget per run that is checked before every model call, using spend read from your own usage ledger. Step caps and token caps limit one dimension each, while a budget limits what you actually pay, whatever shape the loop takes. Pair it with a per-tenant daily ceiling so one bad run cannot become a bad month.

Should a step cap just kill the run?

Usually it should stop the loop and return the best partial result with a clear status, not throw away the work. Mark the run as truncated, log why, and alert on the rate of truncated runs, because a rising rate means your prompt, tools or model choice has a problem.

Related notes

LLM Model Routing to Keep Inference Costs Predictable

How I route every AI call in Opaeron through one gateway: task-based model selection, cross-provider fallback chains, JSON repair and per-run cost tracking.

Read

pgvector Iterative Scan in Production: strict_order vs relaxed_order and max_scan_tuples

How PostgreSQL 17 and pgvector 0.8 fix the post-filtering trap with iterative index scans. Benchmark tradeoffs between strict_order and relaxed_order, and how max_scan_tuples stops runaway scans.

Read

Building something in this space and want another pair of hands on it?

Get in touch