ByteNoteByteNote

字节笔记本

2026年6月21日

hermes教程-Weixin (微信)

API中转
¥120

Connect Hermes 到 WeChat (微信),腾讯的个人消息平台。该适配器使用腾讯的 iLink Bot API 用于个人微信账号——这与企业微信 (WeCom) 不同。消息通过长轮询传递,因此无需公共端点或 webhook。

信息

此适配器适用于个人微信账号 (微信)。如果需要企业/公司微信,请参阅 WeCom 适配器

警告 — iLink 机器人身份 — 普通微信群可能无法工作

二维码登录将 Hermes 连接到一个 iLink 机器人身份 (例如 a5ace6fd482e@im.bot),而不是一个完全可脚本化的普通个人微信账号。后果:

  • iLink 机器人身份通常无法像普通联系人那样被邀请进入普通微信群
  • 对于大多数机器人类型的账号,iLink 通常不会将普通微信群事件(包括对用于二维码登录的个人账号的 @ 提及)传递给网关。
  • @ 提及用于扫描二维码的个人微信账号不等同于 @ 提及 iLink 机器人——机器人是一个独立的身份。
  • 下面的 WEIXIN_GROUP_POLICY / WEIXIN_GROUP_ALLOWED_USERS 设置仅在 iLink 为你的账号类型实际返回群事件时生效。如果不返回,无论策略如何,群消息都不会到达 Hermes。

实际上,大多数部署只能可靠地获得发送给 iLink 机器人的私信。如果配置后群消息传递不起作用,限制在 iLink 端,而不是 Hermes。每当 WEIXIN_GROUP_POLICY 设置为除 disabled 之外的任何值时,网关会在启动时记录一条 WARNING

前提条件

  • 一个个人微信账号
  • Python 包:aiohttpcryptography
  • 当 Hermes 通过 messaging 附加组件安装时,包含终端二维码渲染

安装所需的依赖项:

bash
pip install aiohttp cryptography
## 可选:用于终端二维码显示
pip install hermes-agent[messaging]

设置

1. 运行设置向导

连接微信账号的最简单方法是通过交互式设置:

bash
hermes gateway setup

在提示时选择 Weixin。向导将:

  1. 从 iLink Bot API 请求一个二维码
  2. 在终端中显示二维码(或提供一个 URL)
  3. 等待你用微信手机应用扫描二维码
  4. 提示你在手机上确认登录
  5. 自动将账号凭据保存到 ~/.hermes/weixin/accounts/

确认后,你会看到类似这样的消息:

微信连接成功,account_id=your-account-id

向导会存储 account_idtokenbase_url,因此你无需手动配置。

2. 配置环境变量

初始二维码登录后,至少要在 ~/.hermes/.env 中设置账号 ID:

bash
WEIXIN_ACCOUNT_ID=your-account-id
## 可选:覆盖 token(通常从二维码登录自动保存)
## WEIXIN_TOKEN=your-bot-token
## 可选:限制访问
WEIXIN_DM_POLICY=open
WEIXIN_ALLOWED_USERS=user_id_1,user_id_2
## 可选:恢复旧版多行拆分行为
## WEIXIN_SPLIT_MULTILINE_MESSAGES=true
## 可选:用于 cron/通知的主频道
WEIXIN_HOME_CHANNEL=chat_id
WEIXIN_HOME_CHANNEL_NAME=Home

3. 启动网关

bash
hermes gateway

适配器将恢复已保存的凭据,连接到 iLink API,并开始长轮询消息。

功能

  • 长轮询传输 — 无需公共端点、webhook 或 WebSocket
  • 二维码登录 — 通过 hermes gateway setup 进行扫码连接设置
  • 私信消息 — 可配置的访问策略;群消息取决于 iLink 是否实际为连接的身份传递群事件(对于 iLink 机器人账号通常不是这样——请参见上面的警告)
  • 媒体支持 — 图片、视频、文件和语音消息
  • AES-128-ECB 加密 CDN — 所有媒体传输的自动加密/解密
  • 上下文令牌持久化 — 基于磁盘的回复连续性,重启后仍保持
  • Markdown 格式化 — 保留 Markdown,包括标题、表格和代码块,因此支持 Markdown 的微信客户端可以原生渲染
  • 智能消息分块 — 消息在限制内时保持单个气泡;仅当负载过大时在逻辑边界处拆分
  • 输入指示器 — 在代理处理时,在微信客户端显示“正在输入…”状态
  • SSRF 保护 — 出站媒体 URL 在下载前经过验证
  • 消息去重 — 5 分钟滑动窗口防止重复处理
  • 自动重试与退避 — 从临时 API 错误中恢复

配置选项

config.yamlplatforms.weixin.extra 下设置:

默认值描述
account_idiLink Bot 账号 ID(必需)
tokeniLink Bot 令牌(必需,从二维码登录自动保存)
base_urlhttps://ilinkai.weixin.qq.comiLink API 基础 URL
cdn_base_urlhttps://novac2c.cdn.weixin.qq.com/c2c媒体传输的 CDN 基础 URL
dm_policyopen私信访问:openallowlistdisabledpairing
group_policydisabled群访问:openallowlistdisabled
allow_from[]允许私信的用户 ID(当 dm_policy=allowlist 时)
group_allow_from[]允许的群 ID(当 group_policy=allowlist 时)
split_multiline_messagesfalse当为 true 时,将多行回复拆分为多条聊天消息(旧版行为)。当为 false 时,将多行回复保留为一条消息,除非超过长度限制。
text_batch_delay_seconds3.0在缓冲的快速文本消息突发被刷新为单个组合请求之前的静默期(秒)。iLink 单独传递消息,因此此去抖避免每次片段调用一次代理。设置为 0 以立即分发每条消息。
text_batch_split_delay_seconds5.0当最新片段接近拆分阈值(iLink 可能已分块的长消息)时使用的扩展刷新延迟。

访问策略

私信策略

控制谁可以向机器人发送直接消息:

行为
open任何人都可以向机器人发送私信(默认)
allowlist只有 allow_from 中的用户 ID 可以发送私信
disabled忽略所有私信
pairing配对模式(用于初始设置)
bash
WEIXIN_DM_POLICY=allowlist
WEIXIN_ALLOWED_USERS=user_id_1,user_id_2

WEIXIN_ALLOWED_USERS 是一个入站过滤器,而不是邀请系统。二维码登录将一个 iLink 机器人身份连接到 Hermes。其他人不会用自己的账号扫描 Hermes 二维码;他们必须通过微信向连接的 iLink 机器人/联系人发送消息,并且只有当发送者的微信用户 ID 存在于 WEIXIN_ALLOWED_USERS 中时,Hermes 才会处理该私信。

一个实际的设置流程是:

  1. 使用 hermes gateway setup 配对一次 Hermes,并记下连接的 iLink 机器人账号。
  2. 让每个允许的用户向该机器人/联系人发送一条直接消息。
  3. 从网关日志或入站事件负载中读取发送者/用户 ID。
  4. 将这些 ID 添加到 WEIXIN_ALLOWED_USERS,然后重启网关。

如果只有扫描二维码的账号可以与 Hermes 通信,请验证其他用户是否正在向 iLink 机器人身份本身发送消息,而不是执行二维码登录的个人微信账号。iLink 机器人是一个独立的身份,并且普通的微信联系人/群路由可能受到腾讯 iLink 行为的限制。

群策略

控制机器人在哪些群中响应当 iLink 为连接的身份传递群事件时。对于二维码登录的 iLink 机器人身份(例如 ...@im.bot),群事件通常根本不会传递,因此此策略可能无效——请参见页面顶部的 iLink 机器人限制警告。

行为
open机器人在所有群中响应(如果事件被传递)
allowlist机器人仅在 group_allow_from 中列出的群 ID 中响应(如果事件被传递)
disabled忽略所有群消息(默认)
bash
WEIXIN_GROUP_POLICY=allowlist
## 注意:这是一个以逗号分隔的群聊 ID 列表,而不是成员用户 ID,
## 尽管变量名包含 "USERS"。配置时请记住这一点。
WEIXIN_GROUP_ALLOWED_USERS=group_id_1,group_id_2

注意

微信的默认群策略是 disabled(与 WeCom 默认 open 不同)。这是有意为之——个人微信账号可能位于许多群中,而 iLink 机器人身份通常根本无法接收普通微信群消息。如果你将 WEIXIN_GROUP_POLICY 设置为除 disabled 之外的任何值,网关会在启动时记录一条 WARNING

媒体支持

入站(接收)

适配器接收来自用户的媒体附件,从微信 CDN 下载,解密,并在本地缓存以供代理处理:

类型处理方式
图片下载,AES 解密,并缓存为 JPEG。
视频下载,AES 解密,并缓存为 MP4。
文件下载,AES 解密,并缓存。保留原始文件名。
语音如果有文本转录,则提取为文本。否则下载并缓存音频(SILK 格式)。

引用消息: 也会提取来自引用(回复)消息的媒体,以便代理了解用户正在回复的内容。

AES-128-ECB 加密 CDN

微信媒体文件通过加密 CDN 传输。适配器透明地处理:

  • 入站: 使用 encrypted_query_param URL 从 CDN 下载加密媒体,然后使用消息负载中提供的每文件密钥通过 AES-128-ECB 解密。
  • 出站: 文件使用随机 AES-128-ECB 密钥在本地加密,上传到 CDN,并将加密引用包含在出站消息中。
  • AES 密钥为 16 字节(128 位)。密钥可能以原始 base64 或十六进制编码到达——适配器处理两种格式。
  • 这需要 cryptography Python 包。

无需配置——加密和解密自动进行。

出站(发送)

方法发送内容
send带有 Markdown 格式的文本消息
send_image / send_image_file原生图片消息(通过 CDN 上传)
send_document文件附件(通过 CDN 上传)
send_video视频消息(通过 CDN 上传)

所有出站媒体都经过加密 CDN 上传流程:

  1. 生成随机 AES-128 密钥
  2. 使用 AES-128-ECB + PKCS#7 填充加密文件
  3. 从 iLink API 请求上传 URL(getuploadurl
  4. 将密文上传到 CDN
  5. 发送带有加密媒体引用的消息

上下文令牌持久化

iLink Bot API 要求对于每个对等方,在每条出站消息中回显一个 context_token。适配器维护一个基于磁盘的上下文令牌存储:

  • 令牌按账号+对等方保存到 ~/.hermes/weixin/accounts/<account_id>.context-tokens.json
  • 启动时,恢复之前保存的令牌
  • 每条入站消息更新该发送者的存储令牌
  • 出站消息自动包含最新的上下文令牌

这确保了即使网关重启后回复也能连续。

Markdown 格式化

通过 iLink Bot API 连接的微信客户端可以直接渲染 Markdown,因此适配器保留 Markdown 而不是重写它:

  • 标题 保持为 Markdown 标题(###、...)
  • 表格 保持为 Markdown 表格
  • 代码围栏 保持为围栏代码块
  • 过多的空行 在围栏代码块外折叠为双换行

消息分块

消息在平台限制内时作为单条聊天消息传递。仅当负载过大时才拆分传递:

  • 最大消息长度:4000 字符
  • 低于限制的消息即使包含多个段落或换行也保持完整
  • 过大的消息在逻辑边界处拆分(段落、空行、代码围栏)
  • 代码围栏尽可能保持完整(除非围栏本身超过限制,否则绝不中途拆分)
  • 过大的单个块回退到基础适配器的截断逻辑
  • 发送多个块时,块间延迟 0.3 秒以防止微信速率限制丢弃

输入指示器

适配器在微信客户端中显示输入状态:

  1. 当消息到达时,适配器通过 getconfig API 获取一个 typing_ticket
  2. 输入票证按用户缓存 10 分钟
  3. send_typing 发送输入开始信号;stop_typing 发送输入停止信号
  4. 当代理处理消息时,网关自动触发输入指示器

长轮询连接

适配器使用 HTTP 长轮询(而非 WebSocket)接收消息:

工作原理

  1. 连接: 验证凭据并启动轮询循环
  2. 轮询: 使用 35 秒超时调用 getupdates;服务器保持请求直到消息到达或超时到期
  3. 分发: 入站消息通过 asyncio.create_task 并发分发
  4. 同步缓冲区: 一个持久的同步游标(get_updates_buf)保存到磁盘,以便适配器在重启后从正确位置恢复

重试行为

在 API 错误时,适配器使用简单的重试策略:

条件行为
临时错误(第 1-2 次)2 秒后重试
重复错误(第 3 次及以上)退避 30 秒,然后重置计数器
会话过期(errcode=-14暂停 10 分钟(可能需要重新登录)
超时立即重新轮询(正常长轮询行为)

去重

入站消息使用消息 ID 进行去重,窗口为 5 分钟。这防止了网络波动或重叠轮询响应期间的重复处理。

令牌锁

一次只能有一个微信网关实例使用给定的令牌。适配器在启动时获取一个作用域锁,并在关闭时释放。如果另一个网关已经在使用相同的令牌,启动将失败并显示信息性错误消息。

所有环境变量

变量必需默认值描述
WEIXIN_ACCOUNT_IDiLink Bot 账号 ID(来自二维码登录)
WEIXIN_TOKENiLink Bot 令牌(从二维码登录自动保存)
WEIXIN_BASE_URLhttps://ilinkai.weixin.qq.comiLink API 基础 URL
WEIXIN_CDN_BASE_URLhttps://novac2c.cdn.weixin.qq.com/c2c媒体传输的 CDN 基础 URL
WEIXIN_DM_POLICYopen私信访问策略:openallowlistdisabledpairing
WEIXIN_GROUP_POLICYdisabled群访问策略:openallowlistdisabled
WEIXIN_ALLOWED_USERS(空)私信允许列表的用户 ID,逗号分隔
WEIXIN_GROUP_ALLOWED_USERS(空)群允许列表的群聊 ID(不是成员用户 ID),逗号分隔。变量名是遗留的——它期望群 ID,而不是用户 ID。
WEIXIN_HOME_CHANNEL用于 cron/通知输出的聊天 ID
WEIXIN_HOME_CHANNEL_NAMEHome主频道的显示名称
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=openallowlist——但请注意,二维码登录的 iLink 机器人身份(...@im.bot)通常根本无法接收普通微信群消息。如果网关日志没有显示群消息的原始入站事件,则限制在 iLink 端,而不是 Hermes。
媒体下载/上传失败确保已安装 cryptography。检查对 novac2c.cdn.weixin.qq.com 的网络访问
Blocked unsafe URL (SSRF protection)出站媒体 URL 指向私有/内部地址。只允许公共 URL
语音消息显示为文本如果微信提供转录,适配器使用文本。这是预期行为
消息出现重复适配器按消息 ID 去重。如果看到重复,请检查是否运行了多个网关实例
iLink POST ... HTTP 4xx/5xxiLink 服务的 API 错误。检查令牌有效性和网络连接
终端二维码不显示使用 messaging 附加组件重新安装:pip install hermes-agent[messaging]。或者,打开二维码上方打印的 URL


分享: