news 2026/6/13 2:00:55

第十篇:SpringAI 实战 10|全模型流式输出(Streaming)实战:实现打字机效果

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第十篇:SpringAI 实战 10|全模型流式输出(Streaming)实战:实现打字机效果

导读:在上一章中,我们成功构建了多模型共存的底层架构。但在实际体验中,如果调用大模型生成一篇长文,传统的同步请求需要等待几十秒模型完全生成完毕后,才能一次性返回结果。这种“干等”的体验在 AI 应用中是灾难性的。
真正的 AI 应用(如 ChatGPT)都是“边思考边输出”,即流式响应(Streaming Response)。本章我们将基于上一章的多模型架构,引入 Spring WebFlux 的响应式编程,利用 SSE(Server-Sent Events)协议,用极少的代码为 OpenAI、通义千问、DeepSeek 和 Ollama 实现丝滑的“打字机效果”。

一、环境前置说明

运行前提:电脑安装 Ollama客户端,提前拉取开源模型文件

  1. JDK:21
  2. Gradle:8.8
  3. SpringBoot:3.5.14
  4. SpringAI:1.1.7
  5. IDEA:2023 社区版
    (本章代码是在上一篇的基础上新增/修改的)

二、 核心原理:SSE 与 Flux 数据流

要实现流式输出,我们需要理解两个核心技术点:

  1. SSE(Server-Sent Events)协议:这是一种基于 HTTP 的单向通信协议。服务端可以主动向客户端推送数据,非常适合大模型这种“服务端持续生成,客户端持续渲染”的场景。
  2. Reactor 的 Flux 类型:Spring WebFlux 提供了 Flux 响应式流类型。Spring AI 的 ChatClient 原生支持响应式编程,只需将同步的 .call() 替换为 .stream(),底层就会自动将大模型生成的增量 Token 封装为 SSE 数据流推送给前端。

三、 后端改造:一行代码开启流式输出

得益于 Spring AI 的高度抽象,我们无需修改上一章的 MultiModelConfig 配置类,只需在 Controller 层新增流式接口即可。

  1. 引入 WebFlux 依赖
    确保你的 build.gradle 中包含 WebFlux 依赖(Spring AI 的流式响应依赖它):
implementation'org.springframework.boot:spring-boot-starter-webflux'
  1. 新增流式 Controller
    我们在上一章的 MultiModelController 中新增一个流式接口。注意 produces 必须设置为 text/event-stream:
/** * 全模型流式输出接口 */@GetMapping(value="/stream/{provider}",produces=MediaType.TEXT_EVENT_STREAM_VALUE)publicFlux<String>streamChat(@PathVariableStringprovider,@RequestParam(defaultValue="你好,请介绍一下你自己")Stringmsg){ChatClientchatclient=getClientByProvider(provider);// 核心:使用 .stream() 替代 .call(),并调用 .content() 仅返回文本内容returnchatclient.prompt().user(msg).stream().content();}/** * 根据路径参数获取对应的 Client */privateChatClientgetClientByProvider(Stringprovider){returnswitch(provider.toLowerCase()){case"openai"->openaiClient;case"ollama"->ollamaClient;case"qwen"->qwenClient;case"deepseek"->deepseekClient;default->thrownewIllegalArgumentException("Unsupported provider: "+provider);};}

代码解析:Spring WebFlux 检测到返回值是 Flux 且 produces = text/event-stream 时,会自动启用 ServerSentEventHttpMessageWriter。每当大模型生成一个词,Spring 就会自动将其包装成 data: 词语\n\n 的 SSE 格式推送到前端

四、 前端实战:极简 HTML 实现打字机

在 resources/static 目录下新建 stream-test.html文件,代码如下:

<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><title>Spring AI 流式输出测试</title><style>#output{border:1px solid #ccc;padding:15px;min-height:150px;white-space:pre-wrap;font-family:monospace;}button{padding:8px 16px;margin:5px;cursor:pointer;}</style></head><body><h2>多模型流式对话测试</h2><inputtype="text"id="msgInput"value="用五句话聊一聊苏轼"style="width:300px;"><buttononclick="startStream('openai')">OpenAI</button><buttononclick="startStream('qwen')">通义千问</button><buttononclick="startStream('deepseek')">DeepSeek</button><buttononclick="startStream('ollama')">Ollama</button><divid="output">等待输入...</div><script>letcurrentEventSource=null;functionstartStream(provider){constmsg=document.getElementById('msgInput').value;constoutputDiv=document.getElementById('output');// 1. 关闭上一次的连接,防止流冲突if(currentEventSource)currentEventSource.close();outputDiv.innerHTML='';// 2. 建立 SSE 连接consturl=`/ai/stream/${provider}?msg=${encodeURIComponent(msg)}`;currentEventSource=newEventSource(url);// 3. 监听消息,实现打字机追加效果currentEventSource.onmessage=(event)=>{outputDiv.innerHTML+=event.data;// 自动滚动到底部outputDiv.scrollTop=outputDiv.scrollHeight;};// 4. 监听完成或错误currentEventSource.onerror=()=>{currentEventSource.close();};}</script></body></html>

五、 运行与验证

  1. 启动 Spring Boot 应用。
  2. 使用浏览器访问 http://localhost:8080/stream-test.html
  3. 点击不同的模型按钮,你会看到文字像真人打字一样逐字出现在屏幕上。

六、 本章总结

通过本章的实战,我们仅用 .stream().content() 这一行核心代码,就打通了从大模型到前端的流式数据链路。
对后端而言:响应式编程避免了长文本生成时的线程阻塞,单台服务器即可支撑成千上万个并发流式连接。
对前端而言:浏览器原生的 EventSource API 完美契合 SSE 协议,无需引入任何第三方 WebSocket 库。
至此,我们的 AI 应用已经具备了“多模型路由”与“丝滑流式输出”两大核心能力。

六、 参考文献

  1. SpringAI官方文档
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/13 1:59:52

Java小工具:连上MySQL就能导出表数据到Excel,带好所有依赖包

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;一个开箱即用的Java小工具&#xff0c;不用改配置就能连MySQL、查表、生成.xlsx文件。项目结构清晰&#xff0c;src里是核心代码&#xff0c;bin里有编译好的class&#xff0c;lib目录已经打包好了MySQL JDBC驱…

作者头像 李华
网站建设 2026/6/13 1:57:36

MCP Server开发实战:从零构建Agent可调用的服务

#32 MCP Server开发实战&#xff1a;从零构建Agent可调用的服务「Hermes Agent自进化智能体深度解析」系列 | 模块十一 第2篇理解了MCP协议&#xff0c;但你自己能开发一个MCP Server吗&#xff1f; 上一篇#31&#xff0c;我们把MCP协议拆到了螺丝级别——JSON-RPC 2.0的请求响…

作者头像 李华
网站建设 2026/6/13 1:55:50

AKShare:三分钟搞定金融数据,Python量化分析的终极解决方案

AKShare&#xff1a;三分钟搞定金融数据&#xff0c;Python量化分析的终极解决方案 【免费下载链接】akshare AKShare is an elegant and simple financial data interface library for Python, built for human beings! 开源财经数据接口库 项目地址: https://gitcode.com/g…

作者头像 李华
网站建设 2026/6/13 1:50:57

【计算机毕业设计案例】基于 SpringBoot 的老年帮扶志愿任务调度系统的设计与实现(程序+文档+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华