别再往框架源码里塞逻辑了!Hermes Hooks 钩子一招搞定安全拦截与日志审计
了一个安全过滤逻辑,不知道往哪塞?每次 Agent 执行工具调用都想记录日志,难道要改框架源码?Hermes Agent Hooks(钩子)就是为解决这类问题而生的生命周期回调系统,允许在智能体运行的关键节点注入自定义逻辑,实现日志审计、安全拦截、消息告警、上下文注入等扩展能力。本文从钩子类型、核心事件、开发流程、实战示例到最佳实践,带你全面掌握 Hooks 用法,灵活扩展 Agent 功能。
一、钩子系统总览
Hermes 提供两套独立钩子系统,覆盖网关与全会话场景,均为非阻塞设计—— 钩子报错不会导致 Agent 崩溃,仅记录日志。
1.1 网关钩子(Gateway Hooks)
运行环境:仅网关(Telegram/Discord/ 飞书等消息平台)生效。
注册方式:
~/.hermes/hooks/目录下创建HOOK.yaml+handler.py。核心场景:网关启动、会话管理、命令监控、消息告警。
1.2 插件钩子(Plugin Hooks)
运行环境:CLI + 网关全场景生效。
注册方式:Python 插件中通过
ctx.register_hook()代码注册。核心场景:工具拦截、LLM 上下文注入、会话生命周期管理。
1.3 核心价值
✅无侵入扩展:无需修改 Agent 核心代码,按需注入逻辑。
✅全链路可控:覆盖会话启动、工具调用、LLM 推理、会话结束全流程。
✅高稳定性:钩子异常自动捕获,不影响主流程。
✅灵活适配:支持日志、告警、安全、集成等多场景扩展。
图1:钩子系统架构图
注册方式
钩子系统总览
仅消息平台
CLI + 网关全场景
设计特点
非阻塞设计
异常自动捕获 不影响主流程
网关钩子 Gateway Hooks
Telegram
Discord
飞书 / 钉钉
插件钩子 Plugin Hooks
pre_tool_call 拦截
post_tool_call 审计
pre_llm_call 注入
on_session_end 清理
HOOK.yaml + handler.py
~/.hermes/hooks/ 目录
ctx.register_hook
Python 插件代码
清楚了钩子的整体架构,先从网关钩子入手,看它如何在消息平台中发挥作用。
二、网关钩子(Gateway Hooks)
网关钩子仅在消息平台网关运行,适合监控网关级事件、发送平台告警。
2.1 目录结构
每个网关钩子为独立目录,存放于~/.hermes/hooks/:
~/.hermes/hooks/ └── task-alert/ # 钩子名称 ├── HOOK.yaml # 事件配置 └── handler.py # 逻辑处理2.2 配置文件(HOOK.yaml)
声明监听的事件,支持单事件 / 多事件 / 通配符:
name: task-alert description: 长任务执行告警 events: - agent:step # 监听工具调用迭代事件2.3 处理脚本(handler.py)
实现钩子逻辑,需固定handle函数,支持同步 / 异步:
import os import httpx from datetime import datetime # 从环境变量读取 Telegram 配置 BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN") CHAT_ID = os.getenv("TELEGRAM_HOME_CHANNEL") THRESHOLD = 10 # 超过10步触发告警 async def handle(event_type: str, context: dict): # 获取当前迭代次数 iteration = context.get("iteration", 0) if iteration == THRESHOLD and BOT_TOKEN and CHAT_ID: # 构造告警消息 tools = ", ".join(context.get("tool_names", [])) msg = f"⚠️ 任务执行超过{iteration}步,最近工具:{tools}" # 发送 Telegram 告警 async with httpx.AsyncClient() as client: await client.post( f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage", json={"chat_id": CHAT_ID, "text": msg} )2.4 常用网关事件
| 事件 | 触发时机 | 核心上下文 |
|---|---|---|
gateway:startup | 网关启动 | 激活平台列表 |
session:start | 新会话创建 | 用户 ID、会话 ID |
agent:start | Agent 开始处理消息 | 消息内容、用户信息 |
agent:step | 工具调用迭代 | 迭代次数、工具列表 |
agent:end | Agent 处理完成 | 最终响应、会话信息 |
command:* | 任意斜杠命令 | 命令名称、参数 |
2.5 实战示例:启动自检钩子
创建boot-check钩子,网关启动时自动执行自检:
- 创建 HOOK.yaml
name: boot-check description: 网关启动自检 events: - gateway:startup- 创建 handler.py
import subprocess from pathlib import Path BOOT_FILE = Path.home() / ".hermes/BOOT.md" def handle(event_type: str, context: dict): if not BOOT_FILE.exists(): return # 执行自检脚本 subprocess.run(["hermes", "chat", "--quiet", BOOT_FILE.read_text()])- 创建自检文件(~/.hermes/BOOT.md)
1. 检查定时任务状态:hermes cron list 2. 发送启动通知到飞书- 生效:重启网关
hermes gateway restart
网关钩子专注于消息平台场景,而插件钩子则覆盖 CLI 和网关的全会话场景。
三、插件钩子(Plugin Hooks)
插件钩子基于 Python 插件开发,CLI / 网关全场景生效,适合工具拦截、上下文注入。
3.1 注册方式
在插件register()函数中,通过ctx.register_hook()注册钩子:
def register(ctx): # 注册工具调用前钩子 ctx.register_hook("pre_tool_call", warn_dangerous_tool) # 注册LLM推理前钩子 ctx.register_hook("pre_llm_call", inject_memory) # 注册会话结束钩子 ctx.register_hook("on_session_end", cleanup_session)3.2 核心插件钩子
1.pre_tool_call(工具调用前)
触发时机:每次工具执行前。
核心用途:安全拦截、工具审计。
回调示例:
def warn_dangerous_tool(tool_name: str, **kwargs): # 拦截危险工具 if tool_name in ["terminal", "write_file"]: print(f"⚠️ 即将执行高危工具:{tool_name}")2.pre_llm_call(LLM 推理前)
触发时机:每轮对话推理前。
核心用途:注入记忆、安全护栏。
回调示例:
def inject_memory(**kwargs): # 注入用户偏好 return {"context": "用户偏好简洁回答,使用Python开发"}3.on_session_start(会话开始)
触发时机:新会话创建时。
核心用途:初始化会话状态。
4.on_session_end(会话结束)
触发时机:会话结束时。
核心用途:清理资源、同步会话数据。
3.3 实战示例:工具审计钩子
注册post_tool_call钩子,记录所有工具调用:
import json from datetime import datetime # 工具调用后回调 def audit_tool(tool_name: str, args: dict, result: str, **kwargs): log = { "time": datetime.now().isoformat(), "tool": tool_name, "args": args, "result": result[:200] # 截断结果 } # 写入日志 with open("tool-audit.log", "a") as f: f.write(json.dumps(log) + "\n") # 插件注册 def register(ctx): ctx.register_hook("post_tool_call", audit_tool)插件钩子覆盖了核心场景,但 Hermes 还提供了 Shell 钩子、优先级控制等高级能力。
四、高级用法
4.1 Shell 钩子(无代码)
无需 Python 开发,通过配置文件注册 Shell 脚本钩子:
# ~/.hermes/config.yaml hooks: post_tool_call: - matcher: "terminal" # 匹配终端工具 command: "~/scripts/audit-terminal.sh" # 脚本路径4.2 钩子优先级
插件钩子 > Shell 钩子 > 网关钩子。
同类型钩子按目录名 / 注册顺序执行。
4.3 错误处理
钩子异常自动捕获,仅记录日志,不影响主流程。
pre_llm_call钩子可注入上下文,其他钩子返回值忽略。
回顾了全部用法后,最后总结几项最佳实践,帮你科学地运用钩子系统。
五、最佳实践
网关钩子:专注网关级事件(启动、会话、平台告警)。
插件钩子:优先使用插件钩子,覆盖全场景。
轻量逻辑:钩子逻辑保持精简,避免耗时操作。
安全优先:
pre_tool_call拦截高危工具,防止误操作。日志审计:关键事件(工具调用、命令执行)添加日志钩子。