Skip to content

6.11 延迟加载 — ToolSearchTool、prompt.ts 与 Token 节省

前置阅读6.1 全景 · 6.6 搜索工具


学习目标

完成本节学习后,你应该能够:

  1. 解释 为何一次性向模型暴露 42 个工具的完整说明会浪费 Token。
  2. 描述 ToolSearchTool 按需注入的工作流:查询 → 命中工具 → 挂载 schema 与描述片段。
  3. 说明 每个工具目录下的 prompt.ts(或等价文件)写给谁看、包含哪些内容。
  4. 对比 「全量工具列表」与「分层工具列表」在首包延迟误选率上的权衡。
  5. 列举 实现延迟加载时的坑:schema 版本、缓存失效、命中排序。

生活类比:餐厅菜单与厨房小抄

全量工具一本 200 页菜单:顾客(模型)从头读到尾才点菜,点餐时间(首 Token)很长。延迟加载先给分类目录,顾客说「我想吃鱼」,服务员只递上海鲜页再加今日特供小抄prompt.ts)。ToolSearch 就是**「请问有哪几种做法」**的问询台。


Token 经济学(表)

策略system+tools 体积误选风险实现复杂度
全量暴露
静态分组
ToolSearch + 动态挂载中-高

ToolSearchTool 流程

行为
1模型调用 ToolSearchquery 为任务关键词
2宿主在工具元数据索引中检索(BM25/向量/标签)
3返回 Top-K 工具名 + 一行摘要
4模型选定后,宿主注入完整 inputSchema 与详细描述
5下一轮可 call 该工具

prompt.ts:写给 AI 看的说明

区块内容示例
何时使用「多文件重命名用我,不用 Bash sed」
输入诀窍「path 必须相对仓库根」
反模式「不要对大二进制用 FileRead」
与其他工具协作「先 Grep 再 FileEdit」

生活类比prompt.ts岗位培训卡片,不是给人看的 README 全文。


源码片段:工具元数据索引(概念)

typescript
interface ToolPromptModule {
  whenToUse: string;
  tips?: string[];
  antiPatterns?: string[];
}

interface ToolCatalogEntry {
  name: string;
  summary: string;
  tags: string[];
  loadPrompt: () => Promise<ToolPromptModule>;
  loadSchema: () => Promise<{ input: ZodSchema<unknown> }>;
}

const catalog: ToolCatalogEntry[] = [
  {
    name: "FileEdit",
    summary: "对文本文件应用结构化编辑,需先读",
    tags: ["write", "patch", "file"],
    loadPrompt: () => import("./tools/FileEdit/prompt.js").then((m) => m.default),
    loadSchema: () => import("./tools/FileEdit/schema.js").then((m) => m.FileEditInput),
  },
];

async function toolSearch(query: string, k: number) {
  const ranked = rankByQuery(catalog, query); // 简化:关键词打分
  return ranked.slice(0, k).map((e) => ({ name: e.name, summary: e.summary }));
}

async function activateTool(name: string, session: Session) {
  const entry = catalog.find((e) => e.name === name);
  if (!entry) throw new Error("unknown tool");
  const [prompt, schema] = await Promise.all([entry.loadPrompt(), entry.loadSchema()]);
  session.attachTool({ name, prompt, inputSchema: schema.input });
}

Mermaid:延迟加载时序


与 Tool 接口的衔接

延迟加载不改变 Tool 接口,只改变何时description + inputSchema 放进可见上下文

阶段模型可见
初启核心工具(Read/Bash/Search)+ ToolSearch
激活后额外工具的完整契约

缓存与失效

策略说明
按版本哈希schema 变更 bump
会话级缓存避免重复 import
冷启动预热对高频工具同步加载

风险:检索失误

问题缓解
搜不到返回「相近」+ 建议关键词
搜错工具多轮澄清;保留安全默认值
注入恶意条目目录签名、可信源

遥测

指标用途
toolsearch_query优化索引与别名
activate_latency_msimport 性能
mismatch_rate选错工具比例

常见反模式

反模式后果
动态加载无版本新旧 schema 混用
prompt.ts 过长激活后仍爆 Token
无 ToolSearch 回退新用户不会用库

小结

  • 延迟加载把「工具说明书」从首包挪到真正需要时
  • ToolSearchTool 是元工具,**prompt.ts** 是面向模型的操作手册
  • 权衡:Token↓ 可能带来 误选↑,需检索与默认核心工具兜底。

自测题

  1. 哪些工具应始终常驻而不走延迟加载?
  2. prompt.tsdescription 字段如何避免重复冗长?
  3. ESM 动态 import() 在 Serverless 冷启动下有何影响?

上一节6.10 Fail-closed · 下一节6.12 实践


常驻工具集建议(表)

常驻理由
FileRead几乎所有开发任务需读
Glob 或 Grep导航仓库
ToolSearch延迟加载入口
Bash(受限)或替代用户期望跑测试
可延迟理由
NotebookEdit仅笔记本任务
WebFetch仅联网任务
低频 MCP 工具减攻击面与体积

与「工具裁剪」关系

裁剪:从全集删永不用的工具。延迟加载:全集仍在,但描述与 schema 按需出现。二者可组合:先裁剪高危/无用,再对长尾延迟。


FAQ

问:延迟加载会增加一轮对话吗?
答:通常 (先 ToolSearch 再调用);换得 首包更小更聚焦上下文

问:如何避免循环依赖(搜不到就永远不用)?
答:核心工具常驻 + 文档化典型工作流(如「改配置先 Grep」)。

问:prompt.ts 能否用多语言?
答:可以,但应与用户界面语言策略一致,避免模型混读。


小结补充

  • ToolSearch + prompt.ts + 动态 import 是三位一体的 Token 策略。
  • 常驻最小集决定「是否多一轮」与「误选率」的平衡。
  • 监控 toolsearch_query → 激活工具 漏斗,持续优化索引与别名。

本项目仅用于教育学习目的。Claude Code 源码版权归 Anthropic, PBC 所有。