导读想在自己的应用中集成 AI 聊天功能想要实现类似 ChatGPT 的打字机效果本文带你从零开始使用 Spring AI 阿里云通义千问30 分钟打造一个生产级的流式聊天服务 为什么需要流式聊天想象一下这两个场景场景 1传统方式用户请写一篇关于春天的诗 系统等待 5 秒... 系统春天来了万物复苏...一次性显示完整回答场景 2流式方式✨用户请写一篇关于春天的诗 系统春0.5秒 系统春天1秒 系统春天来1.5秒 系统春天来了万2秒 系统春天来了万物复2.5秒 系统春天来了万物复苏...持续输出哪个体验更好显然是第二个这就是我们今天要实现的流式聊天。 项目介绍CodeReactor AI是一个基于 Spring AI 的流式聊天服务核心特性✅实时推送SSE 技术逐字显示 AI 回答✅响应式编程Flux 非阻塞异步处理✅事件驱动区分数据事件和停止事件✅生产就绪完整的错误处理和日志记录技术栈一览Spring Boot Spring AI 阿里云通义千问 Project Reactor就是这么简单不需要复杂的配置几行代码就能实现。 快速开始5 分钟上手第一步准备 API Key访问 阿里云 DashScope 控制台注册账号并创建 API Key。费用说明新用户有免费额度qwen-plus 模型约 0.008 元/千 token非常便宜第二步设置环境变量Windows$env:ALIYUN_API_KEYsk-xxxxxxxxxxxxMac/LinuxexportALIYUN_API_KEYsk-xxxxxxxxxxxx第三步启动项目gitclone https://github.com/your-repo/codereactor-ai.gitcdcodereactor-ai mvn spring-boot:run看到以下日志就成功了Started Application in 3.456 seconds Tomcat started on port(s): 8080 (http)第四步测试接口打开 Postman 或浏览器发送请求POST http://localhost:8080/ai/chat Content-Type: application/json { question: 你好请介绍一下自己, sessionId: test_001 }见证奇迹的时刻你会看到 AI 的回答像打字机一样逐字显示出来 核心原理揭秘什么是 SSESSEServer-Sent Events是一种服务器推送技术允许服务器主动向客户端发送数据。对比三种推送技术技术方向复杂度适用场景HTTP 轮询客户端→服务器⭐简单场景WebSocket双向⭐⭐⭐实时聊天、游戏SSE服务器→客户端⭐⭐流式响应、消息推送我们的场景只需要服务器向客户端推送所以 SSE 是最佳选择代码解析只需 20 行核心代码让我们看看最核心的ChatServiceImpl.javaServicepublicclassChatServiceImplimplementsChatService{privatefinalChatClientchatClient;OverridepublicFluxChatEventVOchat(Stringquestion,StringsessionId){returnthis.chatClient.prompt()// ① 创建提示词.user(question)// ② 设置用户问题.stream()// ③ 启用流式模式 ⭐.chatResponse()// ④ 获取响应流.map(response-{// ⑤ 转换数据格式Stringtextresponse.getResult().getOutput().getText();returnChatEventVO.builder().eventData(text).eventType(1001)// 数据事件.build();}).concatWith(// ⑥ 追加停止事件Flux.just(ChatEventVO.builder().eventType(1002)// 停止事件.build()));}}就这么简单关键就在.stream()这个方法它启用了流式模式。数据流转全过程用户提问 你好 ↓ ChatController 接收请求 ↓ ChatService 调用 AI ↓ 阿里云 DashScope API ↓ 返回流式数据你 → 好 → → ... ↓ 转换为 SSE 格式 ↓ 前端实时显示打字机效果 前端如何接收方法 1使用 fetch ReadableStreamfetch(/ai/chat,{method:POST,headers:{Content-Type:application/json},body:JSON.stringify({question:你好,sessionId:test_001})}).then(response{constreaderresponse.body.getReader();constdecodernewTextDecoder();functionread(){reader.read().then(({done,value}){if(done)return;constchunkdecoder.decode(value);constlineschunk.split(\n);lines.forEach(line{if(line.startsWith(data: )){constdataJSON.parse(line.substring(6));if(data.eventType1001){// 追加文本打字机效果document.getElementById(answer).innerHTMLdata.eventData;}}});read();// 继续读取});}read();});方法 2Vue 3 示例template div input v-modelquestion keyup.entersendQuestion / div idanswer{{ answer }}/div /div /template script setup import { ref } from vue; const question ref(); const answer ref(); async function sendQuestion() { answer.value ; const response await fetch(/ai/chat, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ question: question.value }) }); const reader response.body.getReader(); const decoder new TextDecoder(); while (true) { const { done, value } await reader.read(); if (done) break; const chunk decoder.decode(value); const lines chunk.split(\n); for (const line of lines) { if (line.startsWith(data: )) { const data JSON.parse(line.substring(6)); if (data.eventType 1001) { answer.value data.eventData; // 打字机效果 ✨ } } } } } /script️ 实战技巧技巧 1添加加载动画// 开始请求时显示加载动画constloadingref(true);fetch(/ai/chat,...).then((){loading.valuefalse;// 收到第一个字符时隐藏});技巧 2支持中断letabortControllernewAbortController();// 发送请求fetch(/ai/chat,{signal:abortController.signal// 传入信号});// 用户点击停止按钮abortController.abort();技巧 3错误处理try{awaitfetch(/ai/chat,...);}catch(error){if(error.nameAbortError){console.log(用户主动中断);}else{console.error(请求失败:,error);answer.value抱歉出错了请重试;}} 进阶功能1. 多轮对话会话历史当前版本已预留sessionId可以轻松实现多轮对话// 从 Redis 获取历史消息ListMessagehistoryredisTemplate.get(chat:sessionId);// 构建带历史的 promptchatClient.prompt().messages(history)// 添加历史.user(question)// 当前问题.stream()...效果用户我叫小明 AI你好小明 用户我刚才说了什么 AI你刚才说你叫小明 2. 敏感词过滤.map(response-{Stringtextresponse.getResult().getOutput().getText();// 敏感词过滤if(containsSensitiveWords(text)){text***;}returnChatEventVO.builder().eventData(text).eventType(1001).build();})3. 切换 AI 模型修改application.yamlspring:ai:dashscope:chat:options:# 可选模型model:qwen-turbo# 快速、便宜# model: qwen-plus # 平衡默认# model: qwen-max # 最强、最贵 性能对比指标传统方式流式方式首字延迟5 秒0.5 秒 ⚡用户体验等待焦虑流畅自然 ✨服务器压力高长时间连接低逐步释放实现复杂度简单中等结论流式方式在用户体验上完胜❓ 常见问题Q1API Key 哪里获取访问 阿里云 DashScope 控制台注册后即可创建。Q2费用贵吗新用户有免费额度。qwen-plus 约 0.008 元/千 token正常聊天一天几毛钱。Q3可以本地部署吗可以可以使用 Ollama Llama3 等开源模型但需要较好的 GPU。Q4支持哪些语言通义千问支持中文、英文、日文、韩文等多种语言。Q5如何部署到生产环境打包mvn clean package运行java -jar codereactor-ai.jar建议使用 Docker Nginx HTTPS 应用场景这个聊天服务可以用于智能客服7x24 小时自动回复内容创作辅助写作、翻译、总结代码助手代码解释、Bug 修复教育辅导答疑解惑、知识讲解智能助手日程管理、信息查询 完整代码项目已开源欢迎 Star ⭐Giteehttps://gitee.com/imyzp/codereactor-boot/tree/spring-boot3.5.x/codereactor-dependencies/codereactor-starters/codereactor-ai目录结构codereactor-ai/ ├── src/main/java/com/codereactor/ai/ │ ├── config/SpringAIConfig.java # 配置类 │ ├── controller/ChatController.java # 控制器 │ ├── service/ChatServiceImpl.java # 核心逻辑 ⭐ │ └── model/ # 数据模型 └── src/main/resources/application.yaml # 配置文件 下一步学会了基础用法你可以尝试✅ 添加多轮对话功能✅ 集成向量数据库实现知识库问答✅ 添加语音输入/输出✅ 实现 AI Agent自动调用工具✅ 部署到云端提供公开服务 互动交流如果你有任何问题或想法欢迎Star 项目鼓励作者继续更新留言讨论分享你的使用心得提交 PR一起完善项目 参考资料Spring AI 官方文档阿里云 DashScope 文档Project Reactor 教程作者简介一名热爱开源的全栈开发者专注于 AI 应用开发。欢迎关注我的公众号获取更多技术干货觉得有用点个在看分享给更多人吧标签#SpringAI #人工智能 #聊天机器人 #Java #阿里云 #通义千问 #流式响应 #SSE
手把手教你用 Spring AI 打造流式聊天机器人,媲美 ChatGPT 体验!
导读想在自己的应用中集成 AI 聊天功能想要实现类似 ChatGPT 的打字机效果本文带你从零开始使用 Spring AI 阿里云通义千问30 分钟打造一个生产级的流式聊天服务 为什么需要流式聊天想象一下这两个场景场景 1传统方式用户请写一篇关于春天的诗 系统等待 5 秒... 系统春天来了万物复苏...一次性显示完整回答场景 2流式方式✨用户请写一篇关于春天的诗 系统春0.5秒 系统春天1秒 系统春天来1.5秒 系统春天来了万2秒 系统春天来了万物复2.5秒 系统春天来了万物复苏...持续输出哪个体验更好显然是第二个这就是我们今天要实现的流式聊天。 项目介绍CodeReactor AI是一个基于 Spring AI 的流式聊天服务核心特性✅实时推送SSE 技术逐字显示 AI 回答✅响应式编程Flux 非阻塞异步处理✅事件驱动区分数据事件和停止事件✅生产就绪完整的错误处理和日志记录技术栈一览Spring Boot Spring AI 阿里云通义千问 Project Reactor就是这么简单不需要复杂的配置几行代码就能实现。 快速开始5 分钟上手第一步准备 API Key访问 阿里云 DashScope 控制台注册账号并创建 API Key。费用说明新用户有免费额度qwen-plus 模型约 0.008 元/千 token非常便宜第二步设置环境变量Windows$env:ALIYUN_API_KEYsk-xxxxxxxxxxxxMac/LinuxexportALIYUN_API_KEYsk-xxxxxxxxxxxx第三步启动项目gitclone https://github.com/your-repo/codereactor-ai.gitcdcodereactor-ai mvn spring-boot:run看到以下日志就成功了Started Application in 3.456 seconds Tomcat started on port(s): 8080 (http)第四步测试接口打开 Postman 或浏览器发送请求POST http://localhost:8080/ai/chat Content-Type: application/json { question: 你好请介绍一下自己, sessionId: test_001 }见证奇迹的时刻你会看到 AI 的回答像打字机一样逐字显示出来 核心原理揭秘什么是 SSESSEServer-Sent Events是一种服务器推送技术允许服务器主动向客户端发送数据。对比三种推送技术技术方向复杂度适用场景HTTP 轮询客户端→服务器⭐简单场景WebSocket双向⭐⭐⭐实时聊天、游戏SSE服务器→客户端⭐⭐流式响应、消息推送我们的场景只需要服务器向客户端推送所以 SSE 是最佳选择代码解析只需 20 行核心代码让我们看看最核心的ChatServiceImpl.javaServicepublicclassChatServiceImplimplementsChatService{privatefinalChatClientchatClient;OverridepublicFluxChatEventVOchat(Stringquestion,StringsessionId){returnthis.chatClient.prompt()// ① 创建提示词.user(question)// ② 设置用户问题.stream()// ③ 启用流式模式 ⭐.chatResponse()// ④ 获取响应流.map(response-{// ⑤ 转换数据格式Stringtextresponse.getResult().getOutput().getText();returnChatEventVO.builder().eventData(text).eventType(1001)// 数据事件.build();}).concatWith(// ⑥ 追加停止事件Flux.just(ChatEventVO.builder().eventType(1002)// 停止事件.build()));}}就这么简单关键就在.stream()这个方法它启用了流式模式。数据流转全过程用户提问 你好 ↓ ChatController 接收请求 ↓ ChatService 调用 AI ↓ 阿里云 DashScope API ↓ 返回流式数据你 → 好 → → ... ↓ 转换为 SSE 格式 ↓ 前端实时显示打字机效果 前端如何接收方法 1使用 fetch ReadableStreamfetch(/ai/chat,{method:POST,headers:{Content-Type:application/json},body:JSON.stringify({question:你好,sessionId:test_001})}).then(response{constreaderresponse.body.getReader();constdecodernewTextDecoder();functionread(){reader.read().then(({done,value}){if(done)return;constchunkdecoder.decode(value);constlineschunk.split(\n);lines.forEach(line{if(line.startsWith(data: )){constdataJSON.parse(line.substring(6));if(data.eventType1001){// 追加文本打字机效果document.getElementById(answer).innerHTMLdata.eventData;}}});read();// 继续读取});}read();});方法 2Vue 3 示例template div input v-modelquestion keyup.entersendQuestion / div idanswer{{ answer }}/div /div /template script setup import { ref } from vue; const question ref(); const answer ref(); async function sendQuestion() { answer.value ; const response await fetch(/ai/chat, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ question: question.value }) }); const reader response.body.getReader(); const decoder new TextDecoder(); while (true) { const { done, value } await reader.read(); if (done) break; const chunk decoder.decode(value); const lines chunk.split(\n); for (const line of lines) { if (line.startsWith(data: )) { const data JSON.parse(line.substring(6)); if (data.eventType 1001) { answer.value data.eventData; // 打字机效果 ✨ } } } } } /script️ 实战技巧技巧 1添加加载动画// 开始请求时显示加载动画constloadingref(true);fetch(/ai/chat,...).then((){loading.valuefalse;// 收到第一个字符时隐藏});技巧 2支持中断letabortControllernewAbortController();// 发送请求fetch(/ai/chat,{signal:abortController.signal// 传入信号});// 用户点击停止按钮abortController.abort();技巧 3错误处理try{awaitfetch(/ai/chat,...);}catch(error){if(error.nameAbortError){console.log(用户主动中断);}else{console.error(请求失败:,error);answer.value抱歉出错了请重试;}} 进阶功能1. 多轮对话会话历史当前版本已预留sessionId可以轻松实现多轮对话// 从 Redis 获取历史消息ListMessagehistoryredisTemplate.get(chat:sessionId);// 构建带历史的 promptchatClient.prompt().messages(history)// 添加历史.user(question)// 当前问题.stream()...效果用户我叫小明 AI你好小明 用户我刚才说了什么 AI你刚才说你叫小明 2. 敏感词过滤.map(response-{Stringtextresponse.getResult().getOutput().getText();// 敏感词过滤if(containsSensitiveWords(text)){text***;}returnChatEventVO.builder().eventData(text).eventType(1001).build();})3. 切换 AI 模型修改application.yamlspring:ai:dashscope:chat:options:# 可选模型model:qwen-turbo# 快速、便宜# model: qwen-plus # 平衡默认# model: qwen-max # 最强、最贵 性能对比指标传统方式流式方式首字延迟5 秒0.5 秒 ⚡用户体验等待焦虑流畅自然 ✨服务器压力高长时间连接低逐步释放实现复杂度简单中等结论流式方式在用户体验上完胜❓ 常见问题Q1API Key 哪里获取访问 阿里云 DashScope 控制台注册后即可创建。Q2费用贵吗新用户有免费额度。qwen-plus 约 0.008 元/千 token正常聊天一天几毛钱。Q3可以本地部署吗可以可以使用 Ollama Llama3 等开源模型但需要较好的 GPU。Q4支持哪些语言通义千问支持中文、英文、日文、韩文等多种语言。Q5如何部署到生产环境打包mvn clean package运行java -jar codereactor-ai.jar建议使用 Docker Nginx HTTPS 应用场景这个聊天服务可以用于智能客服7x24 小时自动回复内容创作辅助写作、翻译、总结代码助手代码解释、Bug 修复教育辅导答疑解惑、知识讲解智能助手日程管理、信息查询 完整代码项目已开源欢迎 Star ⭐Giteehttps://gitee.com/imyzp/codereactor-boot/tree/spring-boot3.5.x/codereactor-dependencies/codereactor-starters/codereactor-ai目录结构codereactor-ai/ ├── src/main/java/com/codereactor/ai/ │ ├── config/SpringAIConfig.java # 配置类 │ ├── controller/ChatController.java # 控制器 │ ├── service/ChatServiceImpl.java # 核心逻辑 ⭐ │ └── model/ # 数据模型 └── src/main/resources/application.yaml # 配置文件 下一步学会了基础用法你可以尝试✅ 添加多轮对话功能✅ 集成向量数据库实现知识库问答✅ 添加语音输入/输出✅ 实现 AI Agent自动调用工具✅ 部署到云端提供公开服务 互动交流如果你有任何问题或想法欢迎Star 项目鼓励作者继续更新留言讨论分享你的使用心得提交 PR一起完善项目 参考资料Spring AI 官方文档阿里云 DashScope 文档Project Reactor 教程作者简介一名热爱开源的全栈开发者专注于 AI 应用开发。欢迎关注我的公众号获取更多技术干货觉得有用点个在看分享给更多人吧标签#SpringAI #人工智能 #聊天机器人 #Java #阿里云 #通义千问 #流式响应 #SSE