Hi,大家好,欢迎来到维元码簿。
本文属于 《Claude Code 源码 Deep Dive》 系列,专注于上下文工程中的 Tools 板块——模型怎么知道"我能用什么工具"。如果你想了解整个系列,可以先看系列开篇 | Claude Code 源码架构概览:51万行代码的模块地图。
本文聚焦一件事:30+ 工具的 Schema 在上下文中如何呈现给模型——组装链路、排序逻辑、延迟加载、以及这些设计如何影响缓存。
读完全文,你将能回答这几个问题:
- 30+ 工具的 Schema 是怎么排的?为什么排序影响缓存?
- MCP 工具为什么默认只"报名"不展开?延迟加载的缓存考量是什么?
- 工具的排序决策为什么会反过来影响 System Prompt 的缓存策略?
前情提要:模型收到了什么
在上下文编排系列的前几篇中,我们拆解了发给模型的两大数据块:System Prompt(模型是谁、怎么做事)和 Messages(对话历史、隐藏注入)。但模型收到的不只是指令和对话——它还需要知道"我能做什么"。
paramsFromContext() 返回的完整参数中,真正变成 token 喂给模型的有三个字段:
| 字段 | 作用 | 预估占比 |
|---|---|---|
system | 告诉模型"你是谁、怎么做事"的指令集 | ~30% |
messages | 对话历史:用户输入、模型回复、工具调用结果 | ~60% |
tools | 工具 Schema:告诉模型可以调用哪些工具 | ~10% |
本文拆解第三个板块 Tools——工具信息在上下文中如何呈现。 System Prompt 和 Messages 分别在姊妹篇中展开。
Tools——上下文中的工具信息如何呈现给模型
一个只会"说话"的模型什么都做不了:它不能读文件、不能执行命令、不能搜索代码。Tools 就是模型的能力声明——告诉模型"你能做什么"。
模型实际拿到的单个工具大概长这样:
{
"name": "Read",
"description": "Reads a file from the local filesystem...",
"input_schema": {
"type": "object",
"properties": {
"file_path": { "type": "string", "description": "The path to read" }
},
"required": ["file_path"]
}
}
Claude Code 有 30+ 个这样的内置工具,加上用户通过 MCP 协议接入的外部工具。Tools 占上下文约 10%,但背后的编排逻辑涉及三个层面:工具从哪来、怎么精简、如何保持稳定。
工具不仅在告知能力,更在塑造行为边界。 一个微妙的点:模型知道自己有 Read 工具却没有 Send Email 工具时,行为模式自然不同。System Prompt 告诉模型"不要编造 URL",Tools 告诉模型"你只能读文件不能发邮件"——两者共同定义了模型的能力边界。人格(System Prompt)和能力(Tools)是分开传递的,但共同塑造了用户感知到的"Claude Code 的人设"。
工具来源与组装链路
Claude Code 的工具池由两部分组成:内置工具(30+ 个,如 Read、Edit、Write、Bash、Glob、Grep)和 MCP 外部工具(用户配置的 MCP Server 提供的工具)。
内置工具按职责分为几大类:文件操作(Read/Edit/Write)、搜索(Glob/Grep)、执行(Bash)、信息获取(WebFetch/WebSearch)等。
组装过程分三步:
getTools()获取内置工具,根据运行模式(标准/REPL)和权限规则过滤assembleToolPool()合并内置工具 + MCP 工具,按名称去重(内置优先),按字母排序toolToAPISchema()将每个 Tool 对象转为 API 格式的 JSON Schema
排序不是随意的——内置工具排前面、MCP 工具排后面,这个顺序保证了 prompt cache 的稳定性。如果 MCP 工具穿插在内置工具之间,每次 MCP 连接变化都会导致缓存失效。
这个排序决策还影响了 System Prompt 的缓存策略:有 MCP 工具时,System Prompt 全部降级为 org 级缓存(因为在姊妹篇[身份设定与环境感知](./02-Claude Code深度拆解-上下文里有什么-System Prompt工程.md)中讲过,MCP 工具的 Schema 会影响 System Prompt 的内容)。这就是跨板块的缓存联动——一个看似简单的排序决策,同时影响了 Tools 和 System Prompt 两个板块的缓存效率。
延迟加载:ToolSearch
工具数量多时(特别是有大量 MCP 工具时),全量传 Schema 会占用大量 token。Claude Code 引入了延迟加载机制:
- 非延迟工具(内置工具):每次调用都发送完整 Schema
- 延迟工具(MCP 工具默认延迟):只发工具名和一行摘要,不展开完整 Schema
- ToolSearchTool:一个特殊的内置工具,模型可以用它按需"搜索并加载"延迟工具
具体流程:假设用户配置了 Slack MCP,模型第一次调用时看不到 slack_send_message 的完整 Schema,只看到一个名字。当用户说"给我发一条 Slack 消息"时,模型意识到需要 Slack 工具,于是调用 ToolSearch(query: slack),系统返回 slack_send_message 的完整 Schema。从下一轮开始,这个工具就自动包含在完整工具列表中了。
这个设计有一个精妙的缓存考量:延迟工具标记了 defer_loading,API 服务端在计算 prompt cache 时会忽略这些工具的 token——这意味着工具的增减不会影响 System Prompt 的缓存命中。
延迟加载的用户体验是这样的:当你配置了一个新的 MCP Server(比如 Slack),Claude Code 不会在启动时就加载所有工具的完整 Schema。第一次对话时,模型只知道有一个叫"slack"的工具类别。直到你真的提到 Slack 相关的操作,模型才调用 ToolSearch 加载详细 Schema。这个过程是透明的——你不会感觉到任何延迟,因为加载发生在 Agent 循环内部,和正常的工具调用流程一样。
Schema 缓存
toolToAPISchema() 内部使用会话级缓存(toolSchemaCache,仅 27 行)。工具的 description 生成涉及 feature flag 检查,这些 flag 可能会话中途变化。如果每次重新序列化,Schema 的微妙变化会导致缓存失效。通过缓存,整个会话内工具 Schema 保持稳定。
Tools 小结
工具信息在上下文中的呈现,涉及四个关键设计:
- 来源合并:内置 + MCP,按名称去重,按字母排序保证缓存稳定
- 延迟加载:MCP 工具默认只报名不展开,通过 ToolSearch 按需加载
- Schema 缓存:会话级锁定,防止 feature flag 变化破坏缓存
- 跨板块联动:工具排序反过来影响 System Prompt 的缓存层级
工具占上下文只有 ~10%,但背后的编排逻辑远比表面复杂。模型知道自己有 Read 却没有 Send Email 时,行为模式自然不同——工具列表本身就是一种"能力边界"的塑造。
系列导航:
本文属于 《Claude Code 源码 Deep Dive》 系列中「上下文组成与缓存」命题的子篇章,专注于上下文工程中的 Tools 板块。
本文是完整版《Claude Code 源码深度解析:拆解上下文的组成与缓存》的子命题之一。如果你想了解上下文编排的全景(System Prompt + Messages + Tools + 缓存工程),推荐阅读完整版。
姊妹篇(可独立阅读):
- Claude Code 深度拆解:上下文里有什么——System Prompt 工程
- Claude Code 深度拆解:上下文里有什么——消息上下文管理
- Claude Code 深度拆解:上下文里有什么——Prompt Cache 机制
如果这篇文章对你有帮助,欢迎点赞收藏支持一下。如果你对 Claude Code 源码感兴趣,欢迎关注本系列后续更新。有任何想法或疑问,欢迎评论区留言讨论 👋