ai 的流式输出是怎么做的呢

283 阅读2分钟

流式输出案例

公司早期,我在开发 智能问答平台,早期是全量返回,并不支持,流式输出,整体的内部用户体验比较差,因此接入了 流式接口。

后台返回的形式 @microsoft/fetch-event-source 是一个用于处理服务器发送事件(Server-Sent Events, SSE)的客户端库。它提供了一个可靠的方式来建立与服务器的长连接,接收实时更新,特别适用于流式API响应、实时通知和数据流等场景。

import { fetchEventSource } from '@microsoft/fetch-event-source';

// 建立连接
fetchEventSource('/api/events', {
  method: 'GET',
  headers: {
    'Accept': 'text/event-stream',
    // 可以添加其他请求头,如认证信息
  },
  onmessage(event) {
  //不断的累加响应字符串
    // 处理接收到的消息
    console.log(event.data);
  },
  onopen(response) {
    // 连接打开时的回调
    console.log('Connection opened:', response.status);
  },
  onerror(error) {
    // 错误处理
    console.error('Error:', error);
  },
  onclose() {
    // 连接关闭时的回调
    console.log('Connection closed');
  }
});


当建立链接后,会不断监听到服务端消息传递,前端这里先不断累加响应字符串,然后,一定时间间隔更新内容状态, 最终通过reactmarkdown 来进行展示相关的视图。ai 内容,一般只有转换为markdown 格式,才能更精准的识别内容块的类别,或者代码块等。

我们来探究一下这个SSE .

是什么

这个是和websocket 技术类似属于全双工,半双工,也就是仅服务端可发送信息.相比于websocket更加轻量,兼容性更好,

那么在什么样的背景下产生了这个技术呢?.

首先还是基于HTTP协议,但是http协议本身不支持服务端发送信息,所以会先声明此时通信为流信息,来实现服务端推送.

我们来看下请求头

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

阮一峰的案例说明

var http = require("http");

http.createServer(function (req, res) {
  var fileName = "." + req.url;

  if (fileName === "./stream") {
    res.writeHead(200, {
      "Content-Type":"text/event-stream",
      "Cache-Control":"no-cache",
      "Connection":"keep-alive",
      "Access-Control-Allow-Origin": '*',
    });
    res.write("retry: 10000\n");
    res.write("event: connecttime\n");
    res.write("data: " + (new Date()) + "\n\n");
    res.write("data: " + (new Date()) + "\n\n");

    interval = setInterval(function () {
      res.write("data: " + (new Date()) + "\n\n");
    }, 1000);

    req.connection.addListener("close", function () {
      clearInterval(interval);
    }, false);
  }
}).listen(8844, "127.0.0.1");

此时开启一个8844的服务端推送服务.

然后在前端网页中进行创建eventsource 对象

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
<div id="example"></div>
<script>
  var source = new EventSource('http://127.0.0.1:8844/stream');
  var div = document.getElementById('example');
  
  source.onopen = function (event) {
    div.innerHTML += '<p>Connection open ...</p>';
  };
  
  source.onerror = function (event) {
    div.innerHTML += '<p>Connection close.</p>';
  };
  
  source.addEventListener('connecttime', function (event) {
    div.innerHTML += ('<p>Start time: ' + event.data + '</p>');
  }, false);
  
  source.onmessage = function (event) {
    div.innerHTML += ('<p>Ping: ' + event.data + '</p>');
  };
  
</script>
</body>
</html>

最终实现此时可以看服务端,一直以event stream 流的形式向客户端推送,并在onmesseage回调中获取信息.

image.png

以上为从实际案例到拆解的全过程