ByteNoteByteNote

字节笔记本

2026年6月21日

hermes教程-Webhooks

API中转
¥120

视频教程

视频: 在 YouTube 上观看


快速开始

  1. 通过 hermes gateway setup 或环境变量启用
  2. config.yaml 中定义路由,使用 hermes webhook subscribe 动态创建路由
  3. 将你的服务指向 http://your-server:8644/webhooks/<route-name>

设置

有两种方式启用 webhook 适配器。

通过设置向导

bash
hermes gateway setup

按照提示启用 webhook、设置端口和全局 HMAC 密钥。

通过环境变量

添加到 ~/.hermes/.env

bash
WEBHOOK_ENABLED=true
WEBHOOK_PORT=8644        # 默认值
WEBHOOK_SECRET=your-global-secret

验证服务器

网关运行后:

bash
curl http://localhost:8644/health

预期响应:

json
{"status": "ok", "platform": "webhook"}

配置路由 {#configuring-routes}

路由定义了如何处理不同的 webhook 来源。每条路由是 config.yamlplatforms.webhook.extra.routes 下的一个命名条目。

路由属性

属性必需描述
events接受的事件类型列表(例如 ["pull_request"])。如果为空,则接受所有事件。事件类型从 X-GitHub-EventX-GitLab-Event 或负载中的 event_type 读取。
secret用于签名验证的 HMAC 密钥。如果路由未设置,则回退到全局 secret。仅用于测试时可设置为 "INSECURE_NO_AUTH"(跳过验证)。
prompt模板字符串,支持点号表示法访问负载(例如 {pull_request.title})。如果省略,则完整 JSON 负载会被转储到提示中。
skills为代理运行加载的技能名称列表。
deliver响应发送位置:github_commenttelegramdiscordslacksignalsmswhatsappmatrixmattermosthomeassistantemaildingtalkfeishuwecomweixinbluebubblesqqbotlog(默认)。
deliver_extra额外的投递配置——键取决于 deliver 类型(例如 repopr_numberchat_id)。值支持与 prompt 相同的 {dot.notation} 模板。
deliver_only如果为 true,则完全跳过代理——渲染后的 prompt 模板成为直接投递的文字消息。零 LLM 成本,亚秒级投递。用例见直接投递模式。要求 deliver 是真实目标(不是 log)。

完整示例

yaml
platforms:
  webhook:
    enabled: true
    extra:
      port: 8644
      secret: "global-fallback-secret"
      routes:
        github-pr:
          events: ["pull_request"]
          secret: "github-webhook-secret"
          prompt: |
            审查此拉取请求:
            仓库:{repository.full_name}
            PR #{number}:{pull_request.title}
            作者:{pull_request.user.login}
            URL:{pull_request.html_url}
            差异 URL:{pull_request.diff_url}
            操作:{action}
          skills: ["github-code-review"]
          deliver: "github_comment"
          deliver_extra:
            repo: "{repository.full_name}"
            pr_number: "{number}"
        deploy-notify:
          events: ["push"]
          secret: "deploy-secret"
          prompt: "新推送至 {repository.full_name} 分支 {ref}:{head_commit.message}"
          deliver: "telegram"

提示模板

提示使用点号表示法访问 webhook 负载中的嵌套字段:

  • {pull_request.title} 解析为 payload["pull_request"]["title"]
  • {repository.full_name} 解析为 payload["repository"]["full_name"]
  • {__raw__}——特殊标记,将整个负载以缩进 JSON 形式转储(截断至 4000 字符)。适用于监控告警或通用 webhook,代理需要完整上下文。
  • 缺失的键保留为字面量 {key} 字符串(无错误)
  • 嵌套字典和列表会被 JSON 序列化并截断至 2000 字符

你可以将 {__raw__} 与常规模板变量混合使用:

yaml
prompt: "PR #{pull_request.number} by {pull_request.user.login}: {__raw__}"

如果路由未配置 prompt 模板,则整个负载以缩进 JSON 形式转储(截断至 4000 字符)。

相同的点号表示法模板也适用于 deliver_extra 值。

论坛话题投递

当将 webhook 响应投递到 Telegram 时,你可以通过在 deliver_extra 中包含 message_thread_id(或 thread_id)来定位特定论坛话题:

yaml
webhooks:
  routes:
    alerts:
      events: ["alert"]
      prompt: "告警:{__raw__}"
      deliver: "telegram"
      deliver_extra:
        chat_id: "-1001234567890"
        message_thread_id: "42"

如果 deliver_extra 中未提供 chat_id,则投递回退到目标平台配置的主频道。


GitHub PR 审查(逐步指南) {#github-pr-review}

本演练设置每次拉取请求的自动代码审查。

1. 在 GitHub 中创建 webhook

  1. 进入你的仓库 → SettingsWebhooksAdd webhook
  2. Payload URL 设置为 http://your-server:8644/webhooks/github-pr
  3. Content type 设置为 application/json
  4. Secret 设置为与你的路由配置匹配(例如 github-webhook-secret
  5. Which events? 下,选择 Let me select individual events 并勾选 Pull requests
  6. 点击 Add webhook

2. 添加路由配置

github-pr 路由添加到你的 ~/.hermes/config.yaml,如上方示例所示。

3. 确保 gh CLI 已认证

github_comment 投递类型使用 GitHub CLI 发布评论:

bash
gh auth login

4. 测试

在仓库上打开一个拉取请求。webhook 触发,Hermes 处理事件,并在 PR 上发布审查评论。


GitLab Webhook 设置 {#gitlab-webhook-setup}

GitLab webhook 工作方式类似,但使用不同的认证机制。GitLab 将密钥作为纯文本 X-Gitlab-Token 头发送(精确字符串匹配,非 HMAC)。

1. 在 GitLab 中创建 webhook

  1. 进入你的项目 → SettingsWebhooks
  2. URL 设置为 http://your-server:8644/webhooks/gitlab-mr
  3. 输入你的 Secret token
  4. 选择 Merge request events(以及你需要的任何其他事件)
  5. 点击 Add webhook

2. 添加路由配置

yaml
platforms:
  webhook:
    enabled: true
    extra:
      routes:
        gitlab-mr:
          events: ["merge_request"]
          secret: "your-gitlab-secret-token"
          prompt: |
            审查此合并请求:
            项目:{project.path_with_namespace}
            MR !{object_attributes.iid}:{object_attributes.title}
            作者:{object_attributes.last_commit.author.name}
            URL:{object_attributes.url}
            操作:{object_attributes.action}
          deliver: "log"

投递选项 {#delivery-options}

deliver 字段控制处理 webhook 事件后代理响应的去向。

投递类型描述
log将响应记录到网关日志输出。这是默认值,适用于测试。
github_comment通过 gh CLI 将响应作为 PR/issue 评论发布。需要 deliver_extra.repodeliver_extra.pr_numbergh CLI 必须在网关主机上安装并认证(gh auth login)。
telegram将响应路由到 Telegram。使用主频道,或在 deliver_extra 中指定 chat_id
discord将响应路由到 Discord。使用主频道,或在 deliver_extra 中指定 chat_id
slack将响应路由到 Slack。使用主频道,或在 deliver_extra 中指定 chat_id
signal将响应路由到 Signal。使用主频道,或在 deliver_extra 中指定 chat_id
sms通过 Twilio 将响应路由到 SMS。使用主频道,或在 deliver_extra 中指定 chat_id
whatsapp将响应路由到 WhatsApp。使用主频道,或在 deliver_extra 中指定 chat_id
matrix将响应路由到 Matrix。使用主频道,或在 deliver_extra 中指定 chat_id
mattermost将响应路由到 Mattermost。使用主频道,或在 deliver_extra 中指定 chat_id
homeassistant将响应路由到 Home Assistant。使用主频道,或在 deliver_extra 中指定 chat_id
email将响应路由到 Email。使用主频道,或在 deliver_extra 中指定 chat_id
dingtalk将响应路由到钉钉。使用主频道,或在 deliver_extra 中指定 chat_id
feishu将响应路由到飞书/Lark。使用主频道,或在 deliver_extra 中指定 chat_id
wecom将响应路由到企业微信。使用主频道,或在 deliver_extra 中指定 chat_id
weixin将响应路由到微信。使用主频道,或在 deliver_extra 中指定 chat_id
bluebubbles将响应路由到 BlueBubbles(iMessage)。使用主频道,或在 deliver_extra 中指定 chat_id

对于跨平台投递,目标平台也必须在网关中启用并连接。如果 deliver_extra 中未提供 chat_id,则响应发送到该平台配置的主频道。


直接投递模式 {#direct-delivery-mode}

默认情况下,每个 webhook POST 都会触发一次代理运行——负载成为提示,代理处理它,然后投递代理的响应。这会在每个事件上消耗 LLM token。

对于你只想推送纯通知的场景——无需推理、无需代理循环,只需投递消息——可以在路由上设置 deliver_only: true。渲染后的 prompt 模板成为字面消息体,适配器直接将其分派到配置的投递目标。

何时使用直接投递

  • 外部服务推送——Supabase/Firebase webhook 在数据库更改时触发 → 立即通知 Telegram 中的用户
  • 监控告警——Datadog/Grafana 告警 webhook → 推送到 Discord 频道
  • 代理间 ping——代理 A 通知代理 B 的用户某个长时间运行的任务已完成
  • 后台任务完成——Cron 任务完成 → 将结果发布到 Slack

优势:

  • 零 LLM token——从不调用代理
  • 亚秒级投递——单次适配器调用,无推理循环
  • 与代理模式相同的安全性——HMAC 认证、速率限制、幂等性和消息体大小限制仍然适用
  • 同步响应——投递成功后 POST 返回 200 OK,如果目标拒绝则返回 502,因此上游服务可以智能重试

示例:来自 Supabase 的 Telegram 推送

yaml
platforms:
  webhook:
    enabled: true
    extra:
      port: 8644
      secret: "global-secret"
      routes:
        antenna-matches:
          secret: "antenna-webhook-secret"
          deliver: "telegram"
          deliver_only: true
          prompt: "🎉 新匹配:{match.user_name} 与你匹配成功!"
          deliver_extra:
            chat_id: "{match.telegram_chat_id}"

你的 Supabase 边缘函数使用 HMAC-SHA256 对负载签名,并 POST 到 https://your-server:8644/webhooks/antenna-matches。webhook 适配器验证签名,从负载渲染模板,投递到 Telegram,并返回 200 OK

示例:通过 CLI 动态订阅

bash
hermes webhook subscribe antenna-matches \
  --deliver telegram \
  --deliver-chat-id "123456789" \
  --deliver-only \
  --prompt "🎉 新匹配:{match.user_name} 与你匹配成功!" \
  --description "Antenna 匹配通知"

响应码

状态含义
200 OK投递成功。响应体:{"status": "delivered", "route": "...", "target": "...", "delivery_id": "..."}
200 OK (status=duplicate)在幂等性 TTL(1 小时)内重复的 X-GitHub-Delivery ID。不会重新投递。
401 UnauthorizedHMAC 签名无效或缺失。
400 Bad RequestJSON 消息体格式错误。
404 Not Found未知的路由名称。
413 Payload Too Large消息体超过 max_body_bytes
429 Too Many Requests路由速率限制超出。
502 Bad Gateway目标适配器拒绝消息或抛出异常。错误记录在服务器端;响应体为通用 Delivery failed,以避免泄露适配器内部信息。

配置注意事项

  • deliver_only: true 要求 deliver 是真实目标。deliver: log(或省略 deliver)会在启动时被拒绝——适配器如果发现配置错误的路由将拒绝启动。
  • 在直接投递模式下忽略 skills 字段(没有代理运行,因此没有地方注入技能)。
  • 模板渲染使用与代理模式相同的 {dot.notation} 语法,包括 {__raw__} 标记。
  • 幂等性使用相同的 X-GitHub-Delivery / X-Request-ID 头——使用相同 ID 的重试返回 status=duplicate,并且不会重新投递。

动态订阅(CLI) {#dynamic-subscriptions}

除了 config.yaml 中的静态路由,你还可以使用 hermes webhook CLI 命令动态创建 webhook 订阅。当代理本身需要设置事件驱动触发器时,这尤其有用。

创建订阅

bash
hermes webhook subscribe github-issues \
  --events "issues" \
  --prompt "新 issue #{issue.number}:{issue.title}\n作者:{issue.user.login}\n\n{issue.body}" \
  --deliver telegram \
  --deliver-chat-id "-100123456789" \
  --description "分类新的 GitHub issues"

这将返回 webhook URL 和一个自动生成的 HMAC 密钥。配置你的服务向该 URL 发送 POST 请求。

列出订阅

bash
hermes webhook list

移除订阅

bash
hermes webhook remove github-issues

测试订阅

bash
hermes webhook test github-issues
hermes webhook test github-issues --payload '{"issue": {"number": 42, "title": "Test"}}'

动态订阅的工作原理

  • 订阅存储在 ~/.hermes/webhook_subscriptions.json
  • webhook 适配器在每个传入请求时热重载此文件(基于 mtime 检查,开销可忽略)
  • config.yaml 中的静态路由始终优先于同名的动态路由
  • 动态订阅使用与静态路由相同的路由格式和能力(事件、提示模板、技能、投递)
  • 无需重启网关——订阅后立即生效

代理驱动的订阅

代理可以通过终端工具在 webhook-subscriptions 技能的引导下创建订阅。让代理“为 GitHub issues 设置一个 webhook”,它将运行相应的 hermes webhook subscribe 命令。


安全 {#security}

webhook 适配器包含多层安全机制:

HMAC 签名验证

适配器使用适用于每个来源的适当方法验证传入的 webhook 签名:

  • GitHubX-Hub-Signature-256 头——以 sha256= 为前缀的 HMAC-SHA256 十六进制摘要
  • GitLabX-Gitlab-Token 头——纯文本密钥字符串匹配
  • 通用X-Webhook-Signature 头——原始 HMAC-SHA256 十六进制摘要

如果配置了密钥但未检测到可识别的签名头,则请求被拒绝。

密钥是必需的

每条路由必须有一个密钥——要么直接在路由上设置,要么从全局 secret 继承。没有密钥的路由会导致适配器在启动时失败并报错。仅用于开发/测试时,你可以将密钥设置为 "INSECURE_NO_AUTH" 以完全跳过验证。

INSECURE_NO_AUTH 仅在网关绑定到回环主机(127.0.0.1localhost::1)时才被接受。如果与非回环绑定(如 0.0.0.0 或 LAN IP)结合使用,适配器将拒绝启动——这可以防止意外在公共接口上暴露未经认证的端点。

速率限制

每条路由默认限制为 每分钟 30 个请求(固定窗口)。全局配置:

yaml
platforms:
  webhook:
    extra:
      rate_limit: 60  # 每分钟请求数

超出限制的请求会收到 429 Too Many Requests 响应。

幂等性

投递 ID(来自 X-GitHub-DeliveryX-Request-ID 或时间戳回退)会被缓存 1 小时。重复的投递(例如 webhook 重试)会被静默跳过并返回 200 响应,从而防止重复的代理运行。

消息体大小限制

超过 1 MB 的负载会在读取消息体之前被拒绝。配置:

yaml
platforms:
  webhook:
    extra:
      max_body_bytes: 2097152  # 2 MB

提示注入风险

警告

Webhook 负载包含攻击者控制的数据——PR 标题、提交消息、issue 描述等都可能包含恶意指令。当网关暴露于互联网时,请在沙箱环境(Docker、VM)中运行。考虑使用 Docker 或 SSH 终端后端进行隔离。


故障排除 {#troubleshooting}

Webhook 未到达

  • 验证端口已暴露且可从 webhook 来源访问
  • 检查防火墙规则——端口 8644(或你配置的端口)必须开放
  • 验证 URL 路径匹配:http://your-server:8644/webhooks/<route-name>
  • 使用 /health 端点确认服务器正在运行

签名验证失败

  • 确保路由配置中的密钥与 webhook 来源中配置的密钥完全匹配
  • 对于 GitHub,密钥基于 HMAC——检查 X-Hub-Signature-256
  • 对于 GitLab,密钥是纯文本令牌匹配——检查 X-Gitlab-Token
  • 检查网关日志中的 Invalid signature 警告

事件被忽略

  • 检查事件类型是否在路由的 events 列表中
  • GitHub 事件使用诸如 pull_requestpushissues 等值(X-GitHub-Event 头值)
  • GitLab 事件使用诸如 merge_requestpush 等值(X-GitLab-Event 头值)
  • 如果 events 为空或未设置,则接受所有事件

代理未响应

  • 在前台运行网关以查看日志:hermes gateway run
  • 检查提示模板是否正确渲染
  • 验证投递目标已配置并连接

重复响应

  • 幂等性缓存应防止此问题——检查 webhook 来源是否发送了投递 ID 头(X-GitHub-DeliveryX-Request-ID
  • 投递 ID 缓存 1 小时

gh CLI 错误(GitHub 评论投递)

  • 在网关主机上运行 gh auth login
  • 确保已认证的 GitHub 用户对仓库具有写入权限
  • 检查 gh 是否已安装并在 PATH 中

环境变量 {#environment-variables}

变量描述默认值
WEBHOOK_ENABLED启用 webhook 平台适配器false
WEBHOOK_PORT接收 webhook 的 HTTP 服务器端口8644
WEBHOOK_SECRET全局 HMAC 密钥(当路由未指定自己的密钥时用作回退)(无)

分享: