三篇文章之前,我写了《Hook 系统——工具调用的前与后》。那篇文章讲的是 ECC 的 Hook 架构——PreToolUse、PostToolUse、Stop 这些概念,以及为什么需要它们。
文章发完之后,我做了一件事:照着理论,在自己的 Agent 里做了一个。
结果是:从写代码到跑通测试,用了不到半小时。
这个速度不是因为我厉害,而是因为这件事本质上很简单——Hook 系统的核心只有三个文件、几十行代码。真正难的是"意识到需要它"和"决定动手做它"。
去掉所有概念包装,Hook 系统就是三样东西:
{
"preToolUse": [
{ "matcher": "terminal", "action": "check_dangerous_commands" },
{ "matcher": "write_file", "action": "check_file_path" }
],
"postToolUse": [
{ "matcher": "terminal", "action": "record_tool_usage" }
]
} def check_dangerous_commands(tool_name, input_data):
dangerous = ["rm -rf /", "DROP TABLE", "git push --force"]
for d in dangerous:
if d in str(input_data):
return {"block": True, "reason": f"危险操作被拦截: {d}"}
return {"block": False} def execute_pre_hooks(tool_name, input_data):
registry = json.load(open("registry.json"))
for hook in registry.get("preToolUse", []):
fn = REGISTERED_ACTIONS.get(hook["action"])
if fn:
result = fn(tool_name, input_data)
if result.get("block"):
return result
return {"block": False} 一个 Hook 就是一个 JSON 条目 + 一个 Python 函数。 想加新的 Hook,要么在注册表里加一条(已有动作),要么写个新函数再注册。不需要改任何基础设施代码。
| 命令 | 结果 | 说明 |
|---|---|---|
rm -rf /some/path | ⛔ 拦截 | 匹配危险模式,阻止执行 |
ls -la | ✅ 通过 | 安全命令,放行 |
写文件到 /etc/passwd | ⛔ 拦截 | 不在白名单目录 |
写文件到 /home/dou/test.txt | ✅ 通过 + 记日志 | 白名单内,自动记录 |
整个测试过程不到 1 分钟。
| 场景 | 没有 Hook | 有 Hook |
|---|---|---|
| 执行危险命令 | 靠模型自觉,或者人反应过来 | PreToolUse 自动拦截,根本到不了执行这一步 |
| 写文件到系统目录 | 写坏了才意识到 | PreToolUse 检查路径白名单,直接拒绝 |
| 审计工具调用 | 想不起来查 | PostToolUse 自动记录,随时可以翻 |
这不是功能增强,是模式的转变。 以前的安全是"弹窗确认"——依赖人的注意力和判断力。现在的安全是"规则拦截"——系统自动判断,人只负责定义规则。
1. 先建一个最简单的安全门。 先写一个检查 rm -rf / 的 PreToolUse。5 分钟就能写出来,跑通后你就知道 Hook 系统是怎么回事了。
2. 把写代码的时间花在"定义规则"上,而不是"搭框架"上。 Hook 系统的框架永远是几十行代码。真正有价值的是规则本身——你知道哪些操作是危险的、哪些路径不该写。这些是你的经验,机器没有。
3. 让 PostToolUse 给你积累数据。 不用一开始就想"连续学习"。先让 PostToolUse 记录每次工具调用。一周后你去翻那个日志文件,你会惊讶地发现自己原来做了这么多重复的事。
💬 评论