一、从一次“漫长”的等待说起
当你与一个大型语言模型(LLM)对话时,最直观的体验就是等待。你发送一个问题,然后……等待。服务器需要耗费数秒乃至更长时间生成完整的回答,才能一次性将所有内容返回给你的浏览器或应用。这段时间里,用户面对的是空白的界面或一个加载动画,体验上无疑是“漫长”且不确定的。
流式输出(Streaming) 正是为解决这一痛点而生。它的核心思想是:不等待模型生成完毕,而是一边生成,一边将已生成的部分数据“流”式地推送给客户端。这就像你看视频网站的在线播放,视频数据是持续不断地下载并播放的,而不是等整个文件下载完才能开始看。在大模型领域,这通常表现为回答的文字逐字或逐句地出现在屏幕上,为用户提供了实时的反馈和更佳的交互体验。
二、SSE:流式通信的“高速公路”
要实现服务端向客户端持续推送数据,我们需要一个合适的通信协议。SSE(Server-Sent Events) 就是专为此类场景设计的轻量级协议。它基于标准的 HTTP 协议,是“单向”的:只有服务端能向客户端发送事件流,客户端通过一个持久的 HTTP 连接来接收。
SSE 的优势非常明显:
- 轻量简单:实现起来比 WebSocket 更简单,因为它就是标准的 HTTP。
- 自动重连:浏览器原生支持
EventSourceAPI,内置了连接中断后的自动重连机制。 - 文本友好:数据格式是纯文本,非常适合传递大模型生成的自然语言文本。
- 兼容性好:几乎所有现代浏览器和 HTTP 服务器都支持。
一个典型的 SSE 响应,其 Content-Type 头被设置为 text/event-stream。服务器发送的数据遵循固定的格式,例如:
data: 这是第一条消息\n\n
data: {"token": "你好", "is_end": false}\n\n
data: 这是最后一条,后面会跟两个换行符表示结束\n\n
客户端(如浏览器中的 EventSource 对象)会持续监听这个连接,每当收到一个以 \n\n 结尾的数据块时,就会触发一个事件。
三、MiMo 的流式输出协议解析
MiMo 作为小米的智能大模型,其 API 自然支持流式输出。它的流式输出正是基于 SSE 协议实现的。当你发起 API 请求并将 stream 参数设置为 true 时,服务器会返回一个 SSE 事件流。
在该事件流中,每一条事件(即每一个 data: 行)通常是一个 JSON 对象,包含了模型当前生成的“一块”内容。关键字段如下: