SpringBoot實現(xiàn)大模型流式Streaming響應(yīng)的示例代碼
一、為什么需要流式響應(yīng)
同樣的 HTTP 請求,為什么像 Deepseek這類模型的回答能像打字機一樣逐字輸出,而我們平時寫的接口卻要等全部處理完才返回?
問題的核心在于 響應(yīng)模式:
| 傳統(tǒng)模式 | 流式模式 |
|---|---|
| 服務(wù)器處理完成 → 一次性返回 | 生成一部分 → 立即推送 |
| 客戶端等待總時長 = 服務(wù)器處理時間 | 客戶端首字等待時間通常很短 |
| 適合快速查詢 | 適合耗時生成 |
對于大模型這種 生成式 AI,一個響應(yīng)可能需要幾秒甚至幾十秒。如果用傳統(tǒng)模式,用戶體驗就是:提問 → (10秒空白) → 答案全部出現(xiàn)
而流式響應(yīng)的體驗是:提問 → 0.1秒后 → "我" → "認(rèn)" → "為" → ... → 逐字呈現(xiàn)
實現(xiàn)這種效果有多種技術(shù)方案,本文將介紹基于 Spring Boot WebFlux + SSE 的實現(xiàn)方式。
二、核心技術(shù)選型
實現(xiàn)流式響應(yīng)主要有以下幾種方案:
| 方案 | 優(yōu)點 | 缺點 | 適用場景 |
|---|---|---|---|
| SSE | 單向推送、HTTP協(xié)議、實現(xiàn)簡單 | 不支持雙向通信 | 服務(wù)端主動推送 |
| WebSocket | 雙向通信、實時性強 | 實現(xiàn)復(fù)雜、需要額外協(xié)議 | 聊天、游戲 |
| 長輪詢 | 兼容性好 | 資源消耗大 | 低頻數(shù)據(jù)更新 |
本文選擇 SSE 方案,原因如下:
- Spring Boot 原生支持
ResponseEntity<Flux<String>> - 基于標(biāo)準(zhǔn) HTTP,無需額外協(xié)議協(xié)商
- 代碼簡潔,易于理解和維護
三、項目依賴配置
3.1 Maven 依賴
<?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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>springboot-chat-stream</artifactId>
<version>1.0.0</version>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- Spring Boot WebFlux:響應(yīng)式編程支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- Lombok:簡化代碼 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
3.2 關(guān)鍵依賴說明
spring-boot-starter-webflux:提供響應(yīng)式 Web 支持,核心是 Reactor 的 Flux 類型
Reactor:響應(yīng)式編程庫,Flux<T> 表示 0-N 個元素的異步序列
四、核心代碼實現(xiàn)
4.1 Controller 層:流式響應(yīng)入口
package com.example.chat.controller;
import com.example.chat.service.StreamChatService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
@RestController
@RequestMapping("/api/chat")
@RequiredArgsConstructor
@CrossOrigin(origins = "*") // 開發(fā)環(huán)境允許跨域
public class StreamChatController {
private final StreamChatService chatService;
/**
* 流式聊天接口
* @param prompt 用戶輸入的問題
* @return 流式響應(yīng),text/event-stream 格式
*/
@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public ResponseEntity<Flux<String>> streamChat(@RequestParam String prompt) {
return ResponseEntity.ok()
.header("Cache-Control", "no-cache")
.header("Connection", "keep-alive")
.body(chatService.streamResponse(prompt));
}
}
關(guān)鍵點解析:
produces = MediaType.TEXT_EVENT_STREAM_VALUE:聲明返回 SSE 格式Flux<String>:響應(yīng)式流,可以發(fā)送多個數(shù)據(jù)塊Cache-Control: no-cache:禁用緩存,確保實時推送
4.2 Service 層:模擬大模型流式生成
package com.example.chat.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import java.time.Duration;
@Slf4j
@Service
public class StreamChatService {
/**
* 模擬大模型流式生成響應(yīng)
* @param prompt 用戶問題
* @return 按字符/詞匯流式輸出的響應(yīng)
*/
public Flux<String> streamResponse(String prompt) {
log.info("收到用戶提問: {}", prompt);
// 模擬大模型生成的回復(fù)內(nèi)容
String response = mockLLMResponse(prompt);
// 將響應(yīng)拆分為字符流,每 50ms 發(fā)送一個字符
return Flux.fromArray(response.split(""))
.delayElements(Duration.ofMillis(50))
.doOnNext(chunk -> log.debug("發(fā)送數(shù)據(jù)塊: {}", chunk))
.doOnComplete(() -> log.info("流式響應(yīng)完成"))
.doOnError(e -> log.error("流式響應(yīng)異常", e));
}
/**
* 模擬大模型生成內(nèi)容(實際項目可接入 OpenAI/通義千問等)
*/
private String mockLLMResponse(String prompt) {
return """
【Spring Boot 流式響應(yīng)】
您的問題是:%s
這是一個模擬大模型流式輸出的示例。
在實際應(yīng)用中,你可以:
1. 接入 OpenAI API 使用 GPT-4
2. 接入阿里云通義千問 API
3. 接入本地部署的大模型
流式響應(yīng)的核心是:
- 使用 Spring WebFlux 的 Flux
- 返回 text/event-stream 格式
- 前端使用 EventSource 或 fetch 接收
這樣就能實現(xiàn)像 Deepseek 一樣的絲滑體驗!
""".formatted(prompt);
}
}
核心邏輯:
Flux.fromArray(response.split("")):將字符串拆分為字符數(shù)組轉(zhuǎn)為流.delayElements(Duration.ofMillis(50)):每個字符延遲 50ms 發(fā)送.doOnNext()/.doOnComplete()/.doOnError():生命周期鉤子,用于日志記錄
4.3 接入真實大模型 API(擴展)
// 接入 OpenAI Streaming API 的示例(偽代碼)
public Flux<String> streamOpenAI(String prompt) {
WebClient webClient = WebClient.builder()
.baseUrl("https://api.openai.com/v1")
.defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer YOUR_API_KEY")
.build();
return webClient.post()
.uri("/chat/completions")
.bodyValue(Map.of(
"model", "gpt-4",
"messages", List.of(Map.of("role", "user", "content", prompt)),
"stream", true
))
.retrieve()
.bodyToFlux(String.class)
.map(this::extractContentFromSSE); // 解析 SSE 格式提取 content
}
4.4 啟動類
package com.example.chat;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ChatStreamApplication {
public static void main(String[] args) {
SpringApplication.run(ChatStreamApplication.class, args);
}
}
4.5 配置文件
server:
port: 8080
spring:
application:
name: chat-stream-demo
# 日志配置
logging:
level:
com.example.chat: DEBUG
五、前端對接示例
5.1 使用 EventSource 接收流
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Spring Boot 流式響應(yīng)示例</title>
<style>
body { font-family: Arial; max-width: 800px; margin: 50px auto; padding: 20px; }
#output { border: 1px solid #ddd; padding: 20px; min-height: 100px; background: #f9f9f9; }
input { width: 70%; padding: 10px; }
button { padding: 10px 20px; cursor: pointer; }
</style>
</head>
<body>
<h1>Spring Boot 流式聊天</h1>
<input type="text" id="prompt" placeholder="輸入問題...">
<button onclick="sendQuestion()">發(fā)送</button>
<div id="output"></div>
<script>
function sendQuestion() {
const prompt = document.getElementById('prompt').value;
const output = document.getElementById('output');
output.innerHTML = '等待響應(yīng)...';
// 使用 EventSource 接收 SSE 流
const eventSource = new EventSource(
`/api/chat/stream?prompt=${encodeURIComponent(prompt)}`
);
eventSource.onmessage = (event) => {
output.innerHTML += event.data;
};
eventSource.onerror = () => {
eventSource.close();
output.innerHTML += '
[連接關(guān)閉]';
};
// 30秒后自動關(guān)閉(演示用)
setTimeout(() => eventSource.close(), 30000);
}
</script>
</body>
</html>
5.2 使用 Fetch API(推薦)
async function streamChat(prompt) {
const response = await fetch(`/api/chat/stream?prompt=${encodeURIComponent(prompt)}`);
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);
console.log('收到數(shù)據(jù):', chunk);
// 更新 UI
}
}
六、運行效果
啟動項目后,訪問 http://localhost:8080(需添加靜態(tài)頁面支持),輸入問題,你會看到:
【Spring Boot 流式響應(yīng)】
您的問題是:如何學(xué)習(xí) Spring Boot?
這是一個模擬大模型流式輸出的示例。
...
文字像打字機一樣逐字出現(xiàn),體驗絲滑!
七、總結(jié)
本文介紹了如何使用 Spring Boot WebFlux 實現(xiàn) SSE 流式響應(yīng)。核心是通過 Flux<String> + TEXT_EVENT_STREAM_VALUE 將數(shù)據(jù)分塊推送,配合前端 EventSource 實現(xiàn)逐字顯示效果。相比傳統(tǒng)一次性返回,流式響應(yīng)能顯著降低用戶等待感知,特別適合大模型對話等耗時生成場景。
以上就是SpringBoot實現(xiàn)大模型流式Streaming響應(yīng)的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot流式響應(yīng)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringCLoud搭建Zuul網(wǎng)關(guān)集群過程解析
這篇文章主要介紹了SpringCLoud搭建Zuul網(wǎng)關(guān)集群過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03
spring-boot-maven-plugin?配置有啥用
這篇文章主要介紹了spring-boot-maven-plugin?配置是干啥的,這個是SpringBoot的Maven插件,主要用來打包的,通常打包成jar或者war文件,本文通過示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08
詳解 Hive UDF 開發(fā)之Java 實現(xiàn)步驟與代碼調(diào)試技巧
這篇文章主要介紹了詳解 Hive UDF 開發(fā)之Java實現(xiàn)步驟與代碼調(diào)試技巧,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-12-12
java創(chuàng)建txt文件并寫入內(nèi)容的方法代碼示例
這篇文章主要介紹了java創(chuàng)建txt文件并寫入內(nèi)容的兩種方法,分別是使用java.io.FileWriter和BufferedWriter,以及使用Java7的java.nio.file包中的Files和Path類,需要的朋友可以參考下2025-01-01
利用Springboot+Caffeine實現(xiàn)本地緩存實例代碼
Caffeine是一個基于Java8開發(fā)的提供了近乎最佳命中率的高性能的緩存庫,下面這篇文章主要給大家介紹了關(guān)于利用Springboot+Caffeine實現(xiàn)本地緩存的相關(guān)資料,需要的朋友可以參考下2023-01-01
java:程序包org.bouncycastle.jce.provider不存在問題及解決
這篇文章主要介紹了java:程序包org.bouncycastle.jce.provider不存在問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-05-05
Spring?BeanFactory容器的構(gòu)建和使用示例詳解
BeanFactory是Spring框架中的一部分,它提供了IoC(控制反轉(zhuǎn))的實現(xiàn)機制,下面小編就來和大家簡單聊聊BeanFactory容器的構(gòu)建和使用示例吧2023-07-07
Spring中的之啟動過程obtainFreshBeanFactory詳解
這篇文章主要介紹了Spring中的之啟動過程obtainFreshBeanFactory詳解,在refresh時,prepareRefresh后,馬上就調(diào)用了obtainFreshBeanFactory創(chuàng)建beanFactory以及掃描bean信息(beanDefinition),并通過BeanDefinitionRegistry注冊到容器中,需要的朋友可以參考下2024-02-02

