AI Agent Cost Budgets: Stop Autonomous Workflows From Burning Through Tokens and Cash
Autonomous agents can quietly spend more on retries and tool loops than model quality. This tutorial shows budget guardrails that stop token burn before finance notices.
Your AI agent does not need malice to torch your API bill. It only needs permission to keep trying.
That is the ugly part of autonomous workflows. A normal chatbot has a human brake pedal. An agent has loops, retries, tool calls, memory, search, delegation, and occasionally the confidence of a drunk intern with a company card. If you do not add ai agent cost budget guardrails, your “smart automation” can become a token furnace.
This tutorial shows how to build practical cost budgets around agent workflows: per-run limits, per-user limits, tool-call caps, retry budgets, model routing, and observability that catches waste before the invoice does.
Prerequisites
You do not need to be a full-time backend engineer, but you should understand the moving parts of an AI workflow.
You need:
- An AI agent or workflow that calls an LLM API
- Access to token usage from responses or provider usage dashboards
- A place to store budget state, such as Redis, Postgres, SQLite, or even a temporary in-memory store for testing
- A rough idea of what one successful workflow is worth to your product
The examples below use JavaScript-style pseudocode because it is readable. The pattern works the same in Python, Ruby, Go, no-code orchestrators, and workflow tools.
Step 1: Define What You Are Budgeting
Do not start with “we need to reduce tokens.” That is too vague. Tokens are only one meter.
A real agent budget should track at least five things:
| Budget type | What it prevents | Example |
|---|---|---|
| Money per run | One task getting too expensive | Stop a research agent after $0.20 |
| Tokens per run | Context bloat and runaway loops | Stop after 120,000 total tokens |
| Tool calls per run | Search/browser/database loops | Max 8 web searches |
| Steps per run | Agents talking to themselves forever | Max 12 reasoning/tool steps |
| Spend per user/day | One user draining the pool | Max $5 per user per day |
Expected result: by the end of this step, every agent run has a budget envelope before it starts. Not a dashboard after the damage. A hard envelope.
A sane starter policy:
| Workflow | Max cost/run | Max steps | Max tool calls |
|---|---|---|---|
| Email summary | $0.02 | 3 | 1 |
| Customer support draft | $0.05 | 5 | 3 |
| Web research brief | $0.25 | 12 | 8 |
| Code review assistant | $0.50 | 20 | 10 |
| Deep research agent | $2.00 | 40 | 25 |
Do not copy these numbers blindly. The point is to force a business decision. If a support draft is worth $0.05, it should not spend $0.48 because the agent got curious.
Step 2: Calculate Cost From Token Usage
Providers usually return usage data with input tokens, output tokens, and sometimes cached input tokens. OpenAI’s usage reference includes fields such as input_cached_tokens, input_text_tokens, input_uncached_tokens, and output_tokens. Anthropic documents limits around requests per minute, input tokens per minute, output tokens per minute, and spend limits.
As of August 6, 2026, OpenAI’s pricing page lists gpt-5.6-luna short-context pricing at $0.20 per 1M input tokens, $0.02 per 1M cached input tokens, $0.25 per 1M cache-write tokens, and $1.20 per 1M output tokens. Prices change. Put pricing in config, not in scattered code.
A basic calculator:
const MODEL_PRICES = {
"gpt-5.6-luna": {
inputPerMillion: 0.20,
cachedInputPerMillion: 0.02,
cacheWritePerMillion: 0.25,
outputPerMillion: 1.20
}
};
function dollarsPerToken(pricePerMillion) {
return pricePerMillion / 1_000_000;
}
function estimateOpenAICost(model, usage) {
const price = MODEL_PRICES[model];
const inputTokens = usage.input_tokens ?? 0;
const cachedInputTokens = usage.input_cached_tokens ?? 0;
const cacheWriteTokens = usage.input_cache_write_tokens ?? 0;
const outputTokens = usage.output_tokens ?? 0;
const uncachedInputTokens = Math.max(
inputTokens - cachedInputTokens - cacheWriteTokens,
0
);
return (
uncachedInputTokens * dollarsPerToken(price.inputPerMillion) +
cachedInputTokens * dollarsPerToken(price.cachedInputPerMillion) +
cacheWriteTokens * dollarsPerToken(price.cacheWritePerMillion) +
outputTokens * dollarsPerToken(price.outputPerMillion)
);
}
Expected result: after every model call, you can translate usage into dollars. Not vibes. Dollars.
If your provider does not expose every field, start with the fields it does expose. A slightly conservative estimate is better than a beautiful spreadsheet that arrives three days late.
Step 3: Create a Budget Object for Every Run
Every agent run should carry its own budget state. Treat it like request context.
function createRunBudget({
runId,
userId,
maxDollars,
maxTokens,
maxSteps,
maxToolCalls
}) {
return {
runId,
userId,
maxDollars,
maxTokens,
maxSteps,
maxToolCalls,
spentDollars: 0,
usedTokens: 0,
steps: 0,
toolCalls: 0,
stopped: false,
stopReason: null
};
}
function assertBudgetAvailable(budget) {
if (budget.spentDollars >= budget.maxDollars) {
throw new Error("Budget exceeded: dollars");
}
if (budget.usedTokens >= budget.maxTokens) {
throw new Error("Budget exceeded: tokens");
}
if (budget.steps >= budget.maxSteps) {
throw new Error("Budget exceeded: steps");
}
if (budget.toolCalls >= budget.maxToolCalls) {
throw new Error("Budget exceeded: tool calls");
}
}
Expected result: your agent cannot make “just one more call” unless the budget says yes.
That one guard matters. Most runaway spend comes from boring behavior: retrying malformed output, searching repeatedly, re-reading giant context, or bouncing between specialist agents.
Step 4: Wrap Model Calls With a Cost Gate
Now place the budget check directly around the model call. Do not rely on the agent prompt saying “be efficient.” Prompts are not accounting controls.
async function callModelWithBudget({ client, model, messages, budget }) {
assertBudgetAvailable(budget);
budget.steps += 1;
const response = await client.responses.create({
model,
input: messages,
max_output_tokens: 1200
});
const usage = response.usage ?? {};
const callCost = estimateOpenAICost(model, usage);
budget.spentDollars += callCost;
budget.usedTokens +=
(usage.input_tokens ?? 0) +
(usage.output_tokens ?? 0);
assertBudgetAvailable(budget);
return response;
}
Expected result: each LLM call updates the budget immediately. If the run crosses the line, it stops before the next tool call, next retry, or next “reflection” step.
Add a Preflight Estimate
Post-call accounting is useful, but preflight checks stop obvious mistakes earlier.
function estimatePromptTokens(messages) {
const characters = JSON.stringify(messages).length;
return Math.ceil(characters / 4);
}
function assertPreflightBudget({ messages, budget, maxOutputTokens }) {
const estimatedInputTokens = estimatePromptTokens(messages);
const estimatedTotalTokens = estimatedInputTokens + maxOutputTokens;
if (budget.usedTokens + estimatedTotalTokens > budget.maxTokens) {
throw new Error("Preflight blocked: token budget too small");
}
}
This estimate is crude. That is fine. It catches the worst nonsense: huge documents, accidental transcript dumps, and agent memory that grew into a landfill.
Step 5: Put Budgets Around Tools Too
Tool calls are where agents get expensive in non-obvious ways.
A web search may trigger another model call. A browser action may read a huge page. A database query may return 50,000 rows. A code execution tool may spin for minutes. Your token bill is not only the model. It is the blast radius around the model.
async function runToolWithBudget({ toolName, input, budget, execute }) {
assertBudgetAvailable(budget);
if (budget.toolCalls + 1 > budget.maxToolCalls) {
throw new Error(`Tool budget exceeded before ${toolName}`);
}
budget.toolCalls += 1;
const result = await execute(input);
const resultSize = JSON.stringify(result).length;
const estimatedResultTokens = Math.ceil(resultSize / 4);
budget.usedTokens += estimatedResultTokens;
assertBudgetAvailable(budget);
return result;
}
Expected result: a tool cannot quietly dump a giant result back into the agent loop.
Trim Tool Results Aggressively
Most agents do not need full raw tool output. They need the relevant slice.
Bad tool response:
{
"results": [
{ "title": "...", "url": "...", "fullHtml": "200KB of page markup" }
]
}
Better tool response:
{
"results": [
{
"title": "...",
"url": "...",
"snippet": "The 2-3 sentences that matter",
"publishedDate": "2026-08-01"
}
]
}
Expected result: lower input tokens on the next model call, less noise, fewer hallucinated detours.
Step 6: Add Retry Budgets
Retries are the silent bill killer. One malformed JSON response turns into five more model calls. One flaky tool turns into a loop. One ambiguous task turns into a whole fake investigation.
Use separate retry budgets for each failure type.
const RETRY_LIMITS = {
malformedOutput: 1,
rateLimit: 3,
toolFailure: 2,
lowConfidence: 0
};
function canRetry(runState, reason) {
runState.retries ||= {};
runState.retries[reason] ||= 0;
return runState.retries[reason] < RETRY_LIMITS[reason];
}
function recordRetry(runState, reason) {
runState.retries[reason] ||= 0;
runState.retries[reason] += 1;
}
Expected result: retries become a controlled expense, not a panic reflex.
For rate limits, respect provider headers such as retry-after where available. Anthropic’s API docs explicitly describe 429 errors with retry timing. Retrying faster than the provider tells you is not resilience. It is billing cosplay.
Step 7: Route Models by Budget Tier
Do not send every step to your most expensive model. Agents often need three kinds of intelligence:
| Task | Model tier |
|---|---|
| Classify intent | Cheap, fast model |
| Extract fields | Cheap or mid-tier model |
| Plan workflow | Mid-tier model |
| Final answer on complex task | Stronger model |
| High-stakes decision | Stronger model plus human review |
A routing function:
function chooseModel({ taskType, remainingDollars }) {
if (remainingDollars < 0.03) {
return "gpt-5.6-luna";
}
if (taskType === "classification") {
return "gpt-5.6-luna";
}
if (taskType === "research_summary") {
return "gpt-5.6-terra";
}
if (taskType === "legal_or_financial_review") {
return "human_review_required";
}
return "gpt-5.6-luna";
}
Expected result: the expensive model is reserved for moments where better reasoning actually changes the outcome.
This is where teams waste money out of superstition. They use a premium model for routing, formatting, classification, and “please turn this into JSON.” That is not quality. That is lighting money with extra steps.
Step 8: Add Human Approval Above a Threshold
Autonomy should shrink as cost and risk rise.
Use approval gates when:
- The run is about to exceed a soft budget
- The agent wants to call an expensive tool
- The task involves customer-visible actions
- The workflow touches money, credentials, legal claims, medical advice, or production systems
Example:
function requiresApproval({ budget, action }) {
const spentRatio = budget.spentDollars / budget.maxDollars;
if (spentRatio > 0.75) return true;
if (action.type === "send_email") return true;
if (action.estimatedCost > 0.25) return true;
if (action.risk === "high") return true;
return false;
}
Expected result: agents keep moving on cheap, reversible work and stop for humans on expensive or risky work.
This is not “less autonomous.” It is autonomy with adult supervision.
Step 9: Store Daily and Monthly Spend Limits
Per-run budgets are not enough. A thousand cheap runs can still become an expensive day.
Add user, team, and organization budgets.
async function checkUserDailyBudget({ store, userId, estimatedCost }) {
const key = `usage:${userId}:${new Date().toISOString().slice(0, 10)}`;
const currentSpend = Number(await store.get(key) || 0);
if (currentSpend + estimatedCost > 5.00) {
throw new Error("Daily user budget exceeded");
}
}
async function recordUserSpend({ store, userId, cost }) {
const key = `usage:${userId}:${new Date().toISOString().slice(0, 10)}`;
const currentSpend = Number(await store.get(key) || 0);
await store.set(key, currentSpend + cost, { ttlSeconds: 60 * 60 * 48 });
}
Expected result: one power user, broken workflow, or abusive script cannot drain the whole account.
You should still set provider-side spend limits where available. Anthropic documents monthly spend caps by tier and user-configurable spend limits below those caps. OpenAI has spend-limit and usage tooling in its platform docs. Use provider controls as the outer wall and your application controls as the inner wall.
Step 10: Log the Right Cost Events
A dashboard that only shows total monthly spend is almost useless. By the time it looks scary, the money is gone.
Log these fields for every run:
| Field | Why it matters |
|---|---|
run_id | Trace one workflow |
user_id | Find abusive or expensive usage |
agent_name | Compare workflows |
model | Catch expensive routing mistakes |
input_tokens | Detect context bloat |
cached_input_tokens | See whether caching helps |
output_tokens | Catch rambling responses |
tool_calls | Find looping tools |
retry_count | Catch hidden waste |
estimated_cost | Budget in dollars |
stop_reason | Know whether guardrails fired |
Expected result: you can answer “where did the bill come from?” without spelunking through logs like a doomed intern.
A minimal event:
{
"run_id": "run_123",
"user_id": "user_456",
"agent_name": "research_brief_agent",
"model": "gpt-5.6-luna",
"input_tokens": 42000,
"cached_input_tokens": 18000,
"output_tokens": 2100,
"tool_calls": 5,
"retry_count": 1,
"estimated_cost": 0.011,
"stop_reason": null
}
Common Pitfalls
Pitfall 1: Only Budgeting Final Answers
Agents spend money before the final answer appears. Planning, searching, parsing, tool retries, and self-checks all count. Track the whole run.
Pitfall 2: Ignoring Output Tokens
Output tokens are often more expensive than input tokens. A verbose agent can cost more than a well-contextualized one. Set max_output_tokens and tell the agent what shape the answer must take.
Pitfall 3: Letting Context Grow Forever
Multi-turn agents often resend conversation history. Summarize old context, drop irrelevant tool output, and keep structured state instead of raw transcripts.
Pitfall 4: Treating Rate Limits as Cost Limits
Rate limits prevent traffic spikes. They do not guarantee sane spend. A workflow can stay under rate limits all day and still rack up an impressive bill.
Pitfall 5: Hardcoding Prices Everywhere
Model prices change. Put pricing in one config file or fetch it from an internal pricing table your team maintains. Review it monthly.
Pitfall 6: No Kill Switch
Every serious agent system needs a global off switch by agent, user, workspace, and provider. When the bill graph goes vertical, “we can deploy a fix in 20 minutes” is not a plan.
A Practical Budget Policy You Can Ship This Week
Start with this:
| Guardrail | Default |
|---|---|
| Max cost per simple run | $0.05 |
| Max cost per research run | $0.25 |
| Max steps per run | 12 |
| Max tool calls per run | 8 |
| Max retries per failure type | 1-3 |
| Max user spend per day | $5 |
| Soft approval threshold | 75% of run budget |
| Hard stop threshold | 100% of run budget |
Then tune it from real data.
After one week, look for:
- Agents that hit budget too often
- Users with unusually high spend
- Tool calls with huge outputs
- Prompts with exploding context
- Models used for tasks that cheaper models can handle
- Retry loops caused by bad schemas or weak tool contracts
The goal is not to starve the agent. The goal is to make every dollar intentional.
Final Takeaway
AI agents need budgets the same way production systems need timeouts. Without them, one weird edge case can turn into a very dumb invoice.
Build cost guardrails at four layers: preflight estimates, per-call accounting, per-run hard stops, and user/org spend limits. Then log enough detail to see where the money went.
Autonomous workflows are useful. Unmetered autonomous workflows are just expense reports with better branding.
> Want more like this?
Get the best AI insights delivered weekly.
> Related Articles
AI Agent Approval Workflows: Put Humans at the Right Control Points
Human approval can make an agent safer—or merely slower. Design checkpoints around irreversible actions, changing risk, and evidence people can actually review.
LLM Trace Redaction in Production: Debug Without Logging Private Data
LLM traces are debugging gold and privacy dynamite. Capture structure, decisions, and timing while removing secrets and personal data before storage.
Secret Management for AI Agents: Stop Leaking Credentials Into Prompts
An agent needs tools, not a backpack full of API keys. Keep secrets outside model context, issue short-lived capability tokens, and audit every use.
Tags
> Stay in the loop
Weekly AI tools & insights.