一、 什么是流式输出?

在传统的 HTTP 请求-响应模型中,客户端发送一个请求,服务器需要完整地处理这个请求后,才能将一个完整的结果返回给客户端。对于大模型(LLM)这类需要较长生成时间的应用来说,用户必须等待整个回答生成完毕才能看到内容,这会导致用户体验上的“卡顿感”,用户不知道系统是在正常工作还是已经卡死。

流式输出(Streaming) 正是为了解决这个问题而诞生的核心技术。它的核心思想是:服务器在生成回答的过程中,逐步、分块地将内容推送给客户端。就像打字机一样,每生成一个词、一个句子,就立刻发送给前端显示。这为用户提供了实时的反馈,极大提升了交互的流畅感和“智能体正在思考”的拟人感。

提示:流式输出不是一种全新的协议,而是一种数据传输模式。它通常基于HTTP长连接或类似的技术实现,而 SSE(Server-Sent Events) 就是实现这种模式最经典、最标准的协议之一。

二、 为什么需要 SSE 协议?

既然流式输出这么好,如何实现它呢?你可能会想到几种方案:传统的 AJAX 长轮询(Low Polling)、WebSocket 以及 SSE。长轮询效率低、资源消耗大,基本已被淘汰。WebSocket 虽然强大(支持双向通信),但对于服务器单向、持续地推送事件这个场景来说,它显得有些“重”了。

SSE (Server-Sent Events) 是一项在 HTML5 规范中提出的技术,它正是为“服务器到客户端”的单向实时数据流而设计的。它的优势在于:

对于 MiMo 这类大模型的应用场景,模型只需将生成的 token 一个个“吐”出来,客户端只需“倾听”并显示,这完美契合了 SSE 的设计哲学。因此,SSE 成为了实现大模型流式输出的事实标准

三、 SSE 协议的核心数据格式

SSE 有其非常易懂的文本协议。服务器端推送的 text/event-stream 类型响应,其内容由一系列的事件组成,每个事件由多个字段构成,字段间以换行符(\n)分隔。

一个最简单的事件流数据如下所示:

data: 第一个词

data: 第二个词

data: 第三个词,这句话结束了。

更规范地,一个完整的事件可能包含:

在 MiMo 或其他大模型的流式输出中,你通常会看到服务器返回类似这样的数据流:

data: {"content": "你"}

data: {"content": "好"}

data: {"content": ","}

data: {"content": "有什么"}

data: {"content": "可以帮你"}

data: {"content": "的吗?"}

data: [DONE]
关键提示data: [DONE] 是一个常见的约定,用于明确指示流式响应的结束。客户端收到此消息后,应断开连接并完成本次对话。

四、 MiMo 如何处理流式请求?

当你在 MiMo 的 API 中启用流式输出时(通常通过设置 stream=True),整个调用流程与普通请求有显著不同:

  1. 请求阶段:客户端发起一个普通的 HTTP POST 请求,但会在请求头中期望接收 text/event-stream 类型的响应。
  2. 响应阶段:服务器收到请求后,立即开始生成回答,并持续地以 SSE 事件流的形式返回数据,而不是等到生成完毕。HTTP 连接会保持打开状态,直到流传输完成。
  3. 客户端处理:客户端需要使用支持 SSE 的方法(如浏览器的 EventSource 或后端语言的特定库)来监听这个事件流,逐步接收并处理每一个 data 事件。

这个过程的关键在于服务器的响应不再是单个完整的 JSON 对象,而是一个持续的数据流。这要求客户端的代码逻辑必须从“一次性获取结果”转变为“逐步订阅事件”。

五、 客户端代码实践(Python)

在 Python 中,我们可以使用 requests 库来演示如何消费一个 SSE 流。虽然 requests 本身不直接支持 SSE,但我们可以通过它的流式响应功能手动解析。

import requests
import json

def stream_chat(query):
    url = "https://api.mimo.example.com/v1/chat/completions"
    headers = {
        "Content-Type": "application/json",
        # 假设我们需要一个API Key
        "Authorization": "Bearer YOUR_API_KEY"
    }
    data = {
        "model": "mimo-model",
        "messages": [{"role": "user", "content": query}],
        "stream": True  # 关键:启用流式输出
    }

    # 使用 stream=True 参数发起请求,保持连接打开
    response = requests.post(url, headers=headers, json=data, stream=True)

    full_response = ""
    for line in response.iter_lines():
        if line:
            # 每行数据都以 b'data: ' 开头
            decoded_line = line.decode('utf-8')
            if decoded_line.startswith('data: '):
                json_str = decoded_line[6:]  # 去掉 'data: ' 前缀
                if json_str.strip() == '[DONE]':
                    print("\n\n[流式传输结束]")
                    break
                try:
                    chunk = json.loads(json_str)
                    content = chunk.get('choices', [{}])[0].get('delta', {}).get('content', '')
                    if content:
                        print(content, end='', flush=True)  # 实时打印
                        full_response += content
                except json.JSONDecodeError:
                    # 处理可能存在的非JSON行,如注释
                    continue

    return full_response

# 调用示例
user_input = "用流式输出给我讲个故事。"
final_answer = stream_chat(user_input)

六、 总结与思考

MiMo 采用 SSE 实现流式输出,本质上是选择了最契合其交互场景的技术方案。 对于生成式 AI 而言,用户感知的流畅度直接决定了产品的体验优劣。SSE 以其简单、高效、标准化的特点,成为了连接大模型“思维流”与用户屏幕之间的绝佳管道。

在实际开发中,你需要:

进阶思考:除了 SSE,另一种流行的方式是使用 WebSocket 实现双向流式通信,这更适用于需要高频、低延迟交互的场景(如实时游戏)。但对于大多数对话式 AI 应用,SSE 的“单向流”已经足够,并且架构更简单、更容易扩展。MiMo 的选择反映了其注重实用性和用户体验的产品定位。