摘要

接的工具越多,Agent 越笨——这个反直觉现象的根源在上下文:每个工具的名称、描述与 JSON Schema 都要常驻提示词,十几个 MCP 服务器意味着上百个工具定义长期占用注意力预算,模型选错工具的概率随之上升。全量注入成本高,全量检索多一跳且有盲区。本文给出折中方案:冷热分层。高频工具作为热层常驻上下文;低频工具进入工具注册表,模型通过一个 search_tools 元工具按需召回;召回结果只给 name + 一句话描述,选中才展开完整 schema。配套讨论检索查询改写、召回失败兜底、热层更新策略,并给出评测协议;同时对照 Claude Code、Trae、Cursor、CodeBuddy 四家的公开文档,看这条路线在产品里已经走到了哪一步。这是「哪些 token 该进窗口」这一 context engineering 问题在工具维度上的延伸,与本博客此前的上下文外置方案(水位触发 + 向量召回)同属一条线。


1. 问题:先算一笔工具描述的账

一次工具调用的上下文成本由三部分组成:

  1. 常驻成本:system prompt 里所有工具的定义(名称、描述、参数 schema、枚举值)。只要工具列表在,这笔钱每轮都付。
  2. 选择成本:模型在几十个语义相近的工具描述之间做匹配,工具一多,「该用的不用、不该用的乱用」开始出现。2026 年 9 月一篇社区测评给了个参考数字:Cursor 对活跃工具约有 40 个的软上限,超限告警并可能静默丢工具(注:这是社区文章的说法,Cursor 官方文档未公布具体数字)。Claude Code 的官方文档则换了个说法——「不设固定工具上限,实际限制是你的上下文窗口预算」。两种表述指向同一件事:工具规模被上下文预算卡住,只是卡的位置不同。
  3. 调用成本:工具返回结果本身。这一层通常已有人管(截断、摘要),但前两层长期被忽略。

估算量级(以常见工具定义为参考,非某框架实测):

项目单个工具约占用30 个工具
名称 + 一句话描述50–150 tokens1.5k–4.5k
完整 JSON Schema(含参数、枚举、示例)200–800 tokens6k–24k
多轮对话中的重复占用每轮一次每轮 6k–24k

一笔 24k tokens 的常驻开销,会挤占对话历史、检索结果和输出预算;更麻烦的是第 2 项——注意力预算摊薄导致的选择退化,这无法靠「换个更大窗口」解决,因为窗口越大,context rot 越明显。

另一个失败模式是隐性丢弃:部分客户端在工具超限时会静默移除某些工具。模型并不知道自己「本该有但没有」某个能力,于是既不会调用它,也不会报错,而是用一个不存在的工具名幻觉出调用——排查起来极其隐蔽。


2. 三个候选策略

策略常驻成本发现能力额外延迟主要风险
全量注入高完整无token 浪费 + 选择退化
全量检索(工具也 RAG)极低受召回率限制每次多一跳模型不知道某工具存在 → 永远不去搜
冷热分层中(只含热层)热层完整 + 冷层可召回仅冷工具多一跳分层规则需要维护

纯检索方案有一个致命失败模式:检索只能召回模型主动去搜的东西。如果模型从未听说过 k8s_deploy 这个名字,它就不会用「部署」去搜它,于是这个工具等于不存在。把所有工具都藏进检索,等于把「能力目录」从提示词里删掉——模型连自己有什么都不知道。

所以正确答案不是二选一,而是让目录本身可检索、但目录的入口常驻:这正是冷热分层。


3. 业界已经怎么做:四种公开方案

这套思路不是空想,2026 年的编码智能体已经分化出四种路线(以下均来自各家公开文档,检索时间 2026-10)。

3.1 Claude Code:把冷热分层做成默认配置

Claude Code 的 MCP 文档里有一节叫「使用 MCP 工具搜索进行扩展」,几乎就是本文方案的官方版:

  • ToolSearch 默认开启:工具定义延迟加载,会话开始时只装入工具名 + 服务器说明,「添加更多 MCP 服务器对上下文窗口的影响最小」;
  • alwaysLoad: true = 热层:某个服务器的工具若每回合都要用,标成 alwaysLoad 即可豁免延迟、常驻上下文——官方同时提醒「每个预加载的工具都在消耗本可用于对话的上下文」;
  • ENABLE_TOOL_SEARCH=auto / auto:N = 按预算自动切档:工具定义总和少于上下文窗口的 10% 就全量预加载,一旦达到 10% 就全部转为延迟加载(auto:5 即 5%)。分层的分界线不是固定的工具个数,而是 token 预算;
  • 两段式传递:模型先看到工具名,通过 tool_reference 块按需拉取完整定义(要求模型支持该块,Sonnet 4.5 及以上);
  • 服务器说明是检索的路标:官方明确说服务器说明字段「帮助 Claude 理解何时搜索你的工具,类似于 skills」,并把工具描述截断在 2048 字符(CLAUDE_CODE_MAX_MCP_DESCRIPTION_LENGTH 可调);
  • 连接也可延迟:cached · connects on first use 的发现缓存,连服务器本身都按需再连。

3.2 Trae:Skill 按需加载 + 按智能体圈工具

Trae 的文档把同一件事在两个层面做了:

  • Skill(技能)动态按需加载:智能体「先扫描所有技能的简要描述,仅当判断当前任务与某个技能高度相关时,才加载详细内容」,文档原话是这能「减少上下文中的 Token 消耗、避免无关信息干扰决策」。文档还给了一个非常直白的对比——规则是全量加载,技能是按需加载;
  • MCP 按智能体做 allowlist:内置 Agent 自动挂全部 MCP Server,而自定义智能体在创建时逐个勾选要用的 Server 甚至具体工具。这是人工版的冷热分层:每个智能体的「热层」由配置圈定。

3.3 Cursor:靠人肉治理,没有公开的工具检索

Cursor 官方文档的治理手段是:开关启停服务器(FAQ 原话「reducing tool clutter」)、企业级 MCP allowlist、单服务器的 tool allowlist、以及工具调用审批。公开文档里没有 ToolSearch 类的工具检索机制——冷热完全由人手动开关决定。

3.4 CodeBuddy:公开文档只讲接入,不讲治理

腾讯 CodeBuddy 的 MCP 文档目前停留在配置、MCP Market 一键安装和「Agent 根据任务调用工具」这一层;高级功能里有 Skills、Subagents、Hooks,但公开文档未见工具膨胀的治理机制。需要说明:文档没写不等于产品没有——这类机制常常在灰度,不进文档。

3.5 对比与结论

产品冷层(低频工具)放哪热层怎么定检索入口两段式 schema
Claude Code延迟加载,按需发现alwaysLoad + auto:N 预算阈值ToolSearch 元工具tool_reference 块
TraeSkill 正文 / 未勾选的 MCP内置全量 + 按智能体勾选技能简要描述扫描无(Skill 侧)
Cursor手动关掉的服务器人工启用无无
CodeBuddy未公开未公开未公开未公开

三个观察:

  1. 「冷热分层 + 元工具检索 + 两段式 schema」已被最主流的编码智能体验证为默认方案(Claude Code),且它的热层判据正是本文 §5.2 要讨论的 token 预算阈值;
  2. Trae 的 Skill 按需加载证明了同一范式在「工具」之外也成立——描述常驻、正文按需,这是跨能力类型的通用解法;
  3. 差距在「自动」与「人工」:Cursor / CodeBuddy 路线把分层成本丢给用户,Claude Code / Trae 路线把它做进产品。自建 Agent 时,你必须选择站在哪一边。

4. 方案:三层结构

┌──────────────────────────────────────────────┐
│ 热层(常驻 system prompt)                     │
│  · 完整 schema,模型直接可见可调               │
│  · 判据:高频 / 任务无关 / 每个会话几乎必用      │
│  · 例:文件读写、搜索、终端、memory 笔记         │
├──────────────────────────────────────────────┤
│ 元工具(常驻,常驻成本仅 ~200 tokens)          │
│  · search_tools(query, top_k) → name+摘要列表 │
│  · ensure_tool(name) → 展开完整 schema        │
├──────────────────────────────────────────────┤
│ 冷层(工具注册表,向量索引,不进提示词)          │
│  · 每项存:name / 一句话描述 / 触发场景标签      │
│  · 例:MCP 服务器里的低频工具、行业专用工具       │
└──────────────────────────────────────────────┘

三层的分工:

  1. 热层保证常用能力零延迟、零检索、零盲区——这是对「模型不知道就不会去搜」这一失败模式的结构性防御。
  2. 元工具是冷层的唯一入口,它本身是普通工具,因此只占一个工具位的成本,而不是几十个。
  3. 冷层注册表把工具描述从「每轮付费」变成「按需付费」,复用知识库向量检索那一套:query 改写 → 向量召回 → 重排序 → top-k。

两段式 schema 传递

召回阶段只返回 name 与一句话描述(每个约 30–60 tokens),模型据此选定后再调 ensure_tool(name) 拿完整 schema。这样检索本身不会重新制造上下文膨胀——如果召回 top-8 就把八个完整 schema 全塞回去,等于把全量注入拆成八次做,白忙一场。

元工具接口示意

{
  "name": "search_tools",
  "description": "当你需要的能力不在已提供的工具列表里时,用自然语言描述你想做的事,检索可用工具。只返回工具名和一句话说明。",
  "parameters": {
    "query": { "type": "string", "description": "想完成的任务,而非工具名" },
    "top_k": { "type": "integer", "default": 5 }
  }
}

注意 query 的描述是「想完成的任务,而非工具名」:模型天然倾向按工具名搜索,而冷层里它不认识任何工具名。检索入口必须把查询引到意图上。


5. 四个关键设计点

5.1 召回失败要有兜底

检索漏掉工具时,模型会幻觉出不存在的工具名。两条兜底:

  • search_tools 保证 top-k 内一定有可用项(相似度不足时返回最接近的若干个,并附「可能不完全匹配」标注),而不是返回空数组让模型自由发挥;
  • 模型调用不存在的工具时,返回结构化错误:你没有 X;最接近的是 Y / Z,把失败变成一次再检索,而不是一次报错中断。

5.2 热层怎么进、怎么出

热层是策略,不是固定清单。三种可用判据:

判据做法适用
人工白名单配置文件里写死核心工具工具集稳定的项目
频率统计记录调用次数,近 N 次会话内 top-K 进热层工具集动态增减
任务预判按当前任务类型加载对应热层(如「前端任务」带 Playwright)多领域 Agent
预算阈值工具定义总和超过窗口的 N% 就整体转延迟规模不确定的场景

预算阈值这一档已被产品化:Claude Code 的 ENABLE_TOOL_SEARCH=auto 默认以 10% 为界,少于阈值就全量注入,超过就整体转延迟——工具少时冷热分层根本没必要,全量最划算;工具多时才切换到检索。这条「先全量、超预算再分层」的滑动策略,比静态划死一个热层清单更省心。

频率统计最省心,但要注意冷启动:新会话没有统计,只能靠白名单起步,统计逐步接管。无论哪种,热层都要有上限(比如 10–15 个),否则热层自己就会膨胀回全量注入。

5.3 检索质量依赖描述,不依赖名字

注册表里每个工具的一句话描述应该写它解决什么问题,而不是它叫什么。csv_export 的描述写「把查询结果导出为 CSV 文件给用户下载」,比写「CSV 导出工具」召回率高得多——因为发起检索的是任务意图,不是工具名。这条规则和「不要把 30 个描述写得互相重叠」是同一件事的两面:描述重叠时,重排序分不开它们,模型拿到 top-5 也照样选错。

5.4 冷层工具的权限仍要单独管

分层是上下文治理,不是权限治理。一个藏在冷层里的高危工具,被召回后依然是高危工具。冷热分层与此前记录的 MCP 边界做法(默认关闭高危、只读先行、人工确认)是正交的两层,必须同时上。


6. 评测协议

没有数字的方案只是审美。建议至少测四个指标:

指标定义期望方向
Tool recall@k任务实际需要的工具出现在召回 top-k 中的比例提高
任务成功率同一批任务在全量注入 vs 分层下的端到端成功率不显著下降
常驻 token每轮 system prompt 中工具定义占用显著下降
端到端延迟含冷工具任务的额外一跳开销可量化、可接受

关键对照是任务成功率不能显著下降:如果省了 20k token 却让成功率掉了 15 个点,这笔交易是亏的。另外要单独统计「幻觉出不存在工具」的发生率——这是分层方案特有的失败类型,全量注入下几乎不会出现,必须盯住。

评测集要覆盖三类任务:只用热层工具的、必须命中冷层的、以及「看似需要冷层其实热层就够」的(测模型会不会过度检索)。


7. 边界:什么时候不该用

  1. 工具总数少于 10 个。分层的管理成本和多一跳延迟,此时省下的 token 不够本,全量注入就是最优解。
  2. 模型不会主动发起元调用。分层假设模型能在「现有工具不够用」时想到去调 search_tools。能力弱或被严格限制工具调用格式的模型,可能从不触发检索——冷层形同虚设,还平白少了一批能力。这条要先在你的具体模型上验证。
  3. 强一致的低延迟场景。实时交互里多一跳(检索 + 再展开 schema + 再调用)可能直接超时预算,热层做大更划算。
  4. 工具集本身高度动态且每个都高频。都高频就没有冷层,分层退化成全量注入的复杂版。

8. 结论

工具描述的膨胀本质是 context engineering 问题:哪些 token 每轮都值得占注意力预算。答案和对话历史一样——不是全留,不是全扔,而是分层 + 按需召回:

  • 热层管可达性(模型知道自己有什么、直接能用);
  • 冷层注册表管成本(低频能力不每轮付费);
  • 两段式 schema 管召回本身别再膨胀;
  • 兜底反馈管检索失败不退化成幻觉。

这与此前的上下文外置方案是同一套思路的两个应用面:那边外置的是对话原文,这边外置的是工具描述,都是「暂时不在窗口,而非不存在」,都靠向量召回按需搬回,都需要 recall 与成功率的评测兜底。

分层不是免费的——它引入了元工具、注册表维护和一跳延迟。但只要工具数量过了某个阈值(经验值在 15–20 个上下),这笔账就开始划算。先在你的工具集上把第 6 节的四个指标量出来,再决定要不要全量铺开。


参考来源

均为 2026-10 访问的公开文档:

  1. Claude Code 文档 · 通过 MCP 将 Claude Code 连接到工具(含「使用 MCP 工具搜索进行扩展」一节:ToolSearch、alwaysLoad、ENABLE_TOOL_SEARCH=auto、tool_reference)
  2. Trae 文档 · 技能(Skill)(动态按需加载、规则 vs 技能的全量/按需对比)
  3. Trae 文档 · 在智能体中使用 MCP Server(按智能体勾选 Server 与工具)
  4. Cursor 文档 · Model Context Protocol(启停、allowlist、审批)
  5. CodeBuddy 文档 · MCP
  6. 社区文章:MCP 服务器推荐:2026 值得装的 10 个(含避坑)(2026-09-08,Cursor 约 40 工具软上限的说法出处)