SSE 定义
- Server-Sent: 由服务器发送
- Events: 事件,指服务器主动推给客户端的数据或消息
- Server-SendEvetns: SSE 服务器发送事件 流式输出
SSE 是一种 基于 HTTP 协议的服务器向客户端单向推送数据的技术,允许服务器主动、持续地向客户端发送文本流数据,而无需客户端反复发起请求(告别传统的 "轮询")。
| 维度 | SSE(Server-Sent Events) | WebSocket |
|---|---|---|
| 通信方向 | 单向(服务器→客户端) | 双向(客户端↔服务器) |
| 底层协议 | 基于 HTTP/HTTPS,无需升级 | 需升级 HTTP 协议为 WebSocket 协议 |
| 数据类型 | 仅支持文本(UTF-8) | 支持文本 + 二进制 |
| 重连机制 | 客户端内置自动重连 | 需开发者手动实现重连逻辑 |
| 开发成本 | 极低(HTTP 生态,前端原生 API 支持) | 较高(需处理协议升级、心跳保活) |
| 适用场景 | 服务器单向推送(如实时通知、流式回复) | 双向交互(如聊天框、在线游戏) |
流失输出定义
流式输出(StreamingOutput) 是一种 逐步返回大模型生成结果的技术,生成一点儿返回一点儿,允许服务器将响应内容分批次实时传输给客户端,而不是全部内容生成完毕后一次性返回。能显著提升用户体验,尤其适用于大模型响应慢的场景(比如长生成文本或者复杂模型推理结果)。
spring ai alibaba两种流式输出
1.ChatModel Stream流式输出
2.ChatClietn Stream流式输出
SSE 后端开发
要求同时存在多种大模型产品在系统里共存使用
新建Module

POM文件
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.miao</groupId>
<artifactId>SpringAIAlibaba-test01</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>SAA-04StreamingOutput</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 模型服务灵积 调用alibaba生态的协议 对标openai协议 -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
<version>1.0.0.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.38</version>
</dependency>
</dependencies>
</project>
properties配置
ini
server.port=8082
#大模型对话中文UTF8编码处理
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
server.servlet.encoding.charset=UTF-8
spring.application.name=SAA-03
#spring-ai-alibaba config
#百炼大模型的api-key
spring.ai.dashscope.api-key=${qwen-api-key}
spring.ai.dashscope.url=https://dashscope.aliyuncs.com/compatible-mode/v1
spring.ai.dashscope.model=qwen3-vl-flash
启动类
typescript
package com.miao.sse;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SSA04SSEApplication {
public static void main(String[] args) {
SpringApplication.run(SSA04SSEApplication.class, args);
}
}
业务
1.ChatModel实现 2.ChatClietn实现
ChatModel实现Stream流式输出
config 配置qwen和DeepSeek模型
java
package com.miao.sse.config;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SaaLLMConfig {
private static final String QWEN_MODEL = "qwen3-max";
private static final String DEEPSEEK_MODEL = "deepseek-v3.1";
@Value("${spring.ai.dashscope.url")
private String qwenUrl;
@Bean(name = "deepseek")
public ChatModel deepSeek() {
return DashScopeChatModel.builder()
.dashScopeApi(DashScopeApi.builder()
.apiKey(System.getenv("qwen-api-key"))
.build())
.defaultOptions(DashScopeChatOptions.builder()
.withModel(DEEPSEEK_MODEL)
.build())
.build();
}
@Bean(name = "qwen")
public ChatModel qwen() {
return DashScopeChatModel.builder()
.dashScopeApi(DashScopeApi.builder()
.apiKey(System.getenv("qwen-api-key"))
.build())
.defaultOptions(DashScopeChatOptions.builder().withModel(QWEN_MODEL).build())
.build();
}
}
业务实现Controller
ChatModelController
kotlin
package com.miao.sse.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
@RestController
public class ChatModelController {
@Resource(name = "qwen")
private ChatModel qwen;
@Resource(name = "deepseek")
private ChatModel deepseek;
@GetMapping("/qwen")
public String qwenChat(@RequestParam(name = "msg", defaultValue = "你是谁") String message) {
return qwen.call(message);
}
@GetMapping("/deepseek")
public Flux<String> deepseekChat(@RequestParam(name = "msg", defaultValue = "你是谁") String message) {
return deepseek.stream(message);
}
}
ChatClietn实现Stream流式输出
config 配置deepseek和qwen两个ChatClient
typescript
package com.miao.sse.config;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SaaLLMConfig {
private static final String QWEN_MODEL = "qwen3-max";
private static final String DEEPSEEK_MODEL = "deepseek-v3.1";
@Value("${spring.ai.dashscope.url")
private String qwenUrl;
@Bean(name = "deepseek")
public ChatModel deepSeek() {
return DashScopeChatModel.builder()
.dashScopeApi(DashScopeApi.builder()
.apiKey(System.getenv("qwen-api-key"))
.build())
.defaultOptions(DashScopeChatOptions.builder()
.withModel(DEEPSEEK_MODEL)
.build())
.build();
}
@Bean(name = "qwen")
public ChatModel qwen() {
return DashScopeChatModel.builder()
.dashScopeApi(DashScopeApi.builder()
.apiKey(System.getenv("qwen-api-key"))
.build())
.defaultOptions(DashScopeChatOptions.builder().withModel(QWEN_MODEL).build())
.build();
}
@Bean(name = "deepseekChatClient")
public ChatClient deepSeekChatClient(@Qualifier("deepseek") ChatModel deepseekModel) {
return ChatClient.builder(deepseekModel)
.defaultOptions(ChatOptions.builder().model(DEEPSEEK_MODEL).build())
.build();
}
@Bean(name = "qwenChatClient")
public ChatClient qwenChatClient(@Qualifier("qwen") ChatModel qwenModel) {
return ChatClient.builder(qwenModel)
.defaultOptions(ChatOptions.builder().model(QWEN_MODEL).build())
.build();
}
}
业务实现 controller
kotlin
package com.miao.sse.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
@RestController
public class ChatClientController {
@Resource(name = "qwenChatClient")
private ChatClient qwenClient;
@Resource(name = "deepseekChatClient")
private ChatClient deepseekClient;
@GetMapping("/qwen/client")
public Flux<String> qwenChat(@RequestParam(name = "msg", defaultValue = "你是谁") String message) {
return qwenClient.prompt().user(message).stream().content();
}
@GetMapping("/deepseek/client")
public Flux<String> deepseekChat(@RequestParam(name = "msg", defaultValue = "你是谁") String message) {
return deepseekClient.prompt().user(message).stream().content();
}
}