claude-hooks

在软件工程与智能体(Agent)架构开发中,Hook(钩子) 是一种极其核心的进阶设计模式。它通过在核心流程中埋下“插座”,实现了高内聚、低耦合的代码结构。

一、 为什么需要 Hooks?(痛点与核心价值)

1. 传统硬编码的痛点 (s03 阶段)

在没有引入 Hook 之前,诸如“权限检查”、“日志记录”、“耗时统计”等横切关注点(Cross-cutting Concerns)的代码,必须硬编码(Hardcode)在系统的核心业务循环(如 agent_loop)内部。

  • 后果: 导致核心循环代码迅速臃肿,变成难以维护的“屎山代码”;且每次增加新功能,都必须修改核心底层逻辑,极易引入新 Bug。

2. Hooks 的解耦哲学

Hooks 允许核心流程保持绝对的纯粹和单一职责(Stay boring on purpose)。它只在特定的生命周期关键节点留出事件插座(Event Slots)。核心代码只管在走到这一步时“高喊”一声触发事件,而具体执行什么业务逻辑,完全由外部注册的函数决定。


二、 Hook 系统的底层技术实现

在底层,一个标准的 Hook 系统由 1 个核心字典(注册表) 和 2 个核心函数(注册与触发) 支撑,代码极其朴素优雅:

1. 初始化钩子注册表(HOOKS 字典)

1
2
3
4
5
6
7
# 蓄水池:用来存放不同节点挂载的回调函数列表
HOOKS = {
    "UserPromptSubmit": [],  # 用户输入后,大模型思考前
    "PreToolUse": [],        # 大模型决定调用工具,但工具尚未真正执行前
    "PostToolUse": [],       # 工具执行完毕,拿到结果后
    "Stop": []               # 核心循环准备退出前
}

2. 注册钩子(register_hook)

1
2
3
4
5
6
7
def register_hook(event: str, callback):
    """
    管道工:把外部定义的业务函数追加到对应事件的列表中排队。
    此时函数并不运行,只是登记。
    """
    if event in HOOKS:
        HOOKS[event].append(callback)

3. 触发钩子(trigger_hooks)与高级拦截机制

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def trigger_hooks(event: str, *args):
    """
    引爆器:在核心循环中被动触发,按顺序遍历并执行该事件下挂载的所有钩子。
    """
    for callback in HOOKS[event]:
        result = callback(*args)
        # 💡 核心设计:拦截机制 (Interceptor)
        # 如果某一个高优先级的钩子(如安全检查)返回了非空内容,立刻中断后续执行,实现安全拦截
        if result is not None:
            return result
    return None

三、 Hook 的实际使用流程(三步连贯动作)

使用 Hook 系统在开发中遵循标准的 写钩子 $\rightarrow$ 登钩子 $\rightarrow$ 踩钩子 闭环:

1. 第一步:写钩子(编写独立的业务扩展功能)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 开发一个日志钩子
def log_hook(block):
    print(f"【HOOK 日志】AI 准备调用工具: {block.name}")
    return None  # 返回 None 表示不拦截,放行

# 开发一个安全拦截钩子
def permission_hook(block):
    if block.name == "bash" and "rm -rf" in block.input.get("command", ""):
        return "Permission denied: 严禁执行危险的删库跑路命令!" # 触发拦截
    return None

2. 第二步:登钩子(将功能挂载到对应的插座上)

1
2
3
# 在程序初始化时进行功能拼装
register_hook("PreToolUse", permission_hook)  # 优先进行安全检查
register_hook("PreToolUse", log_hook)        # 其次记录日志

3. 第三步:踩钩子(核心循环中的被动触发)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
def agent_loop(messages: list):
    while True:
        # ... AI 思考产出 tool_use 指令 ...

        # 💥 核心代码在此“踩”下触发器,解耦业务逻辑
        blocked = trigger_hooks("PreToolUse", block)

        if blocked:
            # 如果被前面的安全钩子拦截了(返回了拦截报错字符串),则直接跳过工具执行
            results.append({"type": "tool_result", "content": str(blocked)})
            continue

        # ... 如果没被拦截,正常运行底层的工具(如读写文件) ...

四、 本次 Agent 架构(s04)基于 Hook 实现的功能清单

通过 Hook 模式,s04 版本在不污染 agent_loop 主干的前提下,完美插入了以下 5 个跨切面功能:

钩子名称 挂载节点 核心功能说明
context_inject_hook UserPromptSubmit 在用户提交问题进入 AI 思考前,做环境感知或前置日志记录。
permission_hook PreToolUse 核心防线:拦截高危敏感命令(sudo, rm -rf),处理文件越界写入并弹出用户确认提示。
log_hook PreToolUse 统一接管工具调用的前置控制台日志打印。
large_output_hook PostToolUse 后置监控:检查工具执行输出是否超过 10 万字,过大时进行告警,防止撑爆上下文。
summary_hook Stop 在整个会话周期结束时,自动盘点并打印本次任务一共消耗了多少次工具调用。

comments powered by Disqus
使用 Hugo 构建
主题 Stack 由 Jimmy 设计