三种扩展机制的分界线只有一条:触发权在谁手上。技能和子智能体由模型决定要不要用, 钩子由系统在事件发生时触发。 所以钩子适合的是「必须做、漏一次就出事」的事。它能干的活很窄,但那一窄条没人能替代。
前三章讲了记忆、技能、子智能体,它们的共同点都是「模型决定用不用」。 这一章换一条根:有几个东西不该由模型决定,而该由系统保证。这一节先把这条根说清。
一、三种机制,一条分界线
技能:模型读描述,觉得这次用得上就读正文、照着做。它可能不读。 子智能体:模型觉得这活该隔离出去干,就派一个。它可能不派。 钩子:系统在某个事件发生时,按配置去跑一段东西。模型没有否决权,也没有选择权。
三者的差别不是「能力强弱」,是「谁握方向盘」。前两个的钥匙在模型手里,钩子的钥匙在配置手里。 这条分界线一画,后面所有的问题都变成一句话:这件事能不能接受「模型这次没想到」?
二、不能接受,就必须用钩子
「改完 py 文件自动格式化」——模型九成会想到,但漏掉的那一次不会报错,文件就是没格式化。 「任何 rm -rf 都要拦下来」——这不是「想到就做」,是「必须每次都判」。 交给模型判断等于把护栏交给了被保护的人。 演示里按九成的触发率算:改一百个文件,写成技能大约漏十次。写成钩子漏零次。
漏的那十次不会有任何提示。你下次 review 才看见,或者永远看不见。 所以钩子的第一判据不是「好不好写」,是「漏了会不会出事」。
三、反过来,什么事不该做成钩子
第一类:需要判断的。「按改动内容写提交信息」要理解改动是什么,规则写不出来。 钩子能跑命令、能调模型评一次,但它自己不会「理解」。 硬做只会做成一个「看起来在检查、其实什么都没检查」的东西。 第二类:不是每次都该做的。「审两百个文件」一个月跑一次,做成钩子等于每次改文件都触发。
第三类:很慢的。 钩子挂在工具调用后面,它慢一秒,每次工具调用都慢一秒——这一点在 5.9 节会用真跑的计时说清。 三类合起来是个很窄的窗口:必须做、能用规则判、不慢。三条缺一条就该换别的机制。
四、钩子和「权限」不是一回事
有人把钩子当成权限系统,觉得挂了钩子就等于设了边界。这个理解差一层。 权限管的是「这个工具能不能用」,粒度粗、由平台执行、改起来要动配置。 钩子管的是「这次调用要不要放行」,粒度细、由你写的脚本执行、可以判断参数内容。
所以两者的关系是:权限是第一道门,钩子是门里的检查员。门没拦住的人,检查员还能拦。 但反过来不成立:钩子不能替代权限。因为钩子自己也可能写错、也可能被绕过(3.6 节那个前缀漏洞)。
五、它在整条链上的位置
把前面几章串起来看:记忆决定「开场知道什么」,技能决定「会做什么」,子智能体决定「在哪儿做」。 钩子决定的是「什么时候不许做、做完必须补什么」。它不产出内容,它管事前的闸和事后的补。 这个位置有个特点:它是唯一一个「即使模型犯错也能兜住」的机制。
所以工程上成熟的做法是:让模型尽量自由地干,把兜底的东西全做成钩子。 而不是反过来——用一大堆提示词去约束模型。 一句话收这一节:提示词是请求,钩子是保证。该保证的事,别写成请求。
六、动手 Demo:八个需求,各该用哪种扩展机制
八个需求,三种机制(技能、子智能体、钩子)。逐个判该用哪个,判完再看一眼「写成技能会漏多少」。 判据只有一条:这件事漏做一次会不会出事。
if u"自动" in text or u"拦" in text or u"注入" in text or u"都要" in text:
got = u"钩子" # 必须每次都做
elif u"汇总" in text or u"并行" in text:
got = u"子智能体" # 要隔离上下文
else:
got = u"技能" # 模型按需取用
实跑输出:
--------------------------------------------------------------------
八个需求,各该用哪种扩展机制
--------------------------------------------------------------------
三种机制的触发权不一样:技能和子智能体是模型决定要不要用,钩子是系统按事件触发,模型没有否决权。
① 三种机制的触发权
--------------------------------------------------------------------
| 机制 | 谁决定 | 会不会漏 | 擅长 |
|---|---|---|---|
| 技能 | 模型读描述后自己决定 | 可能不触发 | 知识、做法 |
| 子智能体 | 模型决定派不派 | 可能不派 | 隔离上下文 |
| 钩子 | 系统在事件发生时触发 | 一定触发 | 必须做的动作 |
② 八个需求逐个判
--------------------------------------------------------------------
| 需求 | 该用 | 判成 | 结果 |
|---|---|---|---|
| 每次改完 py 文件自动格式化 | 钩子 | 钩子 | 对 |
| 提交前按项目规范写提交信息 | 技能 | 技能 | 对 |
| 审两百个文件并汇总问题 | 子智能体 | 子智能体 | 对 |
| 任何 rm -rf 都要拦下来 | 钩子 | 钩子 | 对 |
| 解释这段代码什么意思 | 技能 | 技能 | 对 |
| 每次会话开始注入当前分支 | 钩子 | 钩子 | 对 |
| 把这次改动按模块整理成变更说明 | 技能 | 技能 | 对 |
| 三个方向并行调研再合并 | 子智能体 | 子智能体 | 对 |
八个判对 8 个。判据只有一条:这件事漏做一次会不会出事?会,就必须做成钩子;
不会、只是效率问题,才交给模型自己决定。
③ 写成技能会漏多少
--------------------------------------------------------------------
假设模型在九成的情况下会想到「改完要格式化」——这个假设已经很乐观了。
改一百个文件,写成技能大约漏 10 次,写成钩子漏 0 次。
漏的那十次不会有任何提示:文件就是没格式化,你下次 review 才看见。
④ 反过来,什么事不该做成钩子
--------------------------------------------------------------------
第一类:需要判断的。
「按改动内容写提交信息」要理解改动,规则写不出来——钩子只能跑脚本,脚本不会理解。
第二类:不是每次都该做的。「审两百个文件」一个月跑一次,做成钩子等于每次改文件都触发。
第三类:很慢的。钩子挂在工具调用后面,它慢一秒,每一次工具调用都慢一秒。
! 所以钩子的适用面很窄但很硬:必须做、能用规则判、不慢。三条缺一条,就该换技能或者子智能体。
①三种机制的触发权:技能和子智能体是模型决定,钩子是系统按事件触发。 这一列「会不会漏」是整章的起点。 ②八个判对八个。判据只有一条:这件事漏做一次会不会出事。会,就必须做成钩子; 不会、只是效率问题,才交给模型自己决定。 ③写成技能会漏多少:按九成触发率算,改一百个文件大约漏十次,写成钩子漏零次。 这个假设已经很乐观了——真实场景里「模型这次没想到」的概率比一成高。而漏的那十次不会有任何提示。 ④最后一段划边界:需要判断的、不是每次都该做的、很慢的,三类都不该做成钩子。 三类合起来是个很窄的窗口:必须做、能用规则判、不慢。缺一条就该换机制。
30 秒实验
- 把「九成触发率」改成五成,重跑第 ③ 步。漏的次数变成多少?这说明钩子的价值跟什么成正比?
- 给八个需求再加一条「提交信息里不许出现 emoji」,它该用哪种机制?判根据哪一条?
- 把「审两百个文件」改成「每天凌晨审两百个文件」,它还是不该用钩子吗?如果不该,该用什么?
常见误区
- 把钩子当成「更高级的技能」。技能是模型按需取用,钩子是系统必然触发,两者的触发权在不同人手上。
- 用提示词去保证「必须做」。提示词是请求,钩子是保证;该保证的事写成请求,就一定会漏。
- 把需要判断的活做成钩子(「检查代码写得对不对」)。钩子能调模型,但它自己不会理解。
- 把钩子当权限系统用。权限是第一道门,钩子是门里的检查员,钩子替代不了权限。
- 给很慢的操作挂钩子。它挂在工具调用后面,慢一次就是每次都慢。
自测三问(点开对答案)
1. 三种扩展机制的分界线是什么? —— 触发权在谁手上。 技能和子智能体由模型决定要不要用,钩子由系统在事件发生时触发,模型没有否决权。 2. 为什么「必须做」是第一判据? —— 因为钩子的价值全在「不漏」。漏了会不会出事,决定了这件事能不能交给模型自己决定。 3. 钩子能替代权限系统吗? —— 不能。权限管「这个工具能不能用」,钩子管「这次调用放不放行」。 钩子自己也会写错、也会被绕过,所以它是在权限之内的一道补充。定位清楚了,下一节看钩子到底能挂在哪些时刻:事件有十七个,分五组。
- ☐ (本篇完,下一篇 5.2 事件生命周期:17 个事件)
相关笔记
- allowed-tools:权限清单是筛子不是边界
- 事件生命周期:十七个事件怎么分组
- Claude Code 橙皮书 · 索引
- 🐎 Claude Code 实战 · 索引