SpringBoot实现大模型流式Streaming响应的示例代码

 更新时间:2026年01月19日 08:30:04   作者:风象南  
这篇文章主要为大家详细介绍了SpringBoot实现大模型流式Streaming响应的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

一、为什么需要流式响应

同样的 HTTP 请求,为什么像 Deepseek这类模型的回答能像打字机一样逐字输出,而我们平时写的接口却要等全部处理完才返回?

问题的核心在于 响应模式

传统模式流式模式
服务器处理完成 → 一次性返回生成一部分 → 立即推送
客户端等待总时长 = 服务器处理时间客户端首字等待时间通常很短
适合快速查询适合耗时生成

对于大模型这种 生成式 AI,一个响应可能需要几秒甚至几十秒。如果用传统模式,用户体验就是:提问 → (10秒空白) → 答案全部出现

而流式响应的体验是:提问 → 0.1秒后 → "我" → "认" → "为" → ... → 逐字呈现

实现这种效果有多种技术方案,本文将介绍基于 Spring Boot WebFlux + SSE 的实现方式。

二、核心技术选型

实现流式响应主要有以下几种方案:

方案优点缺点适用场景
SSE单向推送、HTTP协议、实现简单不支持双向通信服务端主动推送
WebSocket双向通信、实时性强实现复杂、需要额外协议聊天、游戏
长轮询兼容性好资源消耗大低频数据更新

本文选择 SSE 方案,原因如下:

  • Spring Boot 原生支持 ResponseEntity<Flux<String>>
  • 基于标准 HTTP,无需额外协议协商
  • 代码简洁,易于理解和维护

三、项目依赖配置

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:响应式编程支持 -->
        <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 关键依赖说明

spring-boot-starter-webflux:提供响应式 Web 支持,核心是 Reactor 的 Flux 类型

Reactor:响应式编程库,Flux<T> 表示 0-N 个元素的异步序列

四、核心代码实现

4.1 Controller 层:流式响应入口

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 = "*") // 开发环境允许跨域
public class StreamChatController {

    private final StreamChatService chatService;

    /**
     * 流式聊天接口
     * @param prompt 用户输入的问题
     * @return 流式响应,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));
    }
}

关键点解析:

  • produces = MediaType.TEXT_EVENT_STREAM_VALUE:声明返回 SSE 格式
  • Flux<String>:响应式流,可以发送多个数据块
  • 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 {

    /**
     * 模拟大模型流式生成响应
     * @param prompt 用户问题
     * @return 按字符/词汇流式输出的响应
     */
    public Flux<String> streamResponse(String prompt) {
        log.info("收到用户提问: {}", prompt);

        // 模拟大模型生成的回复内容
        String response = mockLLMResponse(prompt);

        // 将响应拆分为字符流,每 50ms 发送一个字符
        return Flux.fromArray(response.split(""))
                .delayElements(Duration.ofMillis(50))
                .doOnNext(chunk -> log.debug("发送数据块: {}", chunk))
                .doOnComplete(() -> log.info("流式响应完成"))
                .doOnError(e -> log.error("流式响应异常", e));
    }

    /**
     * 模拟大模型生成内容(实际项目可接入 OpenAI/通义千问等)
     */
    private String mockLLMResponse(String prompt) {
        return """
                【Spring Boot 流式响应】
                您的问题是:%s

                这是一个模拟大模型流式输出的示例。
                在实际应用中,你可以:
                1. 接入 OpenAI API 使用 GPT-4
                2. 接入阿里云通义千问 API
                3. 接入本地部署的大模型

                流式响应的核心是:
                - 使用 Spring WebFlux 的 Flux
                - 返回 text/event-stream 格式
                - 前端使用 EventSource 或 fetch 接收

                这样就能实现像 Deepseek 一样的丝滑体验!
                """.formatted(prompt);
    }
}

核心逻辑:

  • Flux.fromArray(response.split("")):将字符串拆分为字符数组转为流
  • .delayElements(Duration.ofMillis(50)):每个字符延迟 50ms 发送
  • .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 流式响应示例</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()">发送</button>
    <div id="output"></div>

    <script>
        function sendQuestion() {
            const prompt = document.getElementById('prompt').value;
            const output = document.getElementById('output');
            output.innerHTML = '等待响应...';

            // 使用 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 += '

[连接关闭]';
            };

            // 30秒后自动关闭(演示用)
            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('收到数据:', chunk);
        // 更新 UI
    }
}

六、运行效果

启动项目后,访问 http://localhost:8080(需添加静态页面支持),输入问题,你会看到:

【Spring Boot 流式响应】
您的问题是:如何学习 Spring Boot?

这是一个模拟大模型流式输出的示例。
...

文字像打字机一样逐字出现,体验丝滑!

七、总结

本文介绍了如何使用 Spring Boot WebFlux 实现 SSE 流式响应。核心是通过 Flux<String> + TEXT_EVENT_STREAM_VALUE 将数据分块推送,配合前端 EventSource 实现逐字显示效果。相比传统一次性返回,流式响应能显著降低用户等待感知,特别适合大模型对话等耗时生成场景。

以上就是SpringBoot实现大模型流式Streaming响应的示例代码的详细内容,更多关于SpringBoot流式响应的资料请关注脚本之家其它相关文章!

相关文章

  • Java 实战项目锤炼之网上图书馆管理系统的实现流程

    Java 实战项目锤炼之网上图书馆管理系统的实现流程

    读万卷书不如行万里路,只学书上的理论是远远不够的,只有在实战中才能获得能力的提升,本篇文章手把手带你用Java+jsp+servlet+mysql+ajax实现一个网上图书馆管理系统,大家可以在过程中查缺补漏,提升水平
    2021-11-11
  • Java操作Mysql的方法

    Java操作Mysql的方法

    这篇文章主要介绍了Java操作Mysql的方法,实例分析了Java针对有返回结果和没有返回结果的sql操作的相关技巧,需要的朋友可以参考下
    2015-02-02
  • 详解如何获取PreparedStatement参数示例详解

    详解如何获取PreparedStatement参数示例详解

    这篇文章主要为大家介绍了详解如何获取PreparedStatement参数示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • 详解eclipse项目中.classpath文件的使用

    详解eclipse项目中.classpath文件的使用

    这篇文章主要介绍了详解eclipse项目中.classpath文件的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • Java查看和修改线程优先级操作详解

    Java查看和修改线程优先级操作详解

    JAVA中每个线程都有优化级属性,默认情况下,新建的线程和创建该线程的线程优先级是一样的。本文将为大家详解Java查看和修改线程优先级操作的方法,需要的可以参考一下
    2022-08-08
  • Java面试题篇之Sleep()方法与Wait()方法的区别详解

    Java面试题篇之Sleep()方法与Wait()方法的区别详解

    这篇文章主要给大家介绍了关于Java面试题篇之Sleep()方法与Wait()方法区别的相关资料,wait()是Object类中的方法,而sleep()是Thread类中的静态方法,wait()方法用于多个线程之间的协作和通信,而sleep()方法用于线程的休眠,需要的朋友可以参考下
    2024-07-07
  • Java的设计模式之代理模式使用详解

    Java的设计模式之代理模式使用详解

    这篇文章主要介绍了Java的设计模式之代理模式使用详解,代理模式是23种设计模式之一,它关心的主要是过程,而不是结果,代理模式主要提供了对目标对象的间接访问方式,即通过代理对象来访问目标对象,需要的朋友可以参考下
    2024-01-01
  • 超详细讲解SpringCloud Commons公共抽象的用法

    超详细讲解SpringCloud Commons公共抽象的用法

    这篇文章主要介绍了超详细讲解SpringCloud Commons公共抽象的用法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • Java中list.foreach()和list.stream().foreach()用法详解

    Java中list.foreach()和list.stream().foreach()用法详解

    在Java中List是一种常用的集合类,用于存储一组元素,List提供了多种遍历元素的方式,包括使用forEach()方法和使用Stream流的forEach()方法,这篇文章主要给大家介绍了关于Java中list.foreach()和list.stream().foreach()用法的相关资料,需要的朋友可以参考下
    2024-07-07
  • springboot项目配置多个kafka的示例代码

    springboot项目配置多个kafka的示例代码

    这篇文章主要介绍了springboot项目配置多个kafka,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04

最新评论