22 工具系统与执行边界深挖
这一章把焦点放到 Claude Code 最核心、也最容易被表面化理解的一层:tool system。
如果前几章已经把 query loop、message/context assembly、hooks、memory、config/state/governance 这些外围骨架拆开了,那么这一章要回答的是更靠近 agent “手和脚”的问题:
- Claude Code 里的 tool 到底是什么抽象?
- tool 是怎样被注册、暴露给模型、执行、回填结果的?
- tool system 和 command、hooks、skills、MCP 分别是什么关系?
- 执行边界是画在 tool 定义、tool registry、permission pipeline,还是 query loop 里?
这一章不重讲前面已经讨论过的 permission 治理全景,也不展开具体 UI 交互,而是重点回答:
- tool 在 runtime 中是什么单位
- tool call 怎样从模型输出变成真实执行
- tool system 的边界在哪里
- Claude Code 为什么没有把“一切可执行能力”都混成同一种插件
flowchart TD
A[tool 定义层 schema] --> B[registry 聚合当前可用工具]
B --> C[model exposure 暴露面]
C --> D[execution orchestration 调度]
D --> E[governance permission / mode / trust]
E --> F[tool_result 回填 message state]
一、先给出总体判断
如果只基于当前源码做判断,我会把 Claude Code 的工具系统概括成:
一套由 tool schema 暴露、tool registry 组织、query loop 调度、permission system 裁决、以及 tool result 回填共同组成的受控执行子系统;它既是模型可调用能力的统一入口,又被刻意限制在清晰的执行边界内。
更具体地说,它至少可以拆成五层:
- tool 定义层:每个工具的名称、输入 schema、执行函数、元信息
- tool registry / aggregation 层:把可用工具收集成当前 query 可暴露的集合
- model exposure 层:把工具描述转成 API 可见的 tool schema
- execution orchestration 层:query loop 中对 tool use / tool result 的调度
- governance / boundary 层:permissions、mode、trust、headless 约束
这意味着 Claude Code 的 tool system 并不是:
- 一个随便塞函数的函数表
- 一个开放式“任意插件执行器”
- 或者把 shell、skills、hooks、MCP 全部揉成一个统一黑箱
而更像:
- 模型可调用执行面的标准化子系统
二、tool 在 Claude Code 中首先是什么,不是什么
1. tool 是“模型可见的受约束能力单元”
在 Claude Code 里,tool 最核心的特征不是“能执行代码”,而是:
- 有稳定名字
- 有输入结构
- 有暴露给模型的 schema
- 有运行时实现
- 有权限/模式约束
- 有结果回填格式
因此 tool 更接近:
- agent runtime 中可被模型调用的标准能力接口
而不是简单的内部 helper function。
这点很关键,因为很多系统会误把“任何内部函数”都视作潜在 tool;Claude Code 的做法明显更克制:只有进入 tool contract 的能力,才算真正的 tool。
2. tool 不等于 command
前面章节已经能看到 queued commands、slash commands、SDK/system messages、skills 等概念。它们和 tool 有交集,但不是一回事。
比较稳妥的区分是:
- tool:模型调用的执行接口
- command:用户或系统发起的命令式入口
- skill:高层工作流/提示资产
- hook:runtime 某阶段的挂接点
- MCP:外部能力提供机制
也就是说,tool system 是 Claude Code 的“执行接口层”,但不是整个扩展系统的总称。
三、tool system 的核心职责
1. 向模型声明“你可以调用什么”
tool system 的第一职责,不是执行,而是暴露能力面。
这包括:
- 当前有哪些工具可用
- 每个工具叫什么
- 参数长什么样
- 参数需要满足什么约束
- 哪些工具在当前 query 中被启用
也就是说,在真正运行之前,tool system 先解决的是:
- 模型能看到什么操作面
这是一个很重要的边界,因为 Claude Code 并不是让模型直接访问内部 runtime API,而是先通过 tool schema 做一层能力投影。
2. 把模型生成的 tool use 转成可控执行
第二职责才是执行。
这一步通常包括:
- 接收模型输出中的 tool use
- 解析 tool name 和 input
- 在 registry 中找到对应实现
- 经过 permission / mode 判断
- 执行工具
- 生成 tool result 消息
- 送回主消息流
因此 tool execution 不是“模型说了就跑”,而是一个 runtime adjudication 过程。
3. 把执行结果重新纳入消息状态机
第三职责是回填。
Claude Code 的 agent loop 不是“跑个工具然后在外面自己拼字符串”,而是把工具输出重新纳入:
- message state
- follow-up 判断
- 后续模型轮次上下文
这说明 tool system 不只是 side effect executor,它还是主状态机的一部分。
四、tool registry 的位置与意义
1. registry 是 execution surface 的组织层
在任何像 Claude Code 这样的 agent runtime 里,工具数量一旦变多,就必须有某种 registry / aggregation 层;否则 query loop 根本无法稳定地回答:
- 当前哪些工具可用?
- 哪些是内建工具?
- 哪些来自额外来源?
- 哪些当前 query 应该隐藏?
- 同名/冲突如何处理?
因此 registry 的意义不是“好看地列个表”,而是:
- 把离散工具实现收敛成当前 query 的执行面
它解决的是能力组织问题。
2. registry 是 model exposure 和 runtime implementation 之间的桥
tool 定义本身可能带有很多内部信息,但不是所有内部信息都应暴露给模型。
所以 registry / aggregation 往往起到桥接作用:
- 向内连接具体实现
- 向外输出 API-compatible tool schema
这层如果没有,系统就容易出现两个问题:
- 模型看到的工具描述和真实实现不一致
- runtime 无法根据 query 条件裁剪暴露面
Claude Code 的整体架构明显更偏向后者:让 tool system 在 query 入口处形成“当前可见工具集合”。
五、tool execution 为什么不能直接等同于 Bash
1. Bash 只是 tool 的一种,不是 tool system 本身
从整个仓库脉络看,Bash 工具虽然重要,但 Claude Code 从来没有把“有 Bash 就等于 agent 会执行”这件事当成系统全貌。
因为 tool system 里至少还包括:
- 文件读写工具
- 搜索工具
- 编辑工具
- 计划/任务管理工具
- 浏览/抓取类工具
- 调度类工具
- 可能的 MCP 暴露工具
这说明 Bash 很强,但它只是统一工具面中的一个成员。
2. 如果把执行全都退化成 Bash,边界会立刻变坏
为什么 Claude Code 要保留大量专门工具,而不是让模型用 Bash 做一切?架构上最核心的原因有三个:
- 可审计性:专门工具比 Bash 更容易理解和审查
- 权限颗粒度:不同工具可以挂接不同治理策略
- 结果结构化:专门工具的输入输出更可控
所以 Claude Code 的 tool system 并不是在追求“最强大的万能执行器”,而是在追求:
- 模型能力面尽量强,同时执行边界尽量窄
六、tool 与 permission system 的关系
1. tool system 提供能力,permission system 决定能否落地
前一章已经说明,权限系统不是 schema 注释,而是 runtime 执行裁决层。放到工具系统语境里,这意味着:
- tool system 负责“可以调用哪些能力”
- permission system 负责“当前这次能不能真的执行”
因此两者不是重复关系,而是上下游关系。
2. permission 不只是前置检查,也是 execution path 的塑形器
权限判断不仅会决定 allow / deny / ask,还会改变执行路径本身:
- 是否弹出确认
- 是否进入 classifier 分支
- 是否在 headless 下直接拒绝
- 是否允许 bypass
- 是否要求更高信任来源
所以更准确地说:
- permission system 不只是工具系统前面的一道门
- 它还是工具执行路径的分叉器
这意味着 Claude Code 的工具系统本质上是:
- 带治理分叉的执行系统
七、tool 与 query loop 的关系
1. tool execution 属于主状态机,而不是外部插件回调
这是理解 Claude Code tool system 的关键点之一。
在很多粗糙的 agent 设计里,tool call 只是“模型吐出一个 JSON,然后外部跑一下,再把结果拼回去”。Claude Code 更明显不是这种风格。
从前面章节已经能确定:
- query loop 负责 assistant → tool → tool_result → continue / stop 的主推进
- tool result 回到消息状态
- 后续是否继续由主循环决定
这说明 tool execution 不是外挂,而是主状态机的一部分。
2. tool result 不是普通日志,而是状态转移输入
工具执行后的结果之所以重要,不只是因为它告诉用户发生了什么,而是因为它会影响:
- 后续模型是否继续
- 后续模型看到什么上下文
- recovery / stop-hook / attachments 等后续机制
因此 tool result 在 Claude Code 中更接近:
- 消息状态机中的结构化反馈节点
而不是单纯日志输出。
八、tool system 和 hooks / skills / MCP 的边界
1. 和 hooks 的边界:tool 是执行面,hook 是阶段挂点
tool 是模型明确调用的能力接口;hook 是 runtime 在特定生命周期阶段自动触发的挂接点。
所以:
- tool 更偏显式执行
- hook 更偏阶段化旁路
二者都能“做事”,但语义完全不同。
2. 和 skills 的边界:tool 是低层能力,skill 是高层工作流资产
skills 更像:
- prompt 资产
- 工作流模板
- 指导 agent 怎样组织任务
tool 则更像:
- 真正落地动作的原子/半原子执行接口
因此 skill 不应直接等同于 tool;更准确地说,skill 往往会引导模型去使用 tool。
3. 和 MCP 的边界:MCP 更像能力来源,tool 是最终暴露形态之一
从架构上看,MCP 更适合理解成:
- 外部能力如何接入 Claude Code runtime
而 tool system 关心的是:
- 当前 query 最终给模型呈现什么能力面
所以 MCP 和 tool 并不互斥。更合理的关系是:
- MCP server 提供能力来源
- tool system 决定这些能力如何进入模型可调用面
九、Claude Code 的 tool system 为什么显得“克制”
1. 它没有把所有 side-channel 都升级成 tool
从前面几章已经看到,Claude Code 有很多 runtime 机制:
- relevant memory prefetch
- post-sampling hooks
- stop hooks
- skill improvement
- auto dream
- prompt suggestion
但这些并没有全都被包装成 tool。
这说明团队有一个很明确的边界意识:
- 不是所有能执行逻辑的东西都适合变成模型显式调用接口
这很重要,因为 tool 一旦暴露给模型,就意味着:
- 成为主执行面的一部分
- 进入权限与上下文预算问题
- 需要稳定 schema 和结果语义
2. 它更偏“把工具面做稳”,而不是“把一切都做成工具”
这是一种成熟取舍。
如果系统把任何内部机制都改成 tool,短期看很统一,长期往往会变成:
- 暴露面膨胀
- 模型决策负担变重
- 权限治理变复杂
- 调试成本升高
Claude Code 当前更像在坚持:
- tool 是重要但受限的能力面
- 不是系统中唯一的动作形态
十、源码链路下几个更稳的判断
1. tool 是模型可调用能力的标准 contract,而不是随意函数暴露
从整体结构看,Claude Code 明显把 tool 当作正式 contract 对待:有 schema、有执行面、有治理面、有回填路径。
2. tool registry 的真正作用是形成“当前 query 的可执行表面”
不是简单收集,而是把多来源能力裁剪、整理、转换成 query 当前能用的那一层 surface。
3. tool execution 与 query loop 强耦合,但与内部其他 side-channel 有明显边界
也就是说:
- tool execution 是主路径
- hook / prefetch / extraction 更像旁路或尾部机制
这让主状态机保持清晰。
4. tool system 的核心价值之一是把能力治理嵌进执行面
如果没有 tool-level contract,就很难把:
- schema 暴露
- permission gating
- result normalization
- auditability
稳定地装进同一套运行时结构里。
本章小结
如果把这一章压缩成一句话,可以说:
Claude Code 的 tool system 不是一个简单的函数调度器,而是一套由 tool contract、registry、模型暴露、主循环调度、权限裁决与结果回填共同组成的受控执行子系统;它既承担模型操作面的核心职责,又通过清晰边界避免把所有 runtime 机制都混成同一种“工具”。
从源码脉络能得出的倾向性结论包括:
- tool 是模型可调用能力的标准 contract,而不是任意内部函数;
- registry 的关键作用是形成当前 query 的可执行表面;
- tool execution 属于 query loop 主状态机的一部分,而不是外置回调;
- permission system 不是附属检查,而是工具执行路径的重要塑形器;
- Claude Code 刻意保留了 tool、hook、skill、MCP 等不同能力形态的边界,没有为追求表面统一而全部工具化。
源码证据索引
src/query.ts— tool use / tool_result 的主循环推进与回填- tool 相关模块 — tool contract、registry、执行实现
src/utils/permissions/permissions.ts— tool 执行前的 permission 决策与模式分叉src/hooks/useCanUseTool.tsx— permission pipeline 的 UI/interaction bridge