文章目录
- 实现目的
- 效果比对
- 非stream模式
- stream模式
- 实现方案
- 方案思路总体描述
- 前端
- 方案对比
- event-source-polyfill代码示例
- 前端实现遇到的问题与解决方法
- 后端
- 参考资料
- 时序图
- 关键代码示例
- 后端实现时遇到的问题与解决方法
实现目的
stream
是OpenAI API
中的一个参数,用于控制请求的模式。当将stream
参数设置为True
时,API
会以流式方式返回响应,即在请求过程中会立即返回部分结果,而不需要等待完整的响应。
这使得实时交互、大规模数据处理和逐步呈现结果成为可能。
我们的AI Assistant,本质上也是一个聊天机器人,因此非常需要流式方式返回来以提高交互性和响应速度。
通过使用流式方式返回响应,我们可以在用户输入后立即开始处理,并逐步返回部分结果,使用户能够更快地获得反馈,以及更加流畅的交互体验。
同时,它更能够让用户在等待完整响应的同时,逐步阅读和理解部分结果,以便更连贯地进行对话。
效果比对
下面是两种请求方式的交互示意以及效果对比
非stream模式
- 交互示意
- 实际效果
stream模式
-
交互示意
-
实际效果
实现方案
方案思路总体描述
前端采用**EventSource**
来进行请求服务器端的实时数据更新。EventSource提供了一种简单的、基于事件的方式来接收服务器端的实时事件通知。通过使用EventSource,前端可以建立持久的、基于HTTP的连接,以接收服务器端的实时数据更新。
后端采用**Reactor Flux**
技术来处理异步数据流,它是Reactive Streams
规范中的一种数据流处理规范。Flux可以处理非阻塞的异步数据流,并具备背压处理能力,从而实现高效的响应式编程。通过使用Flux,后端可以有效地处理大量的异步数据流,并根据消费者的处理能力进行背压控制,确保数据流的稳定和高效处理。
结合前端的EventSource
和后端的Flux
,我们可以简单地建立起一个实时数据更新的机制。
前端通过EventSource与后端建立持久连接,一旦后端有新的数据更新,就会通过EventSource将数据推送给前端。前端接收到数据后,可以根据需要进行相应的处理和展示。
前端
前端前后换了4种方案,最终使用了event-source-polyfill
来进行处理。
方案对比
几种方案的对比如下:
方案 | 实现参考 | 优缺点 | 使用注意 |
---|---|---|---|
sse.js | sse.js | 无需第三方依赖,不适用于React | 需要显式调用stream()方法发起请求 |
sse.jsx | SSE.jsx | 无需第三方依赖,使用于React,但是打包后无效 | 需要显式调用stream()方法发起请求 |
react-native-sse | https://www.npmjs.com/package/react-native-sse/v/1.0.1 | 仅适用于RN,不适用于fishx(打包后可用,但是会导致基于React构建的fishx项目启动报错)支持POST\GET | 无需显式调用open()方法,否则可能出现连续请求的问题 |
event-source-polyfill | https://www.npmjs.com/package/event-source-polyfill | 适用于fishx. 但只支持GET请求(如果想传参则需要采用url带参的形式) | 无需显式调用open()方法,否则可能出现连续请求的问题 |
event-source-polyfill代码示例
import { EventSourcePolyfill } from 'event-source-polyfill';const streamChatWithBSS = (value, now) => {let es = null;try {// 1.生成带参URLconst baseUrl = '/chat';const params = {}const queryString = Object.keys(params).map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`