工具调用是AI Agent的核心原语——选工具、填参数、拿结果、继续推理。但一个被大多数开发者忽视的事实是:每次工具调用都在征收一笔隐形的"Token税"。TokenMix 2026年实测数据显示,一次标准的Function Call平均消耗346个额外Token;Scott Spence连接四个MCP服务器后,对话尚未开始就吃掉66,000个Token;一个10步Agent在系统提示和工具Schema的重复注入上烧掉超过200,000个Token。本文从Token经济学视角出发,拆解工具调用的五层成本结构,并给出从Schema瘦身到动态检索的完整降本栈。
工具调用并非"调一次付一次"的简单模型。在Agent的多轮执行中,Token消耗来自五个叠加层:
| 成本层 | 触发时机 | 典型消耗 | 是否可规避 |
|---|---|---|---|
| Schema注入 | 每轮请求 | 50-200 Token/工具 | 可部分规避 |
| 系统提示膨胀 | 每轮请求 | 500-5000 Token | 需架构改造 |
| 工具调用输出 | 模型生成时 | 100-500 Token/调用 | 不可规避 |
| 工具返回结果 | 执行完成后 | 200-∞ Token | 可截断压缩 |
| 历史累积 | 多步Agent | 线性增长 | 需上下文管理 |
最致命的不是单次调用的开销,而是Schema注入的每轮重复。无论Agent在第N步是否使用某个工具,该工具的完整Schema定义都会被注入到上下文中。10个工具、10步执行,就意味着同一份Schema被注入了10次。
场景A:单工具调用(TokenMix基准测试)
无工具调用: prompt → completion
150 Token → 200 Token
有工具调用: prompt + schema → tool_call → tool_result → completion
150 + 346 Token → 180 Token → result → 200 Token
Token增量: +346 Token(纯Schema + 调用格式开销)
TokenMix对OpenAI、Anthropic、Google、DeepSeek四家的工具调用接口进行了统一测量,发现平均每次工具调用的额外Token开销为346个,这包括Schema定义的解析Token、函数名和参数的输出Token、以及工具结果回传的格式Token。
场景B:四服务器MCP设置(Codex CLI实测)
Daniel Vaughan在优化Codex CLI时发现,连接四个MCP服务器后,每轮对话的输入Token增加了约7,000个。这7000个Token来自四个服务器的工具Schema注入——无论当前轮次是否需要这些工具,完整的工具描述、参数定义、返回值格式都被塞进了请求。
无MCP: system_prompt(500) + user_input(100) = 600 Token
四MCP: system_prompt(500) + schemas(7000) + user_input(100) = 7600 Token
倍率: 12.7x
场景C:过度工具注册(Scott Spence实测)
开发者Scott Spence在博客中记录了一个极端案例:他注册了大量MCP工具后,对话开始前(用户尚未输入任何内容)上下文已经消耗了66,000个Token。这意味着对于128K上下文窗口的模型,超过50%的上下文空间被工具定义占据,留给实际推理和对话的空间被大幅压缩。
工具数量与Token成本之间并非线性关系。每个工具的Schema定义通常包含工具名称、描述文本、参数JSON Schema、返回值格式四个部分。一个中等复杂度的工具定义通常需要50-200个Token。
# 一个典型工具的Schema定义(约150 Token)
{
"name": "query_database",
"description": "Execute a SQL query against the PostgreSQL database...",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "SQL query..."},
"database": {"type": "string", "enum": ["production", "staging"]},
"limit": {"type": "integer", "minimum": 1, "maximum": 1000}
},
"required": ["query"]
}
}
当工具从10个增长到50个时:
10工具 × 150 Token/工具 = 1,500 Token/轮
50工具 × 150 Token/工具 = 7,500 Token/轮
100工具 × 150 Token/工具 = 15,000 Token/轮
10步Agent × 100工具 = 150,000 Token 纯Schema开销
按Claude Sonnet 4.6定价($3/M input): 每任务$0.45 纯Schema成本
OnlyCLI的对比测试更令人震惊:MCP模式下的Agent相比等价的CLI模式,Token消耗高达35倍。根本原因在于CLI模式按需加载命令,而MCP模式在每轮请求中都携带全量工具Schema。
Agent的执行步数是成本膨胀的第二个加速器。一个10步的Agent任务,其Token消耗并非10倍,而是接近10×工具数的线性叠加,因为每一步都需要重新注入完整的工具上下文。
单步成本 = 基础提示 + 工具Schema + 工具调用 + 工具结果
= 500 + 7500 + 300 + 500
= 8,800 Token
10步成本(无上下文管理):
= Σ(基础提示 + 完整工具Schema × 步数) + 工具调用 × 10
≈ 500×10 + 7500×10 + 800×10
= 88,000 Token
100步成本: ≈ 880,000 Token → 在Sonnet 4.6上约$2.64/任务
tianpan.co的分析指出,一个10步Agent在每步都携带完整系统提示和工具定义的情况下,仅"运输"开销(非推理部分)就超过200,000个Token。这相当于每完成一个中等复杂度的任务,就有$0.6-$0.9花在了"告诉模型有哪些工具可用"上。
工具参数的复杂度直接影响Token开销。一个需要嵌套对象的工具定义,其Schema可能消耗500+ Token:
{
"name": "create_deployment",
"description": "Create a new deployment with the specified configuration...",
"parameters": {
"type": "object",
"properties": {
"name": {"type": "string"},
"replicas": {"type": "integer"},
"containers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"image": {"type": "string"},
"ports": {"type": "array", "items": {"type": "integer"}},
"env": {"type": "object", "additionalProperties": {"type": "string"}},
"resources": {
"type": "object",
"properties": {
"cpu": {"type": "string"},
"memory": {"type": "string"}
}
}
}
}
}
}
}
}
Red Hat的实验显示,将复杂的工具Schema替换为沙箱化的Python函数后,首轮上下文从41,205 Token降至26,635 Token,节省约15,000 Token(36%降幅)。这揭示了降低Schema复杂度是降本的第一道防线。
graph TB
subgraph "工具调用Token降本五栈"
L1["第1层: Schema瘦身<br/>精简描述·压缩枚举·去除冗余字段"]
L2["第2层: 按需注入<br/>动态路由·工具分片·上下文裁剪"]
L3["第3层: 结果压缩<br/>截断·摘要·结构化过滤"]
L4["第4层: 推理重叠<br/>投机执行·流式解析·预取结果"]
L5["第5层: 架构重构<br/>Tool RAG·层级路由·沙箱替代"]
end
L1 --> L2 --> L3 --> L4 --> L5
style L1 fill:#4CAF50,color:#fff
style L2 fill:#2196F3,color:#fff
style L3 fill:#FF9800,color:#fff
style L4 fill:#9C27B0,color:#fff
style L5 fill:#F44336,color:#fff
Schema瘦身是成本最低、见效最快的优化手段。核心原则是:每个Token都应该为模型决策提供增量信息。
策略1:精简描述文本
# Before: 58 Token
"query_database": {
"description": "Execute a SQL query against the PostgreSQL database. "
"Supports SELECT, INSERT, UPDATE, DELETE operations. "
"Results are returned as JSON arrays. Use 'limit' to "
"control result set size. Read-only queries are safe.",
}
# After: 18 Token(-69%)
"query_database": {
"description": "Run SQL on PostgreSQL. Returns JSON. Set limit for rows.",
}
实测表明,过度详细的工具描述不仅增加Token消耗,反而会降低工具选择的准确性——模型在冗长的描述中更容易混淆工具之间的差异。
策略2:压缩枚举和默认值
# Before: 大量枚举值
"region": {
"type": "string",
"enum": ["us-east-1", "us-east-2", "us-west-1", "us-west-2",
"eu-west-1", "eu-west-2", "eu-central-1", "ap-southeast-1",
"ap-northeast-1", "ap-southeast-2", "sa-east-1"]
}
# After: 用描述替代枚举
"region": {
"type": "string",
"description": "AWS region code (e.g. us-east-1)"
}
策略3:去除冗余字段
移除模型不需要的title、examples、$comment等纯文档字段。只保留模型做决策必需的信息:name、description(简洁版)、type和required。
Red Hat实验的启示:用沙箱化Python函数替代复杂JSON Schema,首轮上下文从41,205降至26,635 Token。核心思路是:让模型执行代码来构造复杂参数,而不是在Schema中穷举所有可能的结构。
按需注入解决的是"每轮都注入所有工具Schema"的根本问题。核心策略有三:
策略1:工具分片(Tool Sharding)
将工具按功能域分组,每轮只注入当前域的工具:
# 工具分片路由器
TOOL_SHARDS = {
"database": [query_db, insert_db, migrate_db],
"filesystem": [read_file, write_file, list_dir],
"network": [http_get, http_post, dns_lookup],
"compute": [run_code, spawn_vm, manage_queue],
}
def select_shard(user_query: str) -> list[str]:
"""轻量分类器决定注入哪个工具分片"""
embedding = embed(user_query)
shard_scores = cosine_similarity(embedding, shard_centroids)
return top_k_shards(shard_scores, k=1) # 只注入1个分片
# 效果: 100工具 → 每轮只注入~25工具的Schema
策略2:MCP Gateway过滤
FutureAGI提出的MCP Gateway架构在Agent和MCP服务器之间增加一个过滤层:
Agent → MCP Gateway → MCP Server 1
→ MCP Server 2
→ MCP Server 3
Gateway的核心功能: - 请求级过滤:分析当前轮次的意图,只转发相关的工具Schema - Schema缓存:避免重复解析和传输已知的工具定义 - 结果截断:对工具返回的超长结果进行摘要
实测数据显示,MCP Gateway可以将Token消耗降低40-60%,同时保持工具选择的准确率下降不超过3%。
策略3:Copilot CLI的上下文管理实践
GitHub Copilot CLI团队的优化案例极具参考价值:通过分析上下文使用情况,将上下文窗口占用从52%降至13%。关键操作是按需加载工具上下文,而非在启动时全量注入。
工具返回的结果往往是Token消耗的大头——一次数据库查询可能返回数千行数据,一次网页抓取可能返回完整的HTML。
策略1:结构化过滤
# 不要将完整的查询结果塞入上下文
def query_database(sql: str) -> dict:
results = execute(sql)
# 坏做法: 返回全部结果(可能数千Token)
# return {"data": results}
# 好做法: 返回摘要 + 样本
return {
"row_count": len(results),
"columns": list(results[0].keys()),
"sample": results[:5], # 只返回前5行
"aggregates": compute_basic_stats(results)
}
策略2:结果摘要化
对长文本结果使用轻量级摘要模型进行压缩:
工具原始返回: 5000 Token(完整网页内容)
→ 摘要压缩后: 300 Token(关键信息提取)
压缩比: 16.7x
mem0的Token优化实践表明,对历史工具调用结果进行摘要压缩,可以将长对话的Token消耗降低3-4倍。
工具调用的延迟成本同样值得关注。传统Agent执行模式是串行的:推理→调用工具→等待结果→继续推理。微软研究院的PASTE(Pattern-Aware Speculative Tool Execution)方法打破了这一串行瓶颈。
PASTE的核心思路:
sequenceDiagram
participant Model as LLM
participant Predict as 预测器
participant Tool as 工具引擎
Note over Model,Tool: 传统串行模式
Model->>Tool: 1. 生成tool_call
Tool-->>Model: 2. 返回结果
Note over Model: 3. 继续生成
Note over Model,Tool: PASTE重叠模式
Model->>Predict: 1. 部分生成→预测下一调用
Predict->>Tool: 2. 提前执行预测的工具
Tool-->>Predict: 3. 预取结果
Model->>Tool: 4. 确认调用
Predict-->>Model: 5. 直接使用预取结果(命中)
PASTE通过分析Agent的历史调用模式,在模型仍在生成Token的同时预测并提前执行下一步工具调用。微软研究院的实验显示: - 延迟降低48%:Agent端到端完成时间减少近一半 - 无损加速:预测正确时结果完全一致,预测错误时回退到正常执行 - Token消耗不变:投机执行不增加额外的Token开销,只是改变了执行时序
Anthropic的Fine-Grained Tool Streaming(eager_input_streaming)从另一个维度降低了工具调用延迟:允许Claude在生成工具参数的过程中就开始流式传输,而非等待完整的JSON参数生成完毕。这意味着工具引擎可以在参数部分就绪时开始预处理,进一步压缩端到端延迟。
当工具数量超过50个时,传统的"全量注入"模式完全失效。这一层的降本策略是从根本上改变工具发现和注入的架构。
Tool RAG:检索增强的工具发现
Red Hat提出的Tool RAG(Tool Retrieval-Augmented Generation)将工具选择问题转化为信息检索问题:
# Tool RAG 架构
class ToolRAG:
def __init__(self, tool_catalog: list[Tool]):
# 将每个工具的名称+描述编码为向量
self.tool_embeddings = {
tool.name: embed(f"{tool.name}: {tool.description}")
for tool in tool_catalog
}
self.tools = {tool.name: tool for tool in tool_catalog}
def select_tools(self, query: str, top_k: int = 5) -> list[ToolSchema]:
"""只检索最相关的top_k个工具Schema注入上下文"""
query_embedding = embed(query)
scores = {
name: cosine_similarity(query_embedding, emb)
for name, emb in self.tool_embeddings.items()
}
top_tools = sorted(scores, key=scores.get, reverse=True)[:top_k]
return [self.tools[name].schema for name in top_tools]
# 效果: 200工具 → 每轮只注入5个最相关工具的Schema
# Token节省: (200-5) × 150 = 29,250 Token/轮
Tool RAG的关键优势是Token消耗与工具总数解耦。无论系统中有10个还是1000个工具,每轮注入的Schema数量固定为top_k(通常3-5个),使Token消耗保持恒定。
层级路由:分层决策
对于超大规模工具库(100+工具),可以采用两级路由:
第一级: 意图分类器(轻量模型/embedding匹配)
→ 确定工具域(数据库/文件系统/网络/...)
第二级: 域内工具选择(主推理模型)
→ 从该域的10-15个工具中选择具体工具和参数
这种方法将100+工具的选择问题分解为两个更简单的子问题,每个子问题的准确率都高于直接在全量工具中选择。
| 指标 | OpenAI | Anthropic | Google Gemini | DeepSeek |
|---|---|---|---|---|
| Schema注入方式 | tools数组 | tools数组 | functionDeclarations | tools数组 |
| 每工具Schema开销 | ~120 Token | ~150 Token | ~100 Token | ~130 Token |
| 强制工具选择 | tool_choice: required |
tool_choice: {type: "tool", name: "..."} |
function_calling_config |
tool_choice: required |
| 并行工具调用 | 支持(默认开启) | 支持(2025.11+) | 支持 | 支持 |
| 流式工具输出 | 支持 | 支持(eager streaming) | 支持 | 支持 |
| Strict Schema | strict: true 保证100%合规 |
tool_choice + JSON Schema |
response_schema 约束 |
JSON Schema |
| Token计费 | 按输入+输出Token计费 | 按输入+输出Token计费 | 按输入+输出Token计费 | 按输入+输出Token计费 |
| 缓存优惠 | Prompt Caching 50% | Prompt Caching 90% | Context Caching 75% | 无官方缓存 |
关键洞察:Anthropic的Prompt Caching提供90%折扣,这对于工具Schema的每轮重复注入是最大的成本杠杆。如果工具Schema不变(通常不变),通过缓存可以将其成本降低至原价的10%。
无缓存: 7,500 Token Schema × $3/M = $0.0225/轮
有缓存: 7,500 Token Schema × $3/M × 10% = $0.00225/轮
10步节省: ($0.0225 - $0.00225) × 10 = $0.2025/任务
以一个典型的企业级RAG Agent为例,该Agent配备15个工具(数据库查询、文档检索、邮件发送、日程管理等),平均执行8步完成任务。
=== 无优化版本 ===
每轮输入:
系统提示: 800 Token
工具Schema: 15 × 150 = 2,250 Token
历史上下文: 累积增长(第8轮约8,000 Token)
用户输入: 200 Token
小计: ~11,250 Token/轮(平均)
8轮总输入: ~90,000 Token
8轮总输出: ~12,000 Token(含工具调用输出)
工具返回: ~8,000 Token
总Token: ~110,000 Token
Claude Sonnet: $3/M in + $15/M out = $0.27 + $0.18 = $0.45/任务
日处理500任务: $225/天 → $6,750/月
=== 五层优化后 ===
每轮输入:
系统提示: 400 Token(瘦身)
工具Schema: 5 × 100 = 500 Token(分片+瘦身)
历史上下文: ~3,000 Token(摘要压缩)
用户输入: 200 Token
小计: ~4,100 Token/轮
8轮总输入: ~33,000 Token(含缓存命中)
8轮总输出: ~10,000 Token
工具返回: ~2,000 Token(结构化过滤)
总Token: ~45,000 Token
缓存折扣后: ~$0.12/任务(-73%)
日处理500任务: $60/天 → $1,800/月
月节省: $4,950(73%成本削减)
这是最常见的误区。LLM Stats的评测数据显示,当工具数量从5个增加到25个时,工具选择的准确率下降12-18%。同时,Token成本线性增长。正确的做法是:
将工具的完整返回结果塞入上下文,再让模型"总结"或"提取关键信息",是一种双重浪费:既浪费了输入Token(完整结果),又浪费了输出Token(模型重述)。正确做法是在工具执行层做预处理,只返回模型决策所需的最小信息。
这是最容易被忽视的降本手段。Anthropic的Prompt Caching对工具Schema的每轮重复注入提供90%折扣。OpenAI的Prompt Caching提供50%折扣。如果你使用了固定的工具集,务必将工具Schema放在可缓存的位置(系统提示的开头或tools数组的固定位置),确保缓存命中。
工具调用失败后让Agent"自我纠正"是常见模式,但无限制的重试循环会指数级增加Token消耗。FutureAGI的分析指出,每次重试不仅消耗当前步骤的Token,还会因为上下文增长(包含失败历史)而增加后续所有步骤的Token消耗。建议设置硬性上限(最多2次重试),并在超过上限时回退到更简单的策略。
| 工具规模 | 推荐策略 | 预期成本降幅 | 实施复杂度 |
|---|---|---|---|
| 1-5工具 | Schema瘦身 + Prompt Caching | 20-30% | 低(1天) |
| 5-15工具 | 分片注入 + 结果压缩 + 缓存 | 40-55% | 中(3-5天) |
| 15-50工具 | Tool RAG + 分片 + 结果压缩 | 55-70% | 中高(1-2周) |
| 50+工具 | 层级路由 + Tool RAG + 架构重构 | 65-80% | 高(2-4周) |
OpenAI用户:
- 开启strict: true避免无效调用的Token浪费
- 使用Prompt Caching,将工具Schema放在系统提示的固定前缀中
- 对GPT-5系列使用并行工具调用减少轮次
Anthropic用户:
- 必须使用Prompt Caching——90%折扣是最大的成本杠杆
- 利用tool_choice的any模式避免模型"忘记"使用工具的无效轮次
- 开启eager_input_streaming降低延迟(不直接降Token,但提高吞吐)
Google Gemini用户:
- 使用Context Caching存储固定的工具Schema
- 利用response_schema约束输出格式,避免重试
- Gemini的长上下文窗口(1M-2M Token)在工具数量大时有天然优势
工具调用的Token经济学在2026年已经成为Agent工程的核心议题。以下指标值得持续跟踪:
当Schema命中率持续低于30%时,意味着70%的工具注入是纯粹的浪费——这是引入Tool RAG或工具分片的明确信号。
graph LR
subgraph "成本诊断决策树"
A["Schema命中率 < 30%?"] -->|"是"| B["引入 Tool RAG<br/>按需检索替代全量注入"]
A -->|"否"| C["Prompt Caching<br/>命中率 > 90%?"]
C -->|"否"| D["调整Schema位置<br/>确保前缀固定"]
C -->|"是"| E["结果Token > 总量30%?"]
E -->|"是"| F["增加结果压缩<br/>结构化过滤"]
E -->|"否"| G["优化完成<br/>维持现状"]
B --> H["重测指标"]
D --> H
F --> H
H --> A
end
工具调用是Agent的"双手",但每次伸手都要付Token税。理解这套税收体系,才能构建真正可持续的Agent生产系统。
[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
