聊聊SpringAI流式输出的底层实现?
在 Spring AI 中,流式输出(Streaming Output)是一种逐步返回 AI 模型生成结果的技术,允许服务器将响应内容分批次实时传输给客户端,而不是等待全部内容生成完毕后再一次性返回。
这种机制能显著提升用户体验,尤其适用于大模型响应较慢的场景(如生成长文本或复杂推理结果)。
技术实现
在 Spring AI 中流式输出的实现有以下两种方式:
- 通过 ChatModel 实现流式输出。
- 通过 ChatClient 实现流式输出。
ChatModel 流式输出
Spring AI 中的流式输出实现非常简单,使用 ChatModel 中的 stream 即可实现:
@RequestMapping(value = "/streamChat", produces = "text/event-stream")
public Flux<String> streamChat(@RequestParam(value = "msg") String msg) {
return chatModel.stream(msg);
}
ChatClient 流式输出
ChatClient 流式输出实现也很简单,也是调用 stream().content() 返回 Flux 对象即可:
@RequestMapping("/stream")
public Flux<String> stream(String question) {
return chatClient.prompt(question)
.stream()
.content();
}
底层实现
那么问题来了流式输出的底层实现究竟是啥呢?
根据以往的经验我们知道,流式输出的实现技术基本有两种:
- Spring MVC(Servlet)+ SSE 实现流式输出。
- Spring WebFlux Reactor 模型实现流式输出。
SSE 介绍
SSE(Server-Sent Events)是一种允许服务器向浏览器或其他客户端推送实时更新的技术。它是一种单向通信机制,服务器可以主动向客户端发送数据,而客户端无需频繁轮询服务器请求数据。SSE 是基于 HTTP 协议的,使用标准的 text/event-stream
MIME 类型来传输数据。
SSE 主要特点
- 单向通信:SSE 仅支持服务器到客户端的单向通信,客户端不能向服务器发送消息。如果需要双向通信,可以结合 WebSocket 或其他技术。
- 基于 HTTP:SSE 使用标准的 HTTP 协议,不需要额外的协议支持,因此兼容性较好。
- 自动重连:客户端在连接中断后会自动尝试重新连接。
- 数据格式:SSE 数据以特定的格式发送,每条消息以 data: 开头,以两个换行符 \n\n 结尾。
- 事件类型:可以为每条消息指定事件类型,客户端可以通过监听特定事件类型来处理不同的消息。
Spring MVC(Spring Web)底层是基于 Servlet 实现的,它是使用 SseEmitter 技术实现 SSE 协议实现流式输出的。
SseEmitter 基本用法
这里提供一个 SseEmitter 的简单使用案例,实现流式输出,让大家更好的理解这个技术点:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
@RestController
public class SseDemoController {
@GetMapping(value = "/sse-demo", produces = "text/event-stream")
public SseEmitter streamData() {
// 设置超时时间(单位:毫秒)
SseEmitter emitter = new SseEmitter(30_000L); // 30秒超时
// 异步任务模拟流式输出
new Thread(() -> {
try {
for (int i = 1; i <= 5; i++) {
String message = "第 " + i + " 条消息";
emitter.send(message);
Thread.sleep(1000); // 每秒发送一次
}
emitter.complete(); // 完成推送
} catch (IOException | InterruptedException e) {
emitter.completeWithError(e); // 异常处理
}
}).start();
return emitter;
}
}
Spring WebFlux 介绍
Spring WebFlux 是 Spring Framework 5 引入的响应式 Web 框架,旨在解决高并发场景下传统同步阻塞模型(如 Spring MVC)的性能瓶颈。其核心目标是通过非阻塞异步编程模型提升系统吞吐量,适用于 I/O 密集型任务(如微服务通信、实时数据流处理)。
Spring WebFlux 与 Spring MVC 不同,它基于 Reactive Streams 规范实现的,支持背压机制(Backpressure),防止数据生产者压垮消费者。
背压机制:通过订阅者主动控制数据流速,避免内存溢出。例如,消费者可动态调整请求量,生产者根据反馈调整数据生成速度.
Spring AI 流式输出
说完了前置知识,咱们回到主题:Spring AI 是如何实现流式输出的?
要搞清楚这个问题,我们需要看流式输出对象 Flux 的实现源码:
查看 Flux 源码我们发现它是属于 reactor.core.publisher 包下的抽象类:
并且看类注释和类所在的 jar 包我们就明白了:
Spring AI 中的流式输出是通过 Reactor Streams 模型实现的,和 Spring WebFlux 的底层实现是一样的技术。
具体执行流程:Reactor Streams 会订阅数据源,当有数据时,Reactor Streams 以分块流的方式发送给客户端(用户)。
Reactor 介绍
Reactor 是一种事件驱动的高性能网络编程模型,主要用于处理高并发的网络 I/O 请求。其核心思想是通过一个或多个线程监听事件,并将事件分发给相应的处理程序,从而实现高效的并发处理。
Reactor 模型的主要特征如下:
- 事件驱动:所有 I/O 操作都由事件触发并处理。
- 非阻塞:操作不会因为 I/O 而挂起,避免了线程等待的开销。
- 高效资源利用:通过少量线程处理大量并发连接,提升性能。
- 组件分离:将事件监听(Reactor)、事件分发(Dispatcher)和事件处理(Handler)解耦,使代码结构更清晰。
Reactor 实现方式有三种:
- 单线程 Reactor 模型:所有操作在一个线程完成,适用于低并发场景。
- 多线程 Reactor 模型:主线程处理连接,子线程池处理 I/O 和业务。
- 主从 Reactor 模型:主线程池处理连接,子线程池处理 I/O(进一步优化资源分配)。
生产级别使用的 Reactor 基本都是主从 Reactor 模型,它的执行流程如下:
小结
Spring AI 中的流式输出有两种实现,而通过查看这两种流式输出的实现源码可知,Spring AI 中的流式输出是通过 Reactor Streams 技术实现的,当客户端发送请求时,会建立连接并订阅数据源,当有数据时,Reactor Streams 以分块流的方式发送给客户端(用户)。
本文已收录到我的技术小站 www.javacn.site,其中包含的内容有:Spring AI、LangChain4j、MCP、Function Call、RAG、向量数据库、Prompt、多模态、向量数据库、嵌入模型等内容。
聊聊SpringAI流式输出的底层实现?的更多相关文章
- HttpURLConnection的流式输出的缺陷和解决方法
转自:http://www.mzone.cc/article/198.html 最近在用applet写文件上传控件的时候发现使用URLConnection来对服务器进行流式输出时的一些问题.我们通常要 ...
- 文件下载(StreamingHttpResponse流式输出)
文件下载(StreamingHttpResponse流式输出) HttpResponse会直接使用迭代器对象,将迭代器对象的内容存储成字符串,然后返回给客户端,同时释放内存.可以当文件变大看出这是一个 ...
- DJANGO的HTTPRESPONSE流式输出
在项目当中遇到的问题,网上有样例代码,但都不行,后来,发现在了1.5版本之后,新的STREAMHTTPRESPONSE对象, 搞定. from django.http import HttpRespo ...
- Openresty的同步输出与流式响应
Openresty的同步输出与流式响应 默认情况下, ngx.say和ngx.print都是异步输出的,先来看一个例子: location /test { content_by_lua_block { ...
- centos 正则,grep,egrep,流式编辑器 sed,awk -F 多个分隔符 通配符 特殊符号. * + ? 总结 问加星 cat -n nl 输出文件内容并加上行号 alias放~/.bash_profile 2015-4-10 第十三节课
centos 正则,grep,egrep,流式编辑器 sed,awk -F 多个分隔符 通配符 特殊符号. * + ? 总结 问加星 cat -n nl 输出文件内容并加上行号 alias放~ ...
- 流式处理的新贵 Kafka Stream - Kafka设计解析(七)
原创文章,转载请务必将下面这段话置于文章开头处. 本文转发自技术世界,原文链接 http://www.jasongj.com/kafka/kafka_stream/ Kafka Stream背景 Ka ...
- 流式计算与计算抽象化------《Designing Data-Intensive Applications》读书笔记15
上篇的内容,我们探讨了分布式计算中的MapReduce与批处理.所以本篇我们将继续探索分布式计算优化的相关细节,并且分析MapReduce与批处理的局限性,看看流式计算是否能给我们在分布式计算层面提供 ...
- “流式”前端构建工具——gulp.js 简介
Grunt 一直是前端领域构建工具(任务运行器或许更准确一些,因为前端构建只是此类工具的一部分用途)的王者,然而它也不是毫无缺陷的,近期风头正劲的 gulp.js 隐隐有取而代之的态势.那么,究竟是什 ...
- Spark Streaming流式处理
Spark Streaming介绍 Spark Streaming概述 Spark Streaming makes it easy to build scalable fault-tolerant s ...
- 流式计算新贵Kafka Stream设计详解--转
原文地址:https://mp.weixin.qq.com/s?__biz=MzA5NzkxMzg1Nw==&mid=2653162822&idx=1&sn=8c4611436 ...
随机推荐
- 应用中的 PostgreSQL项目案例
title: 应用中的 PostgreSQL项目案例 date: 2025/2/3 updated: 2025/2/3 author: cmdragon excerpt: 随着大数据和云计算的兴起,企 ...
- SHA1字符串加密
使用SHA1算法,生成某个字符串的hash值作为该字符串所代表对象的唯一标识: Demo: using System; using System.Collections.Generic; using ...
- DeepSeek引发创业的思考
2025年春节最火的就是DeepSeek,就像08年小沈阳的火一样,越来越多的不是Ai这个行业的人开始越来越关注Ai,作为一个一直从事Ai的工作者,看到了ChatGPT的涌现后,中国再次冲出来的中国式 ...
- AWS - [01] 概述
题记部分 001 || 概述 AWS,全称Amazon Web Services,是亚马逊公司旗下的云计算服务平台,自2006年起向全球用户提供广泛而深入的云计算服务.AWD是全球最全面.应用最广 ...
- 公众号已上线 Ask AI 功能
Get新技能,给公众号接入AI智能体,没花一分钱. 不禁感慨这时代的进步也太快了,曾经科幻小说中描绘的未来已成现实! 下面是笔者在腾讯元宝中创建的智能体"鲸鱼小助手": 如果今后要 ...
- Linux 安装 MySQL 8.0
目录 下载 安装数据库 修改mysql配置文件(若没有则新建) 安装并初始化mysql 查看mysql密码 配置启动 登录MySQL 修改密码 配置远程连接 配置防火墙 常见错误 Windows 安装 ...
- nnUNet 论文解析
一些废话: 毕业论文用 nnUNet 及其自带的功能大概做了一个医学图像的分割模块.现将自己在学习过程中看过的相关论文及相关能找到的笔记记录整理在此.一些浅显的内容目的是在为自己做记录的同时,也希望能 ...
- Mac port 443: Connection refused
MAC 安装brew raw.githubusercontent.com port 443: Connection refused 本人亲自认证过,踩过多种方案,最终认证的解决方案 原因:由于某些你懂 ...
- Windows核心编程 进程与线程
进程 Windows作为多任务操作系统,允许多个程序同时在系统中运行.这些程序被称为进程,进程运行在一片独立的空间中,受到操作系统保护,操作系统的很多资源都是围绕着进程来进行分配,可以理解为操作系统维 ...
- vSphere是什么,你了解么?
最近这两周都在学习VMware vSphere相关知识,昨天在做了一个项目后,VMware虚拟化之旅暂告一段落了.晚上一个人闲下来时回想了之前所学,忆起vSphere时,大脑一片空白... 我突然发现 ...