一、为什么流式输出(Streaming)如此重要?

在与大模型交互时,传统的一次性 HTTP 响应(请求-等待-完整响应)模式会造成明显的延迟感。用户发出问题后,可能需要等待数十秒才能看到完整的答案,体验就像盯着一个加载中的转圈图标。流式输出的核心思想是:一旦模型开始生成第一个 token,就立即将其发送给客户端,后续 token 逐个生成、逐个推送,最终拼接成完整响应。

这种模式极大地提升了用户体验,因为用户几乎能立即看到反馈,类似于打字机效果。从技术层面看,它降低了客户端的首字节等待时间(TTFB),并允许客户端提前对部分内容进行处理。对于像 MiMo 这样需要处理长序列生成任务的模型,流式几乎是必需品。

二、SSE:流式输出的传输基石

实现流式输出有多种方案,而 SSE(Server-Sent Events) 是其中一种基于标准 HTTP 协议的轻量级、单向(服务器到客户端)通信技术。它与 WebSocket 不同,后者是双向的,开销更大。SSE 天生适合“服务器持续推送数据到客户端”的场景,比如实时新闻、日志流,以及我们这里的大模型响应。

SSE 协议的关键特点:

三、MiMo 流式输出的实现原理

当客户端向 MiMo 的 API 发起一个启用了流式的请求时,服务器不会缓存整个响应,而是维持一个 HTTP 连接,并持续地将生成的数据片段推送出去。这些片段遵循 SSE 规范,每一行都以 data: 前缀开头,数据体通常是一个 JSON 对象。

一个典型的 SSE 消息序列可能如下所示:

data: {"id":"chatcmpl-1","object":"chat.completion.chunk","choices":[{"delta":{"content":"你"},"index":0}]}

data: {"id":"chatcmpl-1","object":"chat.completion.chunk","choices":[{"delta":{"content":"好"},"index":0}]}

data: {"id":"chatcmpl-1","object":"chat.completion.chunk","choices":[{"delta":{"content":"!"},"index":0}]}

data: [DONE]

其中,data: [DONE] 是一个特殊标记,明确告知客户端流已结束,连接可以关闭。

四、代码实战:用 Python 消费 MiMo 的流式输出

理解原理后,我们来看如何用代码处理它。使用 requests 库时,需要设置 stream=True,然后逐行读取响应内容。

import requests
import json

api_url = "https://api.example.com/v1/chat/completions"
headers = {"Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json"}
payload = {
    "model": "MiMo-7B",
    "messages": [{"role": "user", "content": "用中文简单介绍一下量子计算。"}],
    "stream": True  # 关键:开启流式输出
}

response = requests.post(api_url, json=payload, headers=headers, stream=True)

full_response = ""
for line in response.iter_lines():
    if line:
        decoded_line = line.decode('utf-8')
        # 跳过 [DONE] 标记和空行
        if decoded_line.startswith('data: ') and decoded_line != 'data: [DONE]':
            # 解析 JSON 数据
            json_str = decoded_line[len('data: '):]
            try:
                chunk = json.loads(json_str)
                delta = chunk['choices'][0]['delta']
                # 提取并拼接增量内容
                if 'content' in delta:
                    content_piece = delta['content']
                    print(content_piece, end='', flush=True)  # 实时打印
                    full_response += content_piece
            except json.JSONDecodeError:
                pass
print()  # 换行
print(f"\n完整响应: {full_response}")

这段代码模拟了我们从 MiMo 获取流式响应的过程。flush=True 参数确保了每个 token 一到就立即打印,而不是被缓冲。

五、解析中的关键细节与注意事项

处理 SSE 流时,有几个细节容易出错,需要特别注意:

提示:如果你使用 JavaScript 的 fetch API,它与 SSE 的配合并不直接。一个更简便的方法是利用原生的 EventSource API 或其 polyfill,它能更好地处理 SSE 的解析和重连逻辑。

六、总结与最佳实践

流式输出结合 SSE 协议,为 MiMo 等大模型应用提供了出色的实时交互基础。在开发中,可以遵循以下最佳实践:

掌握流式输出的处理,意味着你能够构建响应更及时、体验更流畅的 AI 应用。它不仅是技术上的优化,更是产品体验的关键一环。