Heartbeat Event
Heartbeat Event 是 Agent Runtime 定期发送的空事件,用于保持 SSE 连接存活,防止中间代理(Nginx、CDN)因超时而断开连接。
#type / concept
#status / evergreen
#tech / ai
#tech / network
[!info] related notes
- 所属 MOC: Agent Runtime MOC
- 相关: Run Event, SSE Gateway
Heartbeat Event
一句话定义
Heartbeat Event 是 Agent Runtime 定期发送的空事件,用于保持 SSE 连接存活。Nginx 默认 60 秒没有数据就会断开连接,LLM 推理可能需要 30 秒以上,心跳防止连接被误断。
它解决什么问题
LLM 推理期间(特别是复杂推理),可能 30-60 秒没有输出。中间的代理(Nginx、CDN、负载均衡器)会认为连接空闲而断开。心跳让代理知道”连接还活着”。
核心原理
心跳机制
LLM 推理中 (30秒无输出)
│
├─ 0s: 上一个事件
├─ 15s: heartbeat
├─ 30s: heartbeat
└─ 45s: LLM 开始输出
Python 实现
class HeartbeatManager:
def __init__(self, interval: int = 15):
self.interval = interval
self._task = None
async def start(self, emit_fn):
async def heartbeat_loop():
while True:
await asyncio.sleep(self.interval)
await emit_fn(RunEvent(event="heartbeat", data={}))
self._task = asyncio.create_task(heartbeat_loop())
def stop(self):
if self._task:
self._task.cancel()
Go 实现
func heartbeatTicker(w http.ResponseWriter, flusher http.Flusher, done <-chan struct{}) {
ticker := time.NewTicker(15 * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
fmt.Fprintf(w, "event: heartbeat\ndata: {}\n\n")
flusher.Flush()
case <-done:
return
}
}
}
前端处理
// 前端应该忽略 heartbeat 事件,不触发状态更新
es.addEventListener('heartbeat', () => {
// 只用于保活,不做任何处理
});
常见坑
- 不做心跳: Nginx 60 秒超时断开连接
- 心跳太频繁: 增加不必要的网络流量
- 心跳触发前端更新: heartbeat 应该被忽略
- 不随事件重置: 有正常事件时不需要心跳