How to Control AI Agent Cost on VPS
AI agent wey dey run unattended fit bill you quietly. See how to use hard caps, task budgets, prompt caching, batching, and usage fields to track spend.
AI agent wey dey always run fit make bill high: how to control am
AI agent cost control for VPS (virtual private server) na about limits wey you set before agent start, because nobody dey watch meter while e dey run. Put cap for every response with max_tokens, limit loop iterations for your own code, cache the part of prompt wey no dey change, and log usage numbers for every response to see which job dey spend money. Server rental na fixed monthly price. Model API dey charge per token, and loop wey nobody dey monitor fit spend tokens quietly well well.
This assume say agent don already exist and e dey call Messages API from box wey you own. How to build an AI agent with Claude for VPS explain the machinery itself.
Why unattended agent get different cost shape
Interactive session get human inside. If model enter wrong path or read 40,000-line log, the person wey dey watch go stop am. Unattended agent no get this brake: e go run until loop end, then timer go start am again.
Frequency na the multiplier wey many people miss. Job wey run every five minutes go run 288 times for one day and about 8,640 times for one month. Any amount one run cost, na that figure you go multiply. Plenty "always-on" agents no need stay on. Dem need answer within some number of minutes, and schedule fit handle that.
Agent still dey pay for things wey chat window no dey pay for.
- Tool definitions dey follow every request. Tool-use system prompt cost 290 tokens for Claude Opus 4.8 with
tool_choiceofautoornone, and 410 withanyortool. bash tool add another 325. Every MCP server wey you attach add its schemas to that weight, and MCP mean model context protocol. - Tool results na input tokens. Command wey print 8,000 lines go put 8,000 lines inside the next request, and inside every request after am for that turn.
- Fetched pages na input tokens. Average 10 kB web page na roughly 2,500 tokens, and 500 kB research PDF na roughly 125,000.
max_content_tokensdey truncate text ones only, because e "applies to text content, not to binary content such as PDFs". Usemax_usesandallowed_domainsto set limit for PDF instead. - Web search dey cost per search, at $10 for every 1,000 searches, no matter how many results come back. Search wey get error no dey bill.
None of these things cost plenty one time. But all of dem cost plenty 8,640 times.
Hard ceiling and soft ceiling solve different problem
max_tokens dey enforced. E be hard cap for total output of one request, including thinking and response text. Claude no go generate pass am, and model no fit see the number. If e reach am, e go return stop_reason: "max_tokens" and truncated answer. The catch for agents be say every request inside tool-use loop get im own max_tokens, so e dey limit one response, no be the whole task. Ten tool calls at 4,000 na 40,000-token ceiling for the turn.
Task budget na advisory. task_budget dey inside output_config and e tell model how many tokens e get for the whole agentic loop, including thinking, tool calls, tool results and output.
resp = client.beta.messages.create(
model="claude-opus-4-8",
max_tokens=4096,
betas=["task-budgets-2026-03-13"],
output_config={"task_budget": {"type": "tokens", "total": 64000}},
messages=messages,
)"Task budgets na soft hint, no be hard cap." Claude fit pass one budget during an action, but enforced output limit still be max_tokens. "Na only model fit see the countdown", and responses no carry remaining-budget field. The smallest accepted task_budget.total na 20,000 tokens; anything smaller go return 400 error. If budget too small for the work, model fit behave like say e dey refuse. E fit reduce the task scope or stop early.
One detail fit cost money instead of saving money. If your client dey reduce task_budget.remaining for every follow-up request, the changed value go invalidate any cached prefix wey contain am. Set am once, for the first request.
Task budgets dey beta for Claude Fable 5, Claude Opus 4.8 and Claude Opus 4.7. Claude Sonnet 5 and Claude Haiku 4.5 dey listed as Not supported, and task budgets no apply to Claude Code. So a Claude Code session wey you detach inside tmux depend on good session hygiene instead.
The third ceiling dey inside Claude Console: give the agent im own workspace, then set monthly spend limit and per-minute rate limits for am. "You no fit set limits for the Default Workspace", and "Organization-wide limits always apply, even when workspace limits add up to more". Add spend notifications so threshold go alert you before e reach the cap.
Per-job model choice, and what effort actually changes
Model choice na per-job decision. As of July 2026, per million tokens, input then output: Claude Fable 5 na $10 and $50, Claude Opus 4.8 and Opus 4.7 na $5 and $25, Claude Sonnet 5 na $3 and $15, Claude Haiku 4.5 na $1 and $5. Sonnet 5 dey below the sticker price for now, because "Introductory pricing of $2/$10 per million input/output tokens is in effect through August 31, 2026". Step wey only classify log lines no need Opus. No free allowance dey to cover busy schedule too, because Claude API no get free tier apart from the small credit wey dem give when person sign up.
Effort na the second lever. output_config.effort accepts low, medium, high, xhigh and max, and the default na high, so if you set high explicitly, na the same thing as omitting am. Lower effort reduce more than reasoning length: the documentation talk say e make Claude use fewer tool calls and combine operations into one. For agent, na bigger saving, because tool call wey you avoid mean say one whole request no happen.
The trap be say effort dey fight cache. If you change the value between requests, e invalidate prompt caching. For the documented example, request 2 report cache_read_input_tokens: 3546; request 3, after effort change from high to medium, report cache_creation_input_tokens of 3546 and cache_read_input_tokens of 0. So vary effort across workloads, but no change am inside one cached conversation. To control depth without breaking cache, do am for prompt: line like "Answer directly without deliberating." for the newest user message leave the earlier breakpoints intact.
Thinking tokens dey bill at output rates and dey count against max_tokens, na why truncated answer often mean say thinking don chop the budget. Read usage.output_tokens_details.thinking_tokens for the number. Wetin really dey fill Claude token bill break the meter down.
Cache the stable prefix, and stop breaking it by accident
Cache write dey cost 1.25 times the base input price for the five-minute cache, and 2 times for the one-hour cache. Cache read dey cost 0.1 times, so "caching pays off after just one cache read for the 5-minute duration (1.25x write), or after two cache reads for the 1-hour duration (2x write)".
One line explain why this one fit always-on agent: "The cache is refreshed for no additional cost each time the cached content is used." Job wey dey run every two minutes against the five-minute cache go keep the prefix warm all day with one write.
Three ways you fit lose the cache without noticing.
Prefix wey dey change. "Cache prefixes are created in the following order: tools, system, then messages." Any byte change wey happen earlier for that order go invalidate everything after am, and editing tool definitions go invalidate the whole cache. The common mistake na timestamp or run id inside system prompt: every request go then carry different prefix, write fresh entry at 1.25x, and read nothing back. The sign na usage.cache_read_input_tokens dey 0 across calls wey look identical. Move the text wey dey change go the newest user message.
Prefix wey too short. Every model get minimum cacheable length. If request fall below am, system go process am without caching and "no error is returned". The figures include 1,024 tokens for Claude Opus 4.8 and Claude Sonnet 5, and 4,096 for Claude Haiku 4.5. So moving job from Sonnet go Haiku fit switch caching off silently.
Conversation wey pass the lookback limit. "The lookback window is 20 blocks." System go check maximum 20 positions for each breakpoint, then stop. For the documented example, one turn get 35 blocks and breakpoint dey block 35. System go check blocks 35 down to 16. The previous turn entry for block 15 dey outside the window, so no hit go happen. Agent app wey dey add several tool-use and tool-result blocks for each turn fit pass 20 within two or three turns. You get four breakpoints for each request, so use one for the recent messages.
Send anything wey fit wait go the Batches API
“All usage dey charge 50% of the standard API prices”, for both input and output. Batch processing dey asynchronous, “with most batches finishing in less than 1 hour”, and results go show when every request don finish or after 24 hours, whichever one come first. Na the usual case be that, but nobody guarantee am.
Poll processing_status until e read ended. Requests wey return errored, canceled or expired no dey billed. One thing to note if you dey rely on spend cap: “batches fit pass your Workspace configured spend limit small.”
The discounts dey stack, and because batch fit take pass five minutes, the documentation recommend the one-hour cache for batches wey dey share context. So divide the work: anything wey person or webhook dey wait for make e remain for live path, while nightly digest or yesterday log classification fit enter batch for half price.
Log all response usage fields for your own store
You no fit attribute money wey you never record. Every response dey tell you wetin e cost.
u = resp.usage
row = {
"job": job_name,
"model": resp.model,
"uncached_input": u.input_tokens,
"cache_write": u.cache_creation_input_tokens,
"cache_read": u.cache_read_input_tokens,
"output": u.output_tokens,
"stop_reason": resp.stop_reason,
}Add one row for every API call to a JSON-lines file, and tag am with your job name. After one week, you fit tell which job dey spend money and which one only look busy. Monitor cache_read: column wey full of zeros na the commonest cost bug for self-hosted agent.
One field easy to misunderstand. input_tokens dey count only tokens after the last cache breakpoint, so the actual prompt size na total_input_tokens = cache_read_input_tokens + cache_creation_input_tokens + input_tokens. Agent wey report input_tokens: 400 for a large prompt no mean say e cheap: cache carry the remaining tokens.
Count before you send. Token counting free, and e get separate rate limits from message creation. So use count_tokens to reject attachment wey too large instead of paying before you discover am. The result na estimate, so measure again for each model, and never reuse count from another vendor tokenizer. Claude Opus 4.7 and later Opus models, Claude Fable 5, and Claude Sonnet 5 dey use newer tokenizer wey "produces approximately 30% more tokens for the same text". Claude Sonnet 4.6 and earlier, including Claude Haiku 4.5, dey use the previous one.
For the authoritative view, Admin API dey report usage for https://api.anthropic.com/v1/organizations/usage_report/messages and cost for https://api.anthropic.com/v1/organizations/cost_report. Both need admin key (sk-ant-admin01-...) as x-api-key: $ANTHROPIC_ADMIN_KEY with anthropic-version: 2023-06-01, and dem accept bucket_width=1d, group_by[]=model and api_key_ids[]=. One limitation dey: "The Admin API is unavailable for individual accounts."
That last parameter na cheap way to track attribution: give every job im own API key, filter with api_key_ids[], then split the report per key with group_by[]=api_key_id. The filter dey plural, but the grouping dimension dey singular. Keep the keys for environment instead of putting dem inside code, like first Claude API app for VPS dey handle dem.
Set limit for the loop, because nothing else go do am
You must set limit for how many times the loop fit run. Na you write the loop, so na you own the counter:
for step in range(MAX_STEPS): # MAX_STEPS = 12, never "while True"
resp = client.messages.create(...)
if resp.stop_reason != "tool_use":
break
else:
log.warning("job %s hit MAX_STEPS=%d, giving up", job_name, MAX_STEPS)The two limits above no do this work for you: max_tokens limit one response, while the model only know say the task get budget. Hosted product for don stop the process here, like Claude limit for tool calls inside one turn go stop session wey don make too many calls. But loop wey you write by yourself get no such safety limit until you add one.
Put another safety limit outside the process. Run the job with a systemd timer instead of permanent process, and set RuntimeMaxSec= for its service unit. With RuntimeMaxSec=600, system go kill run wey hang after ten minutes instead of make e continue until you notice am. How to run program as systemd service and timer explain the unit files themselves. Use journalctl -u triage-agent.service --since "1 hour ago" to read wetin one run do.
Set limit for retries too, because handler wey retry forever go charge you for every attempt. A 429 or 500 error deserve small number of tries with backoff. A 400 error no deserve any retry, because the same request go fail the same way.
AI agent cost control dey start when you read your own numbers
Nobody fit tell you wetin always-on agent go cost, because na tokens per run multiply by runs per day dey determine the cost, and both parts depend on you. Run am once, read the usage row wey you log, then multiply am by your schedule. Check the cost report two days later and compare am with that calculation. When the two no match, the difference almost always come from broken cache or loop wey run pass the time wey you assume.
This one assume say you get API key, because na your own program dey call Messages API. For your own interactive work, which Claude plan fit the way you dey work cover the subscription side. We check every price and limit here against Anthropic documentation for July 2026, so read the pricing page again before you build budget.
FAQ
Kati e dey cost to run an always-on AI agent for VPS?
Bills dey two, but na only one predictable. Server get fixed monthly price. Model API dey charge per token, so cost na wetin one run use multiply by how often e dey run. Anthropic no publish any figure for self-hosted always-on agent, so treat any quoted number as guess. Log usage from one real run, then multiply am by your schedule.
Wetin be the difference between max_tokens and task budget?
max_tokens dey enforced, and model no dey see am. E cap output for one request, including thinking, and if e reach am, e return stop_reason: "max_tokens". Task budget na the opposite: model dey see the number and use am pace the agentic loop, but "Task budgets are a soft hint, not a hard cap", and the enforced limit still be max_tokens.
Why cache_read_input_tokens dey always zero for my agent?
Na because the prefix dey change between calls, or e short too much to cache. The usual cause na timestamp or run id wey you interpolate inside system prompt: cache dey use the prefix as key, so any byte change invalidate everything after am. If you change tool definitions or the effort value, e do the same thing. Otherwise, na size cause am, because shorter prompts no dey cache and no error dey return.
How I fit stop AI agent from looping forever?
Count iterations inside your loop code and stop for fixed maximum, because max_tokens dey bound one response while agent fit make many responses. Add wall-clock limit outside the process: start the job from systemd timer with RuntimeMaxSec= set, so if run hang, e go die according to schedule. Cap retries too, because retry loop go charge you for every attempt.
I fit set spending limit for one Claude API key?
The documented spend limit dey apply per workspace, no be per key. So give the agent workspace of its own and cap monthly spend there. "You cannot set limits on the Default Workspace". Add spend notifications so threshold fit alert you first. For attribution, give each job its own key, then group the usage report with group_by[]=api_key_id.