SSD Nodes Learn
How to do am Matt ConnorBy Matt Connor · Updated 2026-07-24

how to control AI agent cost for VPS

Stop AI agent from dey spend money for VPS. Learn how to use prompt caching, task budgets, and usage fields to control every loop and token cost.

How to control cost for AI agent wey dey run always

To control AI agent cost for VPS (virtual private server), you must set limits before the agent start. Nobody dey watch the meter while the agent dey run. Cap every response with max_tokens, set limit for loop iterations for your code, cache the part of the 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 unattended loop dey very good to spend tokens quietly.

This one assume say you don build agent wey dey call Messages API from your own box. How to build AI agent with Claude on a VPS go explain the machinery itself.

Why unattended agent cost different

Interactive session get human inside. If model go wrong path or read 40,000-line log, the person wey dey watch go stop am. Unattended agent no get such brake: e go run until loop finish, then timer go start am again.

Frequency na the multiplier many people miss. If job dey run every five-minute, e go run 288 times for day and about 8,640 times for month. Whatever one run cost, na that figure you must multiply. Many "always-on" agents no need to dey on always. Dem only need to answer within some number of minutes, and na schedule be that.

Agent also pay for things wey chat window no dey pay for.

  • Tool definitions dey follow every request. The tool-use system prompt cost 290 tokens on Claude Opus 4.8 with tool_choice of auto or none, and 410 with any or tool. The bash tool add 325 more. Every MCP server wey you attach add its schemas to that weight, MCP na model context protocol.
  • Tool results na input tokens. Command wey print 8,000 lines go put 8,000 lines inside next request, and inside every next request 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_tokens dey truncate text ones only, because e "applies to text content, not to binary content such as PDFs". Use max_uses and allowed_domains for PDF instead.
  • Web search cost per search, na $10 per 1,000 searches, no matter how many results dem bring back. If search error, dem no go bill you.

None of dem expensive for one time. All of dem expensive when dem run 8,640 times.

Hard ceilings and soft ceilings solve different problems

Dem dey enforce max_tokens. Na hard cap for total output of one request, including thinking and response text together. Claude no dey ever pass am, and the model no fit see the number. If e reach am, you go get stop_reason: "max_tokens" and the answer go cut short. For agents, the wahala be say: every request inside tool-use loop get its own max_tokens, so e dey limit one response and no be the whole task. Ten tool calls for 4,000 means 40,000-token ceiling for that turn.

Task budget na advisory. task_budget dey inside output_config and e dey tell the 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 mid-action, and the enforced limit on output still na max_tokens. "The countdown na only the model fit see", and responses no dey carry any remaining-budget field. The minimum task_budget.total wey dem dey accept na 20,000 tokens, and if e less than that, e go return 400 error. If budget too small for the work, the model go behave like say e refuse to work, so e go reduce the task or stop early.

One detail dey cost money instead of to save am. If your client dey reduce task_budget.remaining for every follow-up request, the new value go make any cached prefix wey get am invalid. 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 list as Not supported, and task budgets no apply to Claude Code, so Claude Code session detached in tmux depend on session hygiene instead.

The third ceiling dey inside Claude Console: give the agent its own workspace, then set monthly spend limit and per-minute rate limits for am. "You no fit set limits for Default Workspace", and "Organization-wide limits always apply, even if workspace limits add up to more". Add spend notifications so that threshold go alert you before the cap reach.

Model choice for every job, and wetin really dey change effort

Model choice na decision wey you go make for every single job. As of July 2026, for every 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 price still low pass wetin dem write for now, because "Introductory pricing of $2/$10 per million input/output tokens is in effect through August 31, 2026". If your task na just to classify log lines, you no need Opus.

Effort na the second lever. output_config.effort dey accept low, medium, high, xhigh and max, and the default na high, so if you set high explicitly, e be like say you no put am at all. Lower effort dey cut cost pass reasoning length: documentation talk say e dey make Claude use fewer tool calls and combine operations into one. For agent, na that one dey save more money, because if you avoid one tool call, na one whole request wey no go happen.

The trap na say effort dey fight the cache. If you change the value between requests, the prompt caching go spoil. For the example wey dem write, request 2 report cache_read_input_tokens: 3546; request 3, wey change effort from high to medium, report cache_creation_input_tokens of 3546 and cache_read_input_tokens of 0. So, change effort for different workloads, no change am inside one cached conversation. To control depth without spoil the cache, do am inside the prompt: write something like "Answer directly without deliberating." for the newest user message, so that the earlier breakpoints go remain intact.

Thinking tokens dey bill for output rates and dem dey count for max_tokens, na why when answer cut short, e 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 go explain everything well.

Cache the stable prefix, and stop breaking it by accident

Cache write cost dey 1.25 times the base input price for 5-minute cache, and 2 times for 1-hour cache. Cache read cost na 0.1, 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 matter for always-on agent: "The cache is refreshed for no additional cost each time the cached content is used." If job dey fire every 2 minutes against the 5-minute cache, e go keep its prefix warm all day for just one write.

Three ways to lose the cache without you even know.

A prefix that changes. "Cache prefixes are created in the following order: tools, system, then messages." If any byte change for early part of that order, e go invalidate everything wey follow am, and if you edit tool definitions, e go invalidate the whole cache. The classic mistake na to put timestamp or run id inside the system prompt: every request den go carry different prefix, e go write fresh entry at 1.25x, and e no go read anything back. You go see usage.cache_read_input_tokens at 0 for calls wey look identical. Move the text wey dey change into the newest user message.

A prefix that is too short. Every model get minimum cacheable length, and if the request short pass that level, e go process without caching and "no error is returned". The figures include 1,024 tokens on Claude Opus 4.8 and Claude Sonnet 5, and 4,096 on Claude Haiku 4.5, so if you move job from Sonnet to Haiku, caching fit switch off silently.

A conversation that outgrows the lookback. "The lookback window is 20 blocks." The system check at most 20 positions per breakpoint, then e stop. For the example wey dem document, one turn wey get 35 blocks with a breakpoint on block 35 go check blocks 35 down to 16, and the previous turn's entry at block 15 go fall outside the window, so e no go get hit. If agent dey append many tool-use and tool-result blocks per turn, e go cross 20 in two or three turns. You get four breakpoints per request, so use one for the recent messages.

Send anything wey fit wait to the Batches API

"All usage go charge at 50% of the standard API prices", for both input and output. Batch processing dey work asynchronous, "most batches dey finish in less than 1 hour", and you go get results when every request don finish or after 24 hours, whichever come first. Na so e dey normally work, but e no be guarantee.

Poll processing_status until e show ended. Requests wey return errored, canceled or expired no go charge you money. One thing to watch out for if you dey use spend cap: "batches may go slightly over your Workspace's configured spend limit."

The discounts dey stack, and because batch fit take more than five minutes, the documentation recommend say make you use the one-hour cache for batches wey share context. So split the work: anything wey person or webhook dey wait for must stay for live path, but nightly digest or yesterday log classification go enter batch for half price.

Log every response's usage fields to your own store

You no fit know how much money you don spend if you no record am. Every response tell you how much 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 new row for every API call inside one JSON-lines file, and use your job name as tag. After one week, you go fit know which job dey spend money and which one just dey look busy. Watch out for cache_read: if you see column of zeros, na common cost bug for self-hosted agent.

One field easy to misread. input_tokens dey count only the tokens wey come after the last cache breakpoint, so the real prompt size na total_input_tokens = cache_read_input_tokens + cache_creation_input_tokens + input_tokens. If agent report input_tokens: 400 for big prompt, e no mean say e cheap: the rest of the tokens come from cache.

Count the tokens before you send the request. Token counting free and its rate limits different from message creation, so use count_tokens to reject big attachment instead of paying money to find out. The result na just estimate, so re-measure for every model and no use count from another vendor's tokenizer. Claude Opus 4.7 and later Opus models, Claude Fable 5 and Claude Sonnet 5 use new tokenizer wey "produces approximately 30% more tokens for the same text". Claude Sonnet 4.6 and earlier, Claude Haiku 4.5 among them, use the old one.

If you want the correct data, the 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 dey take admin key (sk-ant-admin01-...) as x-api-key: $ANTHROPIC_ADMIN_KEY with anthropic-version: 2023-06-01, and dem dey accept bucket_width=1d, group_by[]=model and api_key_ids[]=. One problem: "The Admin API is unavailable for individual accounts."

That last parameter na smart way to track spend: give every job its own API key, filter with api_key_ids[], and split the report for every key with group_by[]=api_key_id. The filter na plural, but the grouping dimension na singular. Keep the keys for environment instead of inside code, just like how a first Claude API app on a VPS dey do am.

Bound the loop, because nothing else will

You must set a limit for how many times the loop go run. You control the loop, so you must control 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 ceiling wey dem set above no go help you: max_tokens only cap one response, and the model only know the task budget.

Put another brake outside the process. Run the job from a systemd timer instead of a permanent process, and set RuntimeMaxSec= on its service unit. With RuntimeMaxSec=600, if the run hang, system go kill am after ten minutes instead of making am spin until you notice. How to run a program as a systemd service and timer go explain how to write the unit files. Use journalctl -u triage-agent.service --since "1 hour ago" to see wetin the run do.

Cap the retries too, because any handler wey go retry forever go charge money for every attempt. 429 or 500 error deserve few tries with backoff. 400 error no deserve any retry, because the same request go fail the same way.

AI agent cost control start with how you read your own numbers

Nobody fit tell you how much one always-on agent go cost. This one na because cost depend on tokens per run multiply by runs per day, and you go control both sides. Run am once, look the usage row wey you log, and multiply am with your schedule. Two days later, check the cost report against that arithmetic. If the two things no match, the gap na because cache don break or loop run longer than you think.

This one assume say you get API key, because the agent na your own program wey dey call the Messages API. For your own interactive work, which Claude plan fit the way you work go explain the subscription side. We check every price and limit for here against Anthropic documentation for July 2026, so re-read the pricing page before you build budget.

FAQ

How much money e go cost to run always-on AI agent for VPS?

Two bills dey, and only one of dem easy to predict. Server price na fixed monthly amount. Model API dey charge per token, so cost na wetin one run consume multiply by how many times e dey run. Anthropic no give any figure for self-hosted always-on agent, so any number wey dem talk na just guess. Log usage from one real run and multiply am by your schedule.

Wetin be difference between max_tokens and task budget?

max_tokens na hard limit wey model no fit see. E dey cap the output of one request, including thinking, and if e reach that limit, e go give stop_reason: "max_tokens". Task budget na opposite: you dey tell model the number and e go dey control the agentic loop based on am, but "Task budgets are a soft hint, not a hard cap" and the real limit still na max_tokens.

Why cache_read_input_tokens dey always zero for my agent?

Because the prefix dey change between calls, or e too short for cache. The main reason na when you put timestamp or run id inside system prompt: cache dey use prefix as key, so if any single byte change, everything after am go invalid. Changing tool definitions or the effort value dey do the same thing. If no be that, na because of size, since short prompts no dey get cache and system no dey return error.

How I fit stop AI agent from looping forever?

Count iterations inside your loop code and stop am at one fixed maximum, because max_tokens dey bound one response but agent dey make many. Add wall-clock limit outside the process: start the job from one systemd timer with RuntimeMaxSec= set, so if the run jam, the timer go kill am. Cap retries too, because retry loop dey charge money for every attempt.

I fit set spending limit for one single Claude API key?

The spend limit wey dem document na for workspace, no be for single key, so give the agent its own workspace and cap the monthly spend for there. "You cannot set limits on the Default Workspace". Add spend notifications so e go alert you when e reach threshold. For attribution, give each job its own key, then group the usage report with group_by[]=api_key_id.

#claude#ai#agents#api#cost