Skip to content

避免工具爆炸导致上下文爆炸

什么是工具爆炸

Agent 能调用的每一个工具,都要把名称 + 描述 + 参数 JSON Schema 完整地放进上下文,模型才知道它的存在和用法。单个工具定义几百到上千 token,看起来不多——但 MCP(Model Context Protocol)让接入工具变得太容易了:

text
GitHub MCP        ~35 个工具
数据库 MCP        ~10 个工具
浏览器 MCP        ~20 个工具
Jira MCP          ~15 个工具
公司内部 MCP      ~25 个工具
──────────────────────────────
105 个工具 × 500~1500 token ≈ 5~15 万 token

这就是工具爆炸:你还没说第一句话,上下文窗口已经被工具定义吃掉一小半。后果是三重的:

  1. 窗口浪费:200K 的窗口开场先没了 25%~50%,留给真正干活的空间大减,更早触发 compact;
  2. 成本放大:这些定义排在请求最前面,每一轮都要发送——好在有缓存兜底,但任何一个 MCP 的增删都会把整条缓存炸掉;
  3. 决策质量下降:工具越多,模型选错工具、混淆相似工具的概率越高。实测中,几十个可选工具就足以显著拉低工具调用准确率。

诊断:先看 /context

Claude Code 里运行 /context,可以看到系统提示、内置工具、每个 MCP 服务器、记忆文件各占多少 token。如果 "MCP tools" 一项占了几万 token,就该动手了。

对策一:只挂当前任务需要的 MCP

  • 把 MCP 配置放到项目级(.mcp.json)而不是全局——写前端的项目不需要数据库 MCP;
  • claude mcp list 检视,不用的直接移除;
  • Claude Code 支持用 /mcp 按需启停服务器,--mcp-config 也可以按会话指定;
  • 记住缓存规则:增删 MCP 要在会话边界做,不要在长任务中途。

对策二:按需加载工具定义(Tool Search / 延迟加载)

比"少装"更根本的解法是不预载:上下文里只放一个"工具搜索"入口,几百个工具的完整 Schema 存在窗口外,模型需要时先搜索、再按需载入命中的那几个。

  • Anthropic API 提供 Tool Search Tool:给工具标 defer_loading: true,可把工具定义的上下文占用降一个数量级(官方示例中从 ~7.7 万 token 降到 ~9 千);
  • 新版 Claude Code 对 MCP 工具已内置类似机制(工具按需发现),但仍以精简配置为佳——发现机制救不了描述冗长、职责重叠的工具集。

自建 Agent 时同理:与其一次注册 100 个工具,不如注册 search_tools + invoke_tool 两个元工具,或按任务阶段动态注册。

对策三:用"代码接口"替代"工具接口"

很多 MCP 工具本质上是某个 CLI 或 API 的包装。若 Agent 本身能执行代码(Claude Code 的 Bash、Codex 的 shell),往往直接教它调 CLI 更省:

text
❌ GitHub MCP 的 35 个工具常驻上下文
✅ CLAUDE.md 里写一行:"GitHub 操作用 gh CLI"
   gh pr list / gh issue view 42 / gh api ...

CLI 的"文档"(--help)只在需要时才被读取,天然就是按需加载。类似地,能用一段脚本解决的事,不必包装成常驻工具。

对策四:用子代理隔离高噪音工作

工具输出同样会爆炸:一次全仓 grep、一轮浏览器自动化、一次大规模测试,动辄几万 token 的结果涌进主窗口。

Claude Code 的解法是子代理(subagent / Task tool):探索、检索、批量验证这类高噪音工作放到子代理里,它烧的是自己独立的上下文窗口,只把几百 token 的结论带回主对话。主窗口因此保持"小而稳"——同时也保住了缓存前缀。

检查清单

text
□ /context 里 MCP tools 占用 < 2 万 token(经验值)
□ MCP 按项目配置,不搞全局大礼包
□ 会话中途不增删 MCP / 工具
□ 有 CLI 可用的场景优先 CLI,不包装成 MCP
□ 大范围搜索/浏览/批量任务丢给子代理
□ 自建 Agent:工具 > 20 个时考虑 defer_loading / 元工具模式

AI Coding Guideline — 面向 Claude Code / Codex 等 AI 编程工具的实践指南