本文正在参与✍技能视角深化 ChatGPT 征文活动
善于观察的朋友一定会敏锐地发现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