WeCom(企業微信)
將 Hermes 與 WeCom(騰訊的企業級消息平臺)連接。該適配器使用 WeCom 的 AI Bot WebSocket 網關實現實時雙向通信——無需公開端點或 Webhook。
先決條件
- 一個 WeCom 組織賬號
- 在 WeCom 管理控制檯中創建的 AI Bot
- 從 Bot 的憑證頁面獲取的 Bot ID 和 Secret
- Python 包:
aiohttp和httpx
設置
1. 創建 AI Bot
- 登錄 WeCom 管理控制檯
- 導航至 應用 → 創建應用 → AI Bot
- 配置 Bot 名稱和描述
- 從憑證頁面複製 Bot ID 和 Secret
2. 配置 Hermes
運行交互式設置:
hermes gateway setup
選擇 WeCom,並輸入您的 Bot ID 和 Secret。
或者在 ~/.hermes/.env 中設置環境變量:
WECOM_BOT_ID=your-bot-id
WECOM_SECRET=your-secret
# 可選:限制訪問
WECOM_ALLOWED_USERS=user_id_1,user_id_2
# 可選:為 Cron / 通知設置主頻道
WECOM_HOME_CHANNEL=chat_id
3. 啟動網關
hermes gateway
功能特性
- WebSocket 傳輸 —— 持久連接,無需公開端點
- 私信與群組消息 —— 可配置訪問策略
- 按群組發送者白名單 —— 對每個群組中誰可以互動進行細粒度控制
- 媒體支持 —— 支持圖片、文件、語音、視頻的上傳與下載
- AES 加密媒體 —— 自動解密傳入的附件
- 引用上下文 —— 保留回覆的線程結構
- Markdown 渲染 —— 支持富文本響應
- 回覆模式流式輸出 —— 將響應與傳入消息上下文相關聯
- 自動重連 —— 連接中斷時採用指數退避重試
配置選項
在 config.yaml 中的 platforms.wecom.extra 下設置以下選項:
| 鍵 | 默認值 | 描述 |
|---|---|---|
bot_id | — | WeCom AI Bot ID(必需) |
secret | — | WeCom AI Bot Secret(必需) |
websocket_url | wss://openws.work.weixin.qq.com | WebSocket 網關 URL |
dm_policy | open | 私信訪問策略:open、allowlist、disabled、pairing |
group_policy | open | 群組訪問策略:open、allowlist、disabled |
allow_from | [] | 允許私信的用戶 ID 列表(當 dm_policy=allowlist 時) |
group_allow_from | [] | 允許的群組 ID 列表(當 group_policy=allowlist 時) |
groups | {} | 按群組配置(見下文) |
訪問策略
私信策略(DM Policy)
控制誰可以向 Bot 發送私信:
| 值 | 行為 |
|---|---|
open | 任何人都可以向 Bot 發送私信(默認) |
allowlist | 僅 allow_from 列表中的用戶 ID 可以發送私信 |
disabled | 所有私信均被忽略 |
pairing | 配對模式(用於初始設置) |
WECOM_DM_POLICY=allowlist
群組策略(Group Policy)
控制 Bot 在哪些群組中響應:
| 值 | 行為 |
|---|---|
open | Bot 在所有群組中響應(默認) |
allowlist | Bot 僅在 group_allow_from 列表中的群組 ID 中響應 |
disabled | 所有群組消息均被忽略 |
WECOM_GROUP_POLICY=allowlist
按群組發送者白名單
為實現細粒度控制,您可以限制特定群組中哪些用戶可以與 Bot 互動。該配置在 config.yaml 中完成:
platforms:
wecom:
enabled: true
extra:
bot_id: "your-bot-id"
secret: "your-secret"
group_policy: "allowlist"
group_allow_from:
- "group_id_1"
- "group_id_2"
groups:
group_id_1:
allow_from:
- "user_alice"
- "user_bob"
group_id_2:
allow_from:
- "user_charlie"
"*":
allow_from:
- "user_admin"
工作原理:
group_policy和group_allow_from控制某個群組是否被允許。- 如果群組通過了頂層檢查,則
groups.<group_id>.allow_from列表(如果存在)會進一步限制該群組內哪些發送者可以與 Bot 互動。 - 通配符
"*"條目可作為未顯式列出群組的默認規則。 - 白名單條目支持
*通配符以允許所有用戶,且條目不區分大小寫。 - 條目可選擇使用
wecom:user:或wecom:group:前綴格式——前綴會自動剝離。
如果某個群組未配置 allow_from,則該群組中所有用戶均被允許(前提是該群組本身通過了頂層策略檢查)。
媒體支持
入站(接收)
適配器接收用戶發送的媒體附件,並在本地緩存以供 Agent 處理:
| 類型 | 處理方式 |
|---|---|
| 圖片 | 下載並本地緩存。支持基於 URL 和 base64 編碼的圖片。 |
| 文件 | 下載並緩存。文件名保留原始消息中的名稱。 |
| 語音 | 若可用,提取語音消息的文本轉錄。 |
| 混合消息 | WeCom 的混合類型消息(文本 + 圖片)會被解析,所有組件均被提取。 |
引用消息: 被引用(回覆)的消息中的媒體也會被提取,使 Agent 能夠了解用戶正在回覆的內容。
AES 加密媒體解密
WeCom 使用 AES-256-CBC 對部分入站媒體附件進行加密。該適配器會自動處理解密過程:
- 當入站媒體項包含
aeskey字段時,適配器會下載加密字節,並使用 AES-256-CBC 加密算法配合 PKCS#7 填充進行解密。 - AES 密鑰為
aeskey字段的 base64 解碼值(必須恰好為 32 字節)。 - IV 由密鑰的前 16 字節導出。
- 此功能需要
cryptographyPython 包(運行pip install cryptography安裝)。
無需配置——當接收到加密媒體時,解密將自動透明完成。
出站(發送)
| 方法 | 發送內容 | 大小限制 |
|---|---|---|
send | Markdown 文本消息 | 4000 字符 |
send_image / send_image_file | 原生圖片消息 | 10 MB |
send_document | 文件附件 | 20 MB |
send_voice | 語音消息(僅支持原生語音的 AMR 格式) | 2 MB |
send_video | 視頻消息 | 10 MB |
分塊上傳:文件通過三步協議(初始化 → 分塊 → 完成)以 512 KB 為單位上傳。適配器會自動處理此過程。
自動降級:當媒體超出原生類型大小限制但仍在絕對 20 MB 文件限制內時,將自動作為通用文件附件發送:
- 圖片 > 10 MB → 作為文件發送
- 視頻 > 10 MB → 作為文件發送
- 語音 > 2 MB → 作為文件發送
- 非 AMR 音頻 → 作為文件發送(僅 WeCom 支持 AMR 格式的原生語音)
超過絕對 20 MB 限制的文件將被拒絕,並向聊天發送一條信息提示。
回覆模式流式響應
當機器人通過 WeCom 回調收到消息時,適配器會記住入站請求 ID。如果在請求上下文仍有效時發送響應,適配器將使用 WeCom 的回覆模式(aibot_respond_msg)並啟用流式傳輸,將響應直接關聯到入站消息。這在 WeCom 客戶端中提供更自然的對話體驗。
如果入站請求上下文已過期或不可用,適配器將回退至通過 aibot_send_msg 主動發送消息。
回覆模式也適用於媒體:上傳的媒體可作為對原始消息的回覆發送。
連接與重連
適配器維護與 WeCom 網關的持久化 WebSocket 連接,地址為 wss://openws.work.weixin.qq.com。
連接生命週期
- 連接:打開 WebSocket 連接,併發送包含 bot_id 和 secret 的
aibot_subscribe認證幀。 - 心跳:每 30 秒發送一次應用層 ping 幀,以保持連接活躍。
- 監聽:持續讀取入站幀並分發消息回調。
重連行為
連接丟失後,適配器使用指數退避機制進行重連:
| 嘗試次數 | 延遲 |
|---|---|
| 第 1 次重試 | 2 秒 |
| 第 2 次重試 | 5 秒 |
| 第 3 次重試 | 10 秒 |
| 第 4 次重試 | 30 秒 |
| 第 5 次及以上重試 | 60 秒 |
每次成功重連後,退避計數器重置為 0。斷開連接時,所有待處理的請求未來對象均被標記為失敗,防止調用者無限掛起。
去重
入站消息通過消息 ID 進行去重,窗口為 5 分鐘,最大緩存條目數為 1000 條。這可防止在重連或網絡波動期間重複處理消息。
所有環境變量
| 變量 | 是否必需 | 默認值 | 描述 |
|---|---|---|---|
WECOM_BOT_ID | ✅ | — | WeCom AI Bot ID |
WECOM_SECRET | ✅ | — | WeCom AI Bot Secret |
WECOM_ALLOWED_USERS | — | (空) | 用於網關級別白名單的逗號分隔用戶 ID 列表 |
WECOM_HOME_CHANNEL | — | — | 用於定時任務/通知輸出的聊天 ID |
WECOM_WEBSOCKET_URL | — | wss://openws.work.weixin.qq.com | WebSocket 網關 URL |
WECOM_DM_POLICY | — | open | 私聊訪問策略 |
WECOM_GROUP_POLICY | — | open | 群組訪問策略 |
故障排除
| 問題 | 解決方案 |
|---|---|
WECOM_BOT_ID and WECOM_SECRET are required | 設置兩個環境變量,或在設置嚮導中進行配置 |
WeCom startup failed: aiohttp not installed | 安裝 aiohttp:pip install aiohttp |
WeCom startup failed: httpx not installed | 安裝 httpx:pip install httpx |
invalid secret (errcode=40013) | 確認密鑰與機器人的憑證匹配 |
Timed out waiting for subscribe acknowledgement | 檢查與 openws.work.weixin.qq.com 的網絡連接 |
| 機器人在群組中無響應 | 檢查 group_policy 設置,並確保群組 ID 在 group_allow_from 列表中 |
| 機器人忽略群組中的某些用戶 | 檢查 groups 配置部分中各群組的 allow_from 列表 |
| 媒體解密失敗 | 安裝 cryptography:pip install cryptography |
cryptography is required for WeCom media decryption | 入站媒體為 AES 加密。請安裝:pip install cryptography |
| 語音消息以文件形式發送 | WeCom 僅支持原生 AMR 格式的語音消息。其他格式將自動降級為文件發送。 |
File too large 錯誤 | WeCom 對所有文件上傳有 20 MB 的絕對限制。請壓縮或拆分文件。 |
| 圖片以文件形式發送 | 圖片大小超過 10 MB 時,超出原生圖片限制,將自動降級為文件附件。 |
Timeout sending message to WeCom | WebSocket 可能已斷開。請檢查日誌中是否有重連消息。 |
WeCom websocket closed during authentication | 網絡問題或憑證錯誤。請驗證 bot_id 和 secret。 |