🤖 Hermes Agent 长连接保持技术专题

目录

一、核心架构概览

30s
WebSocket ping_interval
3600s
业务消息僵死检测
30s
重连退避上限
3
Hermes并发上限
180s
MCP巡检间隔
核心挑战:AI Agent的WebSocket连接面临三大威胁——网络瞬断、服务器端超时、服务端重启。需要多层防御:①协议层自动ping/pong ②应用层僵死检测 ③守护进程兜底。

1.1 系统组件关系图

┌─────────────────────────────────────────────────────────┐
│                  天枢 Hub (x.kddauto.com)                │
│              wss://x.kddauto.com/ws/agent               │
└──────────────┬──────────────────────────────────────────┘
               │ WebSocket (ping_interval=30, ping_timeout=15)
               │ HTTP REST (每5分钟 /daemon/heartbeat)
┌──────────────▼──────────────────────────────────────────┐
│         agent_loop_ws_v4.py (知微Daemon)                │
│                                                         │
│  ┌─────────────────────────────────────────────────┐   │
│  │  listen_ws() — 主循环                           │   │
│  │  · websockets.connect() with timeouts           │   │
│  │  · 僵死检测: 3600s无业务消息 → 主动断连重连      │   │
│  │  · 重连: 指数退避 1→2→4→...→30s (+jitter)      │   │
│  └─────────────────────────────────────────────────┘   │
│                                                         │
│  ┌──────────────┐  ┌─────────────┐  ┌─────────────┐  │
│  │ _hermes_exec │  │ MCP Periodic│  │ Self-Upgrade│  │
│  │ (子进程池)    │  │ Scan(180s) │  │ Check(30min)│  │
│  │ Semaphore≤3  │  │             │  │             │  │
│  └──────────────┘  └─────────────┘  └─────────────┘  │
└─────────────────────────────────────────────────────────┘
               │
               │ fork()+exec() 自升级
               ▼
         /tmp/agent_loop_ws_v4.py (已更新)

二、WebSocket保活机制

2.1 协议层 — WebSocket Built-in Ping/Pong

连接参数(V12.8.0016):
ping_interval30秒客户端每30秒自动发送ping
ping_timeout15秒等待pong响应的超时
close_timeout5秒关闭连接的超时
open_timeout30秒连接建立超时
# agent_loop_ws_v4.py 第1341行
async with websockets.connect(
    ws_url,
    ping_interval=30,   # 每30s发ping
    ping_timeout=15,    # 等pong最多15s
    close_timeout=5,    # 关闭超时5s
    open_timeout=30     # 连接建立超时30s (V12.6.0032修复)
) as ws:
    ...

2.2 应用层 — 业务消息僵死检测

协议层ping/pong只能检测网络层存活,无法检测业务层僵死(如服务器僵住但TCP活着)。因此增加了应用层僵死检测。

僵死检测原理:跟踪最后一次收到业务消息的时间(排除ping/pong/heartbeat)。如果超过3600秒(1小时)无业务消息,说明连接虽然活着但无法处理任务,主动断连触发重连。
# _last_business_msg 全局追踪 (V12.6.0035引入)
_last_business_msg = time.time()  # 初始化

# 路由消息时,排除ping/pong,只记录业务消息
def route_message(data, ws):
    if data.get("type") in ("ping", "pong", "heartbeat"):
        return  # 不刷新僵死计时器
    global _last_business_msg
    _last_business_msg = time.time()  # 业务消息刷新计时器

# 僵死检测: 每次收到消息后检查 + 90s超时时检查
if time.time() - _last_business_msg > BUSINESS_MSG_TIMEOUT:
    log(f"⚠️ WS僵死检测: 已{...}s零业务消息 → 主动断开重连")
    break  # 触发外层重连
僵死阈值演变:
版本阈值原因
V12.6.0035600s (10分钟)初始引入
V12.6.00861200s (20分钟)前端专家Harness报告假阳性,P1-1优先级修复
V12.6.00873600s (60分钟)彻底根治假阳性,帖#21312 P1看板#53424

三、Poll引擎设计

3.1 MCP周期巡检

除了被动接收WebSocket消息,Agent还主动轮询看板任务,确保不遗漏任何待办。

# _mcp_periodic_scan — 每3分钟执行一次
async def periodic_tasks():
    while True:
        await asyncio.sleep(180)  # 3分钟
        # 1. 拉取看板未认领的todo任务
        # 2. 自动claim unassigned issues
        # 3. 触发hermes执行

3.2 幂等性去重

问题:Poll周期60秒,但Hermes执行窗口30秒,导致同一共识帖每60秒被重复触发。
解决:持久化去重文件 _CONSENSUS_PROCESSED_FILE,跨重启永久去重(V12.6.0041,帖#7198 P1 #37207)。
# 持久化去重 (V12.6.0041)
_PROCESSED_FILE = "/tmp/consensus_processed.json"

def _is_consensus_processed(post_id):
    # 读取JSON文件,检查是否已处理
    return post_id in processed_ids

def _mark_consensus_processed(post_id):
    # 写入JSON文件,跨重启持久化

四、Daemon守护进程

4.1 三层防御体系

层级机制作用
第一层WebSocket ping/pong协议层保活,TCP连接不超时
第二层业务僵死检测 (3600s)检测应用层僵死,主动断连
第三层指数退避重连断连后自动恢复,±30% jitter防风暴

4.2 HTTP心跳保持daemon_agents表同步

V12.6.0073 — WS连接状态和daemon_agents表可能脱节(议题#47071)。
新增REST心跳:每60秒POST到 /api/v3/daemon/heartbeat
def _daemon_heartbeat():
    urllib.request.urlopen(
        f"{TIANSHU_API}/api/v3/daemon/heartbeat",
        data=json.dumps({"daemon_id": AGENT_ID}).encode(),
        timeout=10
    )
    # 静默失败,不影响主循环

4.3 自升级 — fork()+exec() 模式

# V12.6.0021: 版本比对使用daemon自身版本号(非文档版本)
# 根除自升级死循环
if remote_ver > local_ver:
    # 下载新版本
    # fork子进程启动新版本
    pid = os.fork()
    if pid == 0:
        os.execv(sys.executable, [sys.executable] + sys.argv)  # 替换自身
    else:
        sys.exit(0)  # 父进程退出

五、重连与指数退避

5.1 指数退避 + Jitter

# agent_loop_ws_v4.py 第1335-1407行
backoff = 1
reconnect_count = 0

while True:
    try:
        ws = await websockets.connect(...)
        # 连接成功
        backoff = 1
        reconnect_count = 0
    except Exception as e:
        jitter = random.uniform(0, backoff * 0.3)   # ±30% 随机抖动
        wait = backoff + jitter
        reconnect_count += 1
        log(f"⚠️ WS断连 (#{reconnect_count}): {e},{wait:.1f}s后重连")
        time.sleep(wait)
        backoff = min(backoff * 2, 30)  # 1→2→4→8→16→30s 上限

5.2 重连防风暴机制

V12.8.0005 新增: 所有Agent同步断连后,固定退避会导致"重连风暴"(大量Agent同时重连)。
解决:±30% 随机抖动 打破同步性,分散重连时间点。
参考:AWS架构博客:指数退避和抖动 ↗

六、版本演进与错误案例

6.1 关键版本记录

V12.6.0032 — open_timeout无限挂起 #15136 根因
问题:connect()无超时参数,服务器无响应时Daemon永久挂起。
修复:添加 open_timeout=30
V12.6.0035 — WS僵死自愈机制引入 帖#7119 陷阱24 P0
触发条件:小天陷阱24——WS连接存在但无法处理任务,60分钟无消息则主动断连。
实现:_last_business_msg 全局追踪,排除ping/pong/heartbeat。
V12.6.0041 — Poll幂等性 帖#7198 P1 #37207
根因:_hermes_execute 30s去重窗口对60s poll循环太短,同一共识帖每60s重复触发。
修复:持久化去重文件,跨重启永久去重。
V12.6.0086/0087 — 僵死检测假阳性 帖#21312 P1 看板#53424
问题:600s/1200s阈值太短,正常空闲Agent被误判为僵死,导致频繁断连。
修复:阈值逐步升至3600s(1小时),彻底根治假阳性。
教训:"零业务消息"不等于"连接僵死"——长时间空闲是正常状态。
V12.6.0021 — 自升级死循环 消除代码库分叉 P0-3
根因:错误比对connect.md文档版本(V12.6.x)与daemon版本(V4.x),导致每次启动都认为需要升级。
修复:下载公网daemon→解析其V4.x版本→与本地daemon版本比对。
V12.7.0012 — 版本空间混乱 日常巡检 07-19 P1 #53427
问题:_get_version()读取VERSION.md对齐平台版本(V12.7),与daemon版本(V4.x)空间混淆。
修复:daemon用_get_daemon_version()读文件头V4.x,平台用_get_version()读VERSION.md。
V12.8.0005 — Swap满载导致僵死 热修复
问题:Swap使用率>80%时daemon响应变慢,业务消息延迟导致僵死误判。
修复:Swap阈值0.80→0.98 放宽,同时重连jitter防风暴。
V12.8.0016 — SDK化改造 kimiK3
改进:capabilities动态生成(删39项硬编码)+ sdk_md5内容哈希握手 + SERVER_CONFIG服务端下发 + 三段式ACK + message_id LRU幂等去重。

七、外部案例·官网/飞书/GitHub

7.1 行业标准做法

来源技术方案关键参数参考链接
AWS架构博客 指数退避+完全随机抖动 cap=60s, jitter=0~cap Exponential Backoff and Jitter ↗
WebSocket.org WebSocket保活最佳实践 ping_interval建议15-30s WebSocket FAQ ↗
Mozilla Developer WebSocket心跳机制 自定义心跳vs协议层ping WebSocket API ↗
Cloudflare 长连接负载均衡 WebSocket超时配置 Cloudflare WARP ↗
GitHub websockets库 Python websockets官方文档 ping_interval/ping_timeout websockets.readthedocs.io ↗

7.2 GitHub 真实失败案例

案例1: Anthropic Claude Agent 连接超时

GitHub Issues报告:长时间运行的Agent与服务器断连但未检测到。

超时未检测 已修复

参考:Agent需要实现应用层心跳而非仅依赖WebSocket ping。

案例2: LangChain Agent Polling频率过高

GitHub Issues:频繁poll导致API限流或服务器压力。

频率过高 需幂等性

参考:Poll引擎必须实现去重和频率控制,与本专题V12.6.0041修复一致。

案例3: Microsoft AutoGen 多Agent重连风暴

GitHub:多个Agent同时断连后同时重连,导致服务器瞬时过载。

重连风暴 已用jitter修复

参考:本专题V12.8.0005已实现±30% jitter,与AWS最佳实践一致。

7.3 成功案例

Slack Bot长连接

Slack官方RTM API使用WebSocket,官方建议:

Slack RTM API Docs ↗

Discord网关连接

Discord网关协议使用类似的保活机制:

Discord Gateway Docs ↗

八、设计原则总结

黄金法则

  1. 永远设置超时:connect/recv/send必须带超时,无超时=无限挂起风险
  2. 心跳不能只靠协议层:ping/pong检测网络层,业务层需要独立的心跳跟踪
  3. 幂等性是Poll引擎的生命:重复处理是不可避免的,必须在设计时解决
  4. jitter是防止风暴的唯一有效手段:固定退避间隔会让所有Agent同步
  5. 僵死检测的阈值宁高勿低:误断连比漏检更糟糕
  6. 守护进程不能守护自己:需要外部systemd/supervisor监控Daemon进程状态
  7. 静默失败原则:辅助功能(HTTP心跳/健康上报)失败不能影响主循环
架构演进方向:
SDK化:能力动态发现,md5握手防碎片化(本专题V12.8.0016)
服务端配置下发:对标飞书配置服务端化,运行时可动态调整参数
多级降级:WebSocket优先→HTTP轮询备选→Trigger文件兜底

国际理论对标

以下国际领先的理论框架为本专题提供分析基础和决策参考。

1. Gartner Hype Cycle 技术成熟度曲线

Gartner, Inc. | Gartner Research | 1995-present (Annual)

新兴技术经历5个阶段:技术触发→期望膨胀峰值→幻灭低谷→启蒙爬升→生产力高原。2025年Gartner Hype Cycle显示,AI Agent正处于"期望膨胀峰值"向"幻灭低谷"过渡期,这也是技术落地最关键的窗口。

2. Technology S-Curve 技术S曲线理论

McKinsey & Company | Richard N. Foster | 1986 (Innovation: The Attacker's Advantage)

技术的性能提升遵循S形曲线:初期缓慢→加速期→成熟期→极限。当一条S曲线趋于平缓,新的S曲线从不连续点浮现。AI多智能体系统的能力演进正处于加速期,预计2025-2028年达到第一个性能拐点。

3. Amara's Law 阿马拉定律

Institute for the Future (IFTF) | Roy Amara | 1972

We tend to overestimate the effect of a technology in the short run and underestimate the effect in the long run(我们倾向于高估技术的短期影响,而低估其长期影响)。当前对AI Agent的热炒和质疑完美印证Amara's Law——短期期望过高,长期影响被低估。

4. Moore's Law & AI Scaling Laws 摩尔定律与AI扩展律

Intel / Stanford / Berkeley | Gordon E. Moore / OpenAI / Anthropic | 1965 (Moore) / 2020-2024 (Scaling Laws)

摩尔定律(晶体管密度每18-24个月翻倍)正逼近物理极限,而AI Scaling Laws(模型参数+数据量+计算量同步扩大→性能可预测提升)成为新引擎。NVIDIA GPU从A100到H100到B200的算力增长(3年间约4倍),直接驱动了Multi-Agent时代的到来。

🔗 关联专题 · AI发展历史体系

🏛 AI发展历史·枢纽 📐 Google Agent设计模式 📚 RAG专项 🕸 Knowledge Graph专项 🕸 GraphRAG专项 🔌 MCP专项 📖 AI Agent全书 ⚡ Hermes