如何控制常驻 AI agent 的 VPS API 费用
无人值守 agent 会在每次循环中持续计费。本文介绍硬上限、任务预算、提示缓存与批处理,并说明如何记录用量字段,找出实际耗费最多的任务。
如何防止常驻 AI agent 产生失控费用
在 VPS(虚拟专用服务器)上控制 AI agent 的成本,关键是在 agent 启动前设置上限,因为运行期间不会有人持续查看用量。使用 max_tokens 限制每次响应,在自己的代码中限制循环迭代次数,缓存提示中不会变化的部分,并记录每次响应的用量数据,以确定哪个任务消耗最多。服务器租用费是固定的月费。模型 API 按 token 计费,而无人值守的循环很容易在不易察觉的情况下持续消耗 token。
本文假设 agent 已经存在,并从您管理的服务器调用 Messages API。在 VPS 上使用 Claude 构建 AI agent介绍具体的实现过程。
Why an unattended agent is a different cost shape
An interactive session has a human in it. When the model goes down a wrong path or reads a 40,000-line log, the person watching stops it. An unattended agent has no such brake: it runs until the loop ends, then a timer starts it again.
Frequency is the multiplier people miss. A job on a five-minute schedule runs 288 times a day and about 8,640 times a month. Whatever one run costs, that is the figure you multiply. Many "always-on" agents do not need to be on. They need to answer within some number of minutes, which is a schedule.
An agent also pays for things a chat window does not.
- Tool definitions ride along on every request. The tool-use system prompt costs 290 tokens on Claude Opus 4.8 with
tool_choiceofautoornone, and 410 withanyortool. The bash tool adds 325 more. Every MCP server you attach adds its schemas to that weight, MCP being the model context protocol. - Tool results are input tokens. A command that prints 8,000 lines puts 8,000 lines into the next request, and into every request after it in that turn.
- Fetched pages are input tokens. An average 10 kB web page is roughly 2,500 tokens and a 500 kB research PDF roughly 125,000.
max_content_tokenstruncates the text ones only, because it "applies to text content, not to binary content such as PDFs". Bound a PDF withmax_usesandallowed_domainsinstead. - Web search is priced per search, at $10 per 1,000 searches, however many results come back. A search that errors is not billed.
None of that is expensive once. All of it is expensive 8,640 times.
硬上限和软上限解决的是不同问题
max_tokens会强制执行。 它限制单个请求的总输出,包括思考和响应文本。Claude 不会超过此上限,并且模型无法看到该数值。达到上限后会返回 stop_reason: "max_tokens",响应也会被截断。对于 agent 而言,关键在于:工具调用循环中的每个请求都有自己的 max_tokens,因此它限制的是单次响应,而不是整个任务。一次包含 10 次工具调用、每次上限为 4,000 的流程,其本轮上限为 40,000 个 token。
任务预算仅供参考。 task_budget 位于 output_config 之内,用于告知模型整个 agent 流程可使用的 token 数量,其中包括思考、工具调用、工具结果和输出。
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,
)“任务预算是软提示,不是硬上限。”Claude 可能在一次操作中超过该预算,但输出仍受 max_tokens 强制限制。“只有模型可以看到倒计时”,响应中不会包含剩余预算字段。可接受的 task_budget.total 最小值为 20,000 个 token,设置更小的值会返回 400 错误。预算过小而无法完成任务时,模型会表现出类似拒绝的行为,因此会缩小任务范围或提前停止。
有一个细节不会节省费用,反而会增加费用。如果客户端在每次后续请求中递减 task_budget.remaining,更改后的值会使包含该值的缓存前缀失效。应在第一个请求中设置一次。
Claude Fable 5、Claude Opus 4.8 和 Claude Opus 4.7 支持处于 beta 阶段的任务预算。Claude Sonnet 5 和 Claude Haiku 4.5 被列为 Not supported,而任务预算不适用于 Claude Code。因此,在 tmux 中分离的 Claude Code 会话 取决于会话维护。
第三个上限位于 Claude Console 中:为 agent 分配独立工作区,然后为该工作区设置每月支出上限和每分钟速率限制。“无法为 Default Workspace 设置限制”,并且“组织范围的限制始终生效,即使各工作区限制的总和更高”。添加支出通知,以便在达到上限前通过阈值告警提醒您。
按作业选择模型,以及实际影响成本的因素
模型选择应按作业决定。截至2026年7月,每百万个 token 的输入和输出价格如下:Claude Fable 5 分别为 $10 和 $50,Claude Opus 4.8 与 Opus 4.7 分别为 $5 和 $25,Claude Sonnet 5 分别为 $3 和 $15,Claude Haiku 4.5 分别为 $1 和 $5。目前 Sonnet 5 的实际价格低于标价,因为“每百万个输入/输出 token $2/$10 的介绍性价格有效期截至2026年8月31日”。仅用于分类日志行的步骤不需要 Opus。忙碌的作业计划也无法依靠免费额度来抵扣,因为 Claude API 没有免费层级,注册时获得的小额额度除外。
Effort 是第二个调节因素。output_config.effort 接受 low、medium、high、xhigh 和 max,默认值为 high,因此显式设置 high 等同于省略该设置。降低 effort 减少的不只是推理长度:文档说明,这会让 Claude 发起更少的工具调用,并将多个操作合并为一次。对于 agent,这项节省更大,因为每减少一次工具调用,就少产生一个完整请求。
问题在于,effort 会影响缓存。更改请求之间的该值会使提示缓存失效。在文档示例中,请求2报告了 cache_read_input_tokens: 3546;请求3 将 effort 从 high 改为 medium 后,报告了 cache_creation_input_tokens(共3546)和 cache_read_input_tokens(共0)。因此,应在不同工作负载之间调整 effort,不要在同一个已缓存的对话中调整。若要在不破坏缓存的情况下控制深度,请在提示中说明:在最新用户消息中加入类似“直接回答,不要展开推理。”的一行文字,可以保留之前的缓存断点。
思考 token 按输出价格计费,并计入 max_tokens,因此答案被截断通常意味着思考过程耗尽了预算。读取 usage.output_tokens_details.thinking_tokens 获取该数值。Claude token 费用究竟由什么组成 会拆解这一计量过程。
缓存稳定前缀,避免意外破坏它
在 5 分钟缓存中,写入缓存的费用是基础输入价格的 1.25 倍;在 1 小时缓存中,费用是 2 倍。读取缓存的费用是基础价格的 0.1 倍。因此,“5 分钟缓存只需读取一次即可开始节省成本(写入费用为 1.25 倍),1 小时缓存只需读取两次即可开始节省成本(写入费用为 2 倍)”。
下面这句话说明了它为什么适合持续运行的 agent:“每次使用缓存内容时,缓存都会免费刷新。”针对 5 分钟缓存每两分钟运行一次的任务,只需写入一次,就能让此前缀全天保持热状态。
以下 3 种情况会让缓存失效,而你可能不会立即发现。
前缀发生变化。“缓存前缀按以下顺序创建:tools、system,然后是 messages。”此前缀顺序中较早位置的任何字节变化,都会使其后的全部内容失效;编辑工具定义则会使整个缓存失效。最常见的自我破坏方式,是在系统提示中加入时间戳或运行 ID:这样每个请求都会携带不同的前缀,以 1.25 倍价格写入新条目,却不会命中任何已有缓存。相同调用看起来完全一致,但 usage.cache_read_input_tokens 始终为 0,这就是明显信号。将易变文本移到最新的用户消息中。
前缀过短。每个模型都有可缓存长度下限。低于该长度时,请求会在不使用缓存的情况下处理,并且“不会返回错误”。例如,Claude Opus 4.8 和 Claude Sonnet 5 的下限为 1,024 个 token,Claude Haiku 4.5 的下限为 4,096 个 token。因此,将任务从 Sonnet 切换到 Haiku 可能会静默关闭缓存。
对话超出回溯范围。“回溯窗口为 20 个块。”系统在每个断点最多检查 20 个位置,然后停止。在文档示例中,一轮包含 35 个块,并在第 35 个块设置断点时,系统会检查第 35 到第 16 个块;上一轮位于第 15 个块的条目超出窗口,因此不会命中。agent 每轮追加多个工具调用块和工具结果块时,只需 2 或 3 轮就会超过 20。每个请求有 4 个断点,因此应将其中一个用于最近的消息。
将所有可以延迟的任务提交到 Batches API
输入和输出均按标准 API 价格的 50% 计费。批处理采用异步方式,“大多数批次会在 1 小时内完成”。结果会在所有请求完成后返回,或在 24 小时后返回,以先到者为准。这是通常情况,并非保证。
轮询 processing_status,直到其值为 ended。返回 errored、canceled 或 expired 的请求不会计费。如果您依赖支出上限,还需注意一个例外:“批次的支出可能会略微超过 Workspace 配置的支出上限。”
这些折扣可以叠加。由于批次处理时间可能超过 5 分钟,文档建议对共享上下文的批次使用 1 小时缓存。因此应拆分任务:用户或 webhook 需要等待的内容保留在实时路径上,夜间摘要或前一天的日志分类则提交到批次中,以半价处理。
将每次响应的用量字段记录到自己的存储中
未记录的支出无法归属。每次响应都会告诉您产生了多少成本。
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,
}每次 API 调用向 JSON-lines 文件追加一行,并标记作业名称。一周后,您就能知道哪些作业产生了支出,哪些只是看起来繁忙。请监控 cache_read:全是 0 的列是自托管代理中最常见的成本统计错误。
有一个字段很容易误读。input_tokens只统计最后一个缓存断点之后的 token,因此实际提示词大小是 total_input_tokens = cache_read_input_tokens + cache_creation_input_tokens + input_tokens。大型提示词上报告 input_tokens: 400 的代理并不表示成本低:其余内容来自缓存。
发送前先计数。Token 计数不收费,且其速率限制独立于消息创建,因此应使用 count_tokens 拒绝过大的附件,而不是付费后才发现附件超限。结果只是估算值,因此应针对每个模型重新测量,绝不要复用其他供应商 tokenizer 得出的计数。Claude Opus 4.7 及更高版本的 Opus 模型、Claude Fable 5 和 Claude Sonnet 5 使用较新的 tokenizer,该 tokenizer “对相同文本生成的 token 数大约多 30%”。Claude Sonnet 4.6 及更早版本(包括 Claude Haiku 4.5)使用旧版 tokenizer。
如需查看权威数据,Admin API 会在 https://api.anthropic.com/v1/organizations/usage_report/messages 报告用量,并在 https://api.anthropic.com/v1/organizations/cost_report 报告成本。两者都需要将管理员密钥(sk-ant-admin01-...)作为 x-api-key: $ANTHROPIC_ADMIN_KEY,并配合 anthropic-version: 2023-06-01 使用,同时接受 bucket_width=1d、group_by[]=model 和 api_key_ids[]=。有一项限制:“Admin API 不适用于个人账户。”
最后一个参数提供了一种低成本的归属方法:为每个作业分配独立的 API key,使用 api_key_ids[] 进行筛选,再使用 group_by[]=api_key_id 按 key 拆分报告。筛选器是复数,分组维度是单数。请将这些 key 保存在环境变量中,而不是代码中,正如 在 VPS 上创建第一个 Claude API 应用时的做法。
限制循环次数,因为没有其他机制会替你限制
这里必须设置有上限的迭代次数。循环由您编写,因此计数器也由您控制:
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)上面的两个上限都不能替您完成这项工作:max_tokens限制单次响应,而模型只会获知任务预算。托管产品会在这里停止,就像Claude 对单轮工具调用次数的上限会终止调用次数过多的会话一样;但您自行编写的循环不会自动提供这种保护,必须手动添加。
在进程外再设置一道限制。不要运行永久进程,而应通过 systemd timer 运行任务,并在其 service unit 中设置 RuntimeMaxSec=。设置 RuntimeMaxSec=600 后,运行卡住时会在 10 分钟后终止,而不是一直运行到您发现问题为止。将程序作为 systemd 服务和计时器运行介绍了 unit file 的具体配置。使用 journalctl -u triage-agent.service --since "1 hour ago" 查看某次运行执行了哪些操作。
同时限制重试次数,因为无限重试的处理程序会为每次尝试计费。对于 429 或 500 错误,可以结合退避策略重试几次。对于 400 错误,不应重试,因为相同请求会以相同方式失败。
AI agent 成本控制始于读取自己的数据
没人能直接告诉您常驻 agent 的成本,因为成本等于每次运行消耗的 token 数乘以每天运行次数,而这两项都由您决定。先运行一次,读取您记录的用量行,再乘以计划运行次数。两天后,将成本报告与该计算结果进行核对。如果两者不一致,差值几乎总是由缓存失效或运行时间超出预期的循环造成。
这里假设您使用 API key,因为 agent 是调用 Messages API 的自有程序。对于您自己的交互式工作,哪种 Claude 方案适合您的工作方式介绍了订阅方面的选择。这里的所有价格和限额均已根据 Anthropic 在 July 2026 发布的文档进行核对,因此在制定预算前,请重新查看定价页面。
FAQ
运行持续在线的 VPS AI agent 需要多少成本?
费用分为两部分,只有一部分可以准确预测。服务器按月收取固定费用。模型 API 按 token 计费,因此成本取决于单次运行消耗的 token 数量,以及运行频率。Anthropic 没有公布自托管持续在线 agent 的具体费用,因此任何引用的金额都只能视为估算值。记录一次真实运行产生的 usage,再根据运行计划计算总成本。
max_tokens 和任务预算有什么区别?
max_tokens 由系统强制执行,模型无法看到。它限制单次请求的输出量,其中包括思考内容;达到限制后会返回 stop_reason: "max_tokens"。任务预算则相反:模型会获知预算值,并据此控制 agent 循环,但“任务预算只是软提示,不是硬限制”,真正强制执行的限制仍然是 max_tokens。
为什么我的 agent 的 cache_read_input_tokens 始终为 0?
因为连续调用之间的前缀发生了变化,或者前缀太短,无法进行缓存。常见原因是将时间戳或运行 ID 插入了系统提示词:缓存以此前缀为键,因此任何字节变化都会使其后的全部内容失效。修改工具定义或 effort 值也会产生相同结果。否则问题可能是提示词长度,因为较短的提示词不会被缓存,而且系统不会返回错误。
如何阻止 AI agent 无限循环?
在循环代码中统计迭代次数,并在达到固定上限时停止,因为 max_tokens 只限制单次响应,而 agent 可能生成多次响应。在进程外部添加 wall-clock 时间限制:使用 systemd timer 启动任务,并设置 RuntimeMaxSec=,这样卡住的运行会按计划终止。同时限制重试次数,因为每次重试都会产生费用。
能否为单个 Claude API key 设置支出上限?
文档规定的支出上限按 workspace 设置,而不是按 key 设置。因此,应为该 agent 创建独立的 workspace,并在那里限制月度支出。“无法为 Default Workspace 设置限制”。添加支出通知,以便在达到阈值时先收到提醒。为便于归因,为每个任务分配独立的 key,然后使用 group_by[]=api_key_id 汇总使用情况报告。