工程对接大模型流式和非流式对话底层原理解析

文章目录

  • 前言
  • 一、非流式输出设计
  • 二、stream流式输出设计
  • 三、手撸一个流式输出项目
  • 总结


前言

之前对接过OpenAi大模型的官方API,可以看到它有一个Stream参数,设置成true的时候就是流式的对话输出,现象就是一段一段的往外崩。
官方手册的地址:https://platform.openai.com/docs/api-reference/chat
在这里插入图片描述
在这里插入图片描述
基本知识点是,在用户的提问以后,大模型底层的TransFromer架构能够根据自然语言理解逐词分析概率,继续预测下一部分的输出,这个我们理解为模型的推流过程。那么就会有两种方式进行输出:
(1)同步:等待这部分推流全部结束,通过HTTP响应一次性发送应答内容。
(2)异步:只要模型有输出,就针对推流的内容进行服务端的推送。
所以其实可以理解大模型本身就是异步推流的,区别在于是否等它全部生成完对话再推送。对于流式的服务端推送,整体上有两种实现方案:WebSocket和SSE
那么我们这个流式对话场景用的哪一种呢?
思考一下WebSocket和SSE的区别:
WebSocket全双工,适用于客户端和服务端双向交互,并且WebSocket是独立于HTTP协议之外的另一套协议,实现起来也相对复杂一些。SSE可以理解为单向的HTTP长连接,只需要前端或者浏览器发起一次HTTP get请求,后续服务端就可以向通道传输流式的数据了,SSE比较适合类似流式输出和股票信息实时推送这种场景。

顺便引入一下常见的几种实时通讯技术的对比
https://blog.csdn.net/xwh3165037789/article/details/128137023
在这里插入图片描述
另外其实官方说的比较直接了,设置之后如果数据推流的部分准备好了,就会通过SSE的方式进行服务端推送。
还有需要注意服务端对这个协议的实现要求,协议的描述参考下面地址
https://www.ruanyifeng.com/blog/2017/05/server-sent_events.html
https://www.ruanyifeng.com/blog/2017/05/websocket.html
在这里插入图片描述
通过PostMan请求返回如下,数据内容在Content里面,最后以DONE结尾。
在这里插入图片描述


一、非流式输出设计

stream参数为默认false,所以默认就是同步的。接入OpenAi的API以后,向对应地址发起HTTP请求,同步等待响应的结果就行了。所以本质上还是一次HTTP请求的过程。
但是一般为了进行后续的处理,比如对话做Summary、保存历史记录信息或者利用缓存的话,是可以把这次对话的内容入库的。

二、stream流式输出设计

理解一下整个流程设计:

假如做的是一个对话平台,项目的入口是一个Web页面,通过HTTP的POST请求发起对话,经过网关鉴权身份认证路由到接口,如果body携带的stream参数为true,进入streamChat的处理流程,走主服务转去请求OpenAi的对话接口地址,如果需要进行对话入库的话,这个时候我们的服务端作为大模型服务的客户端,Spring框架的WebFlux部分其实集成好了SseEmitter这个工具方便我们实现SSE功能,需要通过EventSource的factory建立sse连接,并且设置EventSourceListener监听器,重写它的一系列方法,包括onOpen、onEvent、onFailure、onClosed等。比如onEvent这个回调函数的作用就是当大模型输出事件触发的时候,将读取到的数据写入数据库,并且写入是可以通过请求内部的另外的写入HTTP的API触发的。在处理onClosed的时候需要考虑是否计算大模型的TokenSize占用作为附加信息入库和返回。

随后另外开启一个异步任务,线程池里面主要负责以下部分:
(1)心跳检测,SSE中断重连
(2)从数据库里面分页加载数据
(3)通过SSE通道推送数据给前端控制台

三、手撸一个流式输出项目

为了更好理解,我们可以手动实践,写一个这样的项目,做完了的话,估计大家也都能做GPT代理了,项目放在GitHub里面做个了记录。

后端(Spring Boot)
主应用代码

package com.example.ssedemo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication(scanBasePackages = {"com.example.*", "web"})
public class SsEdemoApplication {public static void main(String[] args) {SpringApplication.run(SsEdemoApplication.class, args);}}

Controller层代码

package web;// 导入相关依赖
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;@RestController
@RequestMapping("/api")
public class EventController {private final ExecutorService executor = Executors.newSingleThreadExecutor();private int i = 0;@GetMapping("/stream")public SseEmitter streamData() {SseEmitter sseEmitter = new SseEmitter();// 模拟大模型计算并分批次推送数据executor.execute(() -> {while (true) {try {// 这里是模拟计算过程,实际项目中可能是从数据库、文件或其他来源获取数据String dataChunk = "Data Chunk " + ++i;// 发送一个事件给前端sseEmitter.send(SseEmitter.event().id(Long.toString(i)) // 可选,用于标识事件ID.name("data") // 事件类型名.data(dataChunk, MediaType.TEXT_PLAIN));// 模拟延迟,比如每次间隔1秒Thread.sleep(1000);} catch (IOException | InterruptedException e) {// 关闭 emitter 并处理异常sseEmitter.completeWithError(e);}}// 计算结束或达到某个条件时关闭 emitter
//            sseEmitter.complete();});return sseEmitter;}
}

CROS的配置

package web;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/api/**").allowedOrigins("http://yourfrontenddomain.com") // 替换为您的前端域名.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS").allowedHeaders("*").allowCredentials(true).maxAge(3600);}
}

在使用SpringBoot3版本的时候可能会出现JDK版本报错,处理方式如下:
https://blog.csdn.net/giveupgivedown/article/details/134841844
https://blog.csdn.net/weixin_47889104/article/details/135289440
在这里插入图片描述
如果报错404了,记得添加包扫描路径,类似下面这种
@SpringBootApplication(scanBasePackages = {“com.example.demo”, “com.example.another.package”})
在这里插入图片描述
运行起来项目结构可能是下面这样
在这里插入图片描述
后端启动以后,直接浏览器访问80端口的API地址,
http://localhost:8080/api/stream
就能看到有流式的输出
在这里插入图片描述

其实不写下面的前端代码也行,利用SpringBoot内置的Tomcat直接查看浏览器页面。

前端(使用JavaScript,这里以原生Fetch API为例)

// 创建一个新的EventSource实例,连接到后端提供的SSE端点
var eventSource = new EventSource('http://localhost:8080/api/stream');// 处理接收到的事件
eventSource.addEventListener('data', function(event) {var dataChunk = event.data; // 接收的数据console.log('Received chunk:', dataChunk);// 在这里你可以更新UI,例如将数据添加到页面上document.getElementById('output').innerText += dataChunk + '\n';
});// 监听连接错误
eventSource.onerror = function(error) {console.error('Error occurred:', error);
};// 如果需要,在适当的时候可以关闭连接
// eventSource.close();

上述提供的JavaScript代码片段可以在浏览器环境下执行,它创建了一个与服务器建立连接的EventSource对象,用于接收来自服务器的Server-Sent Events(SSE)。只需要确保你在一个支持SSE的现代浏览器环境中,并且服务器端(这里是Spring Boot后端)已经正确设置了SSE服务接口。将这段JavaScript代码嵌入到HTML文档中,例如在 <\script> 标签内部,以便在浏览器加载页面时执行:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>SSE Streaming Demo</title><style>#output {height: 200px; /* 设置高度以限制输出区域 */overflow-y: scroll; /* 添加滚动条 */word-wrap: break-word; /* 自动换行 */border: 1px solid #ccc; /* 边框仅用于区分展示区域 */padding: 10px;}</style>
</head>
<body>
<div id="output"></div><script>// JavaScript 代码放在这里var eventSource = new EventSource('http://localhost:8080/api/stream');eventSource.addEventListener('message', function(event) { // 修改为 'message' 事件,SSE 的标准事件类型var dataChunk = event.data;var outputElement = document.getElementById('output');var newLineNode = document.createElement('p'); // 使用段落元素以保证格式清晰newLineNode.textContent = dataChunk;outputElement.appendChild(newLineNode);outputElement.scrollTop = outputElement.scrollHeight; // 滚动到底部,展示最新内容});eventSource.onerror = function(error) {console.error('Error occurred:', error);};
</script>
</body>
</html>

其实IDEA支持直接打开或者转到浏览器打开的
在这里插入图片描述
如果出现这个CROS报错,需要给服务端加跨域支持的配置
在这里插入图片描述

关于如何在浏览器执行参考下面
https://www.runoob.com/js/js-chrome.html
https://jingyan.baidu.com/article/e4d08ffdc25e584ed3f60d48.html
https://www.yzktw.com.cn/post/644689.html

先启动服务端的SpringBoot工程,如果跨域配置好了,然后运行前端JS代码
就可以看到服务端推送的流式输出了。这个项目其实可以做得更复杂一点,后续有机会我们继续往里加功能加技术点进去。

其他参考地址
https://blog.csdn.net/fyk844645164/article/details/126680347
https://blog.csdn.net/xwh3165037789/article/details/128137023
https://juejin.cn/post/7209226686373609533
https://blog.csdn.net/weixin_40951507/article/details/135354852
http://wed.xjx100.cn/news/236173.html?action=onClick
https://zhuanlan.zhihu.com/p/674994371
https://blog.csdn.net/qq_45399396/article/details/130972849
https://www.cnblogs.com/1996-Chinese-Chen/p/17913287.html
https://blog.csdn.net/fengtaokelly/article/details/130702235
https://blog.csdn.net/Larry_Lee88/article/details/130995475


总结

以上就是对大模型流式和非流式输出的解析,做完这个真有点想基于GPT代理搞点额外东西了,大模型厂家也挺多的,有人喜欢chatGPT,最近感觉通义千问也挺好,问了很多人是如何利用大模型的,一个技术TL说他经常用大模型来写测试用例,也有人用它帮忙理清思路查Bug或者写Demo或者命令等,未来还是有比较广阔的应用场景的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/653912.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

骑砍战团MOD开发(41)-LOD渲染技术

一.LOD技术 LOD技术&#xff0c;即Level Of Details&#xff0c;是一种在3D图形渲染中常用的技术&#xff0c;主要用于优化渲染性能。 通过在建模时添加LOD模型(低模模型,面数较少),游戏引擎通过计算模型的远近和光照等情况选择性加载原模型(高模)/LOD模型(低模),实现游戏…

html多个好看的背景动态效果(附源码)

文章目录 1.设计来源1.1 图片轮动背景1.2 星空流星背景1.3 动态美女背景1.4 动态屋雨背景1.5 动态街道背景1.6 动态夜幕背景 2.效果和源码2.1 动态效果2.2 透明度配置2.2 源代码 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/…

交叉编译opencv运行平台rk3588

opencv版本&#xff1a;4.8.0 opencv_contrib版本&#xff1a;4.8.0 在源码目录下建build目录&#xff0c;进入该目录配置编译选项生成makefile cmake 配置参数&#xff1a; cmake -DCMAKE_MAKE_PROGRAM:PATH/usr/bin/make -DCMAKE_INSTALL_PREFIX/home/rog/my_file/other_L…

面经基础版案例(路由,请求渲染,传参,组件缓存)

文章目录 1.案例效果分析2.配置一级路由&#xff08;首页&#xff0c;详情&#xff09;3.配置二级路由4.导航高亮效果5.首页的请求渲染6.传参&#xff08;查询参数 $ 动态路由&#xff09;7.详情页渲染8.组件缓存kepp-alive9.总结 1.案例效果分析 2.配置一级路由&#xff08;首…

2001-2019年全球500米分辨率植被聚集指数CAS-CI数据分享

各位同学们好&#xff0c;今天分享的是2001-2019年全球500米分辨率植被聚集指数CAS-CI数据。如果您需要下载或处理遥感数据等方面的帮助&#xff0c;您可以私信或评论。 一、数据简介 植被聚集指数&#xff08;clumping index, CI&#xff09;是一个重要的冠层结构参数&#…

SpringBoot整合Xxl-Job实现异步任务调度中心

目录 一、下载 1、源码 2、项目结构 3、模块说明 二、部署任务调度中心 1、创建数据库xxl-job 2、配置数据库 3、启动admin模块 4、打开任务调度中心 三、SpringBoot整合xxl-job 1、导入依赖 2、配置yml文件 3、配置类 4、启动项目 5、任务配置 6、测试 一、下…

UE5在VisualStudio升级后产生C++无法编译的问题

往期的虚幻引擎项目在VS更新后&#xff0c;编译时会报错&#xff0c;这一般出现在VS升级之后&#xff0c;UE对于VC的编译器定位没有更新导致&#xff1b; 有出现如下问题&#xff1a; 问题1&#xff1a; Running I:/EPCI/Epic Games/UE_5.3/Engine/Build/BatchFiles/Build.ba…

vue3+threejs+koa可视化项目——实现登录注册(第三步)

文章目录 ⭐前言&#x1f496;往期node系列文章&#x1f496;threejs系列相关文章&#x1f496;vue3threejs系列 ⭐koa后端登录注册逻辑&#xff08;jwt&#xff09;&#x1f496; koa登录注册 ⭐vue3前端登录注册权限控制&#x1f496; 登录页面&#x1f496; 注册页面 ⭐总结…

Promethues:普罗米修斯

promethues是一个开源的系统监控以及报警系统。整和zabbix的功能&#xff0c;系统&#xff0c;网络&#xff0c;设备promethues可以兼容网络&#xff0c;设备。容器监控。告警系统。因为他和k8s是一个项目基金开发的产品&#xff0c;天生匹配k8s的原生系统。对容器化和云原生服…

MySQL(下)

四、事务 一、概念 对数据库的一次执行中有多条sql语句执行。这多条sql在一次执行中&#xff0c;要么都成功执行&#xff0c;要么都不执行。保证了数据完整性。MySQL中只有innodb引擎支持事务。 二、特性 事务是必须满足 4 个条件&#xff08;ACID&#xff09;&#x…

江西公务员考试报名照如何上传成功

2024年江西省考报名公告已经发布了&#xff0c;想要参加江西省考报名的姐妹们&#xff0c;快来看看&#xff0c;提前了解报名流程&#xff0c;和报名照上传要求。 网上报名时间&#xff1a;1月28日9:00至2月2日17:00 网上缴费时间&#xff1a;1月28日9:00至2月3日17:00 打印准考…

备战蓝桥杯----数据结构及STL应用(基础2)

上次我们讲了vector的大致内容&#xff0c;接下来让我们讲一下栈&#xff0c;队列吧&#xff01; 什么是栈呢&#xff1f; 很简单&#xff0c;我们用的羽毛球桶就是&#xff0c;我们取的球&#xff0c;是最后放的&#xff0c;栈是一种先进后出的数据结构。 方法函数 s.push(…

SpringBoot深入解析:掌握自动装配机制及其定制化原理

推荐一款我一直在用的ChatGPT4.0国内站点&#xff0c;每日有免费使用额度&#xff0c;支持PC、APP、VScode插件同步使用 SpringBoot篇&#xff1a;SpringBoot的自动装配原理 SpringBoot是一个旨在简化Spring应用初始搭建以及开发过程的框架。它利用了Spring框架的依赖注入特性…

HDFS Federation前世今生

一 背景 熟悉大数据的人应该都知道&#xff0c;HDFS 是一个分布式文件系统&#xff0c;它是基于谷歌的GFS实现的开源系统&#xff0c;设计目的就是提供一个高度容错性和高吞吐量的海量数据存储解决方案。在经典的HDFS架构中有2个NameNode和多个DataNode&#xff0c;如下 从上面…

内网安全:RDP WinRS WinRM SPN Kerberos 横向移动

目录 WinRM协议 RDP协议 域横向移动&#xff1a;RDP协议 RDP协议利用 一. 探针服务 二. 获取NTML Hash 明文密码 三. 连接执行 域横向移动&#xff1a;WinRM WinRS WinRM协议、WinRS命令利用 一. cs 内置端口扫描5985 二. 连接执行 三. 上线CS 四. CS插件横向移动…

第五篇:express路由路径方式(字符串,字符串模式,和正则)

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 &#x1f4d8; 引言&#xff1a; &#x1f4…

(二十一)Flask之上下文管理第二篇(细细扣一遍源码)

每篇前言&#xff1a; &#x1f3c6;&#x1f3c6;作者介绍&#xff1a;【孤寒者】—CSDN全栈领域优质创作者、HDZ核心组成员、华为云享专家Python全栈领域博主、CSDN原力计划作者 &#x1f525;&#x1f525;本文已收录于Flask框架从入门到实战专栏&#xff1a;《Flask框架从入…

《幻兽帕鲁》1月29日游戏服务器推荐!腾讯云降低规格再次降价!

腾讯29日刷新规格&#xff0c;从14M降低到12M&#xff0c;硬盘和流量都有降低&#xff0c;但价格打下来了&#xff01;价格从66元/月降低到32元/月&#xff0c;277元/3个月降低到96元/3个月&#xff01; 三大厂商4核16G的云服务器价格对齐&#xff0c;不过具体参数略有不同 阿里…

C语言数据结构——链表

&#xff08;图像由AI生成&#xff09; 0.前言 在计算机科学中&#xff0c;数据结构是存储和组织数据的一种方式&#xff0c;它不仅影响数据的存储&#xff0c;也影响数据的检索和更新效率。C语言&#xff0c;作为一种经典的编程语言&#xff0c;提供了灵活的方式来处理数据…

GIS应用水平考试一级—2009 年度第二次

全国信息化工程师——GIS应用水平考试 2009 年度第二次全国统一考试一级 试卷说明: 1、本试卷共9页,6个大题,满分150 分,150 分钟完卷。 2、考试方式为闭卷考试。 3、将第一、二、三題的答案用铅笔涂写到(NCIE-GIS)答题卡上。 4、将第四、五、六题的答案填写到主观题答题卡上…