在大屏或电脑上体验更佳——动画和操作区域更宽敞。
输入

Hooks

Hook 是智能体运行时在指定生命周期事件调用的回调。工具执行前的 hook 可以否决请求,阻止文件变化;执行后的 hook 可以检查结果,却无法阻止已经发生的操作。事件和工具匹配器必须同时命中,回调才会运行。

把它看作检查点:放在工具前,可以拦截请求;放在工具后,可以记录结果。即使识别的是同一个问题,检查时机也决定了能阻止什么。

Hook 如何工作

要阻止操作,使用前置检查;需要已完成的结果来记录日志或触发格式化,则使用后置回调。负责分发事件和执行工具的运行框架称为 harness。

一项注册连接事件、匹配器、回调。本模拟把 h1 的 check_release 注册到 PreToolUse 或 PostToolUse,工具匹配器选择 Edit 或 Edit|Write。分发器先匹配事件,再匹配工具名;两项都匹配才调用回调。回调之后才检查目标文件。

两个请求预先给定,模型不参与这段分发,也不会再决定是否运行 check_release。分发和执行属于 harness。

回调保护 release.txt。在前置事件中,它记录调用尝试:目标受保护则返回 deny,其他文件返回 no-decision。harness 在执行前处理结果。no-decision 本身不授权,只把决定交回本例允许调用的基线策略。

在后置事件中,回调收到成功结果,记录已完成的调用;若目标受保护,则报告违规。报告随工具结果返回,但回调不执行补偿写入,文件保持工具写入后的内容。

事件名遵循 Claude Code 的 hooks 参考:前置 hook 在执行前运行,成功后的 hook 接收结果,匹配器筛选工具名。不同事件的输出格式不同,动画中的短标签只概括各自契约;后置阻止报告能追加反馈,不能撤销已发生的副作用。

Hooks 逐步演示

默认把 check_release 注册为 PreToolUse,匹配 Edit|Write。初始文件为 notes.txt = draft、release.txt = locked。locked 只是文本内容,不是操作系统文件锁;两个工具若被调用都能成功。

  1. c1 提议编辑。 Edit("notes.txt", "draft", "reviewed") 请求替换文本。收到请求时,文件和工具调用计数都不变。
  2. 前置事件命中 h1。 事件与工具均匹配。回调记录 c1 的一次尝试,发现目标未受保护,返回 no-decision。回调运行不等于一定否决。
  3. harness 执行 c1。 基线策略允许调用,Edit 把 draft 改为 reviewed,工具计数为 1。成功结果触发 PostToolUse,但 h1 注册在前置事件,此处不调用它。
  4. c2 提议受保护写入。 Write("release.txt", "published") 到达前置事件。Write 在匹配范围内,回调记录第二次尝试,返回 deny。
  5. harness 处理拒绝。 关闭执行路径,把 c2 标为阻止。Write 没有运行,因此没有成功结果,也没有对应的后置成功事件。

最终 notes.txt = reviewed、release.txt = locked,hook 调用 2 次,工具调用 1 次。两条回调记录都只是尝试记录;c1 是否执行,要看调用账本和真实工具结果。受保护文件未变、请求被阻止,两者一起证明前置检查生效。

检查太晚或漏掉工具时

只把事件改为 PostToolUse,两次调用都会通过前置阶段,由基线策略允许执行。c2 先写入 published,回调随后发现违规。报告说明操作已发生,最终文件仍为 published。

改回 PreToolUse,再把匹配器缩为 Edit。c1 会调用回调;c2 也有前置事件,但 Write 不匹配,回调根本没机会检查 release.txt。工具仍执行。时机提前不能弥补覆盖范围缺失。

注册方式Hook 次数工具次数受保护写入
PreToolUse + Edit|Write21被阻止;文件保持 locked
PreToolUse + Edit12未覆盖;文件变为 published
PostToolUse + Edit|Write22执行后报告;文件保持 published
PostToolUse + Edit12未覆盖;文件变为 published

各场景都暂停在 c2 提议请求时:c1 已完成,release.txt 仍为 locked。先判断能否拦截,再播放,依次观察事件、匹配和文件变化。比较 Prevent the write 与 Check after execution 只改变时机;与 Miss the Write tool 比较只改变覆盖范围。请求和文件相同。

后置 hook 适合记录成功结果或格式化已编辑文件。自动格式化示例 展示了后一种用途。先按目的选择事件,再检查哪些工具能进入处理器。

边界情况

  • 工具匹配,事件不符。 匹配 Write 不会让注册在后置事件的回调在前置事件运行。
  • 事件匹配,工具不符。 c2 的前置事件仍发生,只是 Edit 不覆盖 Write。“回调未运行”和“回调返回 no-decision”不同。
  • 匹配但目标无害。 c1 调用回调后仍执行。工具匹配器筛选候选,回调检查具体目标。
  • 执行前阻止。 c2 是被拒绝的请求,不是运行后失败的工具,也不会产生成功结果或后置成功事件。
  • 执行后全部命中。 完整匹配可以审计这两个成功调用,但不能让写入变成未发生。

常见错误

  • 把事件发生当成回调已运行。还要检查注册匹配和调用计数。
  • 把尝试记录当成完成记录。默认回调运行时,工具尚无结果。
  • 把 no-decision 当成允许规则。后续由基线权限策略决定。
  • 认为后置警告会恢复文件。恢复需要另一项操作,这个回调只报告。
  • 把文件名写进工具名匹配器。本例的 Edit|Write 选择工具,回调再检查 release.txt。

模型的简化

本课使用两个预设请求、两个内存文件和一个同步回调,结果确定。匹配、回调和文件操作均在本地执行,没有记录或编造模型输出。基线策略允许两个工具,以便观察 hook 的影响。

真实运行时还涉及路径处理、其他执行入口、多个回调、超时、异步任务、输入改写和更多生命周期事件,有些 hook 自身会调用模型。本课不是生产权限防护实现,也不能替代系统训练。