1. 五个 Sub-Agent 同时启动,账单为什么翻了六倍
多 Agent 编排最容易制造一种「看起来很快、账单很贵」的系统。我拿一个真实跑过的例子说:Supervisor 收到「分析某行业并生成投资建议」,同时拉起市场、财务、政策、竞争、风险五个 Sub-Agent。每个 Agent 都收到完整会话 25K Token、附件摘要 20K Token、Tool Schema 8K Token,光输入就是 53K × 5 = 265K Token。这还没算每个 Agent 各自两次模型调用、5K 输出、Reviewer 读全部结果、Supervisor 最终合并。
单次请求的成本结构不再是「一次模型调用」,而是:
Supervisor 输入 + N 个 Sub-Agent 输入 + N 个 Sub-Agent 输出 + Tool 循环 + Reviewer + 最终合并如果存在嵌套委派(Agent-A 调 B、C,B 再调 D),成本按树状增长。并发只压缩墙钟时间,不减少 Token 总量,反而会因为缺少共享缓存、重复检索、重复摘要、抢占预算造成额外浪费。
这篇要解决的就是这个场景:并行 Sub-Agent 的 Token 成本暴涨,怎么按上下文复制、并发扇出、预算争用三条链路排查,并用统一 Key 通道把每个 Sub-Agent 的调用量记录下来做归因。适合已经在跑多 Agent 编排、发现账单和预期对不上、又不知道从哪一层开始查的开发者。排查顺序比优化技巧更重要,顺序错了会在错误的地方省钱。
2. 用 TaoToken 统一 Key 做多 Sub-Agent 成本观测的前置准备
排查成本暴涨,第一步不是改代码,而是先能看见钱花在哪。多 Agent 系统最麻烦的地方在于:五个 Sub-Agent 可能走五套 Key、五个 Base URL,账单分散在不同后台,你根本拼不出调用树。
TaoToken 在这里的作用是提供一个统一 API 通道:所有 Sub-Agent、Supervisor、Reviewer 都走同一个 Key 和同一个 Base URL,调用量、模型、时间戳集中在一处,方便按run_id/task_id归因。它不替代你的编排框架,只负责把模型调用这一层的账记清楚。
前置准备三件事:
第一,拿到统一 Key。登录后在控制台创建 API Key,建议按环境分(dev / staging / prod),不要多个 Sub-Agent 共用一个 Key 又不打标签,否则归因时你分不清是哪个 Agent 花的。
第二,确认 Base URL 和模型 ID。多 Agent 场景通常要混用模型:Router 用便宜的小模型,复杂研究用强模型,Reviewer 用强模型或规则组合。统一通道下切换模型只改 Model ID,不用改 Key。
第三,给每次 Run 打上可追踪的标识。这是后面成本树归因的基础,没有run_id,你只能看到总量,看不到树。
相关入口:
- API Key 管理:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=subagent_cost
- 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=subagent_cost
- 模型对话验证:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=subagent_cost
注意:统一 Key 的价值在观测,不在「省单价」。如果你的问题是上下文复制导致的 5 倍输入,换任何通道都救不了,必须先做上下文工程。
3. 可复制的并发上限、上下文裁剪与预算阈值配置
这一节给可直接落地的配置。分三块:并发上限、上下文裁剪、预算预留。每块都给可复制的片段。
3.1 并发上限配置(JSON)
全局并发必须是共享的,不能每个 Agent 内部各限 5 并发、20 个 Agent 合计 100 并发。下面这份agent_scheduler.json把 Run 级、Provider 级、模型级三层 Semaphore 都写清楚:
{ "scheduler": { "maximumParallelTasks": 4, "maximumDelegationDepth": 2, "maximumTasksPerRun": 12, "maximumChildrenPerTask": 3, "queueTimeoutSeconds": 30, "defaultJoinPolicy": "QUORUM" }, "providerConcurrency": { "maximumConcurrentRequests": 8, "maximumQueuedRequests": 32, "retryAfterFloorMs": 800, "maximumRetriesPerRun": 6 }, "modelConcurrency": { "strong-model": 3, "small-model": 8, "reviewer-model": 2 } }关键点:maximumParallelTasks是 Run 级上限,providerConcurrency是跨 Run 共享的 Provider 上限。两者取小值生效。maximumDelegationDepth: 2意味着 Supervisor → Agent-A → Agent-B 之后不能再往下委派,防止 A 委派 B、B 又委派 A 的环。
3.2 上下文裁剪配置(TOML)
上下文复制是成本暴涨的第一大来源。下面这份context_view.toml按 Agent 角色定义 Context View,只放完成当前 Task 所需内容:
[context.default] include_full_conversation = false include_all_documents = false include_all_tools = false max_estimated_tokens = 12000 [context.roles.market] allowed_tools = ["web_search", "competitor_lookup"] artifact_filters = ["market_*", "competitor_*"] message_window = 6 [context.roles.finance] allowed_tools = ["financial_api", "ratio_calc"] artifact_filters = ["financial_*", "filing_*"] message_window = 4 [context.roles.legal] allowed_tools = ["regulation_search"] artifact_filters = ["regulation_*", "policy_*"] message_window = 4 [context.roles.reviewer] allowed_tools = [] artifact_filters = ["claim_*", "conflict_*", "evidence_*"] message_window = 2include_full_conversation = false是最重要的一行。研究 Agent 不需要财务审批历史,财务 Agent 也不需要所有原始网页。max_estimated_tokens给每个角色设硬上限,超了就触发 Context Reduction Plan。
3.3 预算预留配置(settings 片段)
预算不是共享资源,是并行 Sub-Agent 最隐蔽的坑:每个 Sub-Agent 都以为自己有完整 100 元预算,总成本可能 100 × N。下面这份budget.settings.json定义 Run 预算和原子预留:
{ "runBudget": { "tokenLimit": 400000, "modelCallLimit": 60, "toolCallLimit": 120, "costLimit": 8.00, "deadlineSeconds": 180 }, "reservation": { "safetyMarginRatio": 0.25, "expiresSeconds": 120, "atomic": true, "reclaimUnused": true }, "retryBudget": { "maximumRetries": 3, "maximumRetryCost": 1.20, "retryable": ["RATE_LIMIT", "TIMEOUT", "TRANSIENT_5XX"] } }safetyMarginRatio: 0.25是给模型输出不确定性留的余量。atomic: true对应数据库层的原子预留,两个 Task 同时抢最后预算时只能一个成功:
update agent_budget set reserved_cost = reserved_cost + :amount, version = version + 1 where run_id = :runId and cost_limit - spent_cost - reserved_cost >= :amount and version = :expectedVersion;没有预留就不启动 Task。这条规则能挡掉大部分「预算争用」导致的超支。
4. 验证请求:对比扇出前后的 Token 消耗
配置写完必须验证,否则你不知道改动有没有生效。验证分两步:先确认统一 Key 通道能正常调用,再对比扇出前后的消耗。
4.1 确认通道可用
用 curl 打一次最小请求,确认 Base URL、Key、Model ID 三件套正确:
curl https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "small-model", "messages": [{"role": "user", "content": "ping"}], "max_tokens": 8 }'返回里带usage.prompt_tokens和usage.completion_tokens,这两个字段是后面归因的原始数据。
4.2 扇出前后对比
改造前:五个 Sub-Agent 各收完整上下文,记录总输入 Token。改造后:按 Context View 裁剪,再记录一次。对比表:
| 指标 | 扇出前 | 扇出后 | 变化 |
|---|---|---|---|
| 单 Agent 输入 | 53K | 11K | -79% |
| 五 Agent 总输入 | 265K | 55K | -79% |
| Tool Schema 占比 | 8K/Agent | 1.5K/Agent | -81% |
| 重复检索次数 | 5 | 1(共享 Artifact) | -80% |
| 单次 Run 总成本 | 8.6 元 | 2.4 元 | -72% |
实测下来,光是把include_full_conversation关掉、Tool 按角色动态收缩、检索结果共享成 Artifact,单次 Run 成本就能降七成左右。并发数没变,墙钟时间基本不变。
4.3 成本树归因
每个节点记录run_id、task_id、agent_role、model_profile、input_tokens、output_tokens、tool_calls、cache_hit、retry。总成本 = Supervisor + 所有子节点 + 所有后代,必须按树归因,不能只看最终模型 Usage。
关键指标:
duplicated_context_tokens / total_input_tokens这个比例高,说明上下文工程失效。健康值应该在 0.15 以下。如果超过 0.4,先别优化模型,回去改 Context View。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth
多 Agent 场景报错往往被并发放大,一个 Agent 的 401 会变成十个 Agent 的重试风暴。按真实报错逐个排。
5.1 401 Unauthorized
最常见。多 Sub-Agent 各自读环境变量,容易出现某个 Agent 拿到空 Key 或旧 Key。排查顺序:
先确认所有 Agent 走同一个 Key 来源,不要有的读TAOTOKEN_API_KEY、有的读硬编码字符串。再确认 Key 没有多余空格或换行,从控制台复制时容易带上。最后确认 Base URL 和 Key 匹配,dev 环境的 Key 打 prod 的 URL 会 401。
如果用了 CC Switch 或 Cline MCP,三件套必须写全:Base URL、Key、Model ID。缺任何一个都会 401 或 404。
5.2 local proxy failed
这个报错通常出现在本地编排框架里,Agent 之间通过本地端口通信,某个 Sub-Agent 进程没起来或端口被占。排查:
确认本地编排服务的端口没被其他 Run 占用,并发高时多个 Run 抢同一端口很常见。确认 Sub-Agent 进程启动顺序,Supervisor 不应该在子进程 ready 之前就发请求。确认没有把本地代理地址误配成远端地址。
5.3 reading choices 报错
reading 'choices'或cannot read property 'choices' of undefined,说明响应体不是预期的 OpenAI 格式。常见原因:Base URL 少了/v1,或者请求打到了错误端点。确认 URL 是https://taotoken.net/api/v1/chat/completions,不是https://taotoken.net/api。
另一个原因是流式响应被当成非流式解析。多 Agent 并发时如果有的用 stream、有的不用,解析层要分开处理。
5.4 OAuth 相关报错
如果用了 Claude Code 或 Codex 这类带 OAuth 的工具,报错通常是 token 过期或 scope 不足。Codex 的auth.json里要确认 Base URL、Key、Model ID 三件套完整。Claude Code 接入时如果只填了 Key 没填 Base URL,会走默认端点导致鉴权失败。
5.5 重试风暴
Provider 限流后,10 个 Agent 同时 429,各自重试 3 次,变成 30 次请求。这是并发扇出最典型的次生灾害。必须共享限流与退避:retryAfterFloorMs全局生效,maximumRetriesPerRun限制整个 Run 的重试次数,而不是每个 Agent 各自算。
排查顺序总结:先看 401(鉴权),再看 local proxy failed(进程/端口),再看 reading choices(端点/解析),最后看 OAuth 和重试风暴(配置/限流)。顺序错了会在鉴权没通的情况下去调并发,白费功夫。
6. 把统一 Key 观测接进你的多 Agent 编排
排查完,最后一步是把观测固化下来,不然下次成本暴涨你还得重来一遍。
第一,所有 Sub-Agent 走统一 Key 和统一 Base URL。这是成本归因的前提,分散的 Key 拼不出调用树。
第二,每次 Run 打run_id,每个 Task 打task_id,每个 Agent 打agent_role。这三个字段是成本树的骨架。
第三,上线检查清单里至少保留这几条:多 Agent 调用树可观测、Sub-Agent 不复制完整会话、Context 按角色构建、Tool 按任务动态收缩、检索与可信压缩 Artifact 可复用、Run 预算在 Task 启动前原子预留、Provider 限流全局共享、晚到结果不污染最终输出。
第四,定期评估 Agent 独有贡献。统计每个 Agent 贡献的最终 Claim 数量、发现的独有风险、结果被采用比例。长期没有独有贡献的 Agent 应该合并或下线,而不是让它继续并行烧钱。
并行应当用于真正独立且有价值的子任务,而不是把一个问题复制给所有 Agent。生产多 Agent 系统追求的不是「同时启动更多模型」,而是在给定预算内获得更多独立、可验证的有效信息。
需要长期跑编码类或 Agent 类任务的,可以看 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=subagent_cost
接入文档和 API Key 管理入口在上面第 2 节已经给过,配置改完先跑一次扇出前后对比,把duplicated_context_tokens / total_input_tokens压到 0.15 以下,再谈模型分层和缓存优化。