引言
在大语言模型(LLM)的应用场景中,用户体验的流畅性至关重要。传统的'请求 - 等待 - 响应'全量模式会让用户在模型生成长文本时面临长时间的空白等待。为了实现类似打字机的实时输出效果,我们需要引入流式传输技术。
本文将从理论层面剖析适合 LLM 场景的 Server-Sent Events (SSE) 协议,对比其与 WebSocket 的优劣,并深入讲解如何在 C++ 中使用 cpp-httplib 库实现流式数据的接收与处理。
第一章:即时通信的基石——SSE 协议解析
HTTP 协议本质上是'请求 - 响应'模型的,服务器处于被动地位,无法主动向客户端推送数据。这种'一问一答'的机制在即时性要求高的场景下显得力不从心。
1.1 为什么选择 SSE?
SSE (Server-Sent Events) 是一种构建在 HTTP 协议之上的轻量级服务器推送技术。它允许服务器在建立连接后,主动、持续地向客户端发送文本数据流。
SSE 具有以下显著特点,使其成为 LLM 流式响应的理想选择:
- 基于 HTTP:无需自定义协议或额外端口,能够穿透大多数防火墙和代理服务器,兼容性极佳。
- 单向通信:LLM 的生成过程正是'用户发送一次提示词(Prompt),模型持续返回生成内容'的模式,完全符合 SSE'服务器到客户端'的单向流特性。
- 轻量简单:相比于复杂的 WebSocket 握手,SSE 的数据格式仅为纯文本,解析成本极低。
- 内置重连:协议规范中包含了自动重连机制(虽然在 SDK 开发中通常由应用层控制)。
1.2 SSE 数据格式
SSE 的数据流由一系列文本块组成,每个块之间用空行分隔。LLM 常用的数据格式如下所示:
data: {"id": "chatcmpl-123", "choices": [{"delta": {"content": "你"}}]}
data: {"id": "chatcmpl-123", "choices": [{"delta": {"content": "好"}}]}
data: [DONE]
客户端只需按行读取以 data: 开头的内容,解析 JSON 即可获得增量文本。
第二章:协议选型——SSE vs WebSocket
除了 SSE,WebSocket 也是实现实时通信的主流技术。为什么在 ChatSDK 中我们坚定地选择 SSE?
2.1 轮询与 WebSocket 的局限
最原始的轮询(Polling) 方式要求客户端不断发送请求询问'生成好了吗?',这会产生大量无效的网络开销且延迟高。
WebSocket 提供了全双工(双向)通信能力,适用于聊天室、多人游戏等需要频繁互动的场景。
2.2 技术特性对比
| 特性 | SSE (Server-Sent Events) | WebSocket |
|---|---|---|
| 通信方向 | 单向:服务器 → 客户端 | 双向:服务器 ↔ 客户端 |
| 设计目的 | 状态更新、日志流、LLM 生成 |


