Budgeting Agent Runs in Production

The expensive run is rarely the one that crashes. It is the one that keeps working. A tool returns something almost useful, the model asks for one more lookup, the lookup needs a follow-up, and each step is reasonable on its own. Nobody made a bad decision. The run just never had a reason to stop, so it stopped when a framework default, a timeout, or the invoice stopped it.
We think every production run should carry a budget the way it carries a prompt: set before it starts, in numbers, with a planned answer to the question "what happens at the limit?" A budget is not mainly a cost control. It is the point where an open-ended loop becomes a managed process, with a partial result and a record instead of a surprise.
One run, four budgets
A run spends four different things, and they do not substitute for each other.
Steps count how many times the loop goes around. This is the budget frameworks already enforce, usually as an afterthought. LangGraph caps the super-steps in a single execution with a recursion limit (25 by default) and raises an error when the limit is hit. The OpenAI Agents SDK does the same in turns: maxTurns defaults to 10, and the run throws once that is reached. Both defaults exist to stop infinite loops. Neither was chosen with your workload in mind, and a run that dies on one has produced an exception, not an answer.
Tokens are the unit the model actually consumes, and they grow in a way steps hide: the tenth step usually carries the transcript of the previous nine, so it costs more than the first. Time is the budget your users feel: a run that is cheap but takes forty minutes has failed a different test. Spend is the one finance will ask about, and it is not a simple multiple of tokens once tools, searches, and spawned sub-agents bill separately.
So set all four, per run, and charge every kind of work to the same ledger. Spawned child runs draw from the parent's account, or the budget is theatre: the parent stays frugal while its children spend freely.

Two kinds of limit, two different jobs
Some limits advise and some enforce, and confusing them produces bad behaviour in both directions.
An advisory budget is shown to the model as it works, so the model can plan against it: finish the core task first, skip the optional third check, start wrapping up. Anthropic's task budgets for Claude work this way: an advisory cap across the whole agentic loop, separate from the per-response output cap, with a minimum of 20,000 tokens. Because the model can see the countdown, it spends differently. Because it is advisory, it is not the wall you rely on when the money has to stop.
The enforced budget lives outside the model, in your runner or the platform, and it does not negotiate. Anthropic's session budgets on Claude Managed Agents are the platform version: a hard dollar cap on one session that pauses the session when it is reached, with a specific stop reason, and raising the budget resumes it. That pause-and-resume shape is the one to copy wherever you enforce a limit. Hitting the budget should checkpoint the run, keep the work already done, and return a partial result that says what was finished and what was not. A hard stop that discards the run teaches teams to set huge budgets so it never fires. Then it never protects anything either.
Set the soft limit well before the hard one: 80% of the budget is a workable trigger. At the soft limit the agent stops starting new lines of work, writes its checkpoint summary, and spends what remains on delivering. Most runs should end there, tidily, and never meet the wall.
Set the numbers from your own runs
Do not pick budgets by intuition. Pick them from the distribution of what good runs actually cost.
Anthropic's guidance for task budgets is to run a representative sample of tasks without a budget first, record what each task spends in total, and start from the high end of that distribution, the p99, then tune up or down. The reasoning transfers to any framework and to all four counters. A budget set at the median fails half your legitimate runs. A budget set at ten times the p99 protects against nothing. The interesting band is just above what good runs use, close enough that a looping run trips it quickly while a thorough run finishes.
Budgets also belong to the task type, not the deployment. Extracting fields from one invoice and researching a supplier across forty documents are different jobs sharing a runtime, and one number stretched across both will be wrong twice: tight enough to break the research, loose enough to let a stuck extraction loop burn. Classify the run at intake, assign the budget for that class, and let the class be visible in the trace so a breach can be read properly later: was the budget wrong, or was the run?

Where budgets go wrong
A few failure shapes are worth naming, because each one looks like discipline from a distance.
A budget on steps alone invites the model to make each step enormous. A budget on spend alone says nothing about a run that loops cheaply for six hours against a system your customer is waiting on. A single global budget for a fleet hides the one task type that is bleeding. And the quietest failure: nobody owns raising a budget. If a legitimate run hits the wall and the only path forward is an engineer editing a config value at midnight, the organisation will route around the system within a month, usually by setting the number so high it stops meaning anything.
Budgets also do not fix a broken loop. An agent retrying a malformed call will spend its whole budget on the same error, punctually. The budget buys you a bounded, visible failure with a checkpoint and a trace. That is a much better failure than an unbounded one. It is still a failure, and the fix still lives in the tool, the prompt, or the evals.
Work with us
If your agents run without per-run budgets, or with a framework default standing in for a decision, that is a contained piece of work with a clear before and after. Tell us about the run you are worried about through Trida AI's intake, and we will help you put numbers, limits, and a proper ending on it.
