ByteNoteByteNote

字节笔记本

2026年6月21日

hermes教程-WhatsApp Business (Cloud API)

API中转
¥120

快速开始

bash
hermes whatsapp-cloud

该向导会引导您完成每个凭据的配置,在您粘贴时逐一验证(可捕获最常见的设置陷阱——将电话号码粘贴到电话号码 ID 字段中),并打印出需要在向导之外完成的部分(启动 cloudflared、配置 Meta 的 webhook 仪表板)的精确后续操作说明。

本页其余部分为手动参考。


前提条件

  1. 一个 Meta 商务管理平台账户。在 business.facebook.com 创建一个。
  2. 一个已启用 WhatsApp 的 Meta 应用。请参阅下面的“创建 Meta 应用”。
  3. 一种将本地端口暴露到公共互联网并支持 HTTPS 的方式。推荐使用 Cloudflare Tunnel(cloudflared)——免费,无需端口转发,无需域名。ngrok、您自己的域名配合反向代理 + TLS,或者将网关直接绑定到公共 IP 的 VPS 也可以。
  4. 可选但推荐:在 PATH 中安装 ffmpeg,以便出站语音消息以原生 WhatsApp 语音笔记气泡(绿色波形)形式呈现,而不是 MP3 音频附件。如果缺少,Hermes 会优雅降级。

创建 Meta 应用

  1. 前往 developers.facebook.com/apps创建应用
  2. 选择用例:“通过 WhatsApp 与客户联系”下一步
  3. 选择或创建一个商务组合。查看发布要求。确认 → 创建应用
  4. 创建后,您将进入 自定义用例 → 在 WhatsApp 上联系 → 快速入门。点击 开始使用 API → 您现在位于 API 设置 页面。
  5. 确保已关联一个 WhatsApp 商务账号(WABA)。如果您在步骤 3 中创建了新组合,系统会自动创建一个。在 API 设置页面中验证。

您需要从仪表板获取以下值——向导会按此顺序提示您:

在仪表板中的位置字段格式备注
电话号码 ID应用仪表板 → WhatsApp → API 设置 → “发件人”下拉菜单下方数字,15-17 位不是电话号码本身。最常见的设置错误是将实际电话号码粘贴到这里。
访问令牌应用仪表板 → WhatsApp → API 设置 → “生成访问令牌”EAA 开头,100+ 字符临时令牌有效期为 24 小时——生产环境请参阅下面的“永久令牌”。
应用密钥应用仪表板 → 设置 → 基本 → 点击“应用密钥”旁边的“显示”32 字符小写十六进制用于验证传入的 webhook 签名。没有它,入站投递将被拒绝并返回 503。
应用 ID(可选)应用仪表板 → 设置 → 基本数字,15-16 位消息传递不需要,但可用于分析。
WABA ID(可选)应用仪表板 → WhatsApp → API 设置 → 靠近顶部数字,15+ 位消息传递不需要,但可用于分析。

永久令牌(生产环境)

临时访问令牌在 24 小时 后过期,这意味着今天生成的令牌明天就会失效。对于生产部署,请使用 系统用户永久令牌

  1. 前往 business.facebook.com/latest/settings系统用户(左侧边栏)。
  2. 添加 → 名称(例如 hermes-bot)→ 角色:管理员
  3. 选择新用户 → 分配资产
    • 选择您的应用 → 在“完全控制”下切换 管理应用
    • 选择您的 WhatsApp 账号 → 在“完全控制”下切换 管理 WhatsApp 商务账号
    • 点击 分配资产
  4. 生成令牌,并包含以下权限:
    • business_management
    • whatsapp_business_messaging
    • whatsapp_business_management
  5. 设置 令牌过期时间:从不
  6. 复制令牌 → 更新 ~/.hermes/.env 中的 WHATSAPP_CLOUD_ACCESS_TOKEN → 重启网关。

系统用户令牌不会过期,除非您明确撤销它们。


将 Hermes 暴露到互联网

Cloud API 通过 HTTPS POST 将入站消息投递到您的 webhook URL——这意味着 Hermes 网关必须能够从 Meta 的服务器访问。三种常见方式:

Cloudflare Tunnel(推荐)

免费,无需端口转发,适用于 Windows / macOS / Linux。作为独立进程与网关一起运行。

安装:

bash
## Windows
winget install Cloudflare.cloudflared
## macOS
brew install cloudflared
## Linux
## 从 https://github.com/cloudflare/cloudflared/releases 下载二进制文件

运行快速隧道(无需 Cloudflare 账户——会为您提供一个 https://<随机>.trycloudflare.com URL):

bash
cloudflared tunnel --url http://localhost:8090

记下打印的 URL——这就是您要提供给 Meta 的地址。

警告——快速隧道会轮换

免费的快速隧道 URL 每次重启 cloudflared 都会改变。如需稳定 URL,请使用 cloudflared tunnel login 登录并创建一个命名隧道。免费 Cloudflare 账户可获得无限命名隧道——请参阅 Cloudflare 文档 了解命名隧道的工作流程。

ngrok

bash
ngrok http 8090

免费版每次重启会显示不同的 URL。付费版可提供稳定的子域名。

您自己的域名 + 反向代理

如果您已有带 TLS 证书的服务器(Caddy、nginx 等),将路由指向 localhost:8090。这是生产环境最稳定的选项,但需要现有基础设施。


在 Meta 端配置 webhook

当您的隧道运行后:

  1. 记下隧道打印的公共 URL——例如 https://abc123.trycloudflare.com
  2. 生成一个 验证令牌——向导会使用 secrets.token_urlsafe(32) 为您生成;如果您手动配置,请运行:
    bash
    python -c "import secrets; print(secrets.token_urlsafe(32))"
    将其保存为 ~/.hermes/.env 中的 WHATSAPP_CLOUD_VERIFY_TOKEN
  3. 启动 Hermes 网关:hermes gateway
  4. 在 Meta 应用仪表板 → WhatsApp → 配置(或根据 UI 版本可能为 用例 → 自定义 → 配置)→ 点击 Webhook 部分的 编辑
  5. 填写:
    • 回调 URLhttps://abc123.trycloudflare.com/whatsapp/webhook
    • 验证令牌:步骤 2 中的字符串(必须完全匹配)
  6. 点击 验证并保存。Meta 会向您的 URL 发送一个 GET 请求,网关回显挑战值,Meta 将 webhook 标记为已验证。
  7. Webhook 字段 下,点击 管理 → 订阅 messages 字段。这告诉 Meta 实际将入站消息投递到您的 webhook。

手动验证循环(在第三个终端中):

bash
TUNNEL="https://abc123.trycloudflare.com"
VERIFY="<您的验证令牌>"
## 应打印 HTTP 200,正文为 "hello"
curl -i "$TUNNEL/whatsapp/webhook?hub.mode=subscribe&hub.verify_token=$VERIFY&hub.challenge=hello"
## 健康检查端点——应显示 verify_token_configured: true 和 app_secret_configured: true
curl "$TUNNEL/health"

接收方白名单(Meta 端)

在开发模式下(在您的应用通过应用审核之前),Meta 会限制您的机器人可以发送消息的号码:

  1. 应用仪表板 → WhatsApp → API 设置 → 收件人 下拉菜单。
  2. 点击 管理电话号码列表
  3. 添加您要发送消息的电话号码(您自己的、团队成员的、友好测试者的)。Meta 会通过短信或 WhatsApp 向每个号码发送一个 6 位验证码。

开发模式下最多 5 个号码。通过应用审核后此限制将解除。


允许列表(Hermes 端)

除了 Meta 的接收方白名单,Hermes 还有自己的按平台允许列表,用于控制 代理处理哪些传入消息。添加到 ~/.hermes/.env

bash
## 逗号分隔的电话号码,包含国家代码,无 '+' / 空格 / 破折号
WHATSAPP_CLOUD_ALLOWED_USERS=15551234567,15557654321
## 或者允许所有人(仅在与 Meta 的接收方白名单结合使用时安全)
## WHATSAPP_CLOUD_ALLOW_ALL_USERS=true

向导会在步骤 6 中设置此项。如果没有允许列表,每条入站消息都会被拒绝——这是有意为之,这样即使接收方白名单被放宽,机器人也不会被随机号码调用。


美化机器人的 WhatsApp 个人资料

WhatsApp 会在聊天标题和联系人列表中显示机器人的 名称和个人资料图片。这些无法通过 Cloud API 设置——它们位于 Meta 的商务管理平台中。

当您的机器人正常工作后,前往 business.facebook.com/wa/manage/phone-numbers,点击您的电话号码,您会找到:

项目位置备注
显示名称电话号码页面顶部更改需经过 Meta 的名称审核流程(约 24-48 小时)。
个人资料图片电话号码页面顶部方形图片,建议 ≥640×640px。立即更新。
关于 / 描述 / 网站 / 邮箱 / 营业时间 / 类别“编辑个人资料”按钮当用户点击机器人名称时,这些会显示在信息面板中。装饰性。
已验证徽章(绿色勾选)商务管理平台 → 安全中心 → 开始验证需要 Meta 的单独企业验证流程。

hermes whatsapp-cloud 向导会在设置结束时打印这些链接。这些都不是机器人运行所必需的——纯粹是为了美化机器人对用户的呈现。


配置参考

所有设置位于 ~/.hermes/.env 中。必填值以 粗体 显示。

变量默认值描述
WHATSAPP_CLOUD_PHONE_NUMBER_ID来自 API 设置的 15-17 位 ID。不是电话号码。
WHATSAPP_CLOUD_ACCESS_TOKENMeta 访问令牌(以 EAA 开头)。临时 24 小时或系统用户永久。
WHATSAPP_CLOUD_APP_SECRET来自设置 → 基本的 32 字符十六进制。没有它,入站将被拒绝并返回 503。
WHATSAPP_CLOUD_VERIFY_TOKEN用于 GET 握手的共享密钥。由向导自动生成。
WHATSAPP_CLOUD_ALLOWED_USERS允许向机器人发送消息的 wa_id,逗号分隔。
WHATSAPP_CLOUD_ALLOW_ALL_USERSfalse设置为 true 以绕过允许列表。
WHATSAPP_CLOUD_APP_ID可选,用于未来的分析集成。
WHATSAPP_CLOUD_WABA_ID可选,用于未来的分析集成。
WHATSAPP_CLOUD_WEBHOOK_HOST0.0.0.0Webhook 服务器绑定的接口。
WHATSAPP_CLOUD_WEBHOOK_PORT8090Webhook 服务器绑定的端口。必须与隧道转发的端口一致。
WHATSAPP_CLOUD_WEBHOOK_PATH/whatsapp/webhookMeta 发送 POST 请求的 URL 路径。
WHATSAPP_CLOUD_API_VERSIONv20.0Meta Graph API 版本。仅当 Meta 文档推荐更新版本时才覆盖。
WHATSAPP_CLOUD_HOME_CHANNEL用作机器人主频道的 wa_id(用于 cron 作业等)。

您可以同时启用 Baileys(whatsapp)和 Cloud(whatsapp_cloud)适配器,分别针对不同的电话号码。


功能

入站

  • 文本消息——直接传递给代理。
  • 图片——自动下载并附加到代理的输入中。具有原生视觉能力的模型(Claude、GPT-4o、Gemini 等)直接读取图片;非视觉模型会收到自动生成的文本描述。
  • 语音笔记——自动下载为 .ogg,通过您配置的 STT 提供商(本地 faster-whisper、OpenAI/Nous、Groq 等)转录,然后作为文本交给代理。
  • 文档——自动下载。小型可读文本文件(.txt.md.json.py.csv 等)不超过 100KB 会被内联到代理的输入中,以便无需工具调用即可读取。较大的文件会缓存在本地,供代理的其他工具访问。
  • 按钮点击——当用户点击机器人之前发送的按钮(澄清选择、命令批准、斜杠命令确认)时,点击会直接路由到相应的处理程序。过时的点击会回退为普通文本输入处理。
  • 回复上下文——当用户回复之前的机器人消息时,代理会看到原始消息作为上下文。

出站

  • 文本——Markdown 会自动转换为 WhatsApp 风格的语法(**粗体***粗体*~~删除线~~~删除线~,标题 → 粗体,[链接](url)链接 (url))。长消息按每块 4096 字符分割。
  • 图片——支持代理生成的图片和本地图片文件,以原生照片附件形式投递。
  • 语音消息——文本转语音输出通过 ffmpeg 转换为原生 WhatsApp 语音笔记气泡(绿色波形)。如果没有安装 ffmpeg,则回退为 MP3 音频附件。请参阅下面的“语音消息”。
  • 视频 / 文档——均支持,以原生附件形式发送。

交互式用户体验

当代理调用以下任何流程时,Hermes 会使用 WhatsApp 的原生交互式消息——点击回答按钮,而不是“回复数字”提示:

  • clarify 工具——多项选择题以快速回复按钮(1-3 个选项)或点击打开列表(4 个以上选项)的形式呈现。选择“✏️ 其他”可让用户输入自由格式答案,代理会将其作为解析结果接收。
  • 危险命令批准——当代理的终端/代码执行遇到门控命令时,用户会看到 ✅ 批准 / ❌ 拒绝 按钮,而无需输入 /approve/deny
  • 斜杠命令确认——特权命令如 /reload-mcp 会显示 ✅ 批准一次 / 🔒 始终允许 / ❌ 取消 按钮。

如果按钮无法渲染(例如在旧版 WhatsApp 客户端上),所有交互式提示都会优雅降级为纯文本。

已读回执和输入指示器

Hermes 会立即确认入站消息:

  • 您的消息在网关收到后会显示 蓝色双勾
  • 当代理准备回复时,您的 WhatsApp 聊天中机器人的名称会显示 “正在输入…”
  • 当机器人的第一条回复消息到达时,输入指示器会自动消失。

这可以清楚地表明机器人何时看到了您的消息,以及何时仍在处理回复。

语音消息

WhatsApp 区分“语音笔记”(绿色波形气泡)和通用音频文件附件。区别仅在于编解码器:语音笔记需要是 audio/ogg 格式,使用 opus 编码。

Hermes TTS 生成 MP3。两种路径:

  • 在 PATH 中安装 ffmpeg(推荐)——出站 TTS 会被转换并以正确的语音笔记形式送达。安装:
    • Windows:winget install Gyan.FFmpeg
    • macOS:brew install ffmpeg
    • Linux:包管理器
  • 没有 ffmpeg——出站 TTS 以 MP3 音频附件形式送达。播放正常,只是看起来不像语音笔记。网关日志中会触发一次性警告,以便您知晓。

您可以通过健康检查端点检查网关是否找到了 ffmpeg:

bash
curl http://localhost:8090/health
## 查找 "ffmpeg_present": true

已知限制

24 小时对话窗口

Meta 只允许在用户最后一条入站消息后的 24 小时窗口内 发送 自由格式消息。超出该窗口,Meta API 只接受预先批准的 消息模板

实际含义:

  • 响应式聊天(用户私信 → 机器人在 24 小时内回复 → 用户回复 → ...)可以一直工作。这覆盖了 >95% 的正常机器人使用场景。
  • 在超过 24 小时间隔后向 WhatsApp 投递的 Cron 作业 会失败,并返回 Graph 错误代码 131047(“重新参与消息”)。
  • 耗时超过 24 小时的 delegate_task 异步结果 同样会失败。
  • 将外部事件路由到 WhatsApp 的 Webhook 订阅者 在用户最近未私信机器人时会失败。

Hermes 会在系统提示中警告代理此窗口,以便模型在安排延迟消息时提及这一点。

消息模板支持(窗口外发送的解决方法)尚未在 Hermes 中实现。如果您需要此功能,请 提交 issue——已计划,但等待明确的需求信号。

群聊

Cloud API 对群聊的支持有限(能力层级由 Meta 控制)。Hermes 的 whatsapp_cloud 适配器在 v1 中 仅处理私信。如果您需要群聊,请使用 Baileys 桥接。

出站速率限制

Meta 的默认吞吐量为 每个商务电话号码每秒 80 条消息,可升级。Hermes 目前未在客户端强制执行此限制——极高容量的发送可能会达到 Meta 的限制。


故障排除

设置验证失败(“无法验证 URL”)在 Meta 仪表板中

几乎总是以下原因之一:

  • 隧道 URL 错误或已过期——cloudflared 快速隧道会轮换。获取新 URL 并更新 .env 和 Meta 仪表板。
  • 验证令牌不匹配——~/.hermes/.env 中的 WHATSAPP_CLOUD_VERIFY_TOKEN 必须与您在 Meta 仪表板中输入的内容完全一致。运行上面的 curl 探测以确认网关的验证握手首先在本地工作。
  • 网关未运行——检查 hermes gateway 是否已启动。
  • 未设置应用密钥——没有它,Hermes 会拒绝入站 POST 并返回 503。Meta 将其解释为“无法验证”。

graph error 100:对象 ID '...' 不存在

您将电话号码(10-11 位)粘贴到了 WHATSAPP_CLOUD_PHONE_NUMBER_ID 中,而不是电话号码 ID(Meta 的 15-17 位内部 ID)。请重新检查 API 设置页面——电话号码 ID 显示在“发件人”下拉菜单的 下方

向导现在会通过验证器捕获此问题,但如果您手动配置,了解这一点很有用。

graph error 190:身份验证错误

您的访问令牌无效。子代码:

  • subcode 463——令牌已过期。临时令牌有效期为 24 小时。重新生成,或切换到系统用户永久令牌(见上文)。
  • subcode 467——令牌已失效(已撤销或密码已更改)。
  • 其他 190——生成令牌时未包含所需权限。确保所有三个权限(business_managementwhatsapp_business_messagingwhatsapp_business_management)都已选中。

graph error 131047:重新参与消息

24 小时对话窗口已过期(请参阅“已知限制”)。要么:

  • 让用户先私信机器人以重新打开窗口。
  • 等待 Hermes 中的模板支持。

入站消息:media metadata fetch failed (status=401)

与出站相同的 401 根本原因(graph error 190)——访问令牌无效或已过期。修复令牌。

机器人回复显示为原始 JSON / 工具调用泄漏

常见原因:为 whatsapp_cloud 配置的工具集缺少代理想要调用的工具。检查 hermes tools list 并验证平台正在使用 hermes-whatsapp(默认的 Cloud 适配器工具集,与 Baileys 相同)。

如果模型发出工具调用形状的文本而不是结构化调用,通常意味着工具集实际上是空的。请参阅 hermes_cli/platforms.py 了解平台到默认工具集的映射。

STT(语音笔记转录)返回空 / “无法转录”

默认的 stt.provider: local 需要 pip install faster-whisper。如果您是 Nous 订阅者,可以将 STT 路由到 Meta 管理的音频网关:

bash
hermes config set stt.provider openai
hermes config set stt.use_gateway true
hermes gateway restart

这会使用您的 Nous Portal 访问令牌,而无需单独的 OpenAI 密钥。


安全说明

  • 将应用密钥视为密码——任何拥有它的人都可以伪造 Hermes 会接受为真实的 webhook 负载。
  • 验证令牌是共享密钥——泄露风险较低(最坏情况下,有人可以将 Meta 的 webhook 重新订阅到他们自己的不同 URL),但仍应避免提交。
  • 访问令牌是机器人的身份——系统用户令牌等同于长期有效的 API 密钥。如果部署被攻破,请立即轮换。
  • 当设置了 WHATSAPP_CLOUD_APP_SECRET 时,webhook 端点只接受签名请求——即使在开发环境中也要保持设置。没有它,网关会拒绝入站投递并返回 HTTP 503。
  • /health 端点未经身份验证——公开它是安全的,因为它只报告配置存在性的布尔值,而不是值本身。但如果您不想暴露它,可以在反向代理/隧道层限制访问。

与 Baileys 桥接的对比

Baileys(hermes whatsappCloud API(hermes whatsapp-cloud
账户类型个人商务
设置扫描二维码Meta 应用 + WABA + 令牌
依赖Node.js + npm纯 Python(httpx + aiohttp)
进程托管的 Node 子进程aiohttp webhook 服务器
需要公共 URL?
账户封禁风险是(非官方 API)否(官方支持)
入站轮询 Node 桥接Meta 的 Webhook POST
出站本地桥接 → BaileysHTTPS 到 graph.facebook.com
群组完全支持仅私信(v1)
24 小时窗口无限制硬性规则——之后需要模板
语音笔记(出站)原生有 ffmpeg 时原生,否则回退 MP3
已读回执是(蓝色双勾)
输入指示器是(回复时自动消失)
交互式按钮仅文本回退原生(澄清、批准、斜杠确认)
生产使用有风险(Meta 可封禁)为此设计

大多数运行 Hermes 用于个人项目的用户更喜欢 Baileys。大多数运行面向客户机器人的用户更喜欢 Cloud API。


另请参阅

分享: