Cost guardrails for AI workflows
A small accounting library that pays for itself in three weeks. Tokens, retries, and the budget alarm.
Loading essay…
A small accounting library that pays for itself in three weeks. Tokens, retries, and the budget alarm.
Loading essay…
A model call costs cents. A bad retry loop costs hundreds of dollars in an afternoon. The first AI bill that surprised us was traced to a single feature where, on a particular error path, the code retried up to thirty times before giving up. The function "worked." The bill did not.
This essay is about the small accounting library we wrote in response, which has paid for itself many times over.
A wrapper around every model call that:
About 200 lines of code total. The whole thing is a thin layer between "my code" and "the model SDK." It looks like this:
type Caller = { tenantId: string; feature: string };
interface ModelCall {
prompt: string;
model: 'cheap' | 'medium' | 'expensive';
maxOutputTokens: number;
}
class GuardedClient {
async call(caller: Caller, req: ModelCall): Promise<string> {
const inputTokens = await this.countTokens(req.prompt, req.model);
const projectedCost = this.priceOf(req.model, inputTokens, req.maxOutputTokens);
if (!await this.budget.canAfford(caller, projectedCost)) {
throw new BudgetExceeded(caller, projectedCost);
}
const start = Date.now();
const result = await this.upstream.complete(req);
const elapsed = Date.now() - start;
await this.budget.charge(caller, {
inputTokens,
outputTokens: result.usage.output_tokens,
cost: this.priceOf(req.model, inputTokens, result.usage.output_tokens),
elapsed,
feature: caller.feature,
});
return result.text;
}
}Five things are loadbearing in those few lines.
The cost of a call is roughly input_tokens × input_price + output_tokens × output_price. We can know input_tokens exactly before sending; we
have to guess output_tokens, which is why maxOutputTokens is a
required parameter. The projection is "input + max output;" the actual
charge is "input + actual output."
canAfford returns false if the tenant's daily spend plus the
projected cost would exceed their cap. We throw, not warn. Soft
warnings get ignored.
Every charge is attributed to both. This lets us answer two different questions:
Cost-per-feature is the more interesting one. Three months in we discovered that one barely-used feature was responsible for 40 % of spend, because it ran a verbose model on a 50 KB prompt and the average user clicked it twice a session. We rewrote it with a smaller prompt and a cheaper model; cost-per-call dropped 12×.
We log elapsed time alongside cost. Slow calls are not always expensive, but a feature that always takes 9 seconds is a UX problem even if it costs nothing.
The budget is on the tenant (the company), not the individual user. This matches how costs are billed. It also avoids the bug where an admin user with privileges burns the user-budget of a colleague who did not consent.
Three budget tiers, declared per tenant plan:
| Plan | Daily $ | Monthly $ | Action when exceeded |
|---|---|---|---|
| Free | 0.10 | 1.00 | Block, suggest upgrade |
| Pro | 5.00 | 100 | Block, alert tenant admin |
| Enterprise | per-contract | per-contract | Soft cap, alert support |
Two unintuitive choices:
We considered "free tier gets nothing." It is hostile. The 10-cent daily budget covers about 30 cheap-model calls, which is enough for a user to evaluate the feature without us subsidising thousands of calls per free user.
The hard cap on Pro is the right default; for Enterprise, blocking their workflow because their admin forgot to update the cap on contract renewal is bad business. Soft cap, alert, conversation.
A small dashboard with five panels:
Three months of operation taught us that #4 is the most useful. A "15 % cost increase per call" line on a feature is a leading indicator that someone tweaked a prompt or upgraded a model without intending to.
Real things from real production:
We spent about a week on the library. It has prevented at least four incidents that would have cost more than that engineering time. It has also let us confidently build with model calls in ways we would not have without it. The "we know what this costs" psychological effect is at least as valuable as the dollar savings.
The next part of this series wraps the AI track. Or jump to the performance track if you want a different shape of essay.