12.4 常见 Hook 设计原则与落地模式
面向经管学生、研究者与从业者的 AI 智能体设计教材

知道 Hooks 能做什么,并不等于会设计稳定的 Hook。很多失败案例不是因为功能不够,而是 Hook 挂得太多、职责太杂、边界太模糊。
五条设计原则
第一,只把必须稳定发生的动作做成 Hook。 如果一个动作只是”有时有帮助”,不妨先留在提示层或 Skill。
第二,一个 Hook 只负责一种判断或一种后处理。 把路径检查、敏感命令拦截、格式修复、通知发送全放进一个 Hook,会让失败原因难以定位。
第三,同步 Hook 做门禁,异步 Hook 做补充。 PreToolUse 适合”允不允许继续”的裁决;异步检查放在写后补充动作里,避免卡死工作流。
第四,输出必须可消费。 好的 Hook 输出不是冗长自言自语,而是能让当前任务立即利用的信息——失败摘要、拦截原因、需要人工复核的具体项。
第五,Hook 要服务整体闭环。 它应与 Skill、测试、审阅和版本控制协同,而不是包办一切。
四类落地模式
| 模式 | 典型事件 | 主要用途 |
|---|---|---|
| 拦截型 | PreToolUse、PermissionRequest |
阻断危险操作、规范权限申请 |
| 检查型 | PostToolUse、PostToolUseFailure |
写后检查、失败回灌 |
| 通知型 | TaskCompleted、Notification |
任务结束提醒、状态播报 |
| 沉淀型 | PostToolUseFailure、SessionEnd |
记录失败样本、积累经验条目 |
拦截型:在 PreToolUse 匹配高危命令,退出码 2 阻断执行。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "if echo \"$CLAUDE_TOOL_INPUT\" | grep -qE 'rm -rf|DROP TABLE|git push --force'; then echo 'BLOCK: 检测到高危命令,已拦截' >&2; exit 2; fi"
}
]
}
]
}
}检查型:在 PostToolUse 对刚写入的文件做格式验证,指向外部 Python 脚本。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "python3 .claude/hooks/check_format.py \"$CLAUDE_FILE_PATH\""
}
]
}
]
}
}通知型:任务完成后通过 Webhook 发送消息。
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "curl -s -X POST 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL' -H 'Content-Type: application/json' -d \"{\\\"text\\\": \\\"Claude Code: $CLAUDE_NOTIFICATION\\\"}\""
}
]
}
]
}
}沉淀型:会话结束时把关键信息追加写入本地日志。
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "echo \"$(date '+%Y-%m-%d %H:%M') 会话结束,最后操作:$CLAUDE_TOOL_NAME\" >> .claude/session-log.txt"
}
]
}
]
}
}四类模式不是互斥分类。真实项目中,同一任务通常组合多种模式:先用拦截型守住危险操作,再用检查型补跑测试,最后通知型报告结果。
设计失当的信号
如果用户看到失败却分不清是提示词、Skill 还是 Hook 触发的,说明职责混写了。一个配置既做安全拦截又做业务判断又发通知,后续很难维护。Hook 是关键节点上的动作接口,不是整套工程系统的唯一承载层。