WhatsApp 在 Hermes 官方文件裡有兩條完整接法:一條是內建的 Baileys 橋接——模擬 WhatsApp Web 會話,掃 QR code 就能用,非官方、有帳號被限制的風險;另一條是 Meta 官方的 WhatsApp Business Cloud API——企業帳號、webhook 架構、沒有封號風險,但要走 Meta 的註冊與驗證流程。兩條路可以同時啟用(各綁一個號碼)。
做完這篇文章你會得到:一個能在 WhatsApp 裡對話的 agent,以及一個明確的答案——你的場景該走哪條路。橋接路徑約 20 分鐘;Cloud API 路徑約 40–60 分鐘(不含 Meta 側的審核等待)。
先講清楚風險,不繞彎子:WhatsApp 官方不支援 Business API 以外的第三方 bot。橋接路徑走的是逆向的 Web 協議,官方文件在警告框裡寫得明白:使用第三方橋接帶有帳號被限制的小概率風險(small risk of account restrictions)。「小」,但存在。這篇文章把兩條路的代價都擺在檯面上,選擇權在你。
這個渠道的能力邊界
官方能力矩陣裡,WhatsApp 佔兩行,差異不小:
| 平台 | 語音 | 圖片 | 檔案 | 主題 | 表情回應 | 輸入中 | 串流 |
|---|---|---|---|---|---|---|---|
| Telegram | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ |
| WhatsApp(橋接) | — | ✅ | ✅ | — | — | ✅ | ✅ |
| WhatsApp Cloud API | ✅ | ✅ | ✅ | — | — | ✅ | — |
| Weixin(微信) | ✅ | ✅ | ✅ | — | — | ✅ | — |
| Feishu / Lark | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
(取自官方 Messaging Gateway 文件的平台對比表。「語音」指 TTS 語音回覆與/或語音訊息轉錄。)
兩條路共同的部分:圖片與檔案收發、輸入中提示;都不支援主題與表情回應。長回覆都按 4,096 字元自動分段;Markdown 自動轉成 WhatsApp 方言(**bold** 轉 *bold*、標題轉粗體、連結轉「文字 (url)」)。
差異的部分:
- 橋接支援串流輸出(邊生成邊編輯同一則訊息)、工具進度提示、原生投票(clarify 選擇題渲染成單選投票)、位置釘選、引用回覆帶附件上下文。
- Cloud API 支援語音(入站語音轉錄;出站 TTS 經 ffmpeg 轉成原生語音氣泡,沒裝 ffmpeg 則以 MP3 附件送達)、已讀回執(藍雙勾)、原生互動按鈕(澄清問題、危險指令核准直接點按鈕),但沒有串流輸出,而且有一條硬規則:24 小時對話視窗——使用者最後一則訊息起算 24 小時內才能自由回覆,超過視窗只能發預先審核過的訊息範本,而範本功能 Hermes 尚未實作。排程任務超過 24 小時才送達 WhatsApp 會失敗(Graph 錯誤碼
131047)。 - 群組:橋接完整支援(靠群組政策管控);Cloud API 目前只支援私訊。
兩條路,怎麼選
| 橋接(Baileys) | Cloud API(官方) | |
|---|---|---|
| 帳號類型 | 個人 WhatsApp | Meta 企業帳號 + 專用商業號碼 |
| 設定方式 | 掃 QR code | Meta app + 四組憑證 + webhook |
| 依賴 | Node.js v18+ 與 npm(橋接是 Node 子程序) | 純 Python,無 Node 依賴 |
| 需要公網 URL | 不需要 | 需要(Meta 要把訊息 POST 進來) |
| 帳號被限制的風險 | 有(非官方 API) | 無(官方支援的路徑) |
| 群組 | 支援 | 目前僅私訊 |
| 24 小時視窗 | 無此限制 | 硬規則,窗外需預審範本 |
| 適合 | 個人專案、快速 demo、單一使用者 | 商業 bot、面向客戶、要穩定 |
官方文件的總結很直白:個人專案多用橋接,面向客戶的 bot 多用 Cloud API。三個補充判斷:
- 走橋接就用專用號碼,不要綁你個人的號。Google Voice(美國、免費)、預付 SIM(一次性 $5–15,每 90 天打一通電話保號)、或 TextNow 這類 VoIP(部分號碼會被 WhatsApp 擋,多試幾個)。
- 走橋接的三條自律,把風險壓到最低:不批量發訊、不發垃圾訊息、不對「沒先發訊給你的人」做主動觸達。WhatsApp 會定期更新 Web 協議,橋接可能暫時失效——更新 Hermes、重新配對即可,但這類中斷在 Cloud API 路上不存在。
- Cloud API 的代價是流程:Meta Business 帳號、建立 app、(生產環境)System User 永久 token、公網 HTTPS 端點、開發模式下最多 5 個收訊號碼的白名單。沒有封號風險,但也不是五分鐘的事。
前置需求
- Hermes Agent 已安裝(安裝步驟見這篇),模型已配置,
hermes gateway跑得起來。 - 橋接路徑:Node.js v18+ 與 npm;一支裝了 WhatsApp 的手機(掃 QR 用);一個準備給 bot 用的號碼。
- Cloud API 路徑:Meta Business 帳號(business.facebook.com);一個能把本地端口暴露成公網 HTTPS 的手段(推薦 Cloudflare Tunnel,免費、免端口轉發、免自有網域;ngrok 或自有網域 + 反向代理也行);選用但推薦 ffmpeg(原生語音氣泡)。
- 兩條路都:理解 環境變數與 .env 與憑證衛生的基本約定——token 是佔位符才進文章,真 token 不進聊天視窗、不進版本庫。
步驟
步驟一:決定走哪條路、用哪個號碼
對照上一節的選擇表做決定。橋接還要多選一個模式:bot(專用號碼,別人直接發訊給這個號,推薦)或 self-chat(用你自己的 WhatsApp,發訊給自己來跟 agent 對話,適合單人快速上手)。
預期輸出:一個明確的決定——例如「橋接 + bot 模式 + 一張 $10 預付 SIM」。
步驟二:(橋接)執行配對精靈
hermes whatsapp
預期輸出:精靈先問模式(bot / self-chat),需要時自動安裝橋接依賴,然後在 Terminal(終端機) 裡顯示一個 QR code。QR 每 20 秒左右刷新;如果顯示亂碼,把 terminal 拉到至少 60 欄寬,或換一個支援 Unicode 的 terminal。
步驟三:(橋接)手機掃碼連結裝置
在手機 WhatsApp:設定 → 已連結的裝置 → 連結裝置,鏡頭對準 terminal 裡的 QR code。
預期輸出:精靈確認連線成功後退出,session 自動存到 ~/.hermes/platforms/whatsapp/session——重啟不用重掃。這個目錄裡是加密金鑰與裝置憑證,等同你 WhatsApp 帳號的完整存取權:不要分享、不要 commit,並收緊權限:
chmod 700 ~/.hermes/platforms/whatsapp/session
步驟四:(橋接)設定存取控制,啟動 gateway
在 ~/.hermes/.env 寫入:
WHATSAPP_ENABLED=true
WHATSAPP_MODE=bot # 或 self-chat
WHATSAPP_ALLOWED_USERS=15551234567 # 國碼開頭、不加 +、逗號分隔
然後啟動:
hermes gateway
預期輸出:gateway 用已存 session 自動拉起 WhatsApp 橋接。用名單內的手機號發一句話給 bot 號碼:先看到「輸入中」,然後回覆邊生成邊更新(串流),長回覆自動分段。注意:不設任何 allowlist 時,gateway 會拒絕所有入站訊息——這是安全措施,不是壞了。
群組(僅 bot 模式)另有一道群政策:WHATSAPP_GROUP_POLICY 預設 pairing(群訊息一律不轉發);要放行特定群,設 allowlist 並把群組 JID(形如 120363001234567890@g.us)加進 WHATSAPP_GROUP_ALLOWED_USERS;再加 WHATSAPP_REQUIRE_MENTION=true 可以只在被 @、被回覆或收到 / 指令時才回應。
步驟五:(Cloud API)建 Meta app,收齊四組憑證
到 developers.facebook.com/apps → Create App,用例選「Connect with customers through WhatsApp」,建立或連結 business portfolio。然後在 App Dashboard 收齊四組值:
| 憑證 | 在哪裡 | 形狀 | 陷阱 |
|---|---|---|---|
| Phone Number ID | WhatsApp → API Setup,「From」下拉選單下方 | 15–17 位數字 | 不是電話號碼本身。把 10–11 位的手機號貼進來是頭號錯誤,之後會報 Graph error 100 |
| Access Token | WhatsApp → API Setup → Generate access token | EAA 開頭、100+ 字元 | 臨時 token 只活 24 小時;生產環境改用 System User 永久 token |
| App Secret | Settings → Basic → App secret 旁按 Show | 32 位小寫十六進位 | 缺它,入站 webhook 一律被拒(HTTP 503) |
| Verify Token | 自己產生(精靈會代勞) | 隨機字串 | 必須與 Meta 儀表板裡填的逐字相同 |
預期輸出:四個值都在手上。生產環境的永久 token:Business Settings → System users → 新增(角色 Admin)→ Assign Assets(app 與 WhatsApp 帳號都給 Full control)→ Generate token,勾選 business_management、whatsapp_business_messaging、whatsapp_business_management 三個權限,過期時間選 Never。
步驟六:(Cloud API)跑精靈填憑證
hermes whatsapp-cloud
預期輸出:精靈逐項收憑證,每貼一項就驗證一項(它會當場抓出「把手機號貼進 Phone Number ID」這個頭號陷阱),寫入 ~/.hermes/.env(變數名前綴 WHATSAPP_CLOUD_),自動產生 Verify Token,最後印出剩下兩件要在精靈外做的事:啟動隧道、到 Meta 儀表板配 webhook。
步驟七:(Cloud API)開隧道、配 webhook、發第一則訊息
啟動隧道(webhook 服務預設綁 8090 端口、路徑 /whatsapp/webhook):
cloudflared tunnel --url http://localhost:8090
預期輸出:一行 https://<隨機字串>.trycloudflare.com 的公網 URL。注意免費快速隧道的 URL 每次重啟都會換;要固定 URL 得 cloudflared tunnel login 建命名隧道。
然後到 Meta App Dashboard → WhatsApp → Configuration → Webhook 按 Edit:Callback URL 填 https://<你的隧道URL>/whatsapp/webhook,Verify Token 填精靈產生的那串,按 Verify and save;再到 Webhook fields → Manage 訂閱 messages 欄位——不訂閱,Meta 不會把入站訊息送進來。
啟動 gateway(hermes gateway)後,想手動驗證回路:
curl -i "https://<你的隧道URL>/whatsapp/webhook?hub.mode=subscribe&hub.verify_token=<VERIFY_TOKEN>&hub.challenge=hello"
預期輸出:HTTP 200、body 是 hello。用你的手機私訊 bot 號碼:訊息立刻變藍雙勾(已讀回執),bot 名稱旁出現「輸入中」,然後收到回覆。開發模式下記得先把收訊號碼加進 Meta 側白名單(API Setup → To → Manage phone number list,最多 5 個號碼,Meta 會發驗證碼)。
誰可以跟你的 Bot 說話
WhatsApp 兩條路的 allowlist 都是沒有就全拒,這一點比微信的預設 open 安全得多,但別因此鬆懈——你的 Bot 背後是能跑終端機指令的 agent。
橋接路徑:WHATSAPP_ALLOWED_USERS=15551234567(國碼開頭、無 +、無空格,逗號分隔)。文件裡有 * 與 WHATSAPP_ALLOW_ALL_USERS=true 兩種「全開」寫法——對有終端機權限的 Bot,不要用它們;GATEWAY_ALLOW_ALL_USERS=true 同理,官方自己標明不建議。陌生人私訊的預設行為是回一個配對碼(全域 unauthorized_dm_behavior: pair),你在機器上核准:
hermes pairing approve whatsapp <CODE>
hermes pairing list
hermes pairing revoke whatsapp <id>
私人號碼不想被陌生人打擾,設 whatsapp.unauthorized_dm_behavior: ignore,未授權私訊直接靜默。配對碼 1 小時過期、有速率限制、密碼學亂數產生。
Cloud API 路徑有雙重名單:Meta 側的收訊白名單管「bot 能發給誰」(開發模式最多 5 人),Hermes 側的 WHATSAPP_CLOUD_ALLOWED_USERS 管「誰的入站訊息會被處理」——不設則全部拒收,這是刻意的:就算 Meta 側白名單哪天放寬了,隨機號碼也叫不動你的 agent。App Secret 要當密碼保管(拿到它就能偽造 Hermes 會接受的 webhook 請求),Access Token 是 bot 的身分,外洩立即撤換。
分級照常可用:gateway.platforms.whatsapp.extra 下設 allow_from / allow_admin_from / user_allowed_commands,admin 能跑全部斜槓指令,一般使用者只能跑你開放的,保底 /help 與 /whoami。
最後,兩條路都繞不開 Prompt Injection(提示詞注入):agent 會讀到不可信的第三方文字(私訊、群訊息、引用的網頁)。allowlist 收緊、危險指令靠 /approve、/deny 把關、群組開 require_mention,是最基本的三道防線。橋接還多一條專屬紀律:session 目錄就是帳號本身,洩了就直接在手機 WhatsApp → 已連結的裝置裡把它解除連結。
常見錯誤與修法
| 症狀 | 原因 | 修法 |
|---|---|---|
| QR code 亂碼、掃不到 | terminal 太窄或不支援 Unicode | 拉到 60 欄以上;換 terminal;確認掃的是 bot 號碼的帳號 |
| QR 一直過期 | QR 約 20 秒刷新 | 重跑 hermes whatsapp;持續過期查網路 |
| 用了一段時間被登出 | WhatsApp 對長期不活躍的連結裝置會解除連結 | 保持手機在線,必要時重新配對 |
| WhatsApp 更新後 bot 失靈 | Web 協議變更,橋接暫時不相容 | 更新 Hermes 到最新版、重新配對 |
| macOS:terminal 裡 node 正常,服務卻報「Node.js not installed」 | launchd 不繼承 shell 的 PATH | 重跑 hermes gateway install 把當前 PATH 快照進 plist,再 hermes gateway start |
| 收不到訊息(橋接) | allowlist 格式錯(要國碼、無 + 無空格) | 核對 WHATSAPP_ALLOWED_USERS;設 WHATSAPP_DEBUG=true 重啟,看 bridge.log 的原始事件 |
| 陌生人私訊會收到配對碼 | 全域預設 unauthorized_dm_behavior: pair | 想靜默就設 whatsapp.unauthorized_dm_behavior: ignore |
| Meta 驗證 webhook 失敗「URL couldn't be validated」 | 隧道 URL 過期/輪換、Verify Token 不一致、gateway 沒在跑、或 App Secret 沒設(入站被拒 503) | 逐項核對;先用 curl 探針在本地確認回路 |
graph error 100 | 把手機號貼進了 Phone Number ID | 到 API Setup 頁「From」下拉選單下方複製 15–17 位的 ID |
graph error 190(subcode 463/467) | token 過期(臨時 token 只有 24 小時)或被撤銷 | 換 System User 永久 token,三個權限勾齊 |
graph error 131047 | 超過 24 小時對話視窗 | 請對方先私訊 bot 重新開窗;延遲送達的排程任務改投其他渠道 |
adapter 顯示 paused-by-breaker | 熔斷器跳開且不自動恢復 | 確認上游健康後 /platform resume whatsapp(Cloud 路徑是 whatsapp_cloud) |
下一步
- 想要最省事的第一個渠道:Telegram 教學——官方 Bot API、免費、十五分鐘
- 要群組與全能力矩陣:飛書/Lark 教學
- 個人帳號自動化這條線你還想再評估:微信教學把灰色地帶的代價講得更細
- 渠道接完,回頭把基礎鏈路驗一遍:裝好 Agent 工具的頭十分鐘