微信 (WeChat)
將 Hermes 連接到 微信(騰訊的個人即時通訊平臺)。該適配器使用騰訊的 iLink Bot API 來支持個人微信賬號——這與企業微信(WeCom)不同。消息通過長輪詢方式傳輸,因此無需公網端點或 Webhook。
此適配器適用於 個人微信賬號(微信)。如需企業/公司微信,請參閱 企業微信適配器。
前提條件
- 一個個人微信賬號
- Python 包:
aiohttp和cryptography qrcode包為可選(用於在設置過程中在終端中渲染二維碼)
安裝所需依賴:
pip install aiohttp cryptography
# 可選:用於終端QR代碼顯示
pip install qrcode
設置
1. 運行設置嚮導
連接微信賬號最簡單的方式是通過交互式設置嚮導:
hermes gateway setup
提示時選擇 Weixin。嚮導將執行以下操作:
- 向 iLink Bot API 請求一個二維碼
- 在終端中顯示二維碼(或提供一個 URL)
- 等待您使用微信手機 App 掃描二維碼
- 提示您在手機上確認登錄
- 自動將賬號憑證保存至
~/.hermes/weixin/accounts/
確認後,您將看到類似如下消息:
微信連接成功,account_id=your-account-id
嚮導會保存 account_id、token 和 base_url,因此無需手動配置。
2. 配置環境變量
首次通過二維碼登錄後,請在 ~/.hermes/.env 中至少設置賬號 ID:
WEIXIN_ACCOUNT_ID=your-account-id
# 可選:覆蓋 token(通常從 QR 登錄自動保存)
# WEIXIN_TOKEN=你的機器人-token
# 可選:限制訪問
WEIXIN_DM_POLICY=open
WEIXIN_ALLOWED_USERS=user_id_1,user_id_2
# 可選:為 Cron / 通知設置主頻道
WEIXIN_HOME_CHANNEL=chat_id
WEIXIN_HOME_CHANNEL_NAME=Home
3. 啟動網關
hermes gateway
適配器將恢復保存的憑證,連接到 iLink API,並開始長輪詢接收消息。
功能特性
- 長輪詢傳輸 —— 無需公網端點、Webhook 或 WebSocket
- 二維碼登錄 —— 通過
hermes gateway setup實現掃碼連接 - 私信與群組消息 —— 可配置訪問策略
- 媒體支持 —— 圖片、視頻、文件和語音消息
- AES-128-ECB 加密 CDN —— 所有媒體傳輸自動加密/解密
- 上下文令牌持久化 —— 磁盤持久化,支持重啟後繼續回覆
- Markdown 格式化 —— 標題、表格和代碼塊會重新格式化以適配微信閱讀
- 智能消息分塊 —— 長消息在邏輯邊界(段落、代碼塊)處自動拆分
- 輸入提示 —— Agent 處理時,微信客戶端會顯示“正在輸入…”狀態
- SSRF 保護 —— 下載前驗證出站媒體 URL
- 消息去重 —— 5 分鐘滑動窗口防止重複處理
- 自動重試帶退避機制 —— 可從臨時 API 錯誤中恢復
配置選項
在 config.yaml 中的 platforms.weixin.extra 下設置以下選項:
| 鍵 | 默認值 | 描述 |
|---|---|---|
account_id | — | iLink Bot 賬號 ID(必需) |
token | — | iLink Bot 令牌(必需,由二維碼登錄自動保存) |
base_url | https://ilinkai.weixin.qq.com | iLink API 基礎 URL |
cdn_base_url | https://novac2c.cdn.weixin.qq.com/c2c | 媒體傳輸的 CDN 基礎 URL |
dm_policy | open | 私信訪問策略:open、allowlist、disabled、pairing |
group_policy | disabled | 群組訪問策略:open、allowlist、disabled |
allow_from | [] | 允許私信的用戶 ID 列表(當 dm_policy=allowlist 時) |
group_allow_from | [] | 允許響應的群組 ID 列表(當 group_policy=allowlist 時) |
訪問策略
私信策略(DM Policy)
控制誰可以向機器人發送私信:
| 值 | 行為 |
|---|---|
open | 任何人都可以向機器人發送私信(默認) |
allowlist | 僅 allow_from 列表中的用戶 ID 可發送私信 |
disabled | 所有私信均被忽略 |
pairing | 配對模式(用於初始設置) |
WEIXIN_DM_POLICY=allowlist
WEIXIN_ALLOWED_USERS=user_id_1,user_id_2
群組策略(Group Policy)
控制機器人在哪些群組中響應:
| 值 | 行為 |
|---|---|
open | 機器人在所有群組中響應 |
allowlist | 機器人僅在 group_allow_from 列表中的群組 ID 中響應 |
disabled | 所有群組消息均被忽略(默認) |
WEIXIN_GROUP_POLICY=allowlist
WEIXIN_GROUP_ALLOWED_USERS=group_id_1,group_id_2
個人微信賬號的默認群組策略為 disabled(與企業微信默認為 open 不同)。這是有意為之,因為個人微信賬號可能加入大量群組。
媒體支持
入站(接收)
適配器接收用戶發送的媒體附件,從微信 CDN 下載,解密後本地緩存,供 Agent 處理:
| 類型 | 處理方式 |
|---|---|
| 圖片 | 下載、AES 解密,並緩存為 JPEG 格式。 |
| 視頻 | 下載、AES 解密,並緩存為 MP4 格式。 |
| 文件 | 下載、AES 解密,並緩存。保留原始文件名。 |
| 語音 | 若有文字轉錄,提取為文本;否則下載 SILK 格式的音頻並緩存。 |
引用消息:來自被引用(回覆)消息的媒體也會被提取,使 Agent 能夠了解用戶回覆的內容上下文。
AES-128-ECB 加密 CDN
微信媒體文件通過加密 CDN 傳輸。適配器會透明地處理此過程:
- 入站(Inbound): 使用
encrypted_query_paramURL 從 CDN 下載加密媒體,然後使用 AES-128-ECB 加密算法配合消息負載中提供的文件級密鑰進行解密。 - 出站(Outbound): 文件在本地使用隨機生成的 AES-128-ECB 密鑰加密,上傳至 CDN,加密後的引用信息包含在出站消息中。
- AES 密鑰長度為 16 字節(128 位)。密鑰可以以原始 base64 或十六進制編碼形式到達 —— 適配器會自動處理這兩種格式。
- 此功能需要安裝
cryptographyPython 包。
無需任何配置 —— 加密與解密過程自動完成。
出站(發送)
| 方法 | 發送內容 |
|---|---|
send | 帶有 Markdown 格式的文本消息 |
send_image / send_image_file | 原生圖片消息(通過 CDN 上傳) |
send_document | 文件附件(通過 CDN 上傳) |
send_video | 視頻消息(通過 CDN 上傳) |
所有出站媒體均通過加密 CDN 上傳流程:
- 生成一個隨機的 AES-128 密鑰
- 使用 AES-128-ECB + PKCS#7 填充對文件進行加密
- 通過 iLink API 請求上傳 URL(
getuploadurl) - 將密文上傳至 CDN
- 發送消息並附帶加密媒體引用
上下文令牌持久化
iLink Bot API 要求每個出站消息必須回傳與特定對端關聯的 context_token。適配器維護一個基於磁盤的上下文令牌存儲:
- 每個賬戶+對端的令牌保存在
~/.hermes/weixin/accounts/<account_id>.context-tokens.json - 啟動時,先前保存的令牌會被恢復
- 每條入站消息都會更新對應發送者的存儲令牌
- 出站消息會自動包含最新的上下文令牌
這確保了即使網關重啟後仍能保持回覆連續性。
Markdown 格式化
微信個人聊天不原生支持完整的 Markdown 渲染。適配器會對內容進行重格式化以提升可讀性:
- 標題(
# 標題)→ 轉換為【標題】(一級標題)或**標題**(二級及以上) - 表格 → 重格式化為帶標籤的鍵值列表(例如:
- 列名: 值) - 代碼塊 → 保持原樣(微信可良好渲染)
- 過多的空白行 → 合併為雙換行
消息分塊
長消息會智能拆分以適配聊天傳輸:
- 單條消息最大長度:4000 字符
- 拆分點優先選擇段落邊界和空行
- 代碼塊保持完整(不會在塊內拆分)
- 縮進的續行(重格式化表格/列表中的子項)與父項保持在一起
- 超大單個塊將回退至基礎適配器的截斷邏輯
輸入狀態指示
適配器會在微信客戶端顯示輸入狀態:
- 當消息到達時,適配器通過
getconfigAPI 獲取typing_ticket - 每個用戶的
typing_ticket緩存 10 分鐘 send_typing發送輸入開始信號;stop_typing發送輸入停止信號- 網關在 Agent 處理消息期間自動觸發輸入狀態指示
長輪詢連接
適配器使用 HTTP 長輪詢(非 WebSocket)接收消息:
工作原理
- 連接: 驗證憑證並啟動輪詢循環
- 輪詢: 調用
getupdates,設置 35 秒超時;服務器保持請求打開,直到有消息到達或超時 - 分發: 入站消息通過
asyncio.create_task併發分發 - 同步緩衝: 持久化的同步遊標(
get_updates_buf)保存在磁盤,確保適配器重啟後能從正確位置恢復
重試行為
在 API 錯誤時,適配器採用簡單的重試策略:
| 條件 | 行為 |
|---|---|
| 臨時錯誤(第 1–2 次) | 2 秒後重試 |
| 重複錯誤(第 3 次及以上) | 退避 30 秒,然後重置計數器 |
會話過期(errcode=-14) | 暫停 10 分鐘(可能需要重新登錄) |
| 超時 | 立即重新輪詢(正常長輪詢行為) |
去重
入站消息通過消息 ID 進行去重,窗口為 5 分鐘。這可防止網絡波動或重疊輪詢響應導致的重複處理。
令牌鎖
同一令牌僅允許一個 Weixin 網關實例使用。適配器在啟動時獲取作用域鎖,並在關閉時釋放。若已有其他網關正在使用相同令牌,啟動將失敗並顯示提示性錯誤信息。
所有環境變量
| 變量 | 必需 | 默認值 | 描述 |
|---|---|---|---|
WEIXIN_ACCOUNT_ID | ✅ | — | iLink Bot 賬號 ID(來自二維碼登錄) |
WEIXIN_TOKEN | ✅ | — | iLink Bot 令牌(通過二維碼登錄自動保存) |
WEIXIN_BASE_URL | — | https://ilinkai.weixin.qq.com | iLink API 基礎 URL |
WEIXIN_CDN_BASE_URL | — | https://novac2c.cdn.weixin.qq.com/c2c | 媒體傳輸的 CDN 基礎 URL |
WEIXIN_DM_POLICY | — | open | 私信訪問策略:open、allowlist、disabled、pairing |
WEIXIN_GROUP_POLICY | — | disabled | 群組訪問策略:open、allowlist、disabled |
WEIXIN_ALLOWED_USERS | — | (空) | 用逗號分隔的用戶 ID,用於私信白名單 |
WEIXIN_GROUP_ALLOWED_USERS | — | (空) | 用逗號分隔的群組 ID,用於群組白名單 |
WEIXIN_HOME_CHANNEL | — | — | 用於定時任務/通知輸出的聊天 ID |
WEIXIN_HOME_CHANNEL_NAME | — | Home | 主頻道的顯示名稱 |
WEIXIN_ALLOW_ALL_USERS | — | — | 網關級別標誌,允許所有用戶(由設置嚮導使用) |
故障排除
| 問題 | 解決方法 |
|---|---|
Weixin startup failed: aiohttp and cryptography are required | 安裝兩者:pip install aiohttp cryptography |
Weixin startup failed: WEIXIN_TOKEN is required | 運行 hermes gateway setup 完成二維碼登錄,或手動設置 WEIXIN_TOKEN |
Weixin startup failed: WEIXIN_ACCOUNT_ID is required | 在 .env 文件中設置 WEIXIN_ACCOUNT_ID,或運行 hermes gateway setup |
Another local Hermes gateway is already using this Weixin token | 首先停止其他網關實例——每個令牌僅允許一個輪詢器 |
會話已過期(errcode=-14) | 您的登錄會話已過期。重新運行 hermes gateway setup 掃描新的二維碼 |
| 設置過程中二維碼已過期 | 二維碼最多自動刷新 3 次。如果持續過期,請檢查網絡連接 |
| 機器人不響應私信 | 檢查 WEIXIN_DM_POLICY —— 若設置為 allowlist,發送者必須在 WEIXIN_ALLOWED_USERS 中 |
| 機器人忽略群消息 | 群組策略默認為 disabled。請將 WEIXIN_GROUP_POLICY 設置為 open 或 allowlist |
| 媒體下載/上傳失敗 | 確保已安裝 cryptography。檢查對 novac2c.cdn.weixin.qq.com 的網絡訪問權限 |
Blocked unsafe URL (SSRF protection) | 外部媒體 URL 指向私有/內部地址。僅允許公共 URL |
| 語音消息顯示為文本 | 若微信提供語音轉文字,適配器將使用文本。這是預期行為 |
| 消息出現重複 | 適配器通過消息 ID 去重。若仍見重複,請檢查是否運行了多個網關實例 |
iLink POST ... HTTP 4xx/5xx | iLink 服務端 API 錯誤。請檢查令牌有效性及網絡連接 |
| 終端二維碼無法渲染 | 安裝 qrcode:pip install qrcode。或打開二維碼上方打印的 URL |