How to give an AI agent a spending limit
Last verified
Four layers, from tightest to loosest. Each catches what the one before it misses, and only the first two act fast enough to matter during a run.
| Layer | Where | Reacts in | Catches |
|---|---|---|---|
| 1. In the loop | Your code | Instantly | This run |
| 2. Per-key project limit | Provider | Minutes | This agent |
| 3. Organisation limit | Provider | Minutes–hours | Everything, catastrophically |
| 4. Daily spend review | A tracker | A day | Trends and drift |
Layer 1 — in the loop
The only layer that stops a run mid-flight. Everything else is cleanup.
class Budget:
def __init__(self, max_usd, in_per_m, out_per_m):
self.max_usd, self.spent = max_usd, 0.0
self.in_per_m, self.out_per_m = in_per_m, out_per_m
def charge(self, usage):
self.spent += (usage.input_tokens / 1e6) * self.in_per_m
self.spent += (usage.output_tokens / 1e6) * self.out_per_m
if self.spent >= self.max_usd:
raise BudgetExceeded(f"${self.spent:.2f} of ${self.max_usd:.2f}")
return self.spent
budget = Budget(max_usd=2.00, in_per_m=3.00, out_per_m=15.00)
for step in range(MAX_STEPS):
result = agent.step()
budget.charge(result.usage)
if result.done:
break
Check between steps, not at the end. A budget evaluated after the run is a report.
Combine with a step cap, a wall-clock timeout, and a repeated-state check — cost control for autonomous agents covers all four.
Layer 2 — a project and key per agent
Providers don't offer per-agent limits. But they do offer per-project limits, and you control which project a key belongs to.
So: one project per agent, one key in it, a spend limit on that project.
- The agent's blast radius is its own budget
- A runaway agent cannot consume the production budget
- You get per-agent cost attribution free, via usage grouped by project
This is the highest-value structural change on this page and it takes ten minutes. OpenAI key types covers the mechanics.
Layer 3 — the organisation limit
Your backstop for everything, including the failure you didn't anticipate. Set it well below the number that would genuinely hurt.
Note that hitting it stops your _entire organisation_, production included. It is the last resort, and it should be set at a number that only a genuine emergency reaches. OpenAI spend limits: hard, soft, and what they miss.
And turn off auto-recharge, or the cap has a bypass.
Layer 4 — daily review
Layers 1–3 handle acute failures. This one catches the slow drift: agent runs that got 30% more expensive after a prompt change, or ten times more frequent after a launch.
Nothing in layers 1–3 notices that, because no individual run misbehaved.
A daily number compared against normal is the whole mechanism. TKN does it across providers with thresholds and a kill switch; a cron job posting to Slack does a decent version for free.
What doesn't work
A budget in the system prompt. "You have a budget of $2, be efficient." The model will deprioritise it when it's trying to complete a task. Useful as a hint, worthless as a control.
Checking cost only at the end. Too late by definition.
Trusting max_tokens. It caps a single response, not a run. An agent making 200 capped calls is still an expensive agent.
A rate limit as a cost limit. Requests per minute is not dollars per minute — one request to an expensive model with a huge context can cost more than a thousand cheap ones.
Letting the agent see the number
Layers 1–4 constrain from outside. You can also give the agent _visibility_ through an MCP server, so it can reason about cost and choose a cheaper path — cost tracking for MCP servers and agents.
Visibility complements enforcement. It does not replace it. Keep the hard limits.