Files
claude-code/spec/feature_20260508_F001_tool-search/spec-design.md
claude-code-best 7be08f53bd feat: 实现 Tool Search 基础设施层(CORE_TOOLS 白名单 + TF-IDF 索引 + ExecuteTool + 搜索增强)
- 新增 CORE_TOOLS 白名单常量(31 个核心工具),重构 isDeferredTool 为白名单制判定
- 新建 TF-IDF 工具索引模块(toolIndex.ts),复用 localSearch.ts 算法函数
- 新建 ExecuteTool 跨 API provider 统一工具执行入口
- 增强 ToolSearchTool:TF-IDF 搜索路径、discover: 模式、并行搜索合并、文本模式回退
- 新增 27 个单元测试,precheck 零错误通过(4108 tests pass)

Co-Authored-By: glm-5.1[1m] <zai-org@claude-code-best.win>
2026-05-08 22:29:15 +08:00

19 KiB
Raw Blame History

Feature: 20260508_F001 - tool-search

需求背景

当前 Claude Code 有 60+ 内置工具和无限 MCP 工具Agent 在处理任务时缺乏"根据任务描述自动发现最匹配工具"的能力。现有 ToolSearchTool 仅处理延迟加载(按需加载 schema via tool_reference),不做语义发现。tool_reference 机制存在以下局限:

  1. 仅 Anthropic 一方 API 支持 — OpenAI/Gemini/Grok 兼容层不支持 tool_reference beta 特性
  2. 破坏 prompt cache — 动态注入工具 schema 导致缓存失效
  3. 工具列表固定 — 每次请求的工具集在请求开始时就确定了,临时添加工具触发缓存全部失效

用户也无法直观了解哪些工具适合当前任务,缺乏推荐机制。

目标

  1. 激进精简初始化工具注入,从 60+ 精简到 ~10 个核心工具 + 2 个入口工具ToolSearch + ExecuteTool
  2. 增强 ToolSearchTool,增加 TF-IDF 文本匹配的"工具发现"能力
  3. 新建 ExecuteTool,提供跨 API provider 的统一工具执行入口
  4. 支持用户输入提示词后自动预取推荐工具(类似 skill prefetch
  5. 在 REPL 中展示工具推荐提示条(类似 skill search tips
  6. 搜索范围覆盖MCP 工具、自定义工具、所有延迟加载的内置工具
  7. 复用 localSearch.ts 的 tokenize/stem/cosineSimilarity 基础设施

方案设计

整体架构

四层设计:初始化精简 + 搜索层 + 执行层 + UI 层。

初始化阶段(激进精简):
  核心工具(~10个始终加载 schema     延迟工具(其余全部,仅注入名称列表)
  Bash / Read / Edit / Write / Glob      WebFetch / WebSearch / NotebookEdit
  Grep / Agent / AskUser / ToolSearch    TodoWrite / CronTools / TeamCreate
  ExecuteTool                            SkillTool / PlanMode / ...50+ 工具)
                                               ↓ MCP 工具也延迟加载

运行时发现与执行:
  用户输入 → 预取管道(异步) → TF-IDF 搜索 → UI 推荐提示
                                                      ↓
  模型处理任务 → ToolSearchTool(TF-IDF搜索) → 返回工具信息文本
                                                      ↓
  模型构造参数 → ExecuteTool(tool_name + params) → 路由执行 → 返回结果

1. 初始化精简(激进策略)

核心思路: 将初始化时注入的工具从 60+ 精简到 ~10 个核心工具 + 2 个入口工具ToolSearch + ExecuteTool。其余 50+ 工具全部延迟加载,仅注入名称列表到延迟工具清单。

始终加载的核心工具31 个):

工具 始终加载的理由
BashTool 几乎所有任务都需要 shell 执行
FileReadTool 读取文件是基础操作
FileEditTool 编辑文件是核心能力
FileWriteTool 写入文件是核心能力
GlobTool 文件搜索是基础操作
GrepTool 内容搜索是基础操作
AgentTool 子 agent 调度是核心架构
AskUserQuestionTool 用户交互是基础能力
ToolSearchTool 工具发现入口
ExecuteTool 延迟工具执行入口(新增)
TaskOutputTool 任务输出查询是高频操作
TaskStopTool 任务停止是 agent 生命周期管理
EnterPlanModeTool 进入计划模式是常见工作流
ExitPlanModeV2Tool 退出计划模式是常见工作流
VerifyPlanExecutionTool 计划执行验证与 ExitPlanMode 配套
TaskCreateTool 任务创建TodoV2是高频操作
TaskGetTool 任务查询TodoV2是高频操作
TaskUpdateTool 任务更新TodoV2是高频操作
TaskListTool 任务列表TodoV2是高频操作
TodoWriteTool 待办写入是任务跟踪基础
SendMessageTool 团队内 agent 通信
TeamCreateTool 团队创建swarm 模式核心)
TeamDeleteTool 团队删除swarm 模式核心)
ListPeersTool 跨会话通信发现
SkillTool 技能调用(/skill 命令)
WebFetchTool Web 内容获取是常见需求
WebSearchTool Web 搜索是常见需求
NotebookEditTool Notebook 编辑是数据分析基础
LSPTool LSP 代码智能是开发基础
MonitorTool 后台监控进程(日志/轮询)
SleepTool 等待时长(轮询 deploy 等场景)

延迟加载的工具(约 26 个内置工具 + 全部 MCP 工具):

所有未在核心列表中的内置工具,包括:

工具 延迟加载的理由
ConfigTool 配置操作低频ant only
TungstenTool 专用工具低频ant only
SuggestBackgroundPRTool PR 建议低频
WebBrowserTool 浏览器操作低频feature-gated
OverflowTestTool 测试专用feature-gated
CtxInspectTool 上下文检查低频debug/feature-gated
TerminalCaptureTool 终端捕获低频feature-gated
EnterWorktreeTool worktree 操作低频
ExitWorktreeTool worktree 操作低频
REPLTool REPL 模式低频ant only
WorkflowTool 工作流脚本低频feature-gated
CronCreateTool 调度创建低频
CronDeleteTool 调度删除低频
CronListTool 调度列表低频
RemoteTriggerTool 远程触发低频
BriefTool 通信通道低频KAIROS
SendUserFileTool 文件发送低频KAIROS
PushNotificationTool 推送通知低频KAIROS
SubscribePRTool PR 订阅低频
ReviewArtifactTool 产物审查低频
PowerShellTool PowerShell 低频(需显式启用)
SnipTool 上下文裁剪低频HISTORY_SNIP
DiscoverSkillsTool 技能发现低频feature-gated
ListMcpResourcesTool MCP 资源列表低频
ReadMcpResourceTool MCP 资源读取低频
TestingPermissionTool 仅测试环境
全部 MCP 工具 按连接动态加载

实现方式:

  1. 系统提示词增强src/context.tssrc/constants/prompts.ts

在系统提示词中加入工具发现引导指令,确保模型始终知道如何获取延迟工具:

When you need a capability that isn't in your available tools, use ToolSearch
to discover and load it. ToolSearch can find all deferred tools by keyword or
task description. After discovering a tool, use ExecuteTool to invoke it with
the appropriate parameters.

Common deferred tools include: CronTools (scheduling), WorktreeTools (git
isolation), SnipTool (context management), DiscoverSkills (skill search),
MCP resource tools, and many more. Always search first rather than assuming
a capability is unavailable.
  1. 新增核心工具集合常量src/constants/tools.ts
export const CORE_TOOLS = new Set([
  // 文件操作
  'Bash', 'Read', 'Edit', 'Write', 'Glob', 'Grep',
  // Agent 与交互
  'Agent', 'AskUserQuestion', 'SendMessage', 'ListPeers',
  // 团队swarm
  'TeamCreate', 'TeamDelete',
  // 任务管理
  'TaskOutput', 'TaskStop',
  'TaskCreate', 'TaskGet', 'TaskUpdate', 'TaskList',
  'TodoWrite',
  // 规划
  'EnterPlanMode', 'ExitPlanMode', 'VerifyPlanExecution',
  // Web
  'WebFetch', 'WebSearch',
  // 编辑器
  'NotebookEdit',
  // 代码智能
  'LSP',
  // 技能
  'Skill',
  // 调度与监控
  'Sleep', 'Monitor',
  // 工具发现与执行(新增)
  'ToolSearch', 'ExecuteTool',
])
  1. 修改 isDeferredTool 判定逻辑ToolSearchTool/prompt.ts
export function isDeferredTool(tool: Tool): boolean {
  if (tool.alwaysLoad === true) return false
  if (tool.name === TOOL_SEARCH_TOOL_NAME) return false
  if (tool.name === EXECUTE_TOOL_NAME) return false
  // 核心工具不延迟
  if (CORE_TOOLS.has(tool.name)) return false
  // MCP 工具和其余内置工具全部延迟
  return true
}
  1. 修改 getAllBaseTools() 注册逻辑src/tools.ts

核心工具直接注册(带完整 schema延迟工具也注册到工具池用于 ExecuteTool 查找),但标记为 deferred。

  1. 延迟工具名称列表注入src/services/api/claude.ts

构建 API 请求时,核心工具的 schema 正常注入。延迟工具仅注入名称列表到 <available-deferred-tools>system-reminder 附件中,模型通过 ToolSearchTool 获取详情。

收益:

  • 初始 prompt 体积减少约 30-40%26 个内置工具 schema → 名称列表,加上 MCP 工具全延迟)
  • Prompt cache 命中率提升(核心 31 工具列表稳定,延迟工具仅名称列表)
  • 支持无限工具扩展(不受 context window 限制)

权衡:

  • 非核心工具首次使用需要一轮 ToolSearch → ExecuteTool 的额外交互
  • 模型需要更积极地使用 ToolSearchTool 发现可用工具

2. 工具索引层

新增文件: src/services/toolSearch/toolIndex.ts

src/services/skillSearch/localSearch.ts 直接 import 复用 tokenizeAndStemcomputeWeightedTfcomputeIdfcosineSimilarity 算法新建工具索引。不提取为独立共享模块——skill 和 tool 的索引结构不同(SkillIndexEntry vs ToolIndexEntry),强行抽象反而增加复杂度。

索引条目结构:

interface ToolIndexEntry {
  name: string                    // 工具名(如 "FileEditTool" 或 "mcp__server__action"
  normalizedName: string          // 小写 + 连字符替换
  description: string             // 工具描述文本
  searchHint: string | undefined  // buildTool 中定义的 searchHint
  isMcp: boolean                  // 是否 MCP 工具
  isDeferred: boolean             // 是否延迟加载工具
  inputSchema: object | undefined // 参数 schemaJSON Schema 格式,供 discover 模式返回)
  tokens: string[]                // 分词后的 token 列表
  tfVector: Map<string, number>   // TF-IDF 向量
}

字段权重:

字段 权重 说明
name 3.0 工具名称CamelCase 拆分、MCP __ 拆分)
searchHint 2.5 工具的 searchHint 字段(高信号)
description 1.0 工具描述文本

索引生命周期:

  • 按需构建,缓存在会话中
  • MCP 工具连接/断开时触发增量更新(复用 DeferredToolsDelta 机制)
  • 内置工具在首次构建时全量索引
  • 仅索引延迟工具(核心工具已在模型上下文中,无需发现)

工具名解析:

  • MCP 工具:mcp__server__action → 拆分为 ["mcp", "server", "action"]
  • 内置工具:FileEditTool → CamelCase 拆分为 ["file", "edit", "tool"]
  • 与现有 ToolSearchTool.parseToolName 逻辑对齐

3. 搜索层增强

修改文件: packages/builtin-tools/src/tools/ToolSearchTool/ToolSearchTool.ts

在现有 searchToolsWithKeywords 基础上,新增 TF-IDF 搜索路径:

增强的搜索流程:

query 输入
    │
    ├── select: 前缀 → 直接选择(保留现有逻辑)
    │
    └── 关键词搜索 → 并行执行两路搜索
         │
         ├── searchToolsWithKeywords现有关键词匹配 + 评分)
         │
         └── searchToolsWithTfIdf新增TF-IDF 余弦相似度)
              │
              └── 合并结果 → 加权求和 → 排序 → top-N

结果合并策略:

  • 关键词匹配分数 × 0.4 + TF-IDF 相似度分数 × 0.6
  • 权重可通过环境变量 TOOL_SEARCH_WEIGHT_KEYWORD / TOOL_SEARCH_WEIGHT_TFIDF 调整
  • 去重:同一工具取两路中最高分

输出格式变更:

mapToolResultToToolResultBlockParam 增加文本模式返回(当 tool_reference 不可用时):

// 当 tool_reference 可用时(现有逻辑,保持不变)
{ type: 'tool_reference', tool_name: "..." }

// 当 tool_reference 不可用时(新增)
{ type: 'text', text: "Found 3 tools:\n1. **ToolName** (score: 0.85)\n   Description...\n   Schema: {...}" }

判断条件:复用 modelSupportsToolReference() 或检测当前 provider 是否支持。

新增 discover 查询模式:

discover:<任务描述>  — 纯发现搜索,不触发延迟加载,只返回工具信息

与现有 select: 模式互补。discover: 返回工具名 + 描述 + 参数 schema文本形式供 ExecuteTool 使用。

4. 执行层ExecuteTool

新增文件: packages/builtin-tools/src/tools/ExecuteTool/

工具定义:

const ExecuteTool = buildTool({
  name: 'ExecuteTool',
  searchHint: 'execute run invoke a tool by name with parameters',

  inputSchema: z.object({
    tool_name: z.string().describe('Name of the tool to execute'),
    params: z.record(z.unknown()).describe('Parameters to pass to the tool'),
  }),

  async call(input, context) {
    // 1. 在全局工具注册表中查找目标工具
    // 2. 验证 params 是否符合目标工具的 inputSchema
    // 3. 调用目标工具的 call 方法
    // 4. 返回执行结果
  },
})

核心逻辑:

  1. 工具查找: 通过 findToolByName 在完整工具池built-in + MCP中查找
  2. 参数验证: 用目标工具的 inputSchema 验证传入参数
  3. 权限继承: 复用目标工具的 checkPermissions 方法
  4. 执行委托: 调用目标工具的 call(input, context) 方法
  5. 结果透传: 直接返回目标工具的执行结果

权限模型:

  • ExecuteTool 本身不做额外权限检查
  • 权限检查委托给目标工具的 checkPermissions
  • 用户审批时显示实际工具名和操作内容(而非 "ExecuteTool"

工具注册:

  • src/tools.tsgetAllBaseTools() 中注册
  • 与 ToolSearchTool 关联启用:当 isToolSearchEnabledOptimistic() 为 true 时注册

5. 预取管道

新增文件: src/services/toolSearch/prefetch.ts

触发时机: 用户提交输入后、发送 API 请求前

流程:

用户输入提交
    │
    ├── 异步启动预取(不阻塞主流程)
    │   │
    │   ├── 提取用户消息文本
    │   ├── 调用 toolIndex.search(message, limit: 3)
    │   └── 存储结果到模块级缓存
    │
    └── API 请求构建时
        │
        └── collectToolSearchPrefetch()
            │
            ├── 有结果 → 注入 system-reminder 或 <available-tools-hint>
            └── 无结果 → 不做任何附加

Hook 集成点: 在 REPL.tsx 的消息提交流程或 QueryEngine 的请求构建环节中集成。

并发安全: 预取为异步操作,不阻塞主请求流程。如果预取未完成则跳过推荐。

6. 用户推荐 UI

新增文件: src/components/ToolSearchHint.tsx

展示形式: 在 REPL 输入区域上方渲染推荐提示条(类似现有 skill search tips 的设计)。

UI 规格:

  • 显示匹配度最高的 2-3 个工具
  • 每个工具显示:工具名 + 简短描述(一行截断) + 匹配分数
  • 样式与现有 skill search tips 对齐Ink 组件,使用 theme 色系)
  • 可通过键盘快捷键选择Tab 切换、Enter 确认)
  • 选择后将工具信息追加到当前消息的上下文中

条件显示:

  • 仅当预取结果非空时显示
  • 匹配分数低于阈值(默认 0.15)时不显示
  • 用户可通过 settings.json 关闭推荐提示

7. 搜索范围控制

采用激进精简策略后,搜索范围逻辑简化为:

  • 索引范围: 所有延迟工具(即核心工具列表之外的全部工具),包括所有 MCP 工具和所有非核心内置工具
  • 排除范围: 核心工具(CORE_TOOLS 集合中的工具)不索引
  • 动态更新: MCP 工具连接/断开时增量更新索引

可通过环境变量 TOOL_SEARCH_EXCLUDE 追加排除项,TOOL_SEARCH_INCLUDE_FORCE 强制索引某些工具。

实现要点

关键技术决策

  1. 复用 vs 重写 TF-IDF 基础设施: 直接 import localSearch.tstokenizeAndStemcomputeWeightedTfcomputeIdfcosineSimilarity 函数。不提取为独立模块,因为 skill 和 tool 的索引结构不同SkillIndexEntry vs ToolIndexEntry强行抽象会增加复杂度。

  2. ExecuteTool vs tool_reference: ExecuteTool 是通用方案,兼容所有 API provider。当 provider 支持 tool_reference 时,优先使用 tool_reference(性能更好,模型认知负担更低)。当不支持时,回退到 ExecuteTool。

  3. 索引更新策略: MCP 工具连接/断开时,通过 DeferredToolsDelta 机制检测变化,增量更新索引而非全量重建。

  4. 预取不阻塞主流程: 预取为 fire-and-forget 异步操作。如果预取未完成API 请求正常发送,不做任何等待。

难点

  1. 权限透传: ExecuteTool 调用目标工具时需要正确透传权限上下文,确保用户审批流程与直接调用目标工具一致。

  2. 参数 schema 验证: MCP 工具的 schema 可能非常复杂嵌套对象、oneOf 等ExecuteTool 需要优雅地处理 schema 验证失败的情况。

  3. 缓存一致性: 工具索引缓存需要在 MCP 连接变化时及时更新,避免搜索到已失效的工具。

依赖

  • src/services/skillSearch/localSearch.ts — TF-IDF 算法复用
  • packages/builtin-tools/src/tools/ToolSearchTool/ — 现有搜索逻辑基础
  • src/utils/toolSearch.ts — 工具搜索基础设施(模式判断、阈值计算)
  • packages/builtin-tools/src/tools/MCPTool/MCPTool.ts — MCP 工具执行参考

新增文件清单

文件 职责
src/services/toolSearch/toolIndex.ts TF-IDF 工具索引构建与查询
src/services/toolSearch/prefetch.ts 用户输入预取管道
packages/builtin-tools/src/tools/ExecuteTool/ExecuteTool.ts 工具执行入口
packages/builtin-tools/src/tools/ExecuteTool/prompt.ts ExecuteTool prompt 定义
packages/builtin-tools/src/tools/ExecuteTool/constants.ts 常量定义
src/components/ToolSearchHint.tsx 用户推荐 UI 组件

修改文件清单

文件 修改内容
packages/builtin-tools/src/tools/ToolSearchTool/ToolSearchTool.ts 新增 TF-IDF 搜索路径、discover 模式
packages/builtin-tools/src/tools/ToolSearchTool/prompt.ts 更新 prompt 文档、修改 isDeferredTool 判定逻辑
src/constants/tools.ts 新增 CORE_TOOLS 常量集合
src/tools.ts 注册 ExecuteTool、调整 getAllBaseTools() 工具注册
src/utils/toolSearch.ts 适配新的延迟判定逻辑
src/constants/prompts.ts 添加 ToolSearch 引导指令到系统提示词
src/services/api/claude.ts 集成预取管道、调整延迟工具注入方式
src/screens/REPL.tsx 集成 ToolSearchHint 组件

验收标准

  • 初始化时仅加载 ~10 个核心工具 schema其余工具延迟加载
  • 延迟工具名称列表正确注入到 API 请求中
  • ToolSearchTool 支持基于 TF-IDF 的工具发现搜索(discover: 模式)
  • ToolSearchTool 支持关键词 + TF-IDF 混合搜索
  • ExecuteTool 可通过 tool_name + params 执行任意已注册工具
  • ExecuteTool 在所有 API providerAnthropic/OpenAI/Gemini/Grok下均可工作
  • MCP 工具连接/断开时索引自动更新
  • 用户输入后预取管道异步工作,不阻塞主流程
  • REPL 中展示工具推荐提示条(可配置开关)
  • bun run precheck 零错误通过
  • 新增单元测试覆盖初始化精简验证、工具索引构建、TF-IDF 搜索、结果合并、ExecuteTool 执行