KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA

SSE 速查 Playbook — keel 龙骨

实时推送与 SSE 的参考信息:SSE 速查 Playbook

一页纸版本。

一、选型

需要客户端高频上行?      → WebSocket
数据分钟级更新?          → 轮询(别上长连接)
单向持续流(token/进度)? → SSE(默认选择)
需传二进制?              → WebSocket
有代理会拦 WS 升级?      → SSE

SSE 优势:普通 HTTP 穿透好、断线重连内建、文本可调试、复用 HTTP 基建。
SSE 限制:单向、只能 GET、EventSource 不能自定义头、HTTP/1.1 同域 6 连接、纯文本。

二、协议

id: 1710000000123-0      ← 事件 ID(重连时由 Last-Event-ID 带回)
event: delta             ← 事件类型(默认 message)
data: {"text":"你好"}     ← 载荷(必须自包含完整 JSON)
                          ← 空行结束一个事件块
: heartbeat              ← 冒号开头是注释,常用作心跳
retry: 5000              ← 建议重连间隔(ms)

响应头:

Content-Type: text/event-stream; charset=utf-8
Cache-Control: no-cache, no-transform
Connection: keep-alive
X-Accel-Buffering: no

终止重连的正确方式:返回 204 或 Content-Type 不是事件流(否则浏览器无限重连)。

三、服务端(FastAPI 要点)

return StreamingResponse(
    event_gen(request, run_id, last_event_id),
    media_type="text/event-stream",
    headers={"Cache-Control": "no-cache, no-transform",
             "Connection": "keep-alive",
             "X-Accel-Buffering": "no"},
)

四件必做:正确 media_type / no-transform / X-Accel-Buffering: no / finally 清理。
另外:request.is_disconnected() 检测断开;事件源加 block 超时让出控制权。

四、nginx(最容易出问题的地方)

proxy_buffering off;          # 头号坑:默认 on 会让客户端一直收不到数据
proxy_cache off;
gzip off;                     # 压缩会攒批,破坏实时性
chunked_transfer_encoding on;
proxy_http_version 1.1;
proxy_set_header Connection '';
proxy_read_timeout 3600s;     # 默认 60s 会掐断
proxy_send_timeout 3600s;
send_timeout 3600s;
proxy_connect_timeout 5s;     # 建立连接仍然要短

超时分层:外层 > 内层 > 心跳间隔 × 2。心跳常取 20~30s(代理空闲超时通常 60s)。

五、续播

事件先落事实日志(Redis Stream / Kafka),SSE 只是日志的订阅视图。
断线 → 浏览器带 Last-Event-ID 重连 → 从断点继续。

六、LLM 流式

事件类型:run_started / delta / tool_call / tool_result / citation / error / done / cancelled

七、容量与治理

稳态连接数 ≈ 日活 × 同时在线比例 × 平均流时长 / 使用间隔
单连接成本:fd×2、协程×1~2、nginx 连接×2、内存 10~100KB

八、排查("卡住了"怎么办)

# ① 直连应用绕过 nginx
curl -N --max-time 10 http://127.0.0.1:8000/runs/1/stream | head
# ② 经过 nginx 看 TTFB
curl -N -o /dev/null -w 'TTFB %{time_starttransfer}s\n' https://domain/runs/1/stream
① 直连有数据?       → 有:中间层问题;无:应用问题
② 服务端在推吗?     → 在推:传输问题(缓冲/压缩/超时);没推:应用问题
③ 断开有规律吗?     → 固定间隔:超时;随机:网络/客户端
④ 个别还是全部?     → 个别:客户端环境;全部:服务端/网关
⑤ 最近有发布吗?     → 长连接问题 80% 与配置变更相关

分水岭是第 ② 步 → 服务端必须记录"已发事件数"。

九、安全

十、压测与演练

进入 keel 阅读