Skills、Hooks 与自动化例程分层设计(详解各层抽象粒度与触发边界)

要理解 Claude Code 的可定制机制,最直观的方法是把它们分成两条独立坐标:一条是「能做什么」,由技能(Skills)、子代理(Subagents)、MCP 服务器(Plugins)负责;另一条是「何时做、按何频率做」,由钩子(Hooks)、/loop 循环与云端例程(Routines)负责。把这两条线放在同一张分层图里,就能看清每个机制的抽象粒度、触发条件与适用场景,避免「该用钩子时写了技能、该写技能时又写成了例程」的常见错配。

一、分层模型:能力层与自动化层是两条独立坐标

很多教程把 Skills、Hooks、Slash Commands、Subagents、MCP 放在同一张表里比,这种「按文件类型分桶」的视角容易让人陷入「我要做个 X,该用哪个」的二分题。更贴近工程实践的视角是把它们放到两条独立坐标上:能力轴(扩展 Claude 能做什么)与自动化轴(决定何时、间隔多久去做什么)。能力轴上的 Skills 负责「按某套步骤办事」,Hooks 负责「对事件反应」,两者落在不同坐标上,互不替代。

Hooks 触发的是「事件」,而事件是确定的、协议层可见的。Claude Code 当前支持 8 类事件,PreToolUse(工具调用前)、PostToolUse(工具调用后)、Stop(任务完成)、SessionStart、SessionEnd、UserPromptSubmit、PreCompact、Notification 等都在内。每一个事件都是一个可挂钩点,可以挂 shell 命令、HTTP 端点或快速 LLM 提示。这种「事件→响应」的模型是经典的事件驱动架构,钩子的输出可以阻止工具调用、拒绝权限、向上下文注入额外内容,也可以直接强制 Claude 继续。

Skills 触发的是「语义匹配」,由 Claude 自身根据 description 判断是否调用。SKILL.md 的 YAML frontmatter 里 description 字段是核心,它告诉模型这个技能在什么上下文中被自动加载;也可以通过 /skill-name 手动触发。这种「模型决策」的模型弹性高,但代价是不可控的,模型可能不调用、错调用,或在不同会话中行为不一致。

二、抽象粒度对比

下面这张表把能力层与自动化层的常见机制按抽象粒度排开,方便一眼看清每层的「最小操作单元」与「适用范围」:

机制 抽象粒度 触发方式 最小操作单元 适用场景
Skills(技能) 步骤集合 模型按 description 匹配或 /技能名 一个完整流程的指令集 部署清单、代码评审、调试流程
Hooks(钩子) 单事件 事件触发(PreToolUse、PostToolUse 等) 一条 shell 命令或 HTTP 调用 自动 lint、命令拦截、Slack 通知
/loop 循环 间隔周期 在当前会话按间隔重复 同一提示或斜杠命令的反复执行 轮询 CI、监控构建、跑定时任务
Routines(例程) 计划/触发器 云端按 cron、Webhook、GitHub 事件触发 无需打开会话的保存提示 无人值守的日报、定时巡检、自动 PR 检查

从粒度上看,Skills 最粗(一次给出一整套流程指令),Hooks 最细(对单条事件反应),/loop 是中等粒度但绑定到当前会话,Routines 则是脱离会话的「云端任务」,粒度与 Skills 相当但运行环境不同。

三、触发边界:什么事件能钩、什么能被自动加载

Hooks 的触发边界是协议事件集。Claude Code 当前支持 8 类事件,分别覆盖「工具调用前后」「会话起止」「用户提交提示」「上下文压缩前」「需要人工介入的通知」。这些事件是确定的、协议层可观测的,因此钩子的行为可预测、可测试。钩子的输出甚至能反向控制会话:PreToolUse 钩子返回非零退出码就能阻止工具调用,SessionStart 钩子能向上下文注入额外信息。

Skills 的触发边界是「模型认为相关」。技能目录被索引后,模型在每次需要决定下一步时都会把 description 与当前任务做匹配,匹配成功才把完整 SKILL.md 加载进上下文。这是「渐进式披露」设计:启动时只加载 description(约 100 个 token),真正调用时才加载完整正文,从而控制上下文开销。代价是行为不可预测:模型可能因为 description 写得不够「主动」而漏调,也可能因为描述太宽而误调。

/loop 与 Routines 的触发边界是「时间/事件」,但区别在运行位置。/loop 把提示或斜杠命令以固定间隔在当前会话里重复运行,会话关闭它就消失,适合「盯着 PR 状态」「等测试跑通」等需要人在旁边的轮询。Routines 把提示保存到云端,由 cron、Webhook 或 GitHub 事件触发,无需打开本地会话,适合「每天生成报告」「外部事件触发时自动检查」这种无人值守场景。

四、典型工作流的层级组合

一个成熟的工作流往往不是单一机制,而是「钩子在前、技能居中、例程在后」的分层组合。举例来说,完整的部署流程可以是:SessionStart 钩子加载项目环境;PostToolUse 钩子在文件写入后跑 lint;用户输入 /deploy 触发一个技能,技能按步骤执行部署;如果部署需要等待外部服务,/loop 在会话里每 5 分钟检查一次状态;如果是周期性日报,例程在云端按 cron 触发,跑完把结果发到 Slack。

这套组合把每层机制的「抽象粒度」匹配到合适的任务上:Hooks 解决「每次写文件都该做什么」,Skills 解决「完整部署该怎么走」,/loop 解决「等待期间的轮询」,Routines 解决「每天早上自动跑」。如果只用其中一层,要么把太多逻辑塞进钩子(脚本臃肿、不可维护),要么把所有动作交给技能(每个动作都要用户手动触发),要么只用循环与会话(离开电脑就停摆)。

下面给出一个很小的钩子配置示例,展示事件触发的边界与最小操作单元:

{
  "hooks": {
    "PostToolUse": [
      { "matcher": "Write|Edit",
        "hooks": [
          { "type": "command",
            "command": "npx eslint --fix $CLAUDE_FILE_PATH 2>&1 | tail -5" }
        ]
      }
    ]
  }
}

这段配置把钩子绑定在「写或编辑文件之后」,最小操作单元是一条 eslint --fix 命令,目标是「每次文件落盘后自动修复可修的 lint 问题」。这正是「事件→单命令」粒度的典型用法。

五、选型决策框架

选型时把三个问题依次问自己:第一,「这件事该在哪个事件上发生?」如果能定位到 PreToolUse、PostToolUse 等具体事件,优先用 Hooks;定位不到,说明它可能不是事件驱动的,转入下一问。第二,「这是不是一套需要模型判断的步骤?」如果回答是,Skills 更合适;模型擅长按上下文决定是否调用,但不擅长保证每次都发生。第三,「这件事是否需要在我不在场时运行?」如果需要,优先用 Routines;如果需要「看着跑」,/loop 即可。

把这三问套到任何候选机制上,通常都能在 5 分钟内决定:纯确定性的事件反应走 Hooks;需要模型按描述匹配的复杂流程走 Skills;会话内的间隔轮询走 /loop;脱离会话的计划/触发走 Routines。常见错配(把流程塞进钩子、把钩子语义化进技能、把 Routines 当成 /loop 的替代)都能被这三问挡住。

下面这套自检顺序可以照搬到团队内部的「机制选型评审清单」,逐步对位:

  1. 列出候选机制所有可能的事件触发点(PreToolUse、PostToolUse、Stop、SessionStart、SessionEnd、UserPromptSubmit、PreCompact、Notification);
  2. 判断每个触发点是否协议层可见且确定可见;是→Hooks,否→进入下一问;
  3. 判断是否需要模型根据上下文决定是否调用;是→Skills,否→继续;
  4. 判断任务是否需要会话在场;是→/loop,否→Routines;
  5. 把最终选择写进设计文档的「机制选型」小节,后续代码评审时按此对照。

常见问题(FAQ)

Q1:Hooks 与 Skills 的本质区别是什么?

Hooks 是事件驱动、确定且不消耗上下文 token;Skills 是模型按描述匹配、弹性高但不可预测。

Q2:/loop 和 Routines 都按时间触发,怎么选?

/loop 绑定到当前会话、随会话退出;Routines 在云端、会话关闭也照常运行。

Q3:能否在 Skill 内部再挂 Hooks?

可以,SKILL.md 的 frontmatter 里有 hooks 字段,能把钩子作用域限制在技能生命周期内。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 qiqicto@qq.com 举报,一经查实,本站将立刻删除。
赞 (0)
套餐观察官的头像套餐观察官普通用户

相关推荐

返回顶部