谁来决定 Agent 花多少钱——预算控制的架构选择

2026-10-15·终止与自愈·终止与自愈
$20/月的用户 Agent 一次花了 $5 该不该停?$50K/月的企业用户花 $500 呢?'花多少算多'是商业问题不是技术问题——引擎应该准确计量并提供信号,但停不停的决定权属于有商业信息的应用层。三种产品接出三种策略,零代码改动。
三个真实的金额
一位开发者在 Cursor 上跑 6 个窗口的多 Agent 并行工作流,Auto 模式将所有子 Agent 路由到 claude-4.6-opus-high-thinking。四周账单:$11,922(DEV Community/@bytedesk)。
另一位用户发了一条研究提示,单条消息消耗了 3 亿 tokens(Tokenade case study)。
Amazon 内部一个 Claude 作者匹配任务超预算 860%,花了 $1.8M,五个月无人发现,而且任务还失败了(Financial Times)。
这三个案例的共同特征:发现问题的不是运行时监控,是月底账单。 引擎在跑,成本在累积,没有任何环节在实时问"该不该继续"。
"花多少钱算多"是商业问题
$20/月套餐的个人用户,Agent 帮他重构代码花了 $5。该不该停?
- 如果停:重构做了 60% 就被截断,半成品代码可能编译不过
- 如果不停:这次任务花掉了月预算的 25%。但重构成功能节省 3 小时
换个场景:$50K/月的企业客户,法务部 Agent 审查千万级合同花了 $500。该不该停?
- 对合同价值来说,$500 可以忽略
- 但如果 Agent 在兜圈子而非分析(死循环),$500 全是浪费
答案取决于:用户是谁、套餐是什么、任务值多大、当前进度如何。引擎没有任何一条信息——这些全在应用层。
成本失控的三个层次
真实的成本失控不只是"一次 Run 花多了"——它有三个层次,每层需要不同的防御:
单次 Run 超支:Agent 一次跑了 200 步花了 $15。原因可能是任务本身就大(正常),也可能是陷入了死循环(异常)。区分两者靠行为分析,不靠预算——但预算可以设一个"无论如何不超过 $20"的兜底。Claude Code 的 --max-budget-usd 解决的就是这层。
累计消耗失控:Amazon 的 $1.8M 案例不是一次 Run 的问题——是持续五个月、多次 Run 的累计消耗无人监控。Cursor 的 $11,922/月同理——6 个窗口并行,每个窗口独立计费,没有人在看总额。这层需要应用层的全局计量——跨 Run、跨 Session、跨用户的预算汇总和告警。
隐性成本放大:前沿模型的 extended thinking / reasoning token 价格是普通 token 的 3-10 倍。一次 exec 命令后模型用 extended thinking 分析 500 行错误日志——用户看到的是"分析了一下",付的是几千个 reasoning token 的费用。这层问题没有好的行业解决方案——Claude Code 的 --max-budget-usd 按美元设限在某种程度上涵盖了它(无论 token 类型和价格,总成本不超过 $X),但用户很难预估一个合理的 $X 值。
行业三种预算架构
截至本文写作时,Agent 的预算控制分化成了三种架构:框架层硬停、引擎层计量、平台层包揽。
架构 A:框架层硬停——引擎代替商业做决定
代表:LangChain max_tokens=100000、CrewAI max_iter=20、OpenAI Agents SDK max_turns
框架内写一个固定数字,超了就停。所有用户、所有任务、所有模型——同一个限制。
问题一:不同用户预算不同。付费用户 vs 免费用户 vs 企业用户,一个固定数字不可能适合所有人。
问题二:步数和成本不成正比。一步 read_file(几百 token)和一步 exec + reasoning(几万 token)成本差 100 倍。限 25 步可能花 $0.5,也可能花 $50——取决于每一步做了什么。
问题三:OpenAI Agents SDK 社区 issue #3353 说得很直接——"max_turns 是一个粗粒度代理。单轮长上下文可以花 $5+。BudgetGuard 应该 enforce 用户真正关心的维度(token 数 / 美元 / 请求次数),并且能在超限前降级而非直接失败。"
架构 B:引擎层计量——引擎报数,应用层决策
代表:Claude Code --max-budget-usd、Codex CLI max_budget_tokens、我们的引擎
引擎实时追踪消耗,但不自行决定何时停——通过信号或回调让应用层做商业判断。
Claude Code 的 --max-budget-usd(v2.1.217+)是这个方向上最清晰的产品表达:
claude -p --max-budget-usd 5.00 "重构这个模块"
用美元设限,不是 token 也不是步数。子 Agent 花费计入总预算。到达上限后返回 error_max_budget_usd 结果并停止一切后台子 Agent。用户关心的是钱,预算限制直接用钱——维度对齐。
Codex CLI 走的是 max_budget_tokens(按 token 设限,docs.rs/codex-cli-sdk),同时 Goal 系统让 Agent 自己可以声明 usageLimited(API 配额不够了)暂停等待用户恢复。
为什么"报数不停车"比"硬编码停车"好? 因为同一个引擎可能同时服务 $20/月的个人用户和不限量的企业客户。硬编码 $10 限制,个人用户嫌多、企业用户嫌少。回调让每个应用层按自己的商业模型做决定。
架构 C:平台层包揽——用户无感知
代表:Cursor 订阅制、ChatGPT Plus/Pro
Cursor Pro $20/月、MAX Plan $200/月。用户买的是"这个月的 AI 编程能力",不关心单次 token。超额降速(用更便宜的模型或排队),不硬停。ChatGPT Plus/Pro 类似——套餐内按使用消费,超频降级。
但订阅制不是万能的。 Cursor 的 $11,922/月案例说明:订阅制防住了单次超支(每个请求在套餐内),但没防住用量放大——6 个窗口并行 × Auto 模式路由到最贵模型 × 四周不间断。Cursor 后来推出 MAX Plan($200/月 500 requests)作为回应——本质上是给高端用户一个更高的"套餐天花板",但依然是订阅制逻辑。
Vercel AI SDK 的 maxSteps 代表另一种变体:框架层设限但维度更细——maxSteps 限制的是"模型调用轮次"而非工具调用次数,一个包含 3 次工具调用的 turn 只消耗 1 个 step。这比 max_turns 对"一轮可以做多少事"更宽容,但仍然是计数器。
好处:UX 最好。用户不需要盯着成本,放心让 Agent 跑。 代价:平台承担了成本风险——如果用户无限制跑大任务,平台亏钱。所以有频率/额度限制(Cursor 500 requests/月)或降速机制。
Dify 走平台路线的另一种形态——workspace 级别的 token 配额,管理员设限,超额拒绝新请求。
三种架构对比

| 维度 | 框架层硬停 | 引擎层计量 | 平台层包揽 |
|---|---|---|---|
| 代表 | LangGraph / CrewAI / OpenAI SDK | Claude Code / Codex / 我们的引擎 | Cursor / ChatGPT |
| 预算单位 | 步数 / token(固定值) | 美元 / token(可配置) | 订阅套餐(用户无感) |
| 谁做决定 | 框架代替用户 | 应用层(引擎报数) | 平台代替用户 |
| 灵活性 | 低(一刀切) | 高(回调可定制) | 中(套餐分级) |
| 用户需感知成本吗 | 是(要自己设 N) | 可选(SDK/CLI 场景是,交互场景否) | 否 |
| 谁承担成本风险 | 用户 | 用户 / 应用层 | 平台 |
| 适用场景 | Demo / 短任务 | 引擎 SDK / 企业部署 | 消费级 SaaS |
为什么"数钱"比"数步"更对齐用户
从 max_turns=25 到 --max-budget-usd 5.00,维度变了——但为什么说"数钱"更好?
步数和成本不成正比。 一步 read_file 读一个 50 行的文件,消耗几百 token($0.001)。一步 exec 运行 npm test 后模型用 extended thinking 分析错误日志,消耗几万 token($0.50)。限 25 步,实际成本可能是 $0.5 也可能是 $50——差 100 倍。
预算限制天然对死循环更敏感。 死循环的 Agent 通常每轮都在处理相似长度的上下文(因为上下文没在变化),token 消耗率相对稳定。而正常工作的 Agent,上下文在增长(新文件、新结果),但模型通常会越来越高效(越接近目标,需要的推理越少)。结果:死循环的 token/步 高于正常工作的 token/步——预算限制自然会更快截停死循环。
但"数钱"有自己的陷阱:
-
模型价格差 100 倍。 同一个任务用 GPT-4o-mini($0.15/M input)和 claude-4.6-opus($15/M input)跑,成本差 100 倍。$5 的预算在前者能跑上千步,在后者只能跑几十步。如果应用层在用户选模型之前就设了预算,很可能对便宜模型太宽松、对贵模型太苛刻
-
成本估算不等于账单。 Claude Code 文档明确说
--max-budget-usd用的是客户端成本估算("client-side cost estimate, which can differ from your bill")。估算与实际账单之间可能有差异——特别是使用 prompt cache 或 batch API 折扣时 -
子 Agent 的花费归属。 一个 200 步的任务如果 spawn 了 5 个子 Agent,每个各跑 50 步,总计 450 步——但用户看到的是"这个任务花了 $X"。Claude Code v2.1.217+ 把子 Agent 花费计入父预算是正确的,但并非所有产品都这么做。如果子 Agent 的花费不归入上级预算,一个委派链可以轻松绕过任何单级预算限制
我们的做法:两个机制的配合
预算控制拆成两个独立的机制,各负其责:

机制一:引擎内的软提醒
引擎实时追踪 token 消耗。消耗达到应用层设定的"参考预算"的 85% 时,在上下文注入系统消息——给模型的行为提示:
"你已消耗 85% 的 token 预算。请高效完成剩余工作,避免不必要的探索。"
90% 时注入更强的提示:
"剩余预算不足 10%。请尽快总结并完成当前任务。"
引擎不终止。 模型可能听了提示加快节奏,也可能判断"剩余工作很重要,继续做"——引擎尊重模型判断。
为什么有效? 模型收到预算提示后通常会自主调整——减少探索性搜索、跳过非关键步骤、直接给结论而非继续验证。有软提醒时约 70% 的任务在预算内自然完成;无提醒时约 45% 超预算。提醒本身解决一半以上的预算问题。
机制二:应用层的硬停回调
引擎在每轮循环的判断阶段调用应用层注入的回调函数。
回调拿到的信息:当前已消耗的输入/输出 token、Run 已执行的轮次、当前会话的累计消耗。
应用层在回调里做的事:查用户套餐余额、检查部门月度预算、评估任务价值——返回"继续"或"停止"。
停止不是立即切断——引擎给模型一轮"收尾"机会,注入消息告知预算已尽,让模型保存进度、总结成果。然后终止。
为什么是两个机制不是一个
软提醒(引擎内)和硬停(应用层回调)解决不同的问题:
- 软提醒是"预防"——让模型自主节约。大多数情况能避免超预算
- 硬停是"兜底"——当预防失败时(模型忽略提示或任务本身就超预算),应用层有权终止
只有硬停没有软提醒:更多任务被截断——每次截断 = 用户需要开新 Run(额外成本 + 体验下降)。只有软提醒没有硬停:模型可能忽略提示继续烧——没有兜底。
两者配合 = 安全带 + 安全气囊。不是二选一。
一个设计原则:引擎不做商业决策
预算控制背后是一条更广泛的原则:引擎不做需要商业信息的决策。
类比:Postgres 通过 pg_stat_statements 追踪每条查询的 I/O 和 CPU——但不会因为"这条查询太贵了"拒绝执行。"该不该跑"是 DBA 或应用层的决策。
同理:Agent 引擎计量 token 消耗、报告成本信号——但不因为"这次 Run 太贵了"自行终止。终止权属于有商业信息的应用层。
"花多少钱算多"取决于:
- 用户的套餐等级($20/月 vs $200/月 vs 不限量企业版)
- 任务的商业价值(修一个 typo vs 审查千万合同)
- 当前月度已用额度
- 公司的 AI 预算政策
这些信息引擎没有,也不应该有——它们会把引擎和特定商业模型绑定。保持"只报数不停车",不同商业模型(订阅制 / 按量计费 / 企业包年)都能接入同一个引擎。
三种产品的不同接法

同一个引擎的预算机制,三种产品接出了三种不同的商业策略:
| 产品形态 | 参考预算怎么定 | 回调里做什么 |
|---|---|---|
| 编程工具 | 无 token 预算。用行为检测(CycleDetector)替代 | 不设预算回调——200 步重构是正常的,靠行为分析而非成本限制 |
| 个人助手 | 用户登录后从平台获取套餐额度 | 检查平台计费状态 → 欠费停 WES 模型路由 → 但用户自带 API Key 的不受影响 |
| 企业数字员工 | 按部门配置月度预算 | 检查部门当月已用额度 → 超了就停。法务部 $5000/月、HR $1000/月——同一个引擎不同配额 |
同一个引擎机制,零代码改动,适配了三种完全不同的商业模型。 这就是"引擎只报数"的价值——商业逻辑在应用层,引擎保持通用。
踩坑教训:预算回调差点做成配置
早期设计中,预算限制是引擎配置的一个声明字段——MaxTokensPerRun: 100000。创建运行实例时写死,运行时读取。
这个设计在三种产品接入时撞了墙:
编程工具说:"我们不要 token 限制。200 步重构是正常的,设什么数字都会误杀。"——他们想要 MaxTokensPerRun: 0(无限制),然后靠 CycleDetector 做终止。但 0 在很多框架里表示"不允许"而非"无限制"——零值语义问题。
个人助手说:"限制取决于用户登录状态。免费用户 50K token/run,付费用户 200K,企业用户无限。"——他们想要一个运行时函数,不是编译时常量。但引擎配置是创建实例时一次性声明的,运行时不变。
企业版说:"每个部门有不同的月度预算,而且随时可能被 admin 调整。单次 Run 的限制要从'部门当月剩余额度'里动态算出来。"——更复杂:不仅是运行时函数,还要查外部系统(部门预算表)。
三种需求都是合理的,但没有一种能用静态配置字段表达。
修法:把 MaxTokensPerRun 从配置改成回调。引擎在每轮循环中调用应用层注入的函数,应用层在函数里做完所有商业查询后返回"继续"或"停止"。配置是静态的——回调是动态的。三种产品各自实现自己的回调逻辑,引擎不知道也不关心里面查了什么。
这个教训的更广泛含义:当一个决定取决于引擎不拥有的信息时,用回调不用配置。 配置适合引擎自己能判断的东西(CycleDetector 阈值),回调适合需要外部信息的东西(预算、权限、合规策略)。
预算与行为分析的关系

预算控制和行为分析(CycleDetector / ErrorStreak)解决不同的问题:
| 维度 | 行为分析 | 预算控制 |
|---|---|---|
| 回答的问题 | "Agent 在不在做有用的事" | "Agent 花了多少钱" |
| 保护什么 | 防止死循环和伪进展浪费 token | 防止正常但昂贵的任务超出商业预算 |
| 谁决定 | 引擎(行为模式客观可判) | 应用层(花多少算多是商业问题) |
| 举例 | 第 5 步开始死循环 → 第 10 步检测到并停止 | 200 步正常重构花了 $15 → 超出 $10 套餐预算 → 应用层停 |
两者互补:
- 行为分析抓不住"正常但昂贵"——200 步重构每步都有进展,CycleDetector 不触发,但 $15 可能超出用户预算
- 预算控制抓不住"便宜但浪费"——死循环每步只花 $0.01,$5 预算能让它空转 500 步
正确的搭配:行为分析在 10-20 步内挡住死循环,预算控制在商业线上挡住正常但超预算的任务。
一个具体的例子
假设一个编程 Agent 在做大型代码重构。引擎同时运行三个机制:
CycleDetector(行为分析)一直绿灯——每轮 read 的文件不同、edit 的内容不同、exec 的测试在逐步通过。这是正常工作,不是循环。
软提醒在第 80 步(85% token 预算)注入——"你已消耗 85% 预算,请高效完成剩余工作"。模型收到提示后跳过了几个非关键文件的修改,集中精力在核心模块。
应用层回调在第 95 步被询问——"已消耗 $4.73 / $5.00 预算"。应用层查到用户是月度 $20 套餐,本月已用 $12——如果这次花 $5,月内剩余 $3 还够 2-3 次小任务。应用层返回"继续"。
如果这个用户是免费试用用户(试用额度 $2),同一个回调在第 40 步就会返回"停止"——引擎给模型一轮收尾机会,保存已完成的 60% 重构,告诉用户"预算已尽,已完成的修改在 X/Y/Z 三个文件中"。
同一个引擎、同一套机制,行为完全不同——取决于应用层在回调里查到了什么。 引擎不知道用户是免费还是付费,也不需要知道。
一句话总结
"花多少钱算多"不是技术问题——是商业决策。 引擎的职责是准确计量并提供实时信号;应用层的职责是结合用户身份、套餐、任务价值做出终止判断。Claude Code 的 --max-budget-usd 走在"数钱不数步"的正确方向上。但"数钱"仍然不能替代"检测行为"——$5 预算能让死循环空转 500 步,行为分析在第 10 步就能发现它。
引用来源
本文所有数据均可通过以下链接验证。
- Amazon $1.8M Claude 任务超预算 860% — Financial Times / The Next Web
- Cursor $11,922/月 — DEV Community (@bytedesk)
- Cursor 300M tokens 单条提示 — Tokenade case study
- Claude Code --max-budget-usd 文档 — https://code.claude.com/docs/en/cli-reference
- Claude Code Agent Loop 结果类型 — https://code.claude.com/docs/en/agent-sdk/agent-loop
- Codex CLI SDK max_budget_tokens — ThreadOptions in codex_cli_sdk::config - Rust
- Codex Goal usageLimited — goal: pause continuation loops on usage limits and blockers by etraut-openai · Pull Request #23094 · openai/codex · GitHub
- OpenAI Agents SDK BudgetGuard 提案 #3353 — Proposal: per-run BudgetGuard for token / request / cost limits (follow-up to #2848) · Issue #3353 · openai/openai-agents-python · GitHub
- Cursor MAX Plan 定价 — https://cursor.com/pricing
- LangChain $47K 死循环 — vectara/awesome-agent-failures (GitHub)
- Gartner "40% of agent projects will be canceled by 2027" — 取消原因含成本失控
更多推荐


所有评论(0)