4.5 工具爆炸:多少个工具算太多
一句话结论:工具数量不是线性成本。工具越多,上下文越长、选择越容易错、误用风险越大——而能力增长却是递减的。所以"工具爆炸"必须被主动治理,手段是按需加载而不是全量暴露。
读这篇之前
需要先读 4.2(描述决定选择)、2.2(上下文是瓶颈)、9.1(Skills 是可加载的能力包,本篇是它的前置)。这一篇收束第 4 章。
一、三个成本,都是非线性的
工具从 5 个增加到 50 个,看起来只是"多了 10 倍选项",实际上有三笔账同时恶化:
成本一:上下文膨胀
每个工具的定义(name + description + schema)通常占 100~300 Token。50 个工具就是 5000~15000 Token,每一轮都要重复发送(2.1 指出这是持续计费)。
如果你跑 20 轮的任务,光工具定义就消耗 10 万~30 万 Token。
成本二:选择准确率下降
这是更严重的成本。回到 2.2 的"半台检索引擎":模型要从工具清单里"检索"出最匹配的那个。
选项越多,相似项越多,误选概率越高。而且误选往往不是"明显错",而是"看起来也能用"——这种错误最难发现。
成本三:描述冲突
50 个工具里,必然有若干功能重叠:
search_code "搜索代码"
search_project "在项目中搜索"
find_in_files "查找文件内容"
三个工具描述都像"搜索",模型无法区分。这不是模型的问题,是你的设计问题。
二、一个经验判断
没有绝对数字,但有几个可操作的参考点:
| 工具数 | 状态 | 建议 |
|---|---|---|
| ≤ 10 | 舒适区 | 全量暴露,基本不需治理 |
| 10 ~ 20 | 需注意 | 检查是否有职责重叠,优化描述边界 |
| 20 ~ 30 | 需要治理 | 开始考虑分组或按需加载 |
| > 30 | 必须治理 | 全量暴露的误用率会明显上升 |
关键不在绝对数量,而在"有多少个工具在功能上接近"。 30 个彼此领域分明的工具,可能比 12 个功能重叠的工具更好用。
一个诊断方法
问自己三个问题:
| 问题 | 如果是"是" |
|---|---|
| 有没有两个工具,你会用同一个词描述它们? | 边界不清 → 合并或改描述 |
| 有没有工具,从来没被调用过? | 可能没用或描述太差 → 删或改 |
| 有没有工具,总是被误调用? | 描述误导 → 改描述或加防呆 |
三、解法一:按阶段加载
最有效的治理手段,不是"减少工具数量",而是不要在每一轮都给全部工具。
因为一个任务的不同阶段,需要的工具完全不同:
| 阶段 | 需要的工具 | 不需要的 |
|---|---|---|
| 理解需求 | 读文件、搜索、查库 | 写文件、发邮件、部署 |
| 制定方案 | 无(纯推理) | 几乎所有工具 |
| 执行修改 | 写文件、改代码 | 搜索互联网 |
| 验证 | 运行测试、读日志 | 发邮件 |
按阶段给工具,有三个收益:
- 选择更准(选项少)
- 上下文更省(2.2)
- 误用风险更低(危险工具在该阶段根本不可见)
这个思路的完整形态就是 Skills——把一组相关能力打包,按需加载。第 9 章整章都在讲它。
四、解法二:分组 + 路由
如果工具确实多、且无法按阶段切分,可以加一层"先分类再分发":
第 1 轮:判断任务类型(不给工具,只要分类结果)
第 2 轮:只加载该类型下的工具
代价是多一轮调用;收益是准确率提升。这是 1.4 讲的"路由模式"在工具层应用。
注意:路由本身也可能出错。所以分类的类别要少(3-5 类),且要有"其他"兜底。
五、解法三:合并同类项
有些"工具爆炸"是自找的。常见模式是把参数当成了工具:
差(工具爆炸):
export_pdf(), export_md(), export_html(), export_docx()
好(一个工具 + 枚举):
export(format: enum(pdf, md, html, docx))
但要注意反向的情况——当副作用等级不同时,必须拆开:
必须拆开:
query(sql) // 只读
execute(sql) // 可写,需要审批
不应合并成一个 exec(sql),因为无法分级
判据:
| 情况 | 做法 |
|---|---|
| 只是参数值不同,副作用相同 | 合并,用枚举 |
| 副作用等级不同 | 必须拆开 |
| 参数结构完全不同 | 拆开 |
六、解法四:让模型自己"发现"工具
工具确实很多、又无法预分组时,有一个更彻底的做法:只给模型一个"工具搜索"工具。
tools: [ search_tools(query) ]
模型先搜"我需要什么能力",再拿到对应的几个工具(动态注入下一轮上下文)。
这个做法的本质:把"50 个工具的选择"变成"一次搜索 + 3 个工具的细选"。
代价是:
- 多一轮交互
- 需要维护工具索引
- 搜索本身可能不准
适用场景:工具集极大(几十上百)、且使用频率分布很不均匀时。第 9 章会讲 Skills 如何用类似机制做这件事。
七、把工具当"公共 API"来治理
工具集一旦稳定,它就成了一个给模型用的 API。值得像对待公共 API 一样治理:
| 治理项 | 做法 |
|---|---|
| 命名规范 | 动词前缀 + 领域(read_file、send_email) |
| 描述模板 | 统一六要素(4.2) |
| 变更管理 | 改名/改描述要跑评测(第 13 章) |
| 废弃流程 | 标记 deprecated,观察期后再删 |
| 回归测试 | 每次改动测"该调 / 不该调"两类用例 |
"该调 / 不该调"两类用例是关键——只测"能调用成功"不够,还要测"不该调用时确实没调用"。
八、常见误区
误区一:工具越多,Agent 能力越强。
能力增长递减,成本增长递增。超过临界点后,加工具会降低整体表现。
误区二:把参数当工具,一个场景一个工具。
这会造成大量相似工具,误选率飙升。参数值不同用枚举,副作用不同才拆工具。
误区三:全量暴露最简单。
简单,但代价高(上下文 + 准确率)。按阶段加载几乎总是更优。
误区四:工具多说明系统强大。
工具多有时说明抽象做得差——本可以合并的东西被拆碎了。
误区五:删工具会丢能力。
多数"从不被调用的工具"其实是被更好的工具覆盖了。定期清理是必要的。
误区六:工具治理是一次性工作。
它需要随能力演进持续做。没有治理的工具集,半年后会变成灾难。
九、第 4 章小结
五篇讲完,把工具这一层压缩成一张表:
| 主题 | 核心结论 | 篇 |
|---|---|---|
| 本质 | Function Calling = 结构化输出 + 工具清单 | 4.1 |
| 描述 | 描述是模型的选择依据;必须写"什么时候不用" | 4.2 |
| 校验与回填 | 参数错是必然;错误信息质量决定能否自修 | 4.3 |
| ACI 设计 | 用户是模型;防呆优于报错 | 4.4 |
| 工具爆炸 | 成本非线性;按需加载优于全量暴露 | 4.5 |
三条最重要的结论:
- 工具是给模型用的界面,不是给人用的 API。 设计标准不同。
- 防呆优于报错。 让错误无法发生,比让它发生后再修更省。
- 工具数量要治理。 按阶段加载是最有效的手段。
十、动手:一张工具集治理的体检表
| # | 检查 | 不达标怎么办 |
|---|---|---|
| 1 | 有没有两个工具你会用同一个词描述? | 合并,或改写描述划清边界 |
| 2 | 有没有工具从没被调用过? | 手动测一次 → 删掉或重写描述 |
| 3 | 有没有工具总被误调? | 加"不适用"说明与互相指路 |
| 4 | 工具总数超过 20 了吗? | 按阶段加载 |
| 5 | 有没有工具参数是自由文本且指向系统(路径/命令)? | 改枚举或白名单(14.4) |
| 6 | 读写有没有分开? | 拆工具(本第第五节) |
| 7 | 每个工具的返回是否精简? | 归一化(2.5) |
第 2 条最值得定期做:它同时能发现"这个工具真没用"和"描述太差没被认出来"两种情况。
一个真实治理案例
某 Agent 的工具集有 34 个工具。一次集中治理做了四件事:
| 动作 | 结果 |
|---|---|
| 删掉 6 个从未被调用的 | 每轮省约 1200 Token |
| 合并 5 个"搜索类"为 2 个 | 误选率明显下降 |
| 把 3 个"万能工具"拆成 9 个明确工具 | 参数错误率下降 |
| 改为按阶段加载 | 单轮工具定义从 6800 → 2400 Token |
总收益:输入成本降约 40%,工具选择准确率提升。
关键点:这些动作都不需要换模型、不需要改提示词——纯粹是工具集设计。
一个规律
工具数量与准确率不是线性关系,而是"先升后降"。
拐点大约在 20-30 个(取决于彼此相似度)。
超过之后,新增工具的收益 < 增加的误选成本。
十一、第 4 章小结
五篇讲完,把"工具调用"这一层压成一张表。
| 主题 | 核心结论 | 篇 |
|---|---|---|
| 本质 | 模型只输出结构化请求,执行在你的代码里 | 4.1 |
| 描述 | 描述是选择依据;最该写"什么时候不用" | 4.2 |
| 校验与回填 | 参数错是必然;错误信息质量决定能否自修 | 4.3 |
| ACI | 用户是模型;防呆优于报错 | 4.4 |
| 工具集 | 成本非线性;按需加载优于全量暴露 | 4.5 |
三条最重要的结论
① 工具是"给模型用的界面",不是"给人用的 API"。
判断标准不同:人读文档能理解"这个函数干什么",模型只能靠 description 判断"什么时候用它"。
② 防呆优于报错。
让参数根本传不错(枚举、拆分工具),比"传错了再报错让它改"省一个量级。
③ 工具数量要治理。
拐点在 20-30 个(取决于相似度)。超过之后,新增工具带来的收益低于它带来的误选成本。
一个自检:你的工具层合格吗
① 每个工具的描述都写了"不适用时用哪个"吗?
② 每个参数都是枚举或白名单吗(没有自由文本路径)?
③ 错误信息能告诉模型"怎么改"吗?
④ 读写分开了吗?
⑤ 工具总数在 20 以内,或已按阶段加载吗?
五条都"是",工具层就基本健康。
十二、一个补充:工具爆炸的三种隐性成本
4.5 讲了 Token 与选择准确率。还有三个更隐蔽的成本。
| 成本 | 表现 |
|---|---|
| 维护 | 每个工具都要写描述、写测试、跟实现同步 |
| 权限面 | 工具越多,需要管控的越权路径越多(14.1) |
| 文档债 | 新人要理解 40 个工具才能改这个 Agent |
第二条最严重:一个 40 工具的系统,你需要为 40 个工具分别定义权限策略,任何一处漏了就是漏洞。
一个判断
每增加一个工具,问三个问题:
① 它能不能被现有工具组合出来?
② 它的副作用等级是什么?权限怎么配?
③ 半年后还有人维护它吗?
三个问题有任何一个答不好,就先别加。
十三、一句话收尾
工具集治理不是"优化",是"止损"。
每多一个工具,就多一份上下文开销、多一份误选概率、多一份权限面积。不治理的工具集不会自己变好,只会慢慢变成没人敢动的黑箱。
定期做那七项体检,成本很低,收益是长期的。
十四、最后一条
工具集是有"体重"的。 每增加一个,都要付出上下文、误选概率、权限面积三份重量。
衡量标准不是"它能做什么",而是"没有它,现有工具组合能不能做到"。 能,就别加。
十五、下一篇
第 2 章讲"模型的边界",第 3 章讲"怎么让它想对",第 4 章讲"怎么让它做到"。
第 5 章进入一个更底层的问题:这一切都在上下文里发生,那上下文该怎么管理?
这是全系列最核心的一章——因为 2.2 已经论证过:上下文是 Agent 能力的天花板。