Putting a circuit breaker on your language model spending
The hardest thing about budgeting a language model call is that you do not know what it costs until after it has run. This is a small middleware you can read in one sitting that meters every call and refuses the ones you cannot afford, built with the same discipline I would bring to a payments system, where nobody is allowed to spend money the platform has not first authorized.
Most teams first confront the cost of language models when the monthly invoice arrives, and it is larger than expected. The model worked, the demo impressed everyone, the feature shipped, and then the invoice arrived and someone had to explain why a single runaway loop spent more in a weekend than the team spends on its entire database tier in a year. The uncomfortable truth is that this is not an accident or a billing error. It is the default behavior of a system that has no control telling it to stop.
The security community has now given this failure a name. In the 2025 edition of its Top 10 for Large Language Model Applications, the Open Worldwide Application Security Project lists Unbounded Consumption as the tenth major risk, cataloged as the entry LLM10. The description reads like a list of the ways people get surprised by a bill. There are calls made with no limit on token or context length, so the model can generate an arbitrarily long and arbitrarily expensive response. There are inference endpoints with no rate limiting, so a single client can submit as many requests as it likes. There are calls with no timeout, so a request can hang and accrue cost during a provider outage. And there is the plainest failure of all, which is simply having no budget, no spending alert, and no usage tracking at all. Framed this way, unbounded consumption is not an exotic attack. It is the absence of the controls that every other part of your infrastructure already takes for granted.
Why language model spend resists the usual tools
If bounding spend were as simple as setting a limit, this would not be worth writing about. The difficulty is specific and it is worth stating plainly. With almost any other resource, you know the cost of an operation before you perform it. A database query has a plan you can inspect. A storage write has a size you can measure. A language model call does not work this way, because the price depends on how many tokens the model produces, and you do not know how many tokens the model will produce until it has already produced them. You are asked to authorize a purchase before anyone will tell you the price.
The pricing itself is straightforward once you see it. Providers bill per million tokens, with separate rates for the tokens you send and the tokens you receive, and the tokens you receive cost considerably more. The published rates for the Claude models make the shape clear. At the time of writing, Claude Opus is five dollars per million input tokens and twenty five dollars per million output tokens. Claude Sonnet is three and fifteen. Claude Haiku is one and five. The five fold gap between the cheapest and the most capable model is the single biggest lever you have, and it is why the demo for this project prints the same request priced three ways, so the choice is visible at the moment you make it rather than at the end of the month.
There is a second lever that is easy to miss, which is caching. When a large part of your prompt repeats from one call to the next, a system prompt, a long document, a set of examples, the provider can cache it. A cached read is billed at roughly a tenth of the normal input rate, while writing something into the cache costs a little more than processing it once. Anthropic documents this in its prompt caching guide, where the savings on a stable prefix can reach about ninety percent. Any honest cost model has to account for these three prices, the fresh input, the cached read, and the cached write, or it will quietly misstate the bill for exactly the workloads that run most often.
Four controls, and the order they run in
The middleware I built for this, which lives in the llm-cost-guardrails repository, is small on purpose. It is four controls and a piece of glue that runs them in the right order, and the whole thing runs offline with no keys, because the cost arithmetic does not need a real model to be correct. The four controls are these.
The first is cost estimation. It turns a count of tokens into a number of dollars, and it understands the cached read discount and the cache write premium described above. It is the foundation, because every other control begins by asking it the same question, which is what this call is going to cost.
The second is the per tenant budget. Each tenant, which might be a customer, a team, or a single application, has a cap, and the budget refuses any call that would carry that tenant past it. The interesting part is how it copes with not knowing the price in advance, and I will come back to that.
The third is rate limiting. Each tenant gets a limit on requests per minute and a limit on tokens per minute, enforced with the classic token bucket algorithm, where an allowance refills at a steady rate and each call draws it down. This mirrors how the providers meter you in the first place. Anthropic, for example, publishes rate limits as requests per minute and input and output tokens per minute, organized into usage tiers. Putting the same kind of limit in front of your own application means a single misbehaving client cannot exhaust the allowance that every other client depends on.
The fourth is the kill switch, and it is the one I would not ship without. It is a circuit breaker on spend. It watches total spending across a rolling window of time, and if that spending crosses a ceiling, it trips, and every call after that is refused until a human looks at the situation and resets it. The per tenant budgets are the locks on the individual doors. The kill switch is the master breaker for the building, for the case where something you did not anticipate is spending money through a door you forgot to lock.
The glue runs them in a deliberate order. First the kill switch, because when total spend has already breached the ceiling no other check is relevant. Then the rate limit, because it is the cheapest check. Then the budget, which reserves the cost of the call. Only then does the actual request run. Every gate fails closed, which is the single most important property in the whole design. If any control says no, the call to the model never happens, so you are never charged for a request you were not allowed to make. A control that lets the spend through and records it afterwards is a logger, not a guardrail.
Reserve first, then reconcile
This brings me back to the problem of not knowing the price in advance, because the budget is where it bites hardest. The solution is older than software, and anyone who has worked in payments will recognize it immediately. It is the authorization hold.
When you hand your card to a hotel at check in, they do not yet know your final bill, so they place a hold for an estimated amount, enough to cover the room and a reasonable guess at extras. That money is set aside. You cannot spend it elsewhere, and the hotel cannot spend it either, until you check out and the charge settles to the real figure. The budget in this middleware works exactly the same way. Before a call, it reserves the worst case cost, which is the full input plus the maximum number of output tokens the call is allowed to produce. After the call returns, it settles that hold to the actual cost, which is almost always lower because most responses are shorter than their ceiling.
hold = worst_case_cost(model, input_tokens, max_output_tokens) # the authorization hold
budgets.reserve(tenant, hold) # refuses the call if the hold will not fit
result, usage = call() # the real request runs
actual = estimate_cost(model, usage) # what it actually cost, from the returned token counts
budgets.reconcile(tenant, hold, actual) # release the hold, record the truth
The reason this matters is concurrency. A real application has many calls from the same tenant in flight at the same time, and if each one only checked the budget against money already spent, they would all see room and they would all proceed, and the tenant would sail past its cap. Reserving the worst case up front closes that gap. The held amounts count against the cap immediately, so a tenant can never authorize more work than its budget allows, no matter how many of its calls are running at once. And if a call fails, its hold is released and it is never charged, the same way an abandoned hotel booking quietly falls off your card.
The industry has already moved here
If this sounds like an edge concern, the numbers say otherwise. The FinOps Foundation, which is the body that defines the common practice for managing cloud spending, has made the management of artificial intelligence cost its leading forward looking priority and has built an entire FinOps for AI body of work around it. In its State of FinOps research, the share of organizations that say they are actively managing artificial intelligence spend has risen to the overwhelming majority in the space of two years, and the foundation went so far as to broaden its own mission statement from managing the value of cloud to managing the value of technology, precisely because spending on models had become too large to sit outside the discipline. The most telling finding is that the hardest part of the job is no longer reducing the number. It is proving that the spending bought something worth having. You cannot have that conversation at all until the spending is measured and bounded, which is what this kind of middleware is for.
A useful way to make spending legible is to stop measuring it in dollars per month and start measuring it in dollars per outcome. A budget tells you that you spent four hundred dollars. A cost per outcome tells you that each resolved support ticket cost eleven cents, which is a number a finance team can actually reason about. The per tenant attribution in this middleware is the first step toward that view, and it pairs naturally with the billing analysis in my ai-finops-agent project.
The payments lens
None of this is new. These are established payments controls applied to a new kind of resource. In a payments platform you assume that any request might be hostile or simply mistaken, so you authorize before you capture, you give every participant only the budget it needs, you put a limit in front of every endpoint, and you build a breaker you can pull when something you did not foresee starts moving money. A language model is just another component that can spend money on your behalf, faster than a human can watch and in amounts that compound quietly. It deserves the same seatbelt. The fact that it speaks fluent English does not make it any less capable of running up a bill, and twenty years of being accountable for other people's cloud invoices has taught me that the cost control you wish you had is always the one you decided to add later.
What this is and is not
This is a teaching grade middleware, and I want to be clear about its edges. The ledger and the limiters keep their state in memory, which is exactly right for understanding the controls and for a single process, and exactly wrong for a deployment spread across many processes, which needs a shared store such as Redis or a database. The pricing table carries published rates that will drift, so it should be re verified against the provider before anyone trusts a figure from it. And budgeting before a call needs an estimate of the input token count, for which you should use the provider's own token counting endpoint rather than guessing from the length of the text. What the project does give you is the shape of the controls, the order they belong in, and the one principle that matters more than any of them, which is to fail closed. Clone the repository and run the demonstration to see a runaway loop stopped before it spends the money rather than after.
References
- OWASP, Top 10 for Large Language Model Applications (2025), entry LLM10 Unbounded Consumption.https://genai.owasp.org/llmrisk/llm102025-unbounded-consumption/
- FinOps Foundation, FinOps for AI overview.https://www.finops.org/wg/finops-for-ai-overview/
- FinOps Foundation, The State of FinOps research.https://data.finops.org/
- Anthropic, Claude model pricing.https://platform.claude.com/docs/en/about-claude/pricing
- Anthropic, Rate limits and usage tiers.https://platform.claude.com/docs/en/api/rate-limits
- Anthropic, Prompt caching.https://platform.claude.com/docs/en/build-with-claude/prompt-caching