逐句回答,流式返回,ChatGPT采用的Server-sent events后端实时推送协议Python3.10实现,基于Tornado6.1

逐句,回答,流式,返回,chatgpt,采用,server,sent,events,后端,实时,推送,协议,python3,实现,基于,tornado6 · 浏览次数 : 1719

小编点评

**ChatGPT 使用 Server-sent events 来实现流式返回的原因:** * **服务器向客户端推送数据:** Server-sent events 允许服务器在客户端请求结束后立即推送数据,而无需客户端一直向服务器发送请求。 * **缓解连接超时问题:** Server-sent events 可以确保新的聊天消息可以直接推送到前端,而无需等待客户端连接关闭。 * **提高性能:** 通过仅推送当有新消息时的数据,Server-sent events 可以提高应用程序的性能。 * **减少网络流量:** Server-sent events 可以仅推送必要的数据,从而减少网络流量。 **其他优势:** * **易于实现:** Server-sent events 是易于实现的协议,即使是基于 Python 的框架也能轻松实现。 * **广泛浏览器兼容性:** Server-sent events 协议支持广泛的浏览器,包括现代浏览器和旧版本浏览器。 * **支持自定义事件和数据:** Server-sent events 支持自定义事件和数据,使其更灵活且可扩展。

正文

善于观察的朋友一定会敏锐地发现ChatGPT网页端是逐句给出问题答案的,同样,ChatGPT后台Api接口请求中,如果将Stream参数设置为True后,Api接口也可以实现和ChatGPT网页端一样的流式返回,进而更快地给到前端用户反馈,同时也可以缓解连接超时的问题。

Server-sent events(SSE)是一种用于实现服务器到客户端的单向通信的协议。使用SSE,服务器可以向客户端推送实时数据,而无需客户端发出请求。

SSE建立在HTTP协议上,使用基于文本的数据格式(通常是JSON)进行通信。客户端通过创建一个EventSource对象来与服务器建立连接,然后可以监听服务器发送的事件。服务器端可以随时将事件推送给客户端,客户端通过监听事件来接收这些数据。

ChatGPT的Server-sent events应用

首先打开ChatGPT网页端,随便问一个问题,然后进入网络选单,清空历史请求记录后,进行网络抓包监听:

可以看到,在触发了回答按钮之后,页面会往后端的backend-api/conversation对话接口发起请求,但这个接口的通信方式并非传统的http接口或者Websocket持久化链接协议,而是基于EventSteam的事件流一段一段地返回ChatGPT后端模型的返回数据。

为什么ChatGPT会选择这种方式和后端Server进行通信?ChatGPT网页端使用Server-sent events通信是因为这种通信方式可以实现服务器向客户端推送数据,而无需客户端不断地向服务器发送请求。这种推送模式可以提高应用程序的性能和响应速度,减少了不必要的网络流量。

与其他实时通信协议(如WebSocket)相比,Server-sent events通信是一种轻量级协议,易于实现和部署。此外,它也具有广泛的浏览器兼容性,并且可以在不需要特殊网络配置的情况下使用。

在ChatGPT中,服务器会将新的聊天消息推送到网页端,以便实时显示新的聊天内容。使用Server-sent events通信,可以轻松地实现这种实时更新功能,并确保网页端与服务器之间的通信效率和稳定性。

说白了,降低成本,提高效率,ChatGPT是一个基于深度学习的大型语言模型,处理自然语言文本需要大量的计算资源和时间。因此,返回响应的速度肯定比普通的读数据库要慢的多,Http接口显然并不合适,因为Http是一次性返回,等待时间过长,而Websocket又过重,因为全双工通信并不适合这种单项对话场景,所谓单项对话场景,就是对话双方并不会并发对话,而是串行的一问一答逻辑,同时持久化链接也会占用服务器资源,要知道ChatGPT几乎可以算是日均活跃用户数全球最高的Web应用了。

效率层面,大型语言模型没办法一下子返回所有计算数据,但是可以通过Server-sent events将前面计算出的数据先“推送”到前端,这样用户也不会因为等待时间过长而关闭页面,所以ChatGPT的前端观感就是像打字机一样,一段一段的返回答案,这种“边计算边返回”的生成器模式也提高了ChatGPT的回答效率。

Python3.10实现Server-sent events应用

这里我们使用基于Python3.10的Tornado异步非阻塞框架来实现Server-sent events通信。

首先安装Tornado框架

pip3 install tornado==6.1

随后编写sse_server.py:

import tornado.ioloop  
import tornado.web  
  
  
push_flag = True  
  
from asyncio import sleep  
  
  
class ServerSentEvent(tornado.web.RequestHandler):  
  
    def __init__(self, *args, **kwargs):  
        super(ServerSentEvent, self).__init__(*args, **kwargs)  
        self.set_header('Content-Type', 'text/event-stream')  
        self.set_header('Access-Control-Allow-Origin', "*")  
        self.set_header("Access-Control-Allow-Headers","*")  
        # 请求方式  
        self.set_header("Access-Control-Allow-Methods","*")  
  
    # 断开连接  
    def on_finish(self):  
        print("断开连接")  
        return super().on_finish()  
  
    async def get(self):  
        print("建立链接")  
        while True:  
            if push_flag:  
                print("开始")  
                self.write("event: message\n");  
                self.write("data:" + "push data" + "\n\n");  
                self.flush()  
                await sleep(2)

建立好推送路由类ServerSentEvent,它继承Tornado内置的视图类tornado.web.RequestHandler,首先利用super方法调用父类的初始化方法,设置跨域,如果不使用super,会将父类同名方法重写,随后建立异步的get方法用来链接和推送消息,这里使用Python原生异步的写法,每隔两秒往前端推送一个事件message,内容为push data。

注意,这里只是简单的推送演示,真实场景下如果涉及IO操作,比如数据库读写或者网络请求之类,还需要单独封装异步方法。

另外这里假定前端onmessage处理程序的事件名称为message。如果想使用其他事件名称,可以使用前端addEventListener来订阅事件,最后消息后必须以两个换行为结尾。

随后编写路由和服务实例:

def make_app():  
    return tornado.web.Application([  
        (r"/sse/data/", ServerSentEvent),  
    ])  
  
if __name__ == "__main__":  
    app = make_app()  
    app.listen(8000)  
    print("sse服务启动")  
    tornado.ioloop.IOLoop.current().start()

随后在后台运行命令:

python3 sse_server.py

程序返回:

PS C:\Users\liuyue\www\videosite> python .\sse_server.py  
sse服务启动

至此,基于Tornado的Server-sent events服务就搭建好了。

前端Vue.js3链接Server-sent events服务

客户端我们使用目前最流行的Vue.js3框架:

sse_init:function(){  
  
  
          var push_data = new EventSource("http://localhost:8000/sse/data/")  
        push_data.onopen = function (event) {  
            // open事件  
            console.log("EventSource连接成功");  
        };  
         
  
        push_data.onmessage = function (event) {  
    try {  
        console.log(event);  
    } catch (error) {  
        console.log('EventSource结束消息异常', error);  
    }  
};  
  
  
       push_data.onerror = function (error) {  
    console.log('EventSource连接异常', error);  
};  
  
  
      }

这里在前端的初始化方法内建立EventSource实例,通过onmessage方法来监听后端的主动推送:

可以看到,每隔两秒钟就可以订阅到后端的message事件推送的消息,同时,SSE默认支持断线重连,而全双工的WebSocket协议则需要自己在前端实现,高下立判。

结语

不仅仅可以实现ChatGPT的流式返回功能,SSE在Web应用程序中的使用场景非常广泛,例如实时的新闻推送、实时股票报价、在线游戏等等,比起轮询和长轮询,SSE更加高效,因为只有在有新数据到达时才会发送;同时SSE支持自定义事件和数据,具有更高的灵活性和复用性,为流式数据返回保驾护航,ChatGPT的最爱,谁不爱?最后奉上项目地址,与众乡亲同飨:github.com/zcxey2911/sse_tornado6_vuejs3

与逐句回答,流式返回,ChatGPT采用的Server-sent events后端实时推送协议Python3.10实现,基于Tornado6.1相似的内容:

逐句回答,流式返回,ChatGPT采用的Server-sent events后端实时推送协议Python3.10实现,基于Tornado6.1

善于观察的朋友一定会敏锐地发现ChatGPT网页端是逐句给出问题答案的,同样,ChatGPT后台Api接口请求中,如果将Stream参数设置为True后,Api接口也可以实现和ChatGPT网页端一样的流式返回,进而更快地给到前端用户反馈,同时也可以缓解连接超时的问题。 Server-sent ev

面试日记 | 移动咪咕

> 2023年校招,前沿技术规划 ## 笔试 移动校招统一笔试 ## 一面 > 群面,上午 + 逐个自我介绍 + 提问,逐个回答 + 最讨厌的人 + 比较关注的前言技术 + 抢答 + 近期做过的自豪的事 ## 二面 > 单人,下午 + 自我介绍 + 介绍一下隐私计算 + 介绍一下对元宇宙的理解 +

WPF实现类似ChatGPT的逐字打印效果

###背景 前一段时间ChatGPT类的应用十分火爆,这类应用在回答用户的问题时逐字打印输出,像极了真人打字回复消息。出于对这个效果的兴趣,决定用WPF模拟这个效果。 >真实的ChatGPT逐字输出效果涉及其语言生成模型原理以及服务端与前端通信机制,本文不做过多阐述,重点是如何用WPF模拟这个效果。

图解算法,原理逐步揭开「GitHub 热点速览」

想必每个面过大厂的小伙伴都被考过算法,那么有没有更快了解算法的方式呢?这是一个老项目,hello-algo 用图解的方式让你了解运行原理。此外,SQL 闯关自学项目也是一个让你能好好掌握 SQL 技术的仓库。说回到面试,这个一周获得近 10k star 的 devops-exercises 定能让你好好刷一场面经。

FPGA CFGBVS 管脚接法

说明 新设计了1个KU040 FPGA板子,回来之后接上JTAG FPGA不识别。做如下检查: 1、电源测试点均正常; 2、查看贴片是否有漏焊,检查无异常,设计上NC的才NC; 3、反复检查JTAG接线是否异常,贴片是否异常; 上述检查均无问题,开始查看原理图,逐个对照XILINX手册进行研究。 其

节点加入到单链表时按需求排序

JAVA实现节点加入到单链表时按需求排序 回顾 在上文《带头节点的单链表的思路及代码实现(JAVA)》中我们想要去实现让数据节点不考虑加入顺序实现数据节点排序效果。 那么我们要如何实现这一需求呢? 一、实现思路 ①理论思路 假设我们要根据数据节点的ID进行排序,那么我们可以通过使用待增加的节点id逐

LuBase 低代码开发框架介绍 - 可私有化部署

框架定位 面向开发人员,针对管理软件领域,对页面交互和通用功能进行高阶封装,逐步打造成平台型、生态型开发工具。 涓涓细流 ,汇聚成海,基于 PBC(组件式开发)开发理念,让功能模块的复用更简单。 让管理软件开发回归到对需求的深入思考和求解。 框架简介 LuBase 是以数据模型驱动,可视化表单和页面

线上问题处理案例:出乎意料的数据库连接池

本文是线上问题处理案例系列之一,旨在通过真实案例向读者介绍发现问题、定位问题、解决问题的方法。本文讲述了从垃圾回收耗时过长的表象,逐步定位到数据库连接池保活问题的全过程,并对其中用到的一些知识点进行了总结。

算法金 | 突破最强算法模型,决策树算法!!

大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 1. 引言 今天我们唠唠 吴恩达:机器学习的六个核心算法! 之决策树算法。 决策树是一种用于分类和回归的机器学习算法。它通过一系列的决策规则将数据逐步划分,最终形成一个类似于树状结构的模

2022年终总结

这是工作的第三年了,IT人的三年之痒,亦或许是觉得自己翅膀硬了,我辞去了毕业后第一份国企工作,投奔了某IT大厂 一、变化 这一年,我从泉城济南,来到了成都;离家的距离从1500公里+缩减到了,700公里,以后回家可以考虑飞机以外的交通工具了。 职业上,从纯开发,逐渐向自动化、测试工具开发靠拢,感觉上