SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor

如何防止常驻 AI Agent 产生高额 API 费用

在 VPS 上运行无人值守 AI Agent 极易导致 API 费用失控。本文提供成本控制方案,包括设置硬性消费上限、利用 Prompt 缓存、优化工具调用开销,以及通过限制循环次数和处理长文本输入来规避高额 token 消耗。

如何防止常驻 AI agent 产生高额费用

在 VPS(虚拟专用服务器)上控制 AI agent 的成本,关键是在 agent 启动前设置上限,因为运行期间没有人持续查看计费情况。使用 max_tokens 限制每次响应,​​在自己的代码中限制循环迭代次数,缓存提示词中不会变化的部分,并记录每次响应的用量数据,以确定哪个任务消耗最多。服务器租赁费是固定的月费。模型 API 按 token 计费,而无人值守的循环很容易在不知不觉中消耗大量 token。

本文假设 agent 已经存在,并且会从您管理的服务器调用 Messages API。在 VPS 上使用 Claude 构建 AI agent介绍具体的实现过程。

为什么无人值守代理的成本结构不同

交互式会话中有人在现场。模型走错方向或读取 40,000 行日志时,监控人员会将其停止。无人值守的代理没有这种制动机制:它会一直运行到循环结束,然后由计时器再次启动。

频率是最容易被忽略的倍数。按每 5 分钟运行一次的任务,每天运行 288 次,每月约运行 8,640 次。单次运行的成本是多少,就用这个数字进行乘法计算。许多“始终运行”的代理其实不需要持续运行。它们只需在规定的分钟数内响应,这属于计划任务。

Agent 还会处理聊天窗口无法处理的付费操作。

  • 每次请求都会附带工具定义。 在 Claude Opus 4.8 中,工具调用系统提示的开销为 290 个令牌,使用 tool_choice 和 auto 或 none 时为此值;使用 any 或 tool 时为 410 个令牌。bash 工具还会额外增加 325 个令牌。每附加一个 MCP 服务器,其架构都会增加到这部分开销中;MCP 是模型上下文协议。
  • 工具结果会计入输入令牌。 如果某条命令输出 8,000 行,这 8,000 行会进入下一次请求,以及该轮对话中之后的每次请求。
  • 抓取的页面会计入输入令牌。 平均大小为 10 kB 的网页约占 2,500 个令牌,大小为 500 kB 的研究 PDF 约占 125,000 个令牌。max_content_tokens 仅会截断文本,因为它“适用于文本内容,不适用于 PDF 等二进制内容”。应改用 max_uses 和 allowed_domains 限制 PDF 的大小。
  • Web 搜索按搜索次数计费,每 1,000 次搜索收费 $10,与返回的结果数量无关。搜索出错时不收费。

这些操作并不是只需承担一次成本,而是要承担 8,640 次成本。

硬上限和软上限解决的是不同问题

max_tokens会强制执行。 它限制单个请求的总输出,包括思考和响应文本。Claude 不会超过此上限,模型也无法看到该数值。达到上限后会返回 stop_reason: "max_tokens",并截断答案。对于代理来说,问题在于:工具调用循环中的每个请求都有自己的 max_tokens,因此它限制的是单次响应,而不是整个任务。一次交互中进行 10 次工具调用、每次上限为 4,000,即表示总上限为 40,000 个 token。

任务预算仅供参考。 task_budget 位于 output_config 内部,用于告知模型整个代理循环可使用的 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.1、Claude Fable 5、Claude Opus 5.5、Claude Opus 5、Claude Opus 4.8、Claude Opus 4.7、Claude Sonnet 5.5 和 Claude Haiku 5.5 支持处于 beta 阶段的任务预算。Claude Sonnet 5 和 Claude Haiku 4.5 标记为 Not supported;任务预算不适用于 Claude Code,因此在 tmux 中分离的 Claude Code 会话取决于会话管理是否规范。

第三个上限位于 Claude Console 中:为代理分配专用工作区,然后为该工作区设置每月支出上限和每分钟速率限制。不能为 Default Workspace 设置支出上限,组织级限制始终生效。添加支出通知,以便在达到上限前收到阈值告警。

按任务选择模型,以及实际能改变成本的设置

模型选择应按任务决定。截至 2026 年 10 月,每百万个 token 的输入和输出价格如下:Claude Fable 5.1 和 Fable 5 分别为 $10 和 $50;Claude Opus 5.5 分别为 $4 和 $20;Claude Opus 5、Opus 4.8 和 Opus 4.7 分别为 $5 和 $25;Claude Sonnet 5.5 和 Sonnet 5 分别为 $2 和 $10;Claude Haiku 5.5 对不超过 100,000 个 token 的提示分别收取 $0.10 和 $0.50,超过该数量后分别为 $0.50 和 $2.50(缓存 token 也计入数量);Claude Haiku 4.5 分别为 $1 和 $5。Anthropic 最初以介绍性价格销售 Sonnet 5,后来将该价格改为标准价格,并取消了原定上涨至 $3 和 $15 的计划。只对日志行进行分类的步骤不需要 Opus。

也不要指望免费额度能够覆盖繁忙的任务计划。除 Claude API 注册时提供的少量额度外,Claude Max、Ultra 和 Team 计划还包含每月 API 额度:Max 为 $100,Ultra 为 $200,Team 共享额度最高为 $500。额度在每个计费周期刷新。符合条件的计划使用满 7 天后即可领取,且不需要支付方式。额度可用于 Claude API、Managed Agents、Agent SDK 和 playground,但不能用于 Claude Code;每个周期结束时额度会过期,不能结转。使用该额度的金额会计入支出上限。额度用尽后,预付请求会停止,除非组织还持有已购买的额度。通过 Anthropic 销售团队开具发票的组织,超过额度后的用量仍按通常方式计费。

Effort 是第二个调节手段。output_config.effort 接受 low、medium、high、xhigh 和 max,但并非每个模型都支持所有级别。大多数模型的默认值是 high,Claude Opus 5.5 和 Claude Haiku 5.5 的默认值是 medium;显式设置模型默认值与省略该设置效果相同。降低 effort 不仅会减少推理长度:文档说明,这会让 Claude 减少工具调用,并将多个操作合并到更少的调用中。对于代理来说,这项节省更明显,因为避免一次工具调用,就等于完全避免了一次请求。

问题在于,effort 会影响缓存。更改请求之间的顶层值会使提示缓存失效。在 Claude Opus 5.5 的文档示例中,请求 2 报告了 cache_read_input_tokens: 3546。请求 3 将 effort 从该模型的默认值 medium 改为 low,并报告 cache_creation_input_tokens(总计 3546)和 cache_read_input_tokens(总计 0)。因此,可以在不同工作负载之间调整顶层 effort,但不要在同一个缓存对话中调整。还有两种方式可以改变推理深度而不破坏缓存。在 Claude Fable 5.1、Opus 5.5、Opus 5、Sonnet 5.5 和 Haiku 5.5 上,可以按消息调整 effort(beta 标头 mid-conversation-output-config-2026-07-01);这会设置新的级别,同时保留缓存前缀。在任何模型上,也可以在提示中进行引导:例如,在最新的用户消息中加入“直接回答,不要进行详细推理。”,不会影响之前的缓存断点。不过,在 Claude Haiku 5.5 上,这句话不能可靠地减少思考过程。

思考 token 按输出价格计费,并计入 max_tokens,因此答案被截断通常意味着思考过程耗尽了预算。读取 usage.output_tokens_details.thinking_tokens 获取具体数量。Claude 的 token 账单实际包含哪些内容会拆解这一计量方式。

缓存稳定前缀,避免意外破坏

五分钟缓存的写入成本是基础输入价格的 1.25 倍,一小时缓存则为 2 倍。在大多数模型上,缓存读取成本为 0.1 倍,因此“对于 5 分钟缓存(1.25 倍写入),读取一次即可回本;对于 1 小时缓存(2 倍写入),读取两次即可回本”。最新模型的读取成本更低:Claude Opus 5.5 和 Claude Sonnet 5.5 为 0.05 倍,Claude Fable 5.1 为 0.025 倍。

一句话解释了为何这适用于常驻代理:“每次使用缓存内容时,缓存都会刷新,且无需额外成本。”一个每两分钟触发一次且针对五分钟缓存的任务,只需一次写入即可全天保持前缀处于活跃状态。

三种导致缓存失效且不易察觉的情况。

前缀发生变化。 “缓存前缀按以下顺序创建:tools、system,然后是 messages。”该顺序中任何字节的变动都会导致其后的所有内容失效,修改工具定义也会使整个缓存失效。典型的误操作是在系统提示词中包含时间戳或运行 ID:这会导致每个请求携带不同的前缀,从而以 1.25 倍的价格写入新条目,且无法读取任何缓存。其特征是相同外观的调用中 usage.cache_read_input_tokens 始终为 0。请将易变文本移至最新的用户消息中。

前缀过短。 每个模型都有最小可缓存长度,低于此长度的请求将直接处理而不使用缓存,且“不会返回错误”。具体数值包括:Claude Fable 5.1、Fable 5、Opus 5.5、Opus 5、Sonnet 5.5 和 Haiku 5.5 为 512 个 token;Claude Opus 4.8 和 Claude Sonnet 5 为 1,024 个 token;Claude Haiku 4.5 为 4,096 个 token。因此,将任务从 Sonnet 5 迁移到 Haiku 4.5 可能会导致缓存功能静默失效。

对话超出了回溯范围。 “回溯窗口为 20 个块。”系统在每个断点处最多检查 20 个位置,之后停止。在文档示例中,一个包含 35 个块且在第 35 块设有断点的轮次,会检查第 35 到 16 块,而上一轮次位于第 15 块的条目超出了窗口范围,因此无法命中。如果代理在每轮对话中追加多个工具使用和工具结果块,两到三轮后就会超过 20 个块的限制。每个请求最多可设置四个断点,请务必将其中一个分配给最近的消息。

将所有可以延迟的请求发送到 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 4.7 及更高版本的模型,包括 Claude Fable 5 和 Claude Sonnet 5,使用更新的 tokenizer,该 tokenizer “对相同文本生成的 token 数量约多 30%”。Claude Sonnet 4.6 及更早版本的模型,包括 Claude Haiku 4.5,使用之前的 tokenizer。

如需查看权威数据,旧版 Usage and Cost 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[]=。成本报告仅按天提供数据,并按 workspace_id或 description分组。有一项限制:“Admin API 不适用于个人账户。”

api_key_ids[]参数提供了一种成本低廉的归因方法:为每个任务分配独立的 API key,使用 api_key_ids[]筛选用量报告,再使用 group_by[]=api_key_id按 key 拆分。筛选维度是复数,分组维度是单数。按照 在 VPS 上创建第一个 Claude API 应用的做法,将这些 key 保存在环境变量中,而不是写入代码。

为循环设置上限,因为没有其他机制会替你完成这件事

这里必须设置有界的迭代次数。循环由你编写,因此计数器也由你控制:

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 执行任务,并为其服务单元设置墙上时钟时间上限。timer 任务通常是 Type=oneshot,而 RuntimeMaxSec=“对 Type=oneshot 服务没有任何作用”,因此应在此处设置 TimeoutStartSec=600。仅对 Type=simple单元使用 RuntimeMaxSec=600。无论采用哪种方式,失控的运行都会在十分钟后被终止,而不是持续运行到你发现问题为止。将程序作为 systemd 服务和 timer 运行介绍了服务单元文件本身。使用 journalctl -u triage-agent.service --since "1 hour ago"查看一次运行执行了哪些操作。

同时限制重试次数。失败的 API 请求不会产生费用,但如果客户端断开连接或超时,原本可能成功的请求仍会产生费用。对于 429 或 500 错误,可以使用带退避的少量重试。对于 400 错误则不应重试,因为相同的请求仍会以相同方式失败。

AI 智能体成本控制始于核对自身数据

没有人能直接告诉你一个常驻智能体的成本,因为成本等于单次运行的 Token 消耗乘以每日运行次数,而这两项数据都掌握在你手中。运行一次,读取你记录的使用量数据,再乘以你的运行频率。两天后,将成本报告与该计算结果进行比对。如果两者不符,通常是因为缓存失效或循环运行时间超出了预期。

此逻辑基于 API Key,因为智能体是你调用 Messages API 的程序。对于个人交互式工作,哪种 Claude 方案适合你的工作方式 涵盖了订阅相关内容。此处的所有价格和限制均已在 2026 年 10 月与 Anthropic 的文档核对过,因此在制定预算前,请务必重新查阅定价页面。

FAQ

运行一个全天候在线的 VPS AI agent 需要多少费用?

费用分为两部分,只有一部分可以准确预测。服务器按月固定计费。模型 API 按 token 用量计费,因此成本取决于单次运行的消耗量以及运行频率。记录一次实际运行中的 usage,再根据运行计划计算总量。

max_tokens 和任务预算有什么区别?

max_tokens由系统强制执行,模型无法看到。它限制单次请求的输出量,其中包括思考内容;达到该限制后会返回 stop_reason: "max_tokens"。任务预算则相反:模型会获知该数值,并据此控制 agent 循环的执行节奏,但“任务预算只是软提示,不是硬限制”,实际强制执行的限制仍是 max_tokens。

为什么我的 agent 的 cache_read_input_tokens 始终为零?

因为调用之间的前缀发生了变化,或者前缀太短,无法进行缓存。常见原因是将时间戳或运行 ID 插入了系统提示词:缓存以此前缀为键,因此任何字节变化都会使其后的全部内容失效。修改工具定义或顶层 effort 值也会产生相同结果。否则,原因就是提示词大小:较短的提示词不会被缓存,而且不会返回错误。

如何阻止 AI agent 无限循环?

在循环代码中统计迭代次数,并设置固定的最大值,因为 max_tokens只限制单次响应,而 agent 会发起多次响应。在进程外部增加墙上时钟时间限制:从 systemd timer 启动作业,并在 oneshot 单元中设置 TimeoutStartSec=,或在 simple 单元中设置 RuntimeMaxSec=,这样卡住的运行就会按计划终止。同时限制重试次数,因为即使客户端超时后请求才成功,该请求仍会产生费用。

可以为单个 Claude API key 设置支出限制吗?

文档规定的支出限制针对 workspace,而不是单个 key。因此,应为该 agent 单独创建一个 workspace,并在那里设置每月支出上限。Default Workspace 不能设置支出限制。添加支出通知,以便在达到阈值时先收到提醒。为了区分不同作业的费用,为每个作业签发独立的 key,然后使用 group_by[]=api_key_id对使用情况报告进行分组。

这篇文章对您有帮助吗?