实时响应的秘密:用Spring Boot轻松实现流式AI输出

article/2025/8/5 15:38:28

1、背景

随着AI的快速发展,越来越多的AI应用诞生了,但是AI也有响应慢的问题,一般不能够即时响应,为了优化用户体验,现在大部分AI应用都是实现了打字机的效果,那么这种效果是如何实现的呢?今天我们先看一下后端的实现逻辑。

代码流程是后端发出请求,请求智能体或AI模型暴露的流式接口,然后返回一个流式接口。

为什么不直接前端请求AI接口,因为有的AI接口在前端直接请求,可能会出现跨域问题。因为AI接口返回的响应中没有包含跨域的Access-Control-Allow-Origin。

2、实现步骤

1、引入依赖

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

2、使用webClient发起对AI接口请求

代码中的URL,请求头、请求体或者请求方法都可以按照对应的AI接口文档进行替换。

WebClient webClient = WebClient.create();Flux<String> resultFlux = webClient.post().uri(URL)  //请求url.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).header(HttpHeaders.AUTHORIZATION, "Bearer "+ API_KEY) // 添加认证头部.bodyValue(requestBody)//请求体.retrieve().bodyToFlux(String.class);  //返回流式结果

3、启动类需要添加@EnableAsync注解

4、如果工程中有过滤器,需要进行配置

我的工程启动后报错

Async support must be enabled on a servlet and for all filters involved in async request processing. This is done in Java code using the Servlet API or by adding "<async-supported>true</async-supported>" to servlet and filter declarations in web.xml.

大概意思是异步支持必须在servlet和所有的过滤器中被标注成是enabled

Servlet和Filter声明:如果您使用的是基于XML的配置,可以在web.xml文件中的servlet和filter声明中添加<async-supported>true</async-supported>元素来启用异步支持

<servlet><servlet-name>myServlet</servlet-name><servlet-class>com.example.MyAsyncServlet</servlet-class><async-supported>true</async-supported>
</servlet><filter><filter-name>myFilter</filter-name><filter-class>com.example.MyAsyncFilter</filter-class><async-supported>true</async-supported>
</filter>

如果您使用的是基于注解的配置或Java配置类,可以通过实现javax.servlet.Servlet接口并覆盖isAsyncSupported()方法返回true,或者通过@WebServlet和@WebFilter注解的asyncSupported属性来设置。我使用的是这种方式

@WebServlet(urlPatterns = "/async", asyncSupported = true)
public class MyAsyncServlet extends HttpServlet {// ...
}@WebFilter(urlPatterns = "/*", asyncSupported = true)
public class MyAsyncFilter implements Filter {// ...
}

5、postman发送请求后结果

controller类接口

 @RequestMapping(method = RequestMethod.POST, value = "/getAIResult",produces = MediaType.TEXT_EVENT_STREAM_VALUE)Flux<String> getAIResult(@RequestBody String content){// 构建请求体HashMap<String, Object> requestBody = new HashMap<>();requestBody.put("model", "6bbdf08d55244bd9be24052ded2a58ef");requestBody.put("context",0);requestBody.put("stream", true);List<HashMap<String, String>> messages = new ArrayList<>();HashMap<String, String> message = new HashMap<>();message.put("role", "user");message.put("content", content);messages.add(message);requestBody.put("messages", messages);WebClient webClient = WebClient.create();Flux<String> resultFlux = webClient.post().uri(URL).header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).header(HttpHeaders.AUTHORIZATION, "Bearer "+ API_KEY) // 添加认证头部.bodyValue(requestBody).retrieve().bodyToFlux(String.class);// 输出响应结果// // 订阅响应以触发实际的 HTTP 请求// resultFlux.subscribe(//         response -> System.out.println("Response received: " + response),//         error -> System.err.println("Error occurred: " + error.getMessage())// );return resultFlux;}

3、使用技术介绍

WebFlux

WebFlux模块是Spring 5引入的一部分,旨在提供一种新的方式来构建响应式的Web应用程序。它允许你以异步和非阻塞的方式处理HTTP请求,这在处理高并发场景时可以显著提高性能。

WebFlux的特点

  • 非阻塞I/O:与传统的Servlet API不同,WebFlux使用的是非阻塞I/O模型,这意味着它可以更有效地利用线程资源。
  • 反应式编程:WebFlux内置了对反应式编程的支持,主要通过Reactor库实现,使得编写和处理异步代码更加容易。
  • 函数式路由:除了注解驱动的控制器,WebFlux还提供了函数式路由API,让你能够以声明性的方式定义路由规则。

以上来自AI内容生成,看完一头雾水,下方给出介绍

非阻塞I/O

含义:非阻塞I/O(Non-blocking I/O)是一种编程模型,它允许应用程序在等待某些操作完成时不会被阻塞。与传统的Servlet API(如Spring MVC)相比,WebFlux采用了基于事件和回调的非阻塞I/O模型。

  • 传统Servlet API (阻塞I/O):在传统的Servlet环境中,每个HTTP请求都会分配一个线程来处理。如果这个处理过程包含了一个长时间运行的操作(例如数据库查询或网络调用),那么该线程会被阻塞直到操作完成。这意味着线程不能用来处理其他请求,从而降低了服务器的效率。

  • WebFlux (非阻塞I/O):WebFlux使用了Netty这样的异步网络框架,它们可以在不阻塞线程的情况下执行I/O操作。当一个请求涉及到耗时的任务时,它不会阻塞当前的线程;相反,任务完成后会触发相应的回调函数继续处理。这种方式使得单个线程可以处理多个并发请求,极大地提高了资源利用率和服务的吞吐量。

反应式编程

含义:反应式编程(Reactive Programming)是一种面向数据流和变化传播的编程范式。它强调的是通过声明式的代码来描述数据流的变化,并能够对这些变化做出响应。WebFlux内置了对反应式编程的支持,主要通过Project Reactor库实现,这是Spring 5引入的一个核心特性。

  • Reactor库:Reactor提供了两个核心类型——MonoFlux,分别表示0到1个元素的异步序列和0到N个元素的异步序列。开发者可以使用这些类型来构建复杂的异步逻辑,而不需要显式地管理线程或同步问题。

  • 好处

    • 简化异步编程:通过组合操作符(如map, flatMap, filter等),你可以轻松地创建复杂的异步工作流,同时保持代码的简洁性和可读性。
    • 错误处理:Reactor还提供了一套强大的错误处理机制,比如onErrorResumeretry等,使得处理异常情况更加直观。
    • 背压支持:对于生产者-消费者模式中的流量控制,Reactor实现了背压(Backpressure),确保系统不会因为过载而崩溃。

函数式路由

含义:函数式路由是WebFlux提供的另一种定义HTTP端点的方式,除了传统的注解驱动控制器之外。它允许你以一种声明性的、函数式的方式来配置路由规则,这在某些情况下可能比注解更灵活、更具表达力。

  • RouterFunction和HandlerFunction:在函数式路由中,RouterFunction用于定义路由匹配逻辑,而HandlerFunction则负责处理实际的请求。两者结合在一起,可以非常清晰地表达出“如果路径匹配,则执行某个处理器”的意图。


http://www.hkcw.cn/article/eedRgqyuwH.shtml

相关文章

Spring Boot 中 RabbitMQ 的使用

目录 引入依赖 添加配置 Simple&#xff08;简单模式&#xff09; 生产者代码 消费者代码 ​编辑 Work Queue&#xff08;工作队列&#xff09; 生产者代码 消费者代码 Publish/Subscribe&#xff08;发布/订阅&#xff09; 生产者代码 消费者代码 Routing&#x…

如何下载MySQL和如何下载MySQL的JDBC驱动包

1.打开MySql 官网 https://www.mysql.com/ 2.点击 DOWNLOADS 和 MySQL Community (GPL) Downloads&#xff08;MySQL Community (GPL) Downloads需要滚到最下面&#xff09; 截屏2022-12-12 14.23.18.png 下载MySQL和下载MySQL的JDBC驱动包前两步是一样的 下载MySQL 3.点击 MyS…

【复杂网络演化博弈_01】理论部分+代码应用

复杂网络演化博弈 一、理论部分&#xff08;1&#xff09;研究背景&#xff08;2&#xff09;群体合作困境&#xff08;3&#xff09;核心要素&#xff08;4&#xff09;网络模型1、规则网络2、随机网络3、小世界网络4、无标度网络 二、网络博弈的进展&#xff08;1&#xff09…

MySQL的备份及还原

备份类型 热备份、温备份、冷备份 &#xff08;根据服务器状态&#xff09; 热备份&#xff1a;读、写不受影响&#xff1b; 温备份&#xff1a;仅可以执行读操作&#xff1b; 冷备份&#xff1a;离线备份&#xff1b;读、写操作均中止&#xff1b; 物理备份与逻辑…

【爬虫学习】动态网页数据抓取实战:Ajax逆向与浏览器自动化

【爬虫学习】动态网页数据抓取实战&#xff1a;Ajax逆向与浏览器自动化 摘要 针对现代网站的动态化趋势&#xff0c;本文深入解析Ajax接口逆向与浏览器自动化技术。通过微博热搜实时数据抓取、知乎无限滚动内容采集等实战案例&#xff0c;演示如何突破动态渲染壁垒&#xff0c…

【Spring Cloud Alibaba】:Nacos 使用全详解

目录 一、服务注册发现1、nacos-provider服务提供者创建2、nacos-consumer服务消费者创建 二、配置管理1、添加配置文件2、拉取配置3、读取配置4、配置热更新方式一&#xff1a;添加 RefreshScope 注解方式二&#xff1a;使用ConfigurationProperties注解代替Value注解。 5、多…

【金仓数据库征文】学校AI数字人:从Sql Server到KingbaseES的数据库转型之路

摘要&#xff1a;本文围绕学校 AI 数字人项目从 Sql Server 数据库替换至 KingbaseES 数据库的实践展开&#xff0c;涵盖迁移背景、两种数据库对比、替换实施步骤、应用效果展示、问题与解决措施等多方面内容&#xff0c;为教育领域类似项目提供了详实参考。 目录 1.背景与需求…

前端框架大对决:uni-app、taro、flutter、RN 哪家强?

文章目录 一、引言二、框架初印象三、开发语言与环境搭建3.1 开发语言特色3.2 环境搭建流程四、跨平台能力4.1 适配平台情况4.2 平台专有功能调用与界面适配特点五、性能表现5.1 渲染机制剖析5.2 性能测试数据六、组件与插件生态6.1 内置组件丰富度6.2 插件市场活跃度七、开发体…

rpcsx-ui-android:打造 RPCSX 模拟器原生态 Android UI

rpcsx-ui-android&#xff1a;打造 RPCSX 模拟器原生态 Android UI rpcsx-ui-android 项目地址: https://gitcode.com/gh_mirrors/rp/rpcsx-ui-android 项目介绍 rpcsx-ui-android 是一款为 RPCSX 模拟器量身定制的原生 Android 用户界面。该项目的目标是为用户提供流…

Android 15强制edge-to-edge全面屏体验

一、背景 Edge-to-edge 全面屏体验并非 Android 15 才有的新功能&#xff0c;早在 Android 15 之前系统就已支持。然而&#xff0c;该功能推出多年来&#xff0c;众多应用程序依旧未针对全面屏体验进行适配。因此&#xff0c;在 Android 15 的更新中&#xff0c;Google 终于决…

MacOS上如何运行内网穿透详细教程

本文以市面常见、好用的内网穿透为例&#xff0c;一款为开源内网穿透工具Frp;另一款为国产新锐软件ZeroNews。 一、Frp&#xff08;开源工作、使用自由&#xff09; 1. 下载 FRP 访问 FRP 的 GitHub 发布页&#xff1a; https://github.com/fatedier/frp/releases 选择适合 …

250207-MacOS修改Ollama模型下载及运行的路径

在 macOS 上&#xff0c;Ollama 默认将模型存储在 ~/.ollama/models 目录。如果您希望更改模型的存储路径&#xff0c;可以通过设置环境变量 OLLAMA_MODELS 来实现。具体步骤如下&#xff1a; 选择新的模型存储目录&#xff1a;首先&#xff0c;确定您希望存储模型的目标目录路…

iOS uni-app 原生插件开发

下面以创建一个物体检测插件为例。 开发环境&#xff1a; XCode 16.3 SDK包 &#xff0c;4.45 HBuilderX 4.45 1. 解压 SDK 2. 创建一个插件&#xff0c;放到 HBuilder-uniPluginDemo 目录下 3. 配置依赖 打开 HBuilder-uniPlugin.xcodeproj 将 ObjectDetector.xcodeproj 拖…

生产力工具|vscode for mac的安装python库和使用虚拟环境(一)

一、在vscode中运行python代码&#xff08;mac或windows&#xff09; &#xff08;一&#xff09;在vscode中安装Python插件 若想在vscode中高效率的编辑Python代码&#xff0c;需要安装Python插件&#xff0c;点击下图中红框内的按钮&#xff1a; 然后在左上角的搜索框中输入…

【超适合小白】苹果电脑MAC——抓包工具-Charles使用超详细教程!!!适合小白!!!

一、Charles是什么&#xff1f; Charles是一个HTTP代理服务器&#xff0c;是类似于一个监视器&#xff0c;简单来说可以直接抓取手机或者浏览器中的接口&#xff0c;当手机/浏览器连接Charles的代理访问互联网时&#xff0c;Charles可以监控浏览器发送和接收的所有数据。它允许…

在macOS上安装MySQL

macOS的MySQL有多种不同的形式&#xff1a; 1、本机包安装程序&#xff0c;它使用本机macOS安装程序&#xff08;DMG&#xff09;引导您完成MySQL的安装。有关详细信息&#xff0c;请参阅第2.4.2节&#xff0c;“使用本机包在macOS上安装MySQL”。您可以将包安装程序与macOS一…

2024年博客之星主题创作|Android 开发:前沿技术、跨领域融合与就业技能展望

目录 引言 一、推动 Android 应用创新的核心力量 1.1 人工智能与机器学习的崛起 1.2 增强现实&#xff08;AR&#xff09;与虚拟现实&#xff08;VR&#xff09;的应用扩展 1.3 5G技术的推动 1.4 跨平台开发技术的成熟 1.4.1 React Native 1.4.2 Flutter 1.4.3 Taro …

中兴B862AV3.2M刷机包晨星MSO9385_2+8_安卓9_免拆机免打开ADB固件包

在开始刷机之前&#xff0c;请务必确认你的设备型号为中兴 B862AV3.2M 且搭载晨星处理器&#xff0c;同时备份好设备中的重要数据&#xff0c;刷机有风险&#xff0c;操作需谨慎&#xff01;以下是详细的刷机步骤&#xff1a; 一、准备工作 下载刷机固件&#xff1a;从可靠的来…

计算机网络:TCP/IP协议(从 MAC 地址到 VLAN 标签:数据链路层如何重构网络拓扑逻辑)

目录 前言数据链路层MAC地址共享介质型网络争用方式令牌传递方式 非共享介质网络根据MAC地址进行转发环路检测技术生成树源路由法 VLAN以太网帧格式 总结写在文末 前言 本期开始将分层进行讲解OSI参考模型或者TCP/IP参考模型&#xff0c;从数据链路到应用层&#xff0c;本期先…

基于 LLM 的商城智能客服助理开发实战

参考LLM开源文档 Datawhale LLM教程&#x1f310;&#x1f4da; 文章目录 &#x1f4a1;实现思路&#x1f680;实现步骤&#x1f4ca; 数据集介绍⚙️ 数据处理&#x1f4dd; 评估输入&#x1f50d; 提取商品关键词&#x1f50d; 检索商品信息&#x1f4dd; 生成并评估回答✨ …