Hermes Gateway 微信适配器 Session Expired 问题修复记录

技术排查 — 微信适配器 token 过期后无限循环报错的根因分析与代码修复

Hermes Gateway 微信适配器 Session Expired 问题修复记录

2026年7月24日

摘要

本文档记录了 Hermes Gateway 微信适配器 Session expired; pausing for 10 minutes 错误反复出现的完整排查过程。问题根因有两个:(1) weixin.py 的 poll loop 在 token 过期后陷入无限重试死循环;(2) writing profile 的 provider 配置缺失导致 agent bridge 无法认证模型调用。通过代码修复 + 配置修正 + 重新扫码登录,问题已彻底解决。


问题现象

Gateway 日志中出现重复报错:

1
ERROR gateway.platforms.weixin: [Weixin] Session expired; pausing for 10 minutes

同时微信客户端收到消息回复:"⚠️ Provider authentication failed. Check the configured credentials; raw provider details are in the gateway logs."

根因分析

原因一:weixin.py _poll_loop 无限重试死循环

gateway/platforms/weixin.py_poll_loop 方法在检测到 iLink Bot token 过期(errcode=-14)后,仅执行 await asyncio.sleep(600) 然后 continue 重试。但 token 不会自动恢复,导致:

  • 每 10 分钟输出一次 Session expired
  • 永远无法恢复,形成 livelock
  • 没有退出条件或重登录触发机制

修复方案: 引入连续过期计数器 consecutive_expired,达到 3 次后设置 self._needs_relogin = True 并退出 poll loop,让外部触发重新登录流程。

原因二:writing profile 缺少 provider 配置

~/.hermes/profiles/writing/config.yaml 中:

1
2
3
4
model:
  default: agnes-2.0-flash
  provider: custom          # ❌ 无效的 provider key
providers: {}               # ❌ 空字典

agent bridge 调用模型时找不到正确的 provider 配置,返回 HTTP 401。

修复方案: 修正 provider 指向 + 补充完整的 providers 配置。


修复步骤

1. 代码修复 — weixin.py

修改文件: ~/.hermes/hermes-agent/gateway/platforms/weixin.py

改动 1:__init__ 添加 self._needs_relogin 初始化

1
2
3
# Set to True when session expired is detected consecutively.
# The poll loop exits and the adapter needs a QR-scan re-login.
self._needs_relogin = False

改动 2:_poll_loop 添加连续过期计数和退出逻辑

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
async def _poll_loop(self) -> None:
    consecutive_expired = 0
    MAX_CONSECUTIVE_EXPIRED = 3
    
    while self._running:
        # ... get updates ...
        
        if ret == SESSION_EXPIRED_ERRCODE or errcode == SESSION_EXPIRED_ERRCODE:
            consecutive_expired += 1
            logger.error("[%s] Session expired (%d/%d)", self.name, consecutive_expired, MAX_CONSECUTIVE_EXPIRED)
            if consecutive_expired >= MAX_CONSECUTIVE_EXPIRED:
                logger.error("[%s] Session expired %d times — needs re-login", self.name, MAX_CONSECUTIVE_EXPIRED)
                self._needs_relogin = True
                break
            await asyncio.sleep(600)
            continue
        
        # Clean up when poll loop exits
        self._release_platform_lock()
        self._mark_disconnected()

2. 配置修复 — writing profile config.yaml

修改文件: ~/.hermes/profiles/writing/config.yaml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
model:
  default: agnes-2.0-flash
  provider: custom:[provider-key]   # ✅ 正确的 provider key
  base_url: https://[api-endpoint]/v1

providers:                                # ✅ 补充 provider 配置
  custom:[provider-key]:
    base_url: https://[api-endpoint]/v1
    api_key: «redacted»                   # 敏感信息已隐藏
    model: agnes-2.0-flash

fallback_providers: []

3. Token 更新 — 重新扫码登录

旧 token 已过期,执行 qr_login() 获取新账号:

项目 旧值 新值
Account ID [已过期] [新扫码获取]
Token [已过期] [新扫码获取]
User ID [已脱敏] 不变

更新 ~/.hermes/.env~/.hermes/profiles/writing/.env 中的 WEIXIN_ACCOUNT_IDWEIXIN_TOKEN

4. 重启 Gateway

1
hermes gateway restart

验证结果:

  • ✅ 新账号连接成功
  • ✅ 消息收发正常
  • ✅ Agent API 调用无 401 错误

经验教训

  1. Token 过期的正确处理方式 — 不应只是 sleep 重试,必须有明确的退出条件和重登录触发机制
  2. Provider 配置必须完整provider 字段指向的 key 必须在 providers 字典中有对应配置
  3. Profile 间配置要一致 — default profile 和 writing profile 的 model/provider 配置应保持一致
  4. 日志中的重复错误通常不是独立问题 — 同一个 root cause 可能产生多条相同的错误日志

后续改进建议

  1. 考虑在 qr_login() 成功后自动更新 .env 文件,避免手动编辑
  2. 增加 token 过期前的主动刷新机制(如果 iLink API 支持)
  3. 将本次修复保存为 skill,方便未来复用

修复完成时间: 2026-07-24 23:45
涉及文件: gateway/platforms/weixin.py, profiles/writing/config.yaml
影响范围: Hermes Gateway 微信适配器