工具动态发现与延迟加载 Deep-Dive

April 24, 2026 · View on GitHub

39+ 个工具的 schema 全部注入系统提示会浪费大量 token。本文基于 Claude Code(v2.1.89 源码分析)的源码分析,介绍其 ToolSearchTool 延迟加载机制——仅加载核心工具,其余按需搜索。

✗ 进度追踪(2026-04-25 更新)PR#3589 —— feat(tools): add ToolSearch for on-demand loading of deferred tool schemas 已 CLOSED(2026-04-24 08:51 UTC 关闭,未合并)。本文描述的方向当前仍无合并 PR,回到"缺失"状态。

PR#3589 原方案技术要点(保留作为未来重启尝试的参考):

  • DeclarativeTool 新增 shouldDefer / alwaysLoad / searchHint 三个标志
  • 默认 deferred:MCP 工具 + lsp / cron_* / ask_user_question / exit_plan_mode
  • ToolSearch 双模式:select:Name1,Name2 精确匹配 + 关键词搜索(支持 +must-word 必需词)
  • 评分对齐 Claude Code spec:built-in 10/5/4/2(name/substring/hint/desc),MCP 12/6(偏向 MCP 以鼓励发现)
  • Resume 支持startChat 扫描历史 function calls 重新 reveal 之前用过的 deferred 工具
  • Compaction 保留/clear 清 revealed,压缩路径(startChat(newHistory))保留
  • Subagent wildcard ['*'] 通过 includeDeferred: true 保持向后兼容
  • 21 文件 / +1051/-11 行 / 20 个新测试 case

CLOSED 状态无 PR body 说明具体关闭原因(可能 review 反馈、stack 拆分、或方案调整)。本 item 维持 P1 追踪,等待后续 PR。


1. 问题与方案

方案系统提示 Token工具可用性
全量加载~15,000+(39 工具 schema)全部可用
延迟加载(Claude Code)~5,000(~10 核心工具)核心始终可用,其余按需

Claude Code 通过 ToolSearchTool 实现第二种方案——核心工具始终在系统提示中,其余工具的 schema 仅在模型调用 ToolSearch 时注入。


2. 延迟加载分类

// 源码: tools/ToolSearchTool/prompt.ts#L62-L108
// 分类逻辑:
类别条件示例
始终加载alwaysLoad: true 或特殊角色ToolSearch 自身、Agent(FORK_SUBAGENT 启用时)、BriefTool、SendUserFileTool
延迟加载shouldDefer: true 或 MCP 工具WebFetch、WebSearch、NotebookEdit、CronCreate、TaskCreate 等
MCP 工具始终延迟所有 mcp__* 前缀工具

3. 搜索模式

3.1 Select 模式(直接选择)

ToolSearch(query: "select:WebFetch,NotebookEdit")
→ 精确匹配工具名(大小写不敏感)
→ 返回匹配工具的完整 schema
→ 已加载工具也会返回(无害的 no-op)

源码: tools/ToolSearchTool/ToolSearchTool.ts#L363-L405

3.2 Keyword 模式(模糊搜索)

ToolSearch(query: "notebook jupyter")
ToolSearch(query: "+slack send")       ← + 前缀 = 必须匹配

评分算法(源码: ToolSearchTool.ts#L186-L302):

匹配类型MCP 工具普通工具
工具名精确部分匹配12 分10 分
工具名部分匹配6 分5 分
searchHint 匹配4 分4 分
描述匹配(词边界)2 分2 分
全名回退3 分3 分

MCP 工具评分略高——因为 MCP 工具始终延迟,搜索是唯一发现路径。

3.3 Schema

// 输入:
{ query: string, max_results?: number }  // max_results 默认 5

// 输出:
{
  matches: [{ name, description, schema }],
  query: string,
  total_deferred_tools: number,
  pending_mcp_servers?: string[]  // 仍在连接中的 MCP 服务器
}

4. 缓存策略

// 源码: ToolSearchTool.ts#L66-L100
// 工具描述缓存:
getToolDescriptionMemoized(toolName)
首次调用: 生成描述 + schema
后续调用: 返回缓存
延迟工具集变化时: maybeInvalidateCache() 清除

// Schema 延迟加载:
lazySchema()  → 仅在 ToolSearch 被调用时加载 schema

5. 系统提示中的呈现

当 ToolSearch 启用时,系统提示中不列出延迟工具的完整 schema,而是一段引导文本:

The following deferred tools are available via ToolSearch:
AskUserQuestion, CronCreate, CronDelete, CronList, ...

模型看到这段文本后,知道可以通过 ToolSearch(query: "select:AskUserQuestion") 获取完整 schema。


6. Qwen Code 对比

维度Claude CodeQwen Code
工具加载核心始终 + 其余延迟全部始终加载
搜索工具ToolSearchTool(keyword + select)
MCP 工具始终延迟始终加载
系统提示 Token~5,000(核心)~15,000+(全部)
缓存描述缓存 + 变更失效N/A

7. 关键源码文件

文件行数职责
tools/ToolSearchTool/ToolSearchTool.ts472搜索引擎(keyword/select/评分/缓存)
tools/ToolSearchTool/prompt.ts122延迟分类逻辑 + 系统提示文本
tools/ToolSearchTool/constants.ts1常量

免责声明: 以上分析基于 2026 年 Q1 源码,后续版本可能已变更。