Spring AI阿里百炼平台实现流式对话:基于 SSE 的实践指南

在大模型应用开发中,流式对话是提升用户体验的关键特性。本文将详细介绍如何利用 Spring AI 结合 Spring Boot,基于 SSE(Server-Sent Events)协议实现高效的流式对话功能,包括动态中断机制和前端交互优化。

技术选型与协议解析

SSE 协议与 WebSocket 的区别

SSE(Server-Sent Events)是一种基于 HTTP 的轻量级服务器向客户端推送信息的协议,与 WebSocket 相比有显著差异:

特性SSEWebSocket
通信方向单向(服务端 → 客户端)全双工(双向通信)
连接方式基于 HTTP 长连接独立的 WebSocket 协议
复杂度简单(无需复杂握手)复杂(需要专门握手过程)
适用场景消息推送、实时通知、流式输出即时通讯、游戏等双向交互场景
数据格式文本/event-stream 格式二进制/文本,需自定义格式

对于仅需服务端向客户端推送流式响应的对话场景,SSE 是更简洁高效的选择。

项目环境搭建

核心依赖配置

首先在 pom.xml 中添加必要依赖(注意修正版本号格式错误):

<!-- Spring AI 依赖管理 -->
<dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>1.0.0-M6</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement><!-- 核心依赖 -->
<dependencies><!-- Spring AI OpenAI 适配 --><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-openai-spring-boot-starter</artifactId></dependency><!-- 阿里百炼 SDK(兼容 OpenAI 协议) --><dependency><groupId>com.alibaba</groupId><artifactId>dashscope-sdk-java</artifactId><version>2.16.9</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId></exclusion></exclusions></dependency><!-- Spring WebFlux(响应式编程支持) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency>
</dependencies>

配置文件设置

application.yml 中配置模型服务信息:

spring:ai:openai:base-url: https://dashscope.aliyuncs.com/compatible-mode  # 阿里百炼兼容接口api-key: sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxx  # 替换为实际API密钥chat:options:model: qwen-plus  # 可替换为实际使用的模型,如qwen-max、qwen-turbo等

核心功能实现

1. ChatClient 配置

创建 ChatClient 实例,配置对话模型、记忆机制和系统提示:

import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatMemory;
import org.springframework.ai.chat.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AiConfig {@Beanpublic ChatClient chatClient(ChatModel chatModel, ChatMemory chatMemory) {return ChatClient.builder(chatModel).defaultOptions(options -> options.withModel("qwen-plus")  // 模型名称.withTemperature(0.7f))  // 新增温度参数,控制输出随机性.defaultSystem("你是一个友好的智能助手,负责解答用户问题")  // 修正引号格式.defaultAdvisors(new SimpleLoggerAdvisor(),  // 日志记录new MessageChatMemoryAdvisor(chatMemory)  // 对话记忆).build();}
}

2. 流式对话控制器

实现支持 SSE 的控制器,包含流式响应和中断功能:

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import java.util.concurrent.atomic.AtomicBoolean;import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;@RestController
@RequestMapping("/api/chat")
@RequiredArgsConstructor
@Slf4j
public class ChatController {private final ChatClient chatClient;private final AtomicBoolean isStreaming = new AtomicBoolean(true);  // 线程安全的状态标识/*** 流式对话接口* @param prompt 用户输入* @param chatId 对话ID(用于记忆上下文)*/@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<String> streamChat(@RequestParam String prompt,@RequestParam(required = false, defaultValue = "default") String chatId) {log.info("收到对话请求 [{}]: {}", chatId, prompt);isStreaming.set(true);  // 重置流式状态return chatClient.prompt().user(prompt).advisors(advisorSpec -> advisorSpec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)).stream().content().takeWhile(data -> isStreaming.get())  // 动态中断控制.doOnCancel(() -> log.info("对话流已取消 [{}]", chatId))  // 取消时日志.concatWithValues("\u0003");  // 结束标记(ETX字符)}/*** 中断流式输出接口*/@PostMapping("/cancel")public void cancelStream() {isStreaming.set(false);log.info("已触发流式输出中断");}
}

3. 前端交互实现

完善前端页面,处理流式数据接收、中断控制和用户体验优化:

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><title>Spring AI 流式对话演示</title><style>.container { max-width: 800px; margin: 20px auto; padding: 0 15px; }#output { border: 1px solid #e0e0e0; padding: 15px; min-height: 300px; border-radius: 8px; }.controls { margin: 15px 0; display: flex; gap: 10px; }input[type="text"] { flex: 1; padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px; }button { padding: 8px 16px; cursor: pointer; border: none; border-radius: 4px; }button.send { background: #4285f4; color: white; }button.cancel { background: #ea4335; color: white; }</style>
</head>
<body><div class="container"><div class="controls"><input type="text" id="prompt" placeholder="请输入问题..."><button class="send" onclick="sendMessage()">发送</button><button class="cancel" onclick="cancelStream()">中断</button></div><h3>AI 回复:</h3><div id="output"></div></div><script>const outputDiv = document.getElementById('output');const promptInput = document.getElementById('prompt');let eventSource = null;// 发送消息function sendMessage() {const prompt = promptInput.value.trim();if (!prompt) return;// 清空输入和输出promptInput.value = '';outputDiv.innerHTML = '';// 创建对话ID(可基于时间戳生成)const chatId = 'chat_' + Date.now();// 建立SSE连接eventSource = new EventSource(`/api/chat/stream?prompt=${encodeURIComponent(prompt)}&chatId=${chatId}`);// 处理收到的消息eventSource.onmessage = (event) => {const data = event.data;// 检测结束标记if (data === '\u0003') {eventSource.close();return;}// 追加内容到输出区域outputDiv.textContent += data;};// 处理错误eventSource.onerror = () => {console.error('连接发生错误');eventSource.close();};}// 中断流式输出function cancelStream() {if (eventSource) {eventSource.close();eventSource = null;}// 通知后端停止生成fetch('/api/chat/cancel', { method: 'POST' }).catch(err => console.error('取消请求失败', err));}</script>
</body>
</html>

关键技术点解析

1. 响应式编程与 Flux

Spring AI 的流式响应基于 Reactor 框架的 Flux 实现:

  • Flux 代表一个异步的序列数据流,适合处理流式输出
  • takeWhile 操作符用于根据条件(isStreaming 状态)控制流的生命周期
  • concatWithValues 用于在流结束时添加终止标记,方便前端处理

2. 动态中断机制

  • 使用 AtomicBoolean 保证多线程环境下的状态安全性
  • 前端通过 /cancel 接口触发中断,后端通过 takeWhile 终止流
  • 结合 eventSource.close() 确保前端资源正确释放

3. 对话记忆管理

  • 通过 ChatMemoryMessageChatMemoryAdvisor 实现上下文记忆
  • chatId 参数用于区分不同对话会话,实现多用户/多会话隔离

常见问题与优化建议

  1. 依赖版本问题:确保 Spring AI 版本与 Spring Boot 版本兼容(建议使用 Spring Boot 3.2+)

通过以上实现,我们基于 Spring AI 和 SSE 协议构建了一个完整的流式对话系统,支持实时响应、动态中断和上下文记忆,为用户提供流畅的对话体验。在实际应用中,可根据业务需求进一步扩展功能,如添加消息加密、内容过滤或多模型切换等特性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/91615.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/91615.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/91615.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu lamp

Ubuntu lamp 前言 在Ubuntu安装lamp架构 我们了解到 lamp是完整的架构 我们前面了解到了 集合了Linux系统 apache MySQL 和PHP语言的完整架构 我们前面说了Centos7中编译安装 lamp 那么 我们去说一下在Ubuntu中安装 ‍ ‍ 安装apache2 ‍ apt直接安装apache2 apt -y install a…

开源向量LLM - Qwen3-Embedding

1 Qwen3-Embedding介绍 Qwen3-Embedding遵循 Apache 2.0 许可证&#xff0c;模型大小从0.6B到8B&#xff0c;支持32k长文本编码。 Model TypeModelsSizeLayersSequence LengthEmbedding DimensionMRL SupportInstruction AwareText EmbeddingQwen3-Embedding-0.6B0.6B2832K10…

云计算服务模式全解析:IaaS、PaaS、SaaS与DaaS的区别与应用

一、云计算概述 云计算是一种通过互联网提供计算服务的模式&#xff0c;其核心特点是输入/输出与计算不在同一主机上。一个完整的云计算环境由云端&#xff08;计算设备&#xff09;、计算机网络和终端&#xff08;输入/输出设备&#xff09;三部分组成&#xff0c;即"云…

qwen 多模态 预训练流程步骤详细介绍

Qwen&#xff08;通义千问&#xff09;是阿里云推出的大语言模型&#xff0c;其多模态预训练是一个复杂且专业的过程&#xff0c;虽然官方没有完全公开全部细节&#xff0c; 但从多模态大模型通用的预训练逻辑上&#xff0c;一般包含以下主要步骤&#xff1a; 数据准备 多模态数…

FastDDS (SharedMemory)

SharedMemSegment Start // Fast-DDS/src/cpp/utils/shared_memory/SharedMemSegment.hppclass SharedSegmentBase {内部类 start class Id { public:typedef UUID<8> type;Id(); // 返回共享内存变量的IDId(const Id& other); // 设置共享内存变量的IDvoid g…

sqli-labs:Less-5关卡详细解析

1. 思路&#x1f680; 本关的SQL语句为&#xff1a; $sql"SELECT * FROM users WHERE id$id LIMIT 0,1";注入类型&#xff1a;字符串型&#xff08;单引号包裹&#xff09;提示&#xff1a;参数id需以闭合 但有意思的是&#xff0c;php代码的输出语句不是如下这种…

标准项目-----网页五子棋(4)-----游戏大厅+匹配+房间代码

页面实现 hall.html <!DOCTYPE html> <html lang"ch"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>游戏大厅</title><l…

MySQL分析步

MySQL分析 -- 库名 set dbName bsa_crmeb_bak; -- 表名 set tableName bsa_crmeb_bak;-- 查看bsa_crmeb_bak数据库基本信息 SELECTSCHEMA_NAME AS 数据库名,DEFAULT_CHARACTER_SET_NAME AS 字符集,DEFAULT_COLLATION_NAME AS 排序规则 FROM information_schema.SCHEMATA WHER…

工程化(二):为什么你的下一个项目应该使用Monorepo?(pnpm / Lerna实战)

工程化(二)&#xff1a;为什么你的下一个项目应该使用Monorepo&#xff1f;&#xff08;pnpm / Lerna实战&#xff09; 引子&#xff1a;前端项目的“孤岛困境” 随着你的项目或团队不断成长&#xff0c;一个棘手的问题会逐渐浮现&#xff1a;代码该如何组织&#xff1f; 最…

应用药品注册证识别技术,为医药行业的合规、高效与创新发展提供核心驱动力

在医药行业的庞杂数据海洋中&#xff0c;药品注册证&#xff08;如中国的“国药准字”、美国的NDA/ANDA批号&#xff09;是药品合法上市流通的“身份证”。面对海量的证书审核、录入与验证需求&#xff0c;传统人工处理方式不仅效率低下、成本高昂&#xff0c;更易因疲劳导致差…

Spring Boot 2.1.18 集成 Elasticsearch 6.6.2 实战指南

Spring Boot 2.1.18 集成 Elasticsearch 6.6.2 实战指南前言&#xff1a;一. JAVA客户端对比二. 导入数据2.1 分析创建索引2.2 代码实现三. ElasticSearch 查询3.1 matchAll 查询3.2 term查询3.3 match查询3.4 模糊查询3.5 范围查询3.6 字符串查询3.7 布尔查询3.8 分页与排序3.…

向量投影计算,举例说明

向量投影计算,举例说明 向量投影是指将一个向量(设为向量b\mathbf{b}b)投射到另一个向量(设为向量a\mathbf{a}a)所在直线上,得到一个与a\mathbf{a}

如何在技术世界中保持清醒和高效

“抽象泄露&#xff0c;是存在的&#xff0c;但你需要了解多少&#xff0c;需要理解多深&#xff0c;这一点是因人而异的&#xff0c;绝对不是别人能够建议的。每个人只会站在自己的立场上去建议别人怎么做。”在写下这句话时&#xff0c;身为一个技术开发者&#xff0c;我似乎…

服装公司数字化转型如何做?

WL贸易集团公司&#xff08;以下简称WL&#xff09;自2012年成立以来&#xff0c;在十余年的发展历程中不断蜕变与升级。公司始终秉持“时尚与品质优先”的核心经营理念&#xff0c;通过严格执行高标准、严要求&#xff0c;牢牢把握产品品质与交货周期两大关键&#xff0c;赢得…

GM DC Monitor 之 银河麒麟 Docker 部署安装手册

官方网站&#xff1a;www.gm-monitor.com 本手册以银河麒麟为例&#xff0c;介绍在 Linux 系统上安装和配置DOCKER服务的详细步骤 一、以root用户执行以下操作命令 1、环境优化 modprobe br_netfilter cat <<EOF > /etc/sysctl.d/docker.conf net.bridge.bridge-n…

网络编程接口bind学习

1、概述下面2个问题你会怎么回答呢?1、bind如果绑定0号端口&#xff0c;可以工作么&#xff0c;如果能正常工作&#xff0c;绑定的什么端口 2、客户端可以调用bind么2、解析2.1、bind如果绑定0号端口&#xff0c;可以工作么&#xff0c;如果能正常工作&#xff0c;绑定的什么端…

FinOps X 2025 核心发布:AI 时代下的 FinOps 转型

2025年&#xff0c;人工智能技术的突破性发展正深刻重塑商业与技术格局&#xff0c;智能技术已成为各领域创新的核心驱动力。在此背景下&#xff0c;FinOps X 2025 围绕 AI 技术对财务运营&#xff08;FinOps&#xff09;的革新作用展开深度探讨&#xff0c;重点呈现了以下关键…

使用Min-Max进行数据特征标准化

在数据处理过程中&#xff0c;标准化是非常重要的步骤之一&#xff0c;特别是在机器学习和数据分析中。Min-Max标准化&#xff08;也称为归一化&#xff09;是一种常用的数据标准化方法&#xff0c;它通过将数据缩放到一个指定的范围&#xff08;通常是0到1之间&#xff09;&am…

【Dart 教程系列第 51 篇】Iterable 中 reduce 函数的用法

这是【Dart 教程系列第 51 篇】,如果觉得有用的话,欢迎关注专栏。 博文当前所用 Dart SDK:3.5.4 文章目录 一:reduce 作用 二:举例说明 1:求和 2:查找最大/最小值 3:字符串拼接 4:自定义对象合并 三:注意事项 一:reduce 作用 reduce 是 Iterable 的一个方法,用于…

使用VSCode配置Flutter

本周&#xff08;学期第四周&#xff09;任务&#xff1a; 1.简单学习Flutter&#xff0c;完成环境安装与配置 2.探索Flutter与Unity集成方案 一、Flutter环境配置 根据Flutter官方文档进行环境配置&#xff1a;开发 Android 应用 | Flutter 中文文档 - Flutter 中文开发者网…