K1.5.2 Task 1.5

HookMatcher:精准匹配节省 40% Hook 处理时间

HookMatcher 通过正则模式把 hook 函数连接到工具调用。匹配器写对了,hook 只对需要它的工具触发——精准定位、不浪费处理、不意外匹配。

注册模式

HookMatcher(
    matcher='process_refund',      # 正则匹配工具名
    hooks=[enforce_refund_limit]    # 要运行的 hook 函数
)

这个 hook 只对 process_refund 触发。其他工具不会触发它。

正则意味着子串匹配

matcher='update' 匹配任何包含 “update” 的工具:update_accountget_status_updateupdate_settings。这会捕获到不想要的工具。

修复:锚定模式。matcher='^update_account$' 只匹配 update_account——起始(^)和结束($)锚点确保精确匹配。

对于管控型 hook(阻止、拒绝),用锚定模式。退款限制 hook 意外地对 check_refund_status 触发就是误触。

没有 matcher = 对每个工具调用都触发

省略 matcher 字段意味着 hook 对所有工具调用运行。这对通用关注点(审计日志)是对的,但对定向管控是浪费。

某系统用一个无 matcher 的 hook 对全部 8 个工具跑安全检查 + 变更日志。分析显示 40% 的 hook 处理时间浪费在 Read、Grep、Glob、Task 和 WebSearch 上——这些都不需要管控检查。

修复:拆成定向 matcher。SDK 级过滤比 hook 函数内部的提前返回逻辑更高效。

用独立 HookMatcher 做分层管控

三层管控,三个独立注册:

# 第 1 层:所有工具的审计日志
HookMatcher(hooks=[audit_log])  # 无 matcher → 所有工具

# 第 2 层:文件修改工具的路径校验
HookMatcher(matcher='Edit|Write', hooks=[validate_path])

# 第 3 层:shell 执行的命令黑名单
HookMatcher(matcher='Bash', hooks=[block_dangerous])

每个 HookMatcher 精确定位需要管控的工具。Read/Grep/Glob 只走审计日志。Edit/Write 走审计 + 路径校验。Bash 走审计 + 安全检查。关注点清晰分离。

反模式:一个 HookMatcher 把三种检查塞进一个函数用 if-else 路由。这混合了关注点、增加维护复杂性、也无法利用 SDK 级的 matcher 过滤。

审计缺口诊断

需求:“记录所有工具调用,校验 Write 路径,完全阻止 Bash。”

已注册:

  • HookMatcher(matcher='Write', hooks=[validate_path])
  • HookMatcher(matcher='Bash', hooks=[block_bash])

缺失:一个无 matcher 的 HookMatcher 做通用审计日志。Read、Grep 和 Glob 调用没有被记录。修复:加 HookMatcher(hooks=[audit_log])

合并反模式

一个团队提议把 12 个 HookMatcher 减到 2 个(一个 PreToolUse,一个 PostToolUse,都不带 matcher,所有路由逻辑放在内部)。“更少注册 = 更简单配置。”

拒绝。 合并去掉了基于 matcher 的过滤:

  • 两个 hook 对每个工具调用都触发,即使只有特定工具需要处理 → 延迟增加
  • 无关的管控逻辑混在单个函数里 → 可维护性降低
  • 改一个工具的逻辑可能破坏另一个的 → 脆弱代码

HookMatcher 模式就是为了在注册层面做关注点分离。更多注册 + 定向 matcher 比更少注册 + 复杂条件逻辑更容易维护。

完整注册示例

一个 CI/CD agent 有 4 个需求:

需求Hook 类型Matcher原因
审计所有调用PreToolUse(无)通用日志
安全管控PreToolUse'Bash|Write'只对危险工具
输出标准化PostToolUse'Read|Grep'只对有原始输出的工具
部署门控PreToolUse'deploy'只对部署工具

四个定向条目,每个只在需要时触发。干净、高效、可维护。

同一 hook 类型的多个 matcher

在同一 hook 类型下注册多个 HookMatcher 条目(比如三个 PreToolUse 条目)是设计意图。它们独立运行——每个对自己匹配的工具触发、跑自己的 hook 函数。


一句话总结: 管控型用带正则锚定的定向 matcher('^tool_name$'),通用日志用无 matcher 条目,每个关注点独立 HookMatcher 条目——合并成少数通吃 hook 浪费 40% 处理时间并混合无关关注点。