3m read
Agent 防遗忘 Hook 机制
agentclaude-codehooks
问题根源
大模型 Agent(Claude Code 等)在长会话中会"忘事"——早期设定的规则逐渐失效、格式化指令被忽略、安全约束松动。原因是提示词(System Prompt / CLAUDE.md)本质是软约束,模型可能因上下文稀释、注意力偏移等原因不再遵守。
解决方案:Hook 机制
四层能力模型
| 层级 | 类型 | 约束力 |
|---|---|---|
| 提示词(Prompts) | 软约束 | 弱 |
| Hook | 强制执行 | 强 |
| 工具(Tools) | 功能扩展 | — |
| MCP 服务器 | 外部集成 | — |
Hook 是其中唯一强制执行的一层,区别于提示词的软约束。
Hook 是什么
在 Agent 生命周期的关键节点挂载的外部 Shell 脚本。每个 Hook 运行后返回退出码,退出码决定 Agent 行为。最常用的三类:
| 事件类型 | 触发时机 | 典型用途 |
|---|---|---|
| Pre Tool Use | 工具执行前 | 拦截危险命令 |
| Post Tool Use | 工具执行后 | 自动格式化 |
| Stop | Agent 任务完成 | 桌面通知 |
实战场景
场景 1:自动格式化(Post Tool Use)
痛点:CLAUDE.md 中反复强调"代码要格式化"但 Agent 经常忽略。
解决:配置 Post Tool Use Hook,匹配 Edit / Write 操作后自动执行 prettier。
hljs json{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"command": "prettier --write ${CLAUDE_TOOL_INPUT_FILE_PATH}"
}
]
}
}
从此不需要在提示词中写任何格式化要求,Hook 强制保证每次编辑后代码整洁。
场景 2:危险命令拦截(Pre Tool Use)
痛点:担心 Agent 误执行 rm -rf 等破坏性命令。
解决:Pre Tool Use Hook 匹配 Bash 命令,脚本判断完整命令内容,命中危险模式则返回退出码 2,直接阻止执行。
hljs json{
"hooks": {
"PreToolUse": [
{
"matcher": "",
"command": "if echo \"$CLAUDE_BASH_COMMAND\" | grep -qE 'rm .*-rf|sudo rm'; then exit 2; fi"
}
]
}
}
退出码含义:0 = 允许,1 = 允许但警告,2 = 拒绝执行。
场景 3:任务结束通知(Stop)
痛点:慢任务(如构建、测试)完成后需用户主动查看,容易错过。
解决:Stop 事件触发桌面通知脚本。
hljs json{
"hooks": {
"Stop": [
{
"command": "osascript -e 'display notification \"Claude 任务完成\" with title \"Claude Code\"'"
}
]
}
}
Hook 使用原则
- 仅用于确定性动作:必须是可写成固定 Shell 脚本、每次都必须执行的动作
- 不可滥用:Hook 过多会成为新的维护负担,只在提示词反复失效时才转为 Hook
- 转换判断标准:如果 CLAUDE.md 中某条规则需要反复强调、多次被忽略 → 应转为 Hook 实现强制约束
- 保持简单:每个 Hook 只做一件事,一个脚本 10 行以内
Hook 是 Agent 工具箱中最被低估的能力。提示词可以说服模型做正确的事,Hook 可以保证它做。