OpenClaw Webhook 与 Hooks 机制详解

目录

    • 摘要
    • [1. 引言 - Webhook 与 Hooks 的区别与联系](#1. 引言 - Webhook 与 Hooks 的区别与联系)
      • [1.1 概念辨析](#1.1 概念辨析)
      • [1.2 架构定位对比](#1.2 架构定位对比)
      • [1.3 协同工作模式](#1.3 协同工作模式)
    • [2. Webhook 机制详解 - 外部事件接入](#2. Webhook 机制详解 - 外部事件接入)
      • [2.1 核心架构](#2.1 核心架构)
      • [2.2 启用与配置](#2.2 启用与配置)
      • [2.3 认证机制](#2.3 认证机制)
      • [2.4 端点详解](#2.4 端点详解)
        • [2.4.1 `/hooks/wake` - 唤醒主会话](#2.4.1 /hooks/wake - 唤醒主会话)
        • [2.4.2 `/hooks/agent` - 运行隔离智能体](#2.4.2 /hooks/agent - 运行隔离智能体)
        • [2.4.3 `/hooks/<name>` - 自定义映射](#2.4.3 /hooks/<name> - 自定义映射)
      • [2.5 响应状态码](#2.5 响应状态码)
    • [3. Hooks 机制详解 - 内部事件钩子](#3. Hooks 机制详解 - 内部事件钩子)
      • [3.1 设计理念](#3.1 设计理念)
      • [3.2 Hook 发现机制](#3.2 Hook 发现机制)
      • [3.3 Hook 结构](#3.3 Hook 结构)
        • [3.3.1 HOOK.md 格式](#3.3.1 HOOK.md 格式)
        • [3.3.2 处理程序实现](#3.3.2 处理程序实现)
      • [3.4 事件类型](#3.4 事件类型)
        • [3.4.1 命令事件](#3.4.1 命令事件)
        • [3.4.2 智能体事件](#3.4.2 智能体事件)
        • [3.4.3 Gateway 事件](#3.4.3 Gateway 事件)
      • [3.5 捆绑的 Hooks](#3.5 捆绑的 Hooks)
        • [3.5.1 session-memory](#3.5.1 session-memory)
        • [3.5.2 command-logger](#3.5.2 command-logger)
        • [3.5.3 boot-md](#3.5.3 boot-md)
    • [4. Webhook 配置实战 - 飞书、GitHub、企业微信](#4. Webhook 配置实战 - 飞书、GitHub、企业微信)
      • [4.1 飞书 Webhook 集成](#4.1 飞书 Webhook 集成)
        • [4.1.1 配置步骤](#4.1.1 配置步骤)
        • [4.1.2 飞书事件处理流程](#4.1.2 飞书事件处理流程)
      • [4.2 GitHub Webhook 集成](#4.2 GitHub Webhook 集成)
        • [4.2.1 配置步骤](#4.2.1 配置步骤)
      • [4.3 企业微信 Webhook 集成](#4.3 企业微信 Webhook 集成)
        • [4.3.1 配置步骤](#4.3.1 配置步骤)
    • [5. Hooks 开发指南 - 自定义钩子函数](#5. Hooks 开发指南 - 自定义钩子函数)
      • [5.1 创建自定义 Hook](#5.1 创建自定义 Hook)
        • [5.1.1 需求分析](#5.1.1 需求分析)
        • [5.1.2 创建 Hook 目录](#5.1.2 创建 Hook 目录)
        • [5.1.3 编写 HOOK.md](#5.1.3 编写 HOOK.md)
        • [5.1.4 编写处理程序](#5.1.4 编写处理程序)
      • [5.2 测试与调试](#5.2 测试与调试)
        • [5.2.1 验证 Hook 发现](#5.2.1 验证 Hook 发现)
        • [5.2.2 启用并测试](#5.2.2 启用并测试)
        • [5.2.3 查看日志](#5.2.3 查看日志)
      • [5.3 最佳实践](#5.3 最佳实践)
        • [5.3.1 保持处理程序快速](#5.3.1 保持处理程序快速)
        • [5.3.2 优雅处理错误](#5.3.2 优雅处理错误)
        • [5.3.3 尽早过滤事件](#5.3.3 尽早过滤事件)
    • [6. 安全与最佳实践](#6. 安全与最佳实践)
      • [6.1 Webhook 安全](#6.1 Webhook 安全)
        • [6.1.1 令牌管理](#6.1.1 令牌管理)
        • [6.1.2 网络安全](#6.1.2 网络安全)
        • [6.1.3 请求体验证](#6.1.3 请求体验证)
      • [6.2 Hooks 安全](#6.2 Hooks 安全)
        • [6.2.1 权限隔离](#6.2.1 权限隔离)
        • [6.2.2 资源控制](#6.2.2 资源控制)
      • [6.3 监控与日志](#6.3 监控与日志)
        • [6.3.1 日志配置](#6.3.1 日志配置)
        • [6.3.2 监控指标](#6.3.2 监控指标)
    • [7. 总结](#7. 总结)
    • [8. 参考资料](#8. 参考资料)

摘要

在现代智能体系统中,事件驱动架构是实现灵活扩展的关键。OpenClaw 提供了两套互补的事件处理机制:Webhook 用于接收外部系统的事件推送,Hooks 用于响应内部命令和生命周期事件。本文深入剖析这两套机制的设计理念、配置方法和最佳实践,帮助开发者构建高度自动化的智能体工作流。通过飞书、GitHub、企业微信等实际案例,展示如何将 OpenClaw 无缝集成到现有业务系统中,实现从被动响应到主动触发的范式转变。🔒


1. 引言 - Webhook 与 Hooks 的区别与联系

1.1 概念辨析

在 OpenClaw 的自动化体系中,Webhook 和 Hooks 是两个容易混淆但本质不同的概念。理解它们的区别,是掌握 OpenClaw 自动化能力的第一步。🎯

Webhook(外部事件接入) 是一种 HTTP 端点机制,允许外部系统通过 HTTP 请求主动"唤醒"OpenClaw 智能体。它是一种"推"模式------外部事件发生时,由外部系统主动通知 OpenClaw,而不是 OpenClaw 轮询检查。这种模式大大降低了延迟,减少了不必要的资源消耗。

Hooks(内部事件钩子) 是一种事件驱动系统,在 OpenClaw 内部命令和生命周期事件触发时自动执行预定义的操作。它是一种"响应"模式------当用户发送 /new/reset/stop 等命令,或 Gateway 启动时,Hooks 会自动执行相应的处理逻辑。

1.2 架构定位对比

为了更清晰地理解两者的定位,我们可以从以下几个维度进行对比:

维度 Webhook Hooks
事件来源 外部系统(飞书、GitHub、企业微信等) 内部事件(命令、生命周期)
触发方式 HTTP POST 请求 事件监听器自动触发
执行环境 隔离的智能体会话 Gateway 网关内部
主要用途 接入外部通知、触发自动化任务 会话管理、审计日志、状态保存
配置方式 Gateway 配置文件 + HTTP 端点 HOOK.md + handler.ts
安全边界 需要令牌认证,请求体视为不可信 内部执行,继承 Gateway 权限

1.3 协同工作模式

Webhook 和 Hooks 并非孤立存在,它们可以协同工作,构建完整的自动化链路。例如:
HTTP POST
触发
执行任务
完成
消息渠道
触发
自动执行
自动执行
外部系统

飞书/GitHub
Webhook 端点
智能体会话
业务处理
发送响应
用户接收
用户命令

/new /reset
Hooks
会话快照
审计日志

在这个架构中,Webhook 负责打通外部世界,而 Hooks 负责维护内部秩序。两者相辅相成,共同构成了 OpenClaw 强大的自动化基础设施。


2. Webhook 机制详解 - 外部事件接入

2.1 核心架构

OpenClaw 的 Webhook 机制由 Gateway 网关提供,暴露一个轻量级的 HTTP 端点用于接收外部事件。其核心架构如下:
智能体 事件队列 Gateway 网关 外部系统 智能体 事件队列 Gateway 网关 外部系统 mode=now 时立即触发 POST /hooks/wake Authorization: Bearer token 验证令牌 加入系统事件 200 OK 触发心跳 读取事件 处理事件

2.2 启用与配置

要启用 Webhook 功能,需要在 Gateway 配置中添加以下设置:

json5 复制代码
{
  hooks: {
    enabled: true,
    token: "shared-secret",  // 必填:用于认证的共享密钥
    path: "/hooks",          // 可选:端点路径,默认为 /hooks
  },
}

配置要点

  • 🔑 hooks.enabled=true 时,hooks.token 为必填项
  • 🛣️ hooks.path 默认为 /hooks,可根据需要自定义
  • 🔒 建议使用强随机字符串作为 token,避免使用简单密码

2.3 认证机制

每个 Webhook 请求必须包含有效的认证令牌。OpenClaw 支持三种认证方式:

认证方式 格式 推荐程度 说明
Authorization Header Authorization: Bearer <token> ⭐⭐⭐ 推荐 标准 OAuth 2.0 风格,最安全
自定义 Header x-openclaw-token: <token> ⭐⭐ 可用 兼容性方案
Query 参数 ?token=<token> ⭐ 已弃用 会记录警告日志,未来版本将移除

安全建议 :始终使用 Authorization: Bearer 头传递令牌,避免令牌出现在 URL 或日志中。

2.4 端点详解

OpenClaw 提供了多个 Webhook 端点,满足不同场景的需求。

2.4.1 /hooks/wake - 唤醒主会话

/hooks/wake 端点用于向主会话添加系统事件,触发智能体处理:

json 复制代码
{
  "text": "收到新邮件,发件人:张三,主题:项目进度更新",
  "mode": "now"
}

参数说明

  • text(必填):事件描述文本,智能体将基于此理解发生了什么
  • mode(可选):触发模式
    • now(默认):立即触发心跳,智能体立即响应
    • next-heartbeat:等待下一次定期心跳检查时处理

使用场景

  • 📧 邮件到达通知
  • 📅 日程提醒
  • 🔔 监控告警
  • 📱 第三方应用通知
2.4.2 /hooks/agent - 运行隔离智能体

/hooks/agent 端点用于启动一个独立的智能体会话,适合需要隔离执行的任务:

json 复制代码
{
  "message": "总结今天收到的所有邮件,提取关键行动项",
  "name": "Email",
  "sessionKey": "hook:email:daily-summary",
  "wakeMode": "now",
  "deliver": true,
  "channel": "last",
  "model": "openai/gpt-5.2-mini",
  "thinking": "low",
  "timeoutSeconds": 120
}

参数详解

参数 类型 必填 说明
message string 智能体要处理的提示或消息
name string Hook 的可读名称,用作会话摘要前缀
sessionKey string 会话标识键,默认为 hook:<uuid>
wakeMode string 触发模式:nownext-heartbeat
deliver boolean 是否发送响应到消息渠道,默认 true
channel string 消息渠道:lastwhatsapptelegram
to string 接收者标识符(电话号码、聊天 ID 等)
model string 模型覆盖,如 anthropic/claude-3-5-sonnet
thinking string 思考级别:lowmediumhigh
timeoutSeconds number 最大运行时间(秒)

隔离执行的优势

  1. 上下文隔离:不会污染主会话的历史记录
  2. 资源控制:可设置独立的超时和模型参数
  3. 会话持久化 :使用一致的 sessionKey 可实现多轮对话
  4. 结果摘要:始终在主会话中发布执行摘要
2.4.3 /hooks/<name> - 自定义映射

通过配置 hooks.mappings,可以创建自定义的 Webhook 端点,将任意请求体转换为标准操作:
映射配置
POST /hooks/gmail
match.source=gmail
模板/代码转换
wake/agent
外部系统
映射匹配
请求体转换
生成标准请求
执行操作
match 条件
action 类型
transform 模块

2.5 响应状态码

状态码 含义 说明
200 成功 /hooks/wake 请求成功
202 已接受 /hooks/agent 异步任务已启动
401 认证失败 令牌无效或缺失
400 请求无效 请求体格式错误
413 请求过大 请求体超过大小限制

3. Hooks 机制详解 - 内部事件钩子

3.1 设计理念

Hooks 是 OpenClaw 内部的事件驱动系统,其设计灵感来源于 Unix 的管道哲学:做一件事,并做好它。每个 Hook 都是一个独立的小脚本,在特定事件发生时自动执行,无需修改核心代码。🚀

这种设计带来了几个关键优势:

  1. 可扩展性:通过添加新 Hook 扩展功能,而非修改核心
  2. 可组合性:多个 Hook 可以响应同一事件,互不干扰
  3. 可维护性:每个 Hook 独立开发、测试和部署
  4. 可发现性:自动发现机制,CLI 管理

3.2 Hook 发现机制

OpenClaw 从三个目录自动发现 Hooks,按优先级顺序加载:
发现流程


Gateway 启动
扫描目录
工作区 Hooks

/hooks/
托管 Hooks

~/.openclaw/hooks/
捆绑 Hooks

/dist/hooks/bundled/
解析 HOOK.md
检查资格
符合条件?
加载处理程序
跳过
注册事件监听

优先级规则

  • 工作区 Hooks(<workspace>/hooks/):每智能体独立,最高优先级
  • 托管 Hooks(~/.openclaw/hooks/):用户安装,跨工作区共享
  • 捆绑 Hooks(<openclaw>/dist/hooks/bundled/):随 OpenClaw 附带

3.3 Hook 结构

每个 Hook 是一个独立的目录,包含两个核心文件:

复制代码
my-hook/
├── HOOK.md          # 元数据 + 文档
└── handler.ts       # 处理程序实现
3.3.1 HOOK.md 格式

HOOK.md 文件使用 YAML frontmatter 定义元数据:

markdown 复制代码
---
name: session-memory
description: "将会话上下文保存到记忆"
homepage: https://docs.openclaw.ai/automation/hooks#session-memory
metadata:
  {
    "openclaw": {
      "emoji": "💾",
      "events": ["command:new"],
      "requires": { "config": ["workspace.dir"] }
    }
  }
---

# Session Memory Hook

当用户发出 `/new` 命令时,自动保存会话上下文到记忆文件。

## 功能

- 提取最后 15 行对话
- 使用 LLM 生成描述性文件名
- 保存到 `<workspace>/memory/YYYY-MM-DD-slug.md`

元数据字段详解

字段 类型 说明
name string Hook 的唯一标识符
description string 简短描述
emoji string CLI 显示的表情符号
events string[] 监听的事件列表
requires.bins string[] 需要的二进制文件
requires.env string[] 需要的环境变量
requires.config string[] 需要的配置路径
requires.os string[] 支持的操作系统
3.3.2 处理程序实现

handler.ts 导出一个 HookHandler 函数:

typescript 复制代码
import type { HookHandler } from "../../src/hooks/hooks.js";

const sessionMemoryHandler: HookHandler = async (event) => {
  // 只处理 'new' 命令
  if (event.type !== "command" || event.action !== "new") {
    return;
  }

  console.log(`[session-memory] 保存会话上下文`);
  console.log(`  会话: ${event.sessionKey}`);
  console.log(`  时间: ${event.timestamp.toISOString()}`);

  // 获取工作区目录
  const workspaceDir = event.context.workspaceDir;
  if (!workspaceDir) {
    console.warn("[session-memory] 工作区目录未配置");
    return;
  }

  // 提取会话上下文
  const sessionEntry = event.context.sessionEntry;
  if (!sessionEntry) {
    console.warn("[session-memory] 无会话条目");
    return;
  }

  // 保存到记忆文件
  const memoryDir = path.join(workspaceDir, "memory");
  await fs.mkdir(memoryDir, { recursive: true });

  const date = new Date().toISOString().split("T")[0];
  const memoryFile = path.join(memoryDir, `${date}-session.md`);

  // 写入记忆
  const content = generateMemoryContent(sessionEntry);
  await fs.writeFile(memoryFile, content, "utf-8");

  console.log(`[session-memory] 已保存到 ${memoryFile}`);
};

export default sessionMemoryHandler;

代码解析

上述代码展示了 Hook 处理程序的核心模式。首先,通过事件类型和动作进行过滤,确保只在正确的时机执行。然后,从事件上下文中提取必要的信息(工作区目录、会话条目)。最后,执行实际的业务逻辑------创建记忆目录、生成文件名、写入内容。整个过程遵循"快速返回、优雅处理错误"的原则,避免阻塞主流程。

3.4 事件类型

OpenClaw 支持多种事件类型,覆盖智能体的完整生命周期:

3.4.1 命令事件
事件 触发时机 典型用途
command 所有命令事件 审计日志、通用监听
command:new /new 命令 保存会话快照、重置前处理
command:reset /reset 命令 清理资源、状态重置
command:stop /stop 命令 取消任务、资源释放
3.4.2 智能体事件
事件 触发时机 典型用途
agent:bootstrap 注入引导文件前 动态修改引导内容
3.4.3 Gateway 事件
事件 触发时机 典型用途
gateway:startup Gateway 启动后 初始化任务、运行 BOOT.md

3.5 捆绑的 Hooks

OpenClaw 附带三个开箱即用的 Hooks:

3.5.1 session-memory

功能 :当用户发出 /new 时,自动保存会话上下文到记忆文件。

输出示例

markdown 复制代码
# Session: 2026-03-20 16:30:00 UTC

- **会话键**: agent:main:main
- **会话 ID**: abc123def456
- **来源**: telegram
- **发送者**: +1234567890

## 最后对话

用户: 帮我总结今天的邮件
智能体: 我已经检查了您的收件箱...

启用方式

bash 复制代码
openclaw hooks enable session-memory
3.5.2 command-logger

功能:将所有命令事件记录到审计日志文件。

日志格式(JSONL):

jsonl 复制代码
{"timestamp":"2026-03-20T08:30:00.000Z","action":"new","sessionKey":"agent:main:main","senderId":"+1234567890","source":"telegram"}
{"timestamp":"2026-03-20T09:45:22.000Z","action":"stop","sessionKey":"agent:main:main","senderId":"user@example.com","source":"whatsapp"}

查看日志

bash 复制代码
# 查看最近命令
tail -n 20 ~/.openclaw/logs/commands.log

# 使用 jq 美化输出
cat ~/.openclaw/logs/commands.log | jq .

# 过滤特定动作
grep '"action":"new"' ~/.openclaw/logs/commands.log | jq .
3.5.3 boot-md

功能 :Gateway 启动时自动运行 BOOT.md 中的指令。

使用场景

  • 🌅 每日启动提醒
  • 📊 自动检查系统状态
  • 🔄 恢复中断的任务

4. Webhook 配置实战 - 飞书、GitHub、企业微信

4.1 飞书 Webhook 集成

飞书(Lark)是企业协作平台,通过 Webhook 可以将飞书机器人与 OpenClaw 连接。

4.1.1 配置步骤

第一步:创建飞书机器人

  1. 在飞书开放平台创建企业自建应用
  2. 获取 App ID 和 App Secret
  3. 配置事件订阅,设置请求地址为 OpenClaw Webhook 端点

第二步:配置 OpenClaw Webhook

json5 复制代码
{
  hooks: {
    enabled: true,
    token: "your-secure-token-here",
    path: "/hooks",
    mappings: {
      "feishu": {
        "match": {
          "source": "feishu"
        },
        "action": "agent",
        "transform": {
          "template": {
            "message": "{{body.event.message.content}}",
            "name": "Feishu",
            "sessionKey": "hook:feishu:{{body.event.sender.sender_id.user_id}}",
            "channel": "last"
          }
        }
      }
    }
  }
}

第三步:处理飞书事件

typescript 复制代码
// transforms/feishu-transform.ts
export default function transformFeishuEvent(body: any) {
  const eventType = body.header?.event_type;
  const senderId = body.event?.sender?.sender_id?.user_id;
  const message = body.event?.message?.content;

  return {
    message: `飞书消息: ${message}`,
    name: "Feishu",
    sessionKey: `hook:feishu:${senderId}`,
    wakeMode: "now",
    deliver: true,
    channel: "last"
  };
}

代码解析

这个转换函数处理飞书推送的事件数据。首先提取事件类型、发送者 ID 和消息内容,然后构造 OpenClaw 标准的 agent 请求格式。sessionKey 使用发送者 ID 作为后缀,确保每个用户有独立的会话上下文。wakeMode: "now" 确保消息立即处理,deliver: true 让响应自动发送回飞书。

4.1.2 飞书事件处理流程

智能体 Transform 模块 OpenClaw Gateway 飞书服务器 智能体 Transform 模块 OpenClaw Gateway 飞书服务器 POST /hooks/feishu 事件数据 验证签名 转换请求体 标准 agent 请求 启动智能体 处理消息 响应结果 回调飞书 API

4.2 GitHub Webhook 集成

GitHub Webhook 可以让 OpenClaw 响应代码仓库事件,如 Push、Pull Request、Issue 等。

4.2.1 配置步骤

第一步:创建 GitHub Webhook

  1. 进入仓库 Settings → Webhooks → Add webhook
  2. Payload URL 设置为 http://your-server:18789/hooks/github
  3. Content type 选择 application/json
  4. Secret 设置为与 OpenClaw 配置相同的 token
  5. 选择要监听的事件类型

第二步:配置 OpenClaw

json5 复制代码
{
  hooks: {
    enabled: true,
    token: "github-webhook-secret",
    mappings: {
      "github": {
        "match": {
          "header": {
            "x-github-event": "*"
          }
        },
        "action": "agent",
        "transform": {
          "module": "./transforms/github-transform.ts"
        }
      }
    }
  }
}

第三步:实现转换模块

typescript 复制代码
// transforms/github-transform.ts
interface GitHubWebhookBody {
  action?: string;
  repository: {
    full_name: string;
    html_url: string;
  };
  sender: {
    login: string;
  };
  pull_request?: {
    title: string;
    number: number;
    body: string;
  };
  issue?: {
    title: string;
    number: number;
    body: string;
  };
}

export default function transformGitHubEvent(
  body: GitHubWebhookBody,
  headers: Record<string, string>
) {
  const eventType = headers["x-github-event"];
  const repo = body.repository.full_name;
  const sender = body.sender.login;

  let message = "";

  switch (eventType) {
    case "pull_request":
      message = `GitHub PR #${body.pull_request?.number}: ${body.pull_request?.title}\n` +
                `仓库: ${repo}\n` +
                `作者: ${sender}\n` +
                `动作: ${body.action}`;
      break;
    case "issues":
      message = `GitHub Issue #${body.issue?.number}: ${body.issue?.title}\n` +
                `仓库: ${repo}\n` +
                `作者: ${sender}\n` +
                `动作: ${body.action}`;
      break;
    case "push":
      message = `GitHub Push to ${repo}\n` +
                `推送者: ${sender}`;
      break;
    default:
      message = `GitHub 事件: ${eventType} on ${repo}`;
  }

  return {
    message,
    name: "GitHub",
    sessionKey: `hook:github:${repo}`,
    wakeMode: "now",
    deliver: true
  };
}

代码解析

这个转换模块处理多种 GitHub 事件类型。通过检查 x-github-event 头判断事件类型,然后提取相关信息构造描述性消息。对于 Pull Request 事件,提取 PR 编号、标题和动作;对于 Issue 事件,提取 Issue 编号和标题;对于 Push 事件,提取推送者信息。sessionKey 使用仓库名作为后缀,确保每个仓库有独立的会话上下文。

4.3 企业微信 Webhook 集成

企业微信(WeCom)是企业级通讯工具,通过 Webhook 可以将企业微信机器人与 OpenClaw 连接。

4.3.1 配置步骤

第一步:创建企业微信机器人

  1. 在企业微信管理后台创建群机器人
  2. 获取 Webhook URL 和签名密钥

第二步:配置 OpenClaw

json5 复制代码
{
  hooks: {
    enabled: true,
    token: "wecom-webhook-secret",
    mappings: {
      "wecom": {
        "match": {
          "source": "wecom"
        },
        "action": "agent",
        "transform": {
          "module": "./transforms/wecom-transform.ts"
        },
        "deliver": true,
        "channel": "last"
      }
    }
  }
}

第三步:实现签名验证

typescript 复制代码
// transforms/wecom-transform.ts
import crypto from "crypto";

function verifyWecomSignature(
  body: string,
  timestamp: string,
  nonce: string,
  signature: string,
  token: string
): boolean {
  // 企业微信签名验证算法
  const arr = [token, timestamp, nonce].sort();
  const sha1 = crypto.createHash("sha1");
  sha1.update(arr.join(""));
  return sha1.digest("hex") === signature;
}

export default function transformWecomEvent(
  body: any,
  headers: Record<string, string>
) {
  const timestamp = headers["timestamp"];
  const nonce = headers["nonce"];
  const signature = headers["msg_signature"];

  // 验证签名(可选,建议启用)
  // if (!verifyWecomSignature(JSON.stringify(body), timestamp, nonce, signature, "your-token")) {
  //   throw new Error("签名验证失败");
  // }

  const message = body.Content || body.Event || "企业微信事件";
  const fromUser = body.FromUserName;

  return {
    message: `企业微信消息: ${message}`,
    name: "WeCom",
    sessionKey: `hook:wecom:${fromUser}`,
    wakeMode: "now",
    deliver: true,
    channel: "last"
  };
}

代码解析

企业微信的签名验证是安全的关键。这个模块实现了标准的签名验证算法:将 token、timestamp、nonce 按字典序排序后拼接,计算 SHA1 哈希值,与传入的签名比对。验证通过后,提取消息内容和发送者,构造 OpenClaw 标准请求格式。sessionKey 使用发送者 ID 作为后缀,确保每个用户有独立的会话。


5. Hooks 开发指南 - 自定义钩子函数

5.1 创建自定义 Hook

让我们通过一个实际案例------自动备份 Hook,来学习如何创建自定义 Hook。

5.1.1 需求分析

目标 :当用户发出 /reset 命令时,自动备份当前会话到指定目录。

要求

  • 备份文件以时间戳命名
  • 包含会话元数据和对话历史
  • 支持配置备份目录
5.1.2 创建 Hook 目录
bash 复制代码
mkdir -p ~/.openclaw/hooks/session-backup
cd ~/.openclaw/hooks/session-backup
5.1.3 编写 HOOK.md
markdown 复制代码
---
name: session-backup
description: "重置会话前自动备份会话数据"
metadata:
  {
    "openclaw": {
      "emoji": "💾",
      "events": ["command:reset"],
      "requires": { "config": ["workspace.dir"] }
    }
  }
---

# Session Backup Hook

在用户发出 `/reset` 命令时,自动备份当前会话数据。

## 功能

- 创建备份目录(如果不存在)
- 生成带时间戳的备份文件名
- 保存会话元数据和对话历史
- 记录备份日志

## 配置

在 Gateway 配置中设置:

{
  "hooks": {
    "internal": {
      "entries": {
        "session-backup": {
          "enabled": true,
          "env": {
            "BACKUP_DIR": "/path/to/backups"
          }
        }
      }
    }
  }
}

## 输出

备份文件保存在 `$BACKUP_DIR/YYYY-MM-DD/HH-MM-SS-session.json`
5.1.4 编写处理程序
typescript 复制代码
// handler.ts
import type { HookHandler } from "../../src/hooks/hooks.js";
import fs from "fs/promises";
import path from "path";

const sessionBackupHandler: HookHandler = async (event) => {
  // 只处理 reset 命令
  if (event.type !== "command" || event.action !== "reset") {
    return;
  }

  console.log("[session-backup] 开始备份会话...");

  // 获取配置
  const backupDir = process.env.BACKUP_DIR || 
    path.join(event.context.workspaceDir || "", "backups");
  
  const sessionEntry = event.context.sessionEntry;
  if (!sessionEntry) {
    console.warn("[session-backup] 无会话条目,跳过备份");
    return;
  }

  try {
    // 创建备份目录
    const now = new Date();
    const dateDir = now.toISOString().split("T")[0];
    const timeStr = now.toTimeString().split(" ")[0].replace(/:/g, "-");
    const backupPath = path.join(backupDir, dateDir);
    await fs.mkdir(backupPath, { recursive: true });

    // 构造备份数据
    const backupData = {
      timestamp: now.toISOString(),
      sessionKey: event.sessionKey,
      sessionId: event.context.sessionId,
      source: event.context.commandSource,
      senderId: event.context.senderId,
      history: sessionEntry.history || [],
      metadata: {
        messageCount: sessionEntry.history?.length || 0,
        workspaceDir: event.context.workspaceDir
      }
    };

    // 写入备份文件
    const backupFile = path.join(backupPath, `${timeStr}-session.json`);
    await fs.writeFile(
      backupFile,
      JSON.stringify(backupData, null, 2),
      "utf-8"
    );

    console.log(`[session-backup] 备份完成: ${backupFile}`);
    
    // 通知用户
    event.messages.push(`💾 会话已备份到: ${backupFile}`);
  } catch (err) {
    console.error("[session-backup] 备份失败:", err);
    // 不抛出错误,让其他 handlers 继续执行
  }
};

export default sessionBackupHandler;

代码解析

这个 Hook 实现了完整的会话备份功能。首先,通过事件过滤确保只在 /reset 命令时执行。然后,从环境变量或工作区目录获取备份路径,创建按日期组织的目录结构。备份数据包含会话的完整信息:时间戳、会话键、来源、发送者 ID、对话历史和元数据。最后,将数据写入 JSON 文件,并通过 event.messages 通知用户备份完成。整个过程使用 try-catch 包装,确保错误不会中断其他 Hooks 的执行。

5.2 测试与调试

5.2.1 验证 Hook 发现
bash 复制代码
# 列出所有发现的 Hooks
openclaw hooks list

# 查看详细信息
openclaw hooks info session-backup

# 检查资格
openclaw hooks check
5.2.2 启用并测试
bash 复制代码
# 启用 Hook
openclaw hooks enable session-backup

# 重启 Gateway
openclaw gateway restart

# 触发事件(发送 /reset 命令)
# 检查备份目录
ls -la ~/.openclaw/workspace/backups/
5.2.3 查看日志
bash 复制代码
# 查看 Gateway 日志
tail -f ~/.openclaw/gateway.log | grep session-backup

# 或使用脚本(macOS)
./scripts/clawlog.sh -f | grep session-backup

5.3 最佳实践

5.3.1 保持处理程序快速
typescript 复制代码
// ✅ 好的做法 - 异步执行,立即返回
const handler: HookHandler = async (event) => {
  void processInBackground(event); // Fire and forget
};

// ❌ 不好的做法 - 阻塞命令处理
const handler: HookHandler = async (event) => {
  await slowDatabaseQuery(event);
  await evenSlowerAPICall(event);
};
5.3.2 优雅处理错误
typescript 复制代码
const handler: HookHandler = async (event) => {
  try {
    await riskyOperation(event);
  } catch (err) {
    console.error("[my-handler] 失败:", err instanceof Error ? err.message : String(err));
    // 不要抛出错误 - 让其他 handlers 继续执行
  }
};
5.3.3 尽早过滤事件
typescript 复制代码
const handler: HookHandler = async (event) => {
  // 只处理特定事件
  if (event.type !== "command" || event.action !== "new") {
    return;
  }

  // 你的逻辑...
};

6. 安全与最佳实践

6.1 Webhook 安全

6.1.1 令牌管理
实践 说明
🔑 使用强随机令牌 至少 32 字符的随机字符串
🔄 定期轮换 建议每 90 天更换一次
🚫 不复用 不要复用 Gateway 认证令牌
📝 安全存储 使用环境变量或密钥管理服务
6.1.2 网络安全

安全边界
HTTPS
HTTP
外部系统
反向代理

Nginx/Caddy
OpenClaw Gateway

localhost:18789
防火墙规则
TLS 终止
请求过滤

建议配置

  • 将 Webhook 端点保持在 loopback、tailnet 或受信任的反向代理之后
  • 使用 HTTPS 加密传输
  • 配置 IP 白名单(如果可能)
  • 启用请求速率限制
6.1.3 请求体验证

OpenClaw 默认将 Webhook 请求体视为不可信,使用安全边界包装。如果需要访问原始请求体:

json5 复制代码
{
  hooks: {
    mappings: {
      "trusted-source": {
        "match": { "source": "internal-system" },
        "allowUnsafeExternalContent": true  // 危险!仅用于受信任的内部来源
      }
    }
  }
}

6.2 Hooks 安全

6.2.1 权限隔离

Hooks 在 Gateway 进程内执行,继承 Gateway 的权限。建议:

  • 📁 限制文件系统访问范围
  • 🔐 避免在 Hooks 中存储敏感信息
  • 📋 审计 Hook 代码,确保没有恶意操作
6.2.2 资源控制
typescript 复制代码
// 设置超时
const handler: HookHandler = async (event) => {
  const timeout = setTimeout(() => {
    throw new Error("操作超时");
  }, 5000);

  try {
    await yourOperation(event);
  } finally {
    clearTimeout(timeout);
  }
};

6.3 监控与日志

6.3.1 日志配置
json5 复制代码
{
  logging: {
    level: "info",
    hooks: {
      enabled: true,
      includePayload: false  // 不记录敏感的请求体
    }
  }
}
6.3.2 监控指标
指标 说明 告警阈值
Webhook 请求量 每分钟请求数 > 100/min
认证失败率 401 响应占比 > 5%
Hook 执行时间 平均执行时长 > 1s
Hook 错误率 执行失败占比 > 1%

7. 总结

OpenClaw 的 Webhook 与 Hooks 机制共同构建了一套完整的事件驱动自动化体系,为智能体系统提供了强大的扩展能力。通过本文的深入剖析,我们可以得出以下关键结论:

Webhook 的核心价值 在于打通外部世界与 OpenClaw 的连接。它采用标准的 HTTP 协议,支持多种认证方式,提供了灵活的请求映射和转换机制。无论是飞书、GitHub 还是企业微信,都可以通过简单的配置实现与 OpenClaw 的无缝集成。/hooks/wake 端点适合轻量级的事件通知,而 /hooks/agent 端点则支持隔离的智能体执行,满足不同场景的需求。

Hooks 的核心价值在于提供内部事件的响应能力。通过自动发现机制和标准化的目录结构,开发者可以轻松创建、部署和管理自定义 Hooks。三个捆绑的 Hooks(session-memory、command-logger、boot-md)展示了 Hooks 的典型应用场景,为开发者提供了良好的参考范例。

安全是自动化的基石。无论是 Webhook 的令牌认证和网络隔离,还是 Hooks 的权限控制和资源限制,都需要开发者给予足够的重视。通过遵循最佳实践,可以在享受自动化便利的同时,确保系统的安全性和稳定性。

实践建议:从小规模开始,先启用捆绑的 Hooks 熟悉机制,再逐步添加自定义功能。对于 Webhook 集成,建议先在测试环境验证,确保签名验证和错误处理正确后再部署到生产环境。定期审查日志和监控指标,及时发现和解决潜在问题。

OpenClaw 的事件驱动架构体现了现代智能体系统的设计哲学:开放、可扩展、安全。掌握 Webhook 和 Hooks,就是掌握了 OpenClaw 自动化能力的钥匙。🚀


8. 参考资料

  1. OpenClaw 官方文档 - Webhook
  2. OpenClaw 官方文档 - Hooks
  3. OpenClaw CLI 参考
  4. 飞书开放平台文档
  5. GitHub Webhook 文档
  6. 企业微信 API 文档
相关推荐
光影少年2 小时前
Python+LangGraph学习路线及发展前景
开发语言·人工智能·python·学习
天天进步20152 小时前
不止于 UI:OpenWork 的核心哲学与“引擎+外壳”架构全景图
人工智能·ui·架构
刘 大 望2 小时前
RAG相关技术介绍及Spring AI中使用--第三期
java·人工智能·后端·spring·机器学习·ai·aigc
Mr数据杨2 小时前
成人收入预测建模与信用评估应用
大数据·人工智能·机器学习·数据分析·kaggle
NOCSAH2 小时前
统好AI:Java技术生态下的智能知识管理新选择
java·开发语言·人工智能
大江东去浪淘尽千古风流人物2 小时前
【cuVSLAM】项目解析:一套偏工程实战的 GPU 紧耦合视觉惯性 SLAM
数据库·人工智能·python·机器学习·oracle
田井中律.2 小时前
知识图谱(使用doccano完成关系抽取)【第九章】
人工智能·知识图谱
阿杰学AI2 小时前
AI核心知识132—大语言模型之 AI for Science(简洁且通俗易懂版)
人工智能·ai·语言模型·自然语言处理·aigc·ai for science·ai4s
Yuanxl9032 小时前
Torchvision 0.26:深度学习视觉库全面解析
网络·人工智能·pytorch·深度学习