Claw Code 源码解析(三):Tool、Skill、Slash Command 与扩展系统
- Published on
- • 17 mins read
这是这组 Claw Code 源码解析的第三篇。
如果只看表面,这个仓库里有三套很容易让人混淆的机制:
- slash command
- tool
- skill
很多项目会把这三件事揉成一团,最后结果通常是:
- 用户命令和模型能力混在一起
- 权限边界不清
- 系统越来越难扩展
Claw Code 最值得学的地方之一,就是它没有偷懒,而是把这三者拆成了不同层级。更有意思的是,这三层并没有停在“命令和工具的整洁分工”上,而是继续长出了 Plugin、MCP、Worker、Task、Cron、Telemetry 这些更平台化的能力。
所以这篇我会一起回答两个问题:
- 为什么 Tool、Skill、Slash Command 要分三层?
- 为什么这三层之上会自然长出一套扩展系统?
先给结论:这三者不是同类东西
我会这样理解它们:
- Slash Command:面向人类输入的控制面
- Tool:面向模型调用的 schema 化能力
- Skill:面向本地复用的提示词包
只要把这三句话记住,后面的很多实现都会突然变得合理。
Slash Command:给人类的控制面
slash command 最像传统 CLI 思维在对话环境里的延伸。它解决的是:
- 人类想直接控制某个行为
- 不想把这个行为交给模型自由判断
- 需要明确、短路径、可记忆的操作方式
这类能力通常包括:
- 查看或切换状态
- 触发特定管理动作
- 查询技能、配置、上下文信息
- 显式执行某个操作,而不是让模型自己决定
slash command 的关键词是:
- 明确
- 可预测
- 面向人类
它不是为了让模型调用,所以不需要把自己包装成一套模型可消费的 schema。
Tool:给模型的能力面
tool 就完全不同了。
模型调用工具,核心不是“像人类那样记住命令”,而是:
- 看到结构化工具定义
- 理解工具名称和用途
- 生成符合 schema 的输入
- 在多轮 loop 中使用结果继续推理
所以 tool 的设计重点会落在:
- 名称
- 描述
- 输入 schema
- 输出处理
- 执行桥接
这也是为什么 tool 会被做成正式注册的能力面,而不是简单的“把内部函数暴露给模型”。
Skill:给本地复用的提示词包
skill 又是第三种东西。
它不是命令,也不是工具。它更像一包可复用的本地能力说明,通常包含:
- 一组专门化指令
- 推荐工作流
- 可能关联某些工具或外部技能
- 某个任务域的最佳实践
skill 的关键词是:
- 可复用
- 本地化
- 偏提示词与工作流知识
这让它非常适合表达那些“不是代码能力,但又需要被系统稳定引用”的东西。
例如:
- 某类测试流程
- 某种写作规范
- 特定工程任务的操作指南
为什么把三者混在一起会出问题
如果一个系统不做这层拆分,最常见的后果是:
- 用户命令开始长得像工具
- 工具开始承担提示词职责
- 提示词包又偷偷在模拟命令
最后你会得到一个很难解释的系统:
- 用户不知道应该输入命令、描述任务,还是触发技能
- 模型不知道哪些东西它能调、哪些只是人类入口
- 权限和可观测性也会变模糊
Claw Code 的做法,本质上是在避免这类塌陷。
GlobalToolRegistry:统一工具注册中心
工具机制里最关键的一层,是统一注册中心。
这意味着工具不是零散挂在各个模块里,而是会被收束到同一个 registry 里。这样带来的收益很实际:
- 模型看到的是统一工具面
- 内置工具、插件工具、运行时工具能走同一条注入路径
- 权限、白名单、可观测性都能在同一层生效
如果没有 registry,工具系统很快就会变成“哪里需要哪里接一个函数”。短期快,长期一定乱。
--allowedTools:工具面裁剪比“有没有工具”更重要
工具系统真正成熟的标志,不是工具数量多,而是你能不能控制 这一轮究竟给模型什么工具面。
--allowedTools 这类能力的意义就在这里。它说明工具不是“固定全开”,而是:
- 可按场景裁剪
- 可按权限限制
- 可按任务最小化暴露
这对 agent 系统非常关键,因为真正的问题通常不是“模型不会用工具”,而是“给它太多工具后行为变得不可控”。
所以工具白名单和别名规范化,不是小细节,而是 agent 安全边界的一部分。
Skill 的查找路径,说明它是本地知识包而不是远程能力
从实现意图看,Skill 明显被视为一种 本地可发现、可复用的提示词资产。
这类机制通常会去几个地方找:
- 项目本地技能目录
- 用户级技能目录
- 系统级技能目录
这个查找策略很有意思,因为它本质上是在做一套“本地知识覆盖链”:
- 项目可以有自己的技能
- 用户可以有全局技能
- 系统可以带默认技能
这和 tool 完全不一样。tool 解决的是执行能力,skill 解决的是任务知识与操作范式。
/skills 命令和 Skill 工具为什么要同时存在
这又是一个很容易被误解的点。
表面看,它们都和 skill 有关,但服务对象不同:
/skills
这是给人看的。用户想知道:
- 当前有哪些 skill
- 某个 skill 叫什么
- 它大概做什么
Skill 工具
这是给模型用的。模型需要:
- 在合适的时候发现某个 skill
- 读取 skill 内容
- 把 skill 作为当前任务的辅助知识
所以同样是“技能”,对人和对模型暴露的接口完全可以不一样。这一点处理得越清楚,系统越稳。
classify_skills_slash_command() 这种设计为什么聪明
从命名就能看出来,这类逻辑不是简单地“有个 /skills 命令”,而是在判断:
- 当前输入是不是技能相关的人类指令
- 应该走 slash command 还是走普通对话路径
这说明 slash command 并不是随便插在 REPL 上的糖,而是被认真纳入输入分类体系里。
这类设计的收益在于:
- 控制面更稳定
- 人类入口不依赖模型猜测
- 系统可以对某些高确定性命令做短路径处理
ToolSearch:模型也需要“找工具的工具”
这是整个设计里一个很有意思的信号。
当系统工具面足够大时,问题已经不再是“有没有工具”,而是:
- 模型知不知道该用哪个
- 它能不能在当前任务里快速发现相关工具
ToolSearch 这种机制本质上是在承认一件事:工具面过大之后,发现成本本身也成了问题。
这说明 Claw Code 并不是把工具系统当成静态列表,而是在考虑更复杂的 agent 使用场景。
为什么三层机制往上,会自然长出 Plugin 和 MCP
当一个系统已经把:
- 人类控制面
- 模型能力面
- 本地知识资产
这三层切开之后,下一步自然会遇到一个问题:外部能力要接到哪里去?
这时就会很自然地长出两种机制:
- Plugin:显式建模的本地或半本地扩展包
- MCP:把外部服务能力接进统一工具面
这两者本质上都不是“另起炉灶”,而是在往同一个 tool plane 上继续加能力。
Plugin:它不是脚本目录,而是正式 manifest
Claw Code 里的插件系统最值得注意的,不是“支持插件”这件事本身,而是它支持的方式非常正式。
manifest 里不仅会声明:
- 名称
- 版本
- 描述
还会声明:
- 权限
- default enabled 状态
- hooks
- lifecycle
- tools
- commands
这意味着插件可以同时扩展:
- 运行时行为
- 工具能力面
- 命令面
换句话说,插件并不是边缘脚本,而是第一层扩展子系统。
Hooks 与 Lifecycle:插件可以参与运行时事件
更进一步,插件不只是“给用户加个新命令”。
当系统允许插件接入:
- 初始化
- 关闭
- tool 使用前
- tool 使用后
- tool 失败后
这些事件时,插件就已经开始参与运行时生命周期了。
这带来的价值非常实际:
- 审计
- 监控
- 前置检查
- 外部通知
- 资源清理
一旦一个 CLI 开始认真对待这些事件,它就已经在往平台走,而不再只是本地终端工具。
MCP:把外部服务能力收束回统一工具面
MCP 在这套结构里非常合理,因为它正好补上了“外部服务能力如何并入系统”的问题。
它的重要性不只是“多支持一种协议”,而是让外部服务继续表现为:
- 模型可理解的工具
- 系统可管理的能力对象
这样一来,本地工具、插件工具、外部服务工具就能在同一个平面里被发现、注册、裁剪和执行。
这比为每种外部集成都单独开旁路成熟很多。
Worker、Task、Team、Cron:系统开始考虑无人值守执行
继续顺着这条逻辑往前走,就会自然长出更重的 orchestration 能力。
Task
task 的意义是:系统开始显式建模“任务”本身,而不只是当前对话回合。
Worker
worker 表明系统开始关心某些工作能不能在不同执行环境、甚至脱离当前交互界面完成。
Team
team 的出现说明系统已经在往多 agent 协调视角靠近,而不是只处理单一 agent turn。
Cron
cron 则意味着系统已经开始考虑周期任务和调度,而不只是一次性对话。
这些能力放在一起时,你会发现方向已经非常明确:它正在从一个会话工具,长成一个 agent orchestration substrate。
为什么这些能力不是外挂“高级功能包”
一个常见误区是觉得 Worker、Task、Cron 这种能力应该放在系统最外层,当成高级包。
但如果你真的往下想,会发现它们最终都要依赖同一套基础设施:
- session
- tools
- permissions
- config
- provider 通信
既然如此,把它们纳入 runtime / tools 的正式边界,反而是更干净的做法。
Claw Code 的选择说明,它把这些能力视为 agent 系统的自然延长线,而不是额外的 fancy feature。
api crate、Streaming、Prompt Cache、Telemetry 为什么也必须一起看
只看工具和扩展,还不足以解释整套系统为什么像平台。真正把它补完整的,是协议层和可观测性层。
api crate 的存在说明,provider 接入在这里不是“发个 HTTP 请求”这么简单。它至少要处理:
- provider abstraction
- structured messages
- streaming
- auth / OAuth
- prompt cache
- usage event
其中最关键的是 streaming。
在 agent runtime 里,streaming 的价值远不只是让文字一点点出现。它还意味着系统可以逐步接收:
- text delta
- tool use 片段
- usage 更新
- 其他结构化事件
这对工具调用 loop 非常关键,因为工具输入往往不是一次性生成完的。
Prompt Cache 则补上了长会话成本和上下文复用的问题;Telemetry 则把运行状态从字符串日志升级成结构化事件,方便监控、回放和诊断。
所以平台化不是只靠 Plugin 和 MCP 撑起来的,而是 工具面 + 扩展面 + 协议层 + 可观测性层 一起长出来的。
为什么这种三层拆分加扩展系统值得借鉴
如果只站在“功能能跑就行”的角度,这种拆分看起来很重。但一旦系统开始变复杂,你会发现它其实是在帮你保住三个边界:
- 人类控制面 不被模型能力污染
- 模型能力面 不被提示词资产污染
- 提示词资产 不被命令系统污染
这三个边界一旦还在,后续无论加:
- 新工具
- 新技能
- 新插件
- 新命令
- 新外部服务接入
- 新任务编排能力
系统都还能继续长。
小结
- Slash Command 是人类控制面,Tool 是模型能力面,Skill 是本地知识资产
GlobalToolRegistry、--allowedTools、ToolSearch说明工具面已经被正式建模- Plugin 和 MCP 把扩展能力继续收束进统一能力面
- Worker、Task、Team、Cron 说明系统开始考虑无人值守和编排
- Streaming、Prompt Cache、Telemetry 让这套系统更像平台而不是命令行糖衣
下一篇单独看这套系统里最有启发性的一部分:上下文预算、prompt cache 和历史压缩。
Table of Contents
- 先给结论:这三者不是同类东西
- Slash Command:给人类的控制面
- Tool:给模型的能力面
- Skill:给本地复用的提示词包
- 为什么把三者混在一起会出问题
- GlobalToolRegistry:统一工具注册中心
- --allowedTools:工具面裁剪比“有没有工具”更重要
- Skill 的查找路径,说明它是本地知识包而不是远程能力
- /skills 命令和 Skill 工具为什么要同时存在
- /skills
- Skill 工具
- classify_skills_slash_command() 这种设计为什么聪明
- ToolSearch:模型也需要“找工具的工具”
- 为什么三层机制往上,会自然长出 Plugin 和 MCP
- Plugin:它不是脚本目录,而是正式 manifest
- Hooks 与 Lifecycle:插件可以参与运行时事件
- MCP:把外部服务能力收束回统一工具面
- Worker、Task、Team、Cron:系统开始考虑无人值守执行
- Task
- Worker
- Team
- Cron
- 为什么这些能力不是外挂“高级功能包”
- api crate、Streaming、Prompt Cache、Telemetry 为什么也必须一起看
- 为什么这种三层拆分加扩展系统值得借鉴
- 小结