1. 概述

1.1 什么是流式输出(Streaming Output)

流式输出(Streaming Output) 是一种服务端响应模式:

服务端在大模型生成内容的过程中,将已生成的部分实时、分批次返回给客户端,而不是等待全部内容生成完毕后再一次性返回。

在大模型(LLM)场景中,生成过程通常是 token-by-token 的,因此天然适合流式返回。


1.2 为什么需要流式输出

在非流式模式下:

  • 用户必须等待模型完全生成结束
  • 请求时间稍长就会被误认为“卡死”

流式输出的核心目标是:

  • 降低首字延迟(TTFB)
  • 显著提升交互体验
  • 让用户感知模型正在工作

2. 流式输出的核心价值

2.1 用户体验层面

指标 非流式 流式输出
首字响应 极低
可感知过程
等待焦虑
交互感

2.2 技术层面

  • 避免一次性返回超大 JSON
  • 减少内存峰值占用
  • 支持“边算边推”,提升吞吐
  • 更符合大模型的生成机制

3. 工作原理(机制解析)

3.1 非流式请求流程

Client Request
      ↓
LLM 全量生成
      ↓
Server 一次性返回完整结果

缺点:

  • 首字延迟 = 总生成时间

3.2 流式输出请求流程

Client Request
      ↓
LLM 生成 token1 → 推送
LLM 生成 token2 → 推送
LLM 生成 token3 → 推送
...
LLM 结束 → 结束信号

关键点:

  • 同一个连接
  • 多次写响应
  • 不中断 HTTP 会话

4. 流式输出的技术本质

4.1 并不是多次请求

流式输出不是轮询,也不是多次 HTTP 请求,而是:

  • 一次请求
  • 一个连接
  • 多次写出(chunk)

4.2 常见底层实现机制

技术 说明 适用性
Chunked Transfer HTTP 分块传输 底层基础
SSE Server-Sent Events ⭐⭐⭐⭐⭐(推荐)
WebSocket 全双工通信 ⭐⭐⭐
Reactive Stream Flux / Flow ⭐⭐⭐⭐

5. 主流实现方式对比

5.1 SSE(Server-Sent Events)——首选

特点:

  • 基于 HTTP
  • 单向(Server → Client)
  • 原生支持自动重连
  • 非常适合 AI 文本流

AI 场景适配度:★★★★★


5.2 WebSocket

特点:

  • 双向通信
  • 支持中途打断生成

问题:

  • 实现复杂
  • 运维成本高
  • 对短连接不友好

5.3 StreamingResponseBody(Servlet)

特点:

  • 传统 Spring MVC 可用
  • 不依赖 WebFlux

限制:

  • 线程阻塞
  • 并发能力有限

6. Java / Spring 后端实现示例

6.1 基于 WebFlux + SSE(推荐)

@GetMapping(value = "/ai/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> stream() {
    return Flux.just("你", "好", ",", "世", "界")
            .delayElements(Duration.ofMillis(300));
}

返回效果(客户端实时接收):

你
好
,
世
界

6.2 基于 StreamingResponseBody

@GetMapping("/ai/stream")
public StreamingResponseBody stream() {
    return outputStream -> {
        for (String s : List.of("你", "好", "世界")) {
            outputStream.write(s.getBytes(StandardCharsets.UTF_8));
            outputStream.flush();
            Thread.sleep(300);
        }
    };
}

7. 前端接收方式

7.1 SSE(EventSource)

const es = new EventSource('/ai/stream');

es.onmessage = (event) => {
  console.log(event.data);
};

7.2 fetch + ReadableStream

const response = await fetch('/ai/stream');
const reader = response.body.getReader();

while (true) {
  const { value, done } = await reader.read();
  if (done) break;
  console.log(new TextDecoder().decode(value));
}

8. 大模型 API 中的流式输出

8.1 通用请求参数

{
  "stream": true
}

8.2 通用返回结构(示意)

{"delta": "你"}
{"delta": "好"}
{"delta": "世界"}
{"finish_reason": "stop"}

9. 典型业务场景

  1. AI 对话系统(ChatGPT 类)
  2. 长文本生成
  3. 代码生成 / 补全
  4. 推理过程可视化
  5. 实时分析 / 日志输出

10. 生产级注意事项(重点)

10.1 错误处理

  • 可能在中途失败

  • 已经返回部分内容

  • 需要:

    • error event
    • finish_reason

10.2 连接生命周期管理

  • 客户端主动断开

  • 服务端必须:

    • 停止模型生成
    • 释放资源

10.3 超时与限流

  • 设置最大生成时间
  • 防止长连接耗尽资源

11. 架构设计建议(AI 场景)

Client
  ↓ SSE
API Gateway
  ↓
AI Service
  ↓ stream
LLM Provider

建议:

  • 网关支持长连接
  • AI 服务单独限流

12. 总结

一句话总结:

流式输出不是为了更快完成生成,而是为了让用户更早、更持续地“看到结果”,
用架构复杂度换取极大的交互体验提升。


13. 延伸阅读方向

  • Spring AI Streaming ChatModel
  • SSE vs WebSocket 选型
  • AI 生成中断与取消设计
  • Token 级别计费与统计

欢迎关注公众号FishTech Notes,收藏点赞关注哦

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐