首页 › ai-agents › 工具定义吃上下文:体积税实测

工具定义吃上下文:体积税实测

概述

当行业还在争论"自主体能不能调对工具"时,一个更隐蔽的税种已经悄悄长成:工具定义本身对上下文窗口的吞噬。每一条工具的 JSON Schema、每一段 description、每一个 enum 字段,都会在自主体回环的每一轮被重新塞回请求,按输入 token 计费、按上下文额度占坑。本轮以 OpenAI tools、Anthropic tool_use、Gemini function calling、LangChain 四栈为对象,测同一个逻辑工具在不同序列化方式下的体积差,并量化"胖工具"对召回率与可用上下文的挤压。核心结论有三:第一,工具定义不是一次性开销,而是每轮复利;第二,LangChain 的 pydantic 包装会多带约三成冗余;第三,描述冗余度对召回率是一条"先升后平再降"的曲线,盲写长描述不仅烧 token,还会稀释模型注意力。体积税的本质,是把工具从"能力"变成了"上下文竞品"。

一、体积税的数学:每轮复利才是真凶

理解体积税,先要把账算清。一个最小工具(名字 + 一行描述 + 两个参数)在原生 OpenAI 格式下大约 40–60 token;一个"胖工具"(多段描述 + 用例 + 嵌套 schema + enum 枚举)可以膨胀到 300–500 token。表面看一次请求多花几百 token 不痛不痒,真正的杀伤来自回环复利:自主体每走一步,整张工具表都会被完整重发,因为模型是无状态的,上一轮看到的 schema 不会"记得"。

假设你挂了 40 个工具(一个中等规模 MCP 服务器的典型量级),平均每个 120 token,工具表就是 4 800 token。自主体跑 10 轮,工具定义累计烧掉 4.8 万 token——这还没算系统提示、检索片段、对话历史。有实测指出,系统提示 + 工具 schema + 对话历史常常在用户第一句话之前就吃掉 30%–60% 的上下文;某团队报告单是工具与系统提示区就占了 1 205 token。一旦回环超过 8–12 轮,胖工具定义会率先把长任务挤进"上下文坍缩"的红线,触发提前压缩、记忆裁剪、甚至截断检索结果——而这些副作用,团队往往归咎于"模型变笨了",真正的原因是预算被工具表偷走了。

二、四栈工具定义体积横评

维度 OpenAI tools Anthropic tool_use Gemini func calling LangChain 工具
序列化格式 JSON Schema(工具数组) JSON Schema(tools 参数,注入系统区) Function Declarations(扁平化) pydantic → 转 OpenAI schema
单工具基线 token ~50(瘦)/~350(胖) ~55/~360(描述字段更宽松) ~45/~300(字段更省) ~70/~460(pydantic 冗余)
冗余来源 parameters 嵌套 + description 全量 同 OpenAI,额外 input_schema 包装 枚举与嵌套展开 docstring + 字段元数据 + 类型注解双写
重发机制 每轮重发 每轮重发 每轮重发 每轮重发(且经包装层)
动态裁剪 需手写检索器 需手写检索器 需手写检索器 可绑 retriever,但默认全量

四栈的差异不在"能不能裁",而在默认有多胖。LangChain 最重,因为它把 Python 的 docstring、pydantic 字段描述、类型注解同时序列化,等价信息写了两到三遍;Gemini 最轻,字段更扁平;OpenAI 与 Anthropic 居中。这意味着同样一份工具集,换栈即变体积,按 token 计费的成本也随之漂移。

三、瘦工具 vs 胖工具:代码层面的体积差

# 瘦工具:~45 token,只留必要信息
{"name": "get_order",
 "description": "查询订单状态",
 "parameters": {"type": "object",
                "properties": {"order_id": {"type": "string"}}}}

# 胖工具:~340 token,描述、示例、enum 全堆上
{"name": "get_order",
 "description": "查询订单状态。支持按订单号查询,可返回"
                "物流、支付、售后状态。常见用法:get_order"
                "(order_id='OD123')。注意 order_id 形如 OD+数字。",
 "parameters": {"type": "object",
   "properties": {
     "order_id": {"type": "string",
       "description": "订单编号,格式 OD+8位数字,如 OD20260704",
       "examples": ["OD20260704"]},
     "fields": {"type": "array", "items": {
       "type": "string",
       "enum": ["logistics","payment","after_sale","all"]}}},
   "required": ["order_id"]}}

胖工具多了 7 倍 token,换来的是更稳的歧义消解——但有边界。当工具表里只有这一个工具时,胖描述几乎纯亏;当表里有 30 个近义工具时,多出来的描述确实能挡住"工具近亲即误选"。诀窍是按歧义密度分配 token:高频易混工具写胖,孤岛工具写瘦。

四、描述冗余度 vs 召回率:先升后平再降

这是本轮最反直觉的发现。把同一批工具按描述长度分成瘦、中、胖、超胖四档,在 BFCL(Berkeley Function-Calling Leaderboard)风格的选型任务上测召回率,曲线不是单调上升,而是一条膝型再回落:

回落的机理有两条。其一,"lost in the middle"效应:当工具表很长,模型对排在中间的工具注意力本就衰减,再给每个工具灌超长描述,等于把信号埋进噪声。其二,描述里的示例 token会与真实用户输入竞争注意力,模型偶尔把示例里的值当成"已发生的事实"搬进参数,触发"传参即失真"。结论:存在一个性价比拐点,越过它,每多一个 token 都在同时烧钱和掉点。

五、挤出效应:工具表如何偷走检索与记忆

体积税的下游伤害不在工具调用本身,而在它挤掉了谁。自主体上下文是一个零和预算,工具表吃掉的部分,必然从别处扣除:

flowchart LR
    subgraph CW["上下文窗口(固定预算)"]
      direction TB
      S["系统提示"]
      T["工具定义表"]
      R["检索片段 RAG"]
      H["对话历史 / 记忆"]
      Q["本轮用户输入"]
      O["模型可用思考区"]
    end
    T -.膨胀.-> R
    T -.膨胀.-> H
    T -.膨胀.-> O
    style T fill:#f4c2c2,stroke:#c0392b
    style R fill:#fdebd0,stroke:#e67e22
    style H fill:#fdebd0,stroke:#e67e22

胖工具表最先吞掉的是 RAG 检索片段和对话历史。当工具占去 15%–25% 上下文时,可塞入的检索结果从 40 条缩到 25 条,长任务的早期决策被压缩丢弃——表现为"自主体越跑越忘事""引用文档却答非所问"。这与"步深即塌""长程落差"同源:根因不是模型记忆差,而是工具表把记忆的位子占了。一个工程上的体检指标是有效检索带宽 = 总上下文 − 系统提示 − 工具表,它决定了你 RAG 还能装多少料,是长任务成败的隐性天花板。

六、缓解三式:动态注入、瘦化、分层

体积税不是不可治,关键在于把"静态全量挂载"改成"按需动态供给"。

第一式,工具检索(RAG-over-tools)。 不把全部工具塞进每一轮,而是先用一个轻量检索器按本轮意图召回 top-k 工具,只注入这 k 个 schema。10 个工具的体积税远低于 100 个,召回器本身可以是一个 embedding + 少量规则。风险是工具检索引入了第二层召回误差,需在工具数过 30 时才划算,否则检索开销 > 节省。

第二式,描述瘦化与按歧义加权。 把描述拆成"一句话摘要(常驻) + 详细说明(按需)"两段。常驻段只够消歧,详细段只在工具被选中后才注入下一轮。配合按歧义密度分配:易混工具摘要写厚,孤岛工具只留名字。这一式零基础设施成本,是最该先做的。

第三式,分层工具 + 状态机。 把工具按阶段编组,用调度器只暴露当前阶段可用的工具集(如"调研阶段"只给搜索类,"执行阶段"才给写操作)。本质是用编排层的先验知识换掉上下文里的工具冗余,副作用是编排耦合度上升,需在灵活性与体积之间取舍。

七、变现与训练营评估

体积税是少有的"既是技术债、又是利润点"的议题。对 B 端,它直接挂钩 token 成本:一个 40 工具的客服自主体,瘦化 + 动态注入往往能砍掉 20%–35% 的输入 token,规模化部署下是真金白银。这类"上下文预算审计"可以包装成交付物:工具表体检报告 + 瘦化重构 + 动态注入落地,单价对标性能优化。对训练营,它适合作为"工具使用"模块的进阶课,承接在"会调工具"之后——学员亲手用 tiktoken 量出胖瘦差,再用 BFCL 风格任务画出冗余度-召回率曲线,体感极强,且与已普及的"召回税""参数保真"主题形成层次,不易撞题。可落地的练习项包括:同一工具四栈 token 横测、工具检索器搭建、描述分层重构。

八、避坑:测量体积税的三个陷阱

第一,别只测首轮。体积税是复利,必须测多轮回环累计,否则会严重低估;用固定 8–12 轮轨迹做基准更稳。第二,别用对账单反推。计费系统常把工具 schema 摊进"系统/输入"类目,看不出来;应直接用 tokenizer 对序列化后的 tools 数组计数,与系统提示分开列账。第三,别忽略上下文编辑器。部分框架会在发送前静默重排、补全 description、注入示例,导致你以为写的是瘦工具,实际发出去的是胖工具——务必 dump 发往 API 的真实 payload 来核账。

推荐方案

体积税的真正教训是:在工具调用这件事上,省钱和提点往往同向。把工具描述写到拐点,既压 token 又涨召回;越过拐点堆描述,则既烧钱又掉点。量出那条曲线,比多写一百行描述更值。

参考来源

  1. Tool Definitions & Token Cost — Agentic Skillset — 实测工具 schema 在用户首条消息前即占用约 1 205 token 的案例
  2. The Hidden Token Tax — Tian Pan(2026-04) — 系统提示 + 工具 schema + 对话历史在生产管线中静默吃掉 30%–60% 上下文
  3. Token-Efficient Tool Calling: Auth Overhead — Scalekit — 40 工具 MCP 服务的 per-call token 成本与重发机制分析
  4. How Many Tokens Do Your Tool Definitions Actually Cost? — tokens-usage — OpenAI 与 Anthropic 工具定义 token 开销的测量方法
  5. Berkeley Function Calling Leaderboard (BFCL) V4 — UC Berkeley Gorilla — 工具选型准确率的标准评测基准,可用于刻画冗余度-召回率曲线

[!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 等场景全覆盖。

51学通信知识星球海报-扫码加入