字节笔记本
2026年6月21日
hermes教程-使用 Webhooks 自动生成 GitHub PR 评论
本指南将引导您将 Hermes Agent 连接到 GitHub,使其能够自动获取拉取请求的 diff、分析代码更改,并在 Webhook 事件触发时自动发布评论,无需手动提示。
当 PR 被打开或更新时,GitHub 会向您的 Hermes 实例发送一个 Webhook POST 请求。Hermes 运行代理,并附带一个提示,指示其通过 gh CLI 检索 diff,然后将响应发布回 PR 线程。
提示 — 想要更简单的设置,无需公共端点?
如果您没有公共 URL,或者只是想快速上手,请查看构建 GitHub PR 审查代理 — 它使用 cron 作业按计划轮询 PR,可在 NAT 和防火墙后工作。
信息 — 参考文档
有关 Webhook 平台的完整参考(所有配置选项、投递类型、动态订阅、安全模型),请参阅 Webhooks。
警告 — 提示注入风险
Webhook 负载包含攻击者控制的数据 — PR 标题、提交消息和描述可能包含恶意指令。当您的 Webhook 端点暴露在互联网上时,请在沙箱环境(Docker、SSH 后端)中运行网关。请参阅下面的安全部分。
先决条件
- Hermes Agent 已安装并运行(
hermes gateway) - 在网关主机上安装并认证了
ghCLI(gh auth login) - 您的 Hermes 实例有一个可公开访问的 URL(如果在本地运行,请参阅使用 ngrok 进行本地测试)
- 对 GitHub 仓库的管理员访问权限(需要管理 Webhook)
步骤 1 — 启用 Webhook 平台
将以下内容添加到您的 ~/.hermes/config.yaml 中:
platforms:
webhook:
enabled: true
extra:
port: 8644 # default; change if another service occupies this port
rate_limit: 30 # max requests per minute per route (not a global cap)
routes:
github-pr-review:
secret: "your-webhook-secret-here" # must match the GitHub webhook secret exactly
events:
- pull_request
## The agent is instructed to fetch the actual diff before reviewing.
## {number} and {repository.full_name} are resolved from the GitHub payload.
prompt: |
A pull request event was received (action: {action}).
PR #{number}: {pull_request.title}
Author: {pull_request.user.login}
Branch: {pull_request.head.ref} → {pull_request.base.ref}
Description: {pull_request.body}
URL: {pull_request.html_url}
If the action is "closed" or "labeled", stop here and do not post a comment.
Otherwise:
1. Run: gh pr diff {number} --repo {repository.full_name}
2. Review the code changes for correctness, security issues, and clarity.
3. Write a concise, actionable review comment and post it.
deliver: github_comment
deliver_extra:
repo: "{repository.full_name}"
pr_number: "{number}"关键字段:
| 字段 | 描述 |
|---|---|
secret(路由级别) | 此路由的 HMAC 密钥。如果省略,则回退到全局的 extra.secret。 |
events | 要接受的 X-GitHub-Event 标头值列表。空列表 = 接受所有。 |
prompt | 模板;{field} 和 {nested.field} 从 GitHub 负载中解析。 |
deliver | github_comment 通过 gh pr comment 发布。log 仅写入网关日志。 |
deliver_extra.repo | 解析为例如负载中的 org/repo。 |
deliver_extra.pr_number | 解析为负载中的 PR 编号。 |
注意 — 负载不包含代码
GitHub Webhook 负载包含 PR 元数据(标题、描述、分支名称、URL),但不包含 diff。上面的提示指示代理运行
gh pr diff来获取实际更改。terminal工具包含在默认的hermes-webhook工具集中,因此无需额外配置。
步骤 2 — 启动网关
hermes gateway您应该看到:
[webhook] Listening on 0.0.0.0:8644 — routes: github-pr-review
验证它正在运行:
curl http://localhost:8644/health
## {"status": "ok", "platform": "webhook"}步骤 3 — 在 GitHub 上注册 Webhook
- 转到您的仓库 → 设置 → Webhooks → 添加 Webhook
- 填写:
- Payload URL:
https://your-public-url.example.com/webhooks/github-pr-review - Content type:
application/json - Secret: 与您在路由配置中设置的
secret相同的值 - Which events? → 选择单个事件 → 勾选 Pull requests
- Payload URL:
- 点击 添加 Webhook
GitHub 将立即发送一个 ping 事件以确认连接。它会被安全地忽略 — ping 不在您的 events 列表中 — 并返回 {"status": "ignored", "event": "ping"}。它仅在 DEBUG 级别记录,因此在默认日志级别下不会出现在控制台中。
步骤 4 — 打开一个测试 PR
创建一个分支,推送更改,然后打开一个 PR。在 30–90 秒内(取决于 PR 大小和模型),Hermes 应该会发布一条审查评论。
要实时跟踪代理的进度:
tail -f "${HERMES_HOME:-$HOME/.hermes}/logs/gateway.log"使用 ngrok 进行本地测试
如果 Hermes 在您的笔记本电脑上运行,请使用 ngrok 将其暴露:
ngrok http 8644复制 https://...ngrok-free.app URL 并将其用作您的 GitHub Payload URL。在免费 ngrok 层级上,每次 ngrok 重启时 URL 都会更改 — 每次会话更新您的 GitHub Webhook。付费 ngrok 账户可以获得静态域名。
您可以直接使用 curl 对静态路由进行冒烟测试 — 无需 GitHub 账户或真实 PR。
提示 — 在本地测试时使用
deliver: log在测试时,将配置中的
deliver: github_comment更改为deliver: log。否则,代理将尝试向测试负载中的虚假org/repo#99仓库发布评论,这将失败。当您对提示输出满意后,再切换回deliver: github_comment。
SECRET="your-webhook-secret-here"
BODY='{"action":"opened","number":99,"pull_request":{"title":"Test PR","body":"Adds a feature.","user":{"login":"testuser"},"head":{"ref":"feat/x"},"base":{"ref":"main"},"html_url":"https://github.com/org/repo/pull/99"},"repository":{"full_name":"org/repo"}}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print "sha256="$2}')
curl -s -X POST http://localhost:8644/webhooks/github-pr-review \
-H "Content-Type: application/json" \
-H "X-GitHub-Event: pull_request" \
-H "X-Hub-Signature-256: $SIG" \
-d "$BODY"
## Expected: {"status":"accepted","route":"github-pr-review","event":"pull_request","delivery_id":"..."}然后观察代理运行:
tail -f "${HERMES_HOME:-$HOME/.hermes}/logs/gateway.log"注意
hermes webhook test <name>仅适用于使用hermes webhook subscribe创建的动态订阅。它不会从config.yaml中读取路由。
过滤特定操作
GitHub 会为许多操作发送 pull_request 事件:opened、synchronize、reopened、closed、labeled 等。events 列表仅根据 X-GitHub-Event 标头值进行过滤 — 它无法在路由级别按操作子类型进行过滤。
步骤 1 中的提示已经通过指示代理对 closed 和 labeled 事件提前停止来处理此问题。
警告 — 代理仍然运行并消耗令牌
“在此停止”指令阻止了有意义的审查,但代理仍然会为每个
pull_request事件运行到完成,无论操作是什么。GitHub Webhook 只能按事件类型(pull_request、push、issues等)进行过滤 — 不能按操作子类型(opened、closed、labeled)进行过滤。没有用于子操作的路由级别过滤器。对于高流量仓库,请接受此成本,或者使用 GitHub Actions 工作流有条件地调用您的 Webhook URL 进行上游过滤。
没有 Jinja2 或条件模板语法。
{field}和{nested.field}是唯一支持的替换。其他所有内容都原样传递给代理。
使用技能实现一致的审查风格
加载一个 Hermes 技能 来为代理赋予一致的审查角色。在 config.yaml 的 platforms.webhook.extra.routes 中的路由内添加 skills:
platforms:
webhook:
enabled: true
extra:
routes:
github-pr-review:
secret: "your-webhook-secret-here"
events: [pull_request]
prompt: |
A pull request event was received (action: {action}).
PR #{number}: {pull_request.title} by {pull_request.user.login}
URL: {pull_request.html_url}
If the action is "closed" or "labeled", stop here and do not post a comment.
Otherwise:
1. Run: gh pr diff {number} --repo {repository.full_name}
2. Review the diff using your review guidelines.
3. Write a concise, actionable review comment and post it.
skills:
- review
deliver: github_comment
deliver_extra:
repo: "{repository.full_name}"
pr_number: "{number}"注意: 仅加载列表中找到的第一个技能。Hermes 不会堆叠多个技能 — 后续条目将被忽略。
将响应发送到 Slack 或 Discord
将路由内的 deliver 和 deliver_extra 字段替换为目标平台:
## Inside platforms.webhook.extra.routes.<route-name>:
## Slack
deliver: slack
deliver_extra:
chat_id: "C0123456789" # Slack channel ID (omit to use the configured home channel)
## Discord
deliver: discord
deliver_extra:
chat_id: "987654321012345678" # Discord channel ID (omit to use home channel)目标平台也必须在网关中启用并连接。如果省略 chat_id,则响应将发送到该平台配置的主频道。
有效的 deliver 值:log · github_comment · telegram · discord · slack · signal · sms
GitLab 支持
相同的适配器适用于 GitLab。GitLab 使用 X-Gitlab-Token 进行身份验证(纯字符串匹配,不是 HMAC)— Hermes 会自动处理两者。
对于事件过滤,GitLab 将 X-GitLab-Event 设置为诸如 Merge Request Hook、Push Hook、Pipeline Hook 等值。在 events 中使用确切的标头值:
events:
- Merge Request HookGitLab 负载字段与 GitHub 不同 — 例如,MR 标题使用 {object_attributes.title},MR 编号使用 {object_attributes.iid}。发现完整负载结构的最简单方法是使用 GitLab Webhook 设置中的测试按钮,结合最近投递日志。或者,从路由配置中省略 prompt — Hermes 会将完整负载作为格式化 JSON 直接传递给代理,代理的响应(在网关日志中可见,使用 deliver: log)将描述其结构。
安全说明
- 切勿在生产中使用
INSECURE_NO_AUTH— 它会完全禁用签名验证。仅用于本地开发。 - 定期轮换您的 Webhook 密钥,并在 GitHub(Webhook 设置)和您的
config.yaml中更新它。 - 速率限制 默认为每条路由 30 次请求/分钟(可通过
extra.rate_limit配置)。超出限制将返回429。 - 重复投递(Webhook 重试)通过 1 小时的幂等性缓存进行去重。缓存键是
X-GitHub-Delivery(如果存在),然后是X-Request-ID,然后是毫秒时间戳。当两个投递 ID 标头都未设置时,重试不会被去重。 - 提示注入: PR 标题、描述和提交消息由攻击者控制。恶意 PR 可能试图操纵代理的操作。当网关暴露在公共互联网上时,请在沙箱环境(Docker、VM)中运行。
故障排除
| 症状 | 检查 |
|---|---|
401 Invalid signature | config.yaml 中的密钥与 GitHub Webhook 密钥不匹配 |
404 Unknown route | URL 中的路由名称与 routes: 中的键不匹配 |
429 Rate limit exceeded | 每条路由 30 次请求/分钟已超出 — 常见于从 GitHub UI 重新投递测试事件时;等待一分钟或提高 extra.rate_limit |
| 未发布评论 | gh 未安装、不在 PATH 中或未认证(gh auth login) |
| 代理运行但无评论 | 检查网关日志 — 如果代理输出为空或仅为“SKIP”,仍会尝试投递 |
| 端口已被占用 | 更改 config.yaml 中的 extra.port |
| 代理运行但仅审查 PR 描述 | 提示未包含 gh pr diff 指令 — diff 不在 Webhook 负载中 |
| 看不到 ping 事件 | 被忽略的事件仅在 DEBUG 日志级别返回 {"status":"ignored","event":"ping"} — 检查 GitHub 的投递日志(仓库 → 设置 → Webhooks → 您的 Webhook → 最近投递) |
GitHub 的“最近投递”选项卡(仓库 → 设置 → Webhooks → 您的 Webhook)显示每次投递的精确请求标头、负载、HTTP 状态和响应体。这是诊断故障的最快方法,无需接触服务器日志。
完整配置参考
platforms:
webhook:
enabled: true
extra:
host: "0.0.0.0" # bind address (default: 0.0.0.0)
port: 8644 # listen port (default: 8644)
secret: "" # optional global fallback secret
rate_limit: 30 # requests per minute per route
max_body_bytes: 1048576 # payload size limit in bytes (default: 1 MB)
routes:
<route-name>:
secret: "required-per-route"
events: [] # [] = accept all; otherwise list X-GitHub-Event values
prompt: "" # {field} / {nested.field} resolved from payload
skills: [] # first matching skill is loaded (only one)
deliver: "log" # log | github_comment | telegram | discord | slack | signal | sms
deliver_extra: {} # repo + pr_number for github_comment; chat_id for others下一步是什么?
- 基于 Cron 的 PR 审查 — 按计划轮询 PR,无需公共端点
- Webhook 参考 — Webhook 平台的完整配置参考
- 构建插件 — 将审查逻辑打包成可共享的插件
- 配置文件 — 使用自己的内存和配置运行专用审查配置文件