当前位置: 首页 > ai >正文

SpringBoot中使用Flux实现流式返回的技术总结

背景

近期在使用deepseek/openai等网页和APP时,发现大模型在思考和回复时,内容是一点点的显示出来的,于是好奇他们的实现方式。经调研和使用开发者工具抓取请求,每次聊天会向后台发送一个http请求,而这个接口跟普通接口一次性返回不一样,而是以流式的返回。

流式返回的核心概念与优势

在传统的 Web 开发中,接口通常以「一次性返回完整响应体」的形式工作。而 ** 流式返回(Streaming Response)** 指的是服务器在处理请求时,将响应结果分段逐步返回给客户端,而非等待所有数据生成完成后再一次性返回。这种模式具有以下核心优势:

1. 提升用户体验

  • 对于大数据量响应(如文件下载、长文本流)或实时交互场景(如聊天机器人对话),客户端可边接收数据边处理,减少「空白等待时间」,提升实时性感知。

2. 降低内存消耗

  • 服务器无需在内存中缓存完整响应数据,尤其适合处理高并发、大流量场景,降低 OOM(内存溢出)风险。

3. 支持长连接与实时通信

  • 天然适配实时数据推送场景(如日志监控、股票行情更新),可与 SSE(Server-Sent Events)、WebSocket 等技术结合使用。

大模型的接口,尤其是那些带推理的模型接口返回,数据就是一点点的返回的,因此如果要提升用户体验,最好的方式就是采用流式接口返回。

在SpringBoot中基于Flux的流式接口实现

1. 依赖配置

在 pom.xml 中引入 WebFlux 依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

2. 流式接口实现(以模拟大模型对话为例)

import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;@RestController
@RequestMapping("/api/chat")
public class ChatController {@PostMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<String> streamChat(@RequestBody ChatRequest request) {// 调用大模型 API 并返回 Flux 流return callLargeModelApi(request.message()).doOnNext(chunk -> log.info("发送响应片段: {}", chunk)).doOnError(error -> log.error("流式处理出错", error));}// 模拟调用大模型 API,返回 Flux 流private Flux<String> callLargeModelApi(String prompt) {// 实际项目中需替换为真实的大模型调用逻辑return Flux.just("您好!", "我是您的AI助手。", "您的问题是:" + prompt, "我将为您提供详细解答...").delayElements(Duration.ofMillis(300)); // 模拟实时响应延迟}
}

3. 关键配置说明

  • 响应格式:设置 produces = MediaType.TEXT_EVENT_STREAM_VALUE,符合 SSE 协议。
  • 异步处理:Flux 流中的元素会被自动转换为 SSE 格式(data: <内容>\n\n)并推送至客户端。
  • 背压控制:通过 onBackpressureBuffer() 或 onBackpressureDrop() 处理客户端消费速率问题。

浏览器端 JS 调用方案

1. 使用 EventSource(简化版)

function connectWithEventSource() {const source = new EventSource("/api/chat");const chatWindow = document.getElementById("chat-window");source.onmessage = (event) => {chatWindow.innerHTML += `<div>${event.data}</div>`;chatWindow.scrollTop = chatWindow.scrollHeight;};source.onerror = (error) => {console.error("EventSource failed:", error);source.close();};
}

2. 使用 Fetch API(支持 POST 请求)

async function connectWithFetch() {const response = await fetch("/api/chat", {method: "POST",headers: { "Content-Type": "application/json" },body: JSON.stringify({ message: "你好" })});const reader = response.body.getReader();const decoder = new TextDecoder();const chatWindow = document.getElementById("chat-window");while (true) {const { done, value } = await reader.read();if (done) break;// 解码并处理数据块const chunk = decoder.decode(value, { stream: true });const messages = chunk.split('\n\n').filter(line => line.trim().startsWith('data:')).map(line => line.replace('data:', '').trim());messages.forEach(msg => {chatWindow.innerHTML += `<div>${msg}</div>`;chatWindow.scrollTop = chatWindow.scrollHeight;});}
}

//TODO

尝试写一个网页,调用流失接口,实现与大模型的交流。

http://www.xdnf.cn/news/6708.html

相关文章:

  • Java8到24新特性整理
  • 芯片生态链深度解析(一):基础材料篇——从砂砾到硅基王国的核心技术突围
  • AI人工智能在教育领域的应用
  • 水库雨水情测报与安全监测系统解决方案
  • 科达嘉数字功放电感应用于英飞凌参考设计REF_MA5302BTLSPS_400W
  • opencv入门指南
  • STM32外设AD-DMA+定时读取模板
  • 如何离线环境下安装Dify插件
  • SettingsIntelligence
  • 梦熊解析:202505基础算法
  • debugfs:Linux 内核调试的利器
  • 如何有效的开展接口自动化测试?
  • 今日行情明日机会——20250516
  • PMP-第十二章 项目采购管理
  • windows平台监控目录、子目录下的文件变化
  • 革新直流计量!安科瑞DJSF1352-D电表:360A免分流直连,精度与空间双突破
  • Linux远程连接服务
  • 1基·2台·3空间·6主体——蓝象智联解码可信数据空间的“数智密码”
  • 5 Celery多节点部署
  • c++,linux,多线程编程详细介绍
  • FC7300 ADC采样理论介绍
  • 宽河道流量监测——阵列雷达波测流系统如何监测河道流量
  • GTS-400 系列运动控制器板卡介绍(三十六)--- 电机到位检测功能
  • Ubuntu 22.04 上安装 Drupal 10并配置 Nginx, mysql 和 php
  • Java 多线程基础:Thread 类核心用法详解
  • E-R图合并时的三种冲突
  • SDT-5土体动力特性测试系统
  • 工具生态构建对比分析
  • 进阶-数据结构部分:1、数据结构入门
  • ASP.NET/IIS New StreamContent(context.Request.InputStream) 不会立即复制整个请求流的内容到内存