🎯 学习目标:理解 Webhook 的工作原理,并搭建一个 GitHub PR/Issue 分诊机器人,自动将代码评审建议推送到 Telegram 或飞书。
概念:门铃 vs 闹钟
在前面的 Day 5 和 Day 6,我们学过两种"主动出击"的方式:
- Cron 像手机闹钟,每天早 8 点响,不管有没有新事情发生。
- Heartbeat 像你自己定时去查邮件,每隔 N 分钟主动问一句"有什么新消息吗"。
这两种方式有一个共同缺点:它们不知道事件什么时候发生。假设你的 GitHub 仓库凌晨 3 点来了一个紧急 PR,Cron 要等到早上才会通知你,中间可能错过了 8 小时。
Webhook 是门铃。GitHub 一发生事件(PR 新开、Issue 被评论),就立刻按响你家的门铃,你的 Agent 即时醒来处理。主动权从你这边转移到了外部系统。
Cron/Heartbeat: 你 → 每隔一段时间 → 问有什么新消息?
Webhook: 外部系统 → 事件发生时 → 主动推送给你
OpenClaw 内置了一个轻量 HTTP 服务端,只需在配置里开启,就能接收来自任何第三方系统的 Webhook 请求。
实战案例:GitHub PR 分诊机器人
场景:你维护着一个开源项目,每天都可能有新的 PR 和 Issue。你不可能每次都亲自去 GitHub 看一眼再决定要不要处理。我们要搭建的是:
- GitHub 有新 PR 或 Issue → 自动触发 Webhook
- OpenClaw 收到后,调用一个专门的"代码评审 Agent"
- Agent 分析:要不要看?有什么风险点?建议怎么回复?
- 把分析报告直接推送到你的 Telegram 或飞书
整体数据流如下:
flowchart LR
GitHub["GitHub<br> PR/Issue 事件"] -- POST /hooks/github --> OC["OpenClaw <br> Webhook 服务"]
OC -- Mapping 解析<br>组装 message --> Agent["hooks Agent<br>代码评审专家"]
Agent -- 分析报告 --> Deliver["deliver: true"]
Deliver -- channel: telegram --> TG["Telegram / 飞书<br>收到分诊报告"]
Step 1:启用 Webhook 服务
打开 ~/.openclaw/openclaw.json,添加 hooks 配置块:
5
{
"hooks": {
"enabled": true,
// 用于验证请求合法性的共享密钥,不能为空
"token": "your-secret-token-here",
"path": "/hooks",
// 默认会话 key,所有 hook 触发的 Agent 共用这个会话隔离空间
"defaultSessionKey": "hook:github",
"allowRequestSessionKey": false,
"allowedSessionKeyPrefixes": ["hook:"],
// 只允许路由到 main 和 hooks 这两个 Agent
"allowedAgentIds": ["main", "hooks"]
}
}
然后在你的 Shell 环境中设置密钥(建议加入 ~/.zshrc 或 ~/.bashrc):
export OPENCLAW_HOOKS_TOKEN="your-secret-token-here"
密钥选取原则:随机生成一个至少 32 位的字符串,不要用简单的单词。可以用以下命令生成:
openssl rand -hex 24
# 输出示例:a7f3c2d8e1b4096f5a23c7d9e0b1f4a2e3d6c8b5
重启 OpenClaw 使配置生效:
openclaw gateway restart
此时,OpenClaw 已经在监听 POST http://127.0.0.1:18789/hooks/{mapping名称} 端点了。例如,当你在后面的 Step 3 中添加名为 github 的 mapping 后,对应端点就是 /hooks/github。
Step 2:创建代码评审专属 Agent
Webhook 请求需要一个专门的 Agent 来处理,而不是直接污染你日常对话的主 Agent。
# 创建名为 "hooks" 的专属 Agent
openclaw agents add hooks
这条命令会在 ~/.openclaw/workspace-hooks/ 下初始化一套独立的工作区。接下来为它配置专业人格,编辑 ~/.openclaw/workspace-hooks/SOUL.md:
你是一位资深代码评审助手,专门处理 GitHub PR 和 Issue 的快速分诊。
每当收到一条 PR 或 Issue 信息,你需要按照以下格式给出分诊报告:
## 📋 [PR/Issue 标题]
**🔴 优先级**:[紧急 / 普通 / 可忽略]
- 判断依据:(说明为什么这个优先级)
**⚠️ 风险点**:
- (列出 1-3 个潜在的技术风险或需要关注的点;如果是新功能 PR 则关注安全性/破坏性变更;如果是 Bug Issue 则关注影响范围)
**💬 建议回复**:
(给出一段可以直接复制粘贴的回复模板,语气友好专业)
---
回复要简洁,控制在 200 字以内。如果信息不足以判断风险,直接说明需要查看具体代码。
Step 3:配置 GitHub Webhook Mapping
OpenClaw 的 hooks.mappings 功能允许你把任意 HTTP payload 转换成 Agent 可以理解的指令。这是整个流程的核心配置。
在 openclaw.json 中添加 mappings 字段:
5
{
"hooks": {
"enabled": true,
"token": "your-secret-token-here",
"path": "/hooks",
"defaultSessionKey": "hook:github",
"allowRequestSessionKey": false,
"allowedSessionKeyPrefixes": ["hook:"],
"allowedAgentIds": ["main", "hooks"],
"mappings": [
{
"name": "github",
"action": "agent",
// 路由到专门的 hooks Agent
"agentId": "hooks",
// 分析完成后推送到 Telegram(改成 "feishu" 即可切换到飞书)
"deliver": true,
"channel": "telegram",
// 用 {{}} 模板语法从 GitHub payload 中提取字段,组装成 messageTemplate
"messageTemplate": "请对以下 GitHub 事件进行分诊:\n\n类型:{{action}} {{pull_request.title}}{{issue.title}}\n作者:{{pull_request.user.login}}{{issue.user.login}}\n仓库:{{repository.full_name}}\n链接:{{pull_request.html_url}}{{issue.html_url}}\n描述:{{pull_request.body}}{{issue.body}}"
}
]
}
}
模板语法说明:字段名是messageTemplate(不是message)。{{pull_request.title}}会从 GitHub 发来的 JSON payload 中提取对应字段。PR 事件和 Issue 事件的 payload 结构不同,{{pull_request.title}}{{issue.title}}这种写法是把两个字段拼在一起——实际只有一个会有值,另一个为空,所以结果是对的。
重启 OpenClaw:
openclaw gateway restart
Step 4:注册 GitHub Webhook
出于安全考虑,不建议使用本机来测试,请在服务器上测试。
OpenClaw 默认只监听 127.0.0.1:18789(本机回环),无法被外网直接访问。建议用 nginx 在 80 端口接收外部请求,再转发给本机的 18789。
# 安装 nginx(CentOS/OpenCloudOS)
yum install -y nginx
# 写 nginx 配置,只暴露 /hooks/ 路径
# 注意:需要在转发时注入 Authorization 头,因为 GitHub 原生 Webhook 不会自动携带它
cat > /etc/nginx/conf.d/openclaw-hooks.conf << 'EOF'
server {
listen 80;
server_name _;
location /hooks/ {
proxy_pass http://127.0.0.1:18789;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 把 OpenClaw token 在转发时注入(替换成你的实际 token)
# 注意:这里的 token 是 OpenClaw 用于身份验证的令牌,和下面 GitHub 填写的 Secret 是两回事
proxy_set_header Authorization "Bearer your-token-here";
}
}
EOF
systemctl enable --now nginx
然后在云服务器控制台安全组中放行 TCP 80 端口的入站流量(18789 无需对外暴露)。
安全性说明:这个方案的安全边界依赖hooks.token。每个请求必须携带正确的Authorization: Bearer才会被处理,错误 token 会触发 429 限速。只要 token 足够随机(openssl rand -hex 24生成),暴力破解的成本极高。/hooks/以外的路径不会被 nginx 转发,其余端口也保持关闭。
得到公网地址后,前往 GitHub:
- 打开你的仓库 → Settings → Webhooks → Add webhook
- Payload URL:
http://你的服务器IP/hooks/github - Content type:选
application/json - Secret:可以留空,或填写任意字符串(此处 GitHub 的 Secret 是用于计算 HMAC 签名的,OpenClaw 当前版本不做签名校验,访问控制由 nginx 注入的
Authorization头承担) - Which events:选
Let me select individual events,勾选:- ✅ Pull requests
- ✅ Issues
- 确保 Active 已勾选,点击 Add webhook
GitHub 会立即发一个 ping 事件测试连通性,你可以在 Webhooks 页面看到绿色勾表示成功。
Step 5:本地测试验证
不需要真的去 GitHub 提一个 PR,可以用 curl 模拟 GitHub 发来的 payload:
# 模拟一个 PR 事件
curl -X POST http://127.0.0.1:18789/hooks/github \
-H 'Authorization: Bearer your-secret-token-here' \
-H 'Content-Type: application/json' \
-d '{
"action": "opened",
"pull_request": {
"title": "feat: 新增用户认证模块,使用 JWT",
"user": { "login": "contributor-alice" },
"html_url": "https://github.com/your-org/your-repo/pull/42",
"body": "本 PR 引入了 JWT 认证。修改了 auth/middleware.ts,移除了旧的 session 机制,并新增了 /api/token 端点。影响所有需要登录的接口。"
},
"repository": { "full_name": "your-org/your-repo" }
}'
预期:
- 命令返回
200 OK - 几秒后,你的 Telegram 或飞书收到一条类似这样的消息:
📋 feat: 新增用户认证模块,使用 JWT
🔴 优先级:紧急
- 判断依据:涉及认证机制的破坏性变更,移除了旧 session 系统
⚠️ 风险点:
- JWT 密钥管理:需确认 secret 是否通过环境变量注入,不能硬编码
- 向后兼容性:移除 session 机制会导致已登录用户被强制登出
- /api/token 端点安全:需检查是否有速率限制防止暴力破解
💬 建议回复:
感谢贡献!这个 PR 引入了认证机制的重要变更。在合并前,能否确认:1)JWT secret 的存储方式;2)是否有迁移方案避免现有用户被登出;3)新端点是否已有限流保护?
下面是实际测试结果截图:

常见问题排查
收到 401 Unauthorized
- 检查
Authorization: Bearer的 token 值是否与配置一致
收到 400 Bad Request
- 检查
Content-Type: application/json是否已设置 - 检查 JSON 格式是否合法(可用
jq校验)
消息没有推送到 Telegram/飞书
- 确认
openclaw.json中deliver: true和channel已正确设置 - 确认 Telegram Bot 或飞书渠道已在
channels中配置并正常工作 - 用
openclaw gateway logs查看实时日志
✅ 今日练习
- 在
openclaw.json中启用 hooks,重启后用 Step 5 的 curl 命令测试/hooks/github端点能正常返回200 - 配置 GitHub Mapping,用模拟 payload 验证分诊报告能推送到 Telegram 或飞书
- (进阶)修改 Mapping 的
channel字段,尝试同时推送到两个渠道
完整配置参考:examples/webhooks/github-pr-triage.json