LLM Streaming 协议设计
LLM 流式输出的三种协议设计模式(Delta / Append / State)、分层 Streaming 架构、工业级事件协议设计。不是 SSE 用法问题,而是在设计"实时生成系统的数据协议"。
[!info] related notes
- 上层应用: 会话与消息流设计
- SSE 管道: 多服务 SSE 管道
- 前端消费: 前端 SSE 消费
- Tool Call: Function Calling 流式累积
- AI 架构: AI Gateway 模型路由器
LLM Streaming 协议设计
SSE 工程化问题的本质不是 SSE 用法,而是在设计一个**“实时生成系统的数据协议”**——LLM 输出的 text deltas 如何传输给前端。
LLM 输出的四层模型
1. raw tokens — 模型输出的原始 token
2. text deltas — 文本增量("你" "好" "世界")
3. semantic chunks — 语义块(一个完整句子、一个 tool_call)
4. UI state — 最终展示状态
SSE 协议设计的核心问题是:在第 2 层和第 3 层之间选择传输粒度。
三种主流协议设计
1. Delta Stream(增量流)— 最主流
只发送新增内容(diff),OpenAI / Claude / Gemini 都用这种。
{ "type": "delta", "content": "你" }
{ "type": "delta", "content": "好" }
{ "type": "delta", "content": "世界" }
前端模型:buffer += delta
| 维度 | 评价 |
|---|---|
| 带宽 | ⭐ 最低 |
| 延迟 | ⭐ 最低 |
| 前端复杂度 | 中(需维护 buffer) |
| 适用场景 | ChatGPT、Claude UI、Copilot、Perplexity |
本质:事件流 = 增量状态
局限:无法回滚/修正,不适合复杂编辑场景。
2. Append Event Stream(追加事件流)— Agent 系统常用
发送结构化增量,而不是纯文本。
{ "type": "append", "role": "assistant", "content": "你好" }
{ "type": "append", "content": "世界" }
{ "type": "append", "node": "answer", "content": "具体建议如下" }
前端模型:messages.push(chunk)
| 维度 | 评价 |
|---|---|
| 带宽 | 中 |
| 延迟 | 中 |
| 前端复杂度 | 中 |
| 适用场景 | LangChain callbacks、Dify workflow、Agent 编排 UI |
本质:事件流 = message log
优势:天然支持 message list、multi-turn UI、可扩展 tool call / metadata。
3. Full State Stream(全状态流)— 编辑器场景
每次发送完整状态快照。
{ "type": "state", "content": "你" }
{ "type": "state", "content": "你好" }
{ "type": "state", "content": "你好世界" }
前端模型:render(fullText)
| 维度 | 评价 |
|---|---|
| 带宽 | ⭐ 最高(O(n²)) |
| 延迟 | 高 |
| 前端复杂度 | ⭐ 最低 |
| 适用场景 | Notion AI、AI editor、文档生成器 |
本质:事件流 = 状态机 snapshot
优势:前端最简单,天然支持 undo / rewrite。
对比总结
| 类型 | 数据模型 | 带宽 | 前端复杂度 | 延迟 | 使用场景 |
|---|---|---|---|---|---|
| Delta | diff | ⭐ 最低 | 中 | ⭐ 最低 | ChatGPT |
| Append | event log | 中 | 中 | 中 | Agent 系统 |
| State | snapshot | ⭐ 最高 | ⭐ 最低 | 高 | AI 编辑器 |
分层 Streaming 架构
生产系统不会只有一层 SSE,而是分层的:
LLM Token Stream ← 模型层(OpenAI / Qwen / Claude)
↓
Chunk Aggregator ← token → 语义 chunk(按句号/Markdown block/tool_call boundary)
↓
Semantic Router ← 输出分流:text→UI / tool→executor / thinking→hidden
↓
Event Bus (SSE/WebSocket) ← 统一协议输出
↓
Frontend State Manager ← Zustand / Redux / XState
各层职责
① Token Stream Layer
接收模型原始 token 流。来源可以是 OpenAI、Qwen、Claude 等任意 provider。
② Chunk Aggregator(关键层)
把 token 聚合为语义 chunk。聚合策略:
- 按标点(句号、换行)
- 按 Markdown 块(代码块、列表)
- 按 function call boundary
③ Semantic Router(高级能力)
把输出分流到不同处理通道:
text→ UI 渲染tool_call→ 后端执行器thinking→ 隐藏面板citation→ 引用面板
④ Event Bus
统一协议输出,格式示例:
{ "type": "text.delta", "content": "你好" }
{ "type": "tool_call", "name": "search" }
{ "type": "done" }
⑤ Frontend State Manager
维护全局流式状态:
{
messages: [],
streamingBuffer: "",
toolCalls: [],
status: "streaming"
}
更高级:LLM Native Event Protocol(趋势)
Multi-channel Stream
{ "channel": "text", "delta": "你好" }
{ "channel": "reasoning", "delta": "用户在问协议设计" }
{ "channel": "tool", "name": "search" }
Structured Streaming
{ "type": "message.delta", "data": { "role": "assistant", "content": "你好" } }
Event Sourcing AI
所有输出都变成 event,类似 Kafka event sourcing:
UserMessageCreated
LLMThinkingStarted
TokenGenerated
ToolCalled
ToolResultReturned
MessageFinalized
结合 BodySense 的推荐协议
BodySense 的场景:SSE + AI chat + function calling + 结构化症状提取。
推荐直接采用 Delta Stream + 语义事件扩展:
{ "type": "start" }
{ "type": "text.delta", "content": "你好" }
{ "type": "text.delta", "content": ",我可以帮你" }
{ "type": "extracted_info", "data": { "body_part": "肩部", "symptom": "疼痛" } }
{ "type": "tool_call", "name": "symptom_extract" }
{ "type": "end" }
后端结构
LLM stream
↓
parser (token → chunk)
↓
event builder
↓
SSE emitter
前端结构
event reducer
↓
message state
↓
UI render
常见错误:char-level split
如果前端出现逐字拆分过细(每个字符一个事件),问题不在 SSE 本身,而是 stream 处理层粒度错了——在 chunk aggregator 层应该按语义边界聚合,而不是逐字符透传。
一句话总结
工业上主流只有三种 streaming:
- Delta Stream → ChatGPT(最推荐,最省带宽、最低延迟)
- Append Stream → Agent / workflow 系统
- State Stream → AI 编辑器
BodySense 推荐 Delta Stream + 语义事件扩展,兼顾打字机效果和 tool_call / 结构化数据传输。