大模型多轮对话 流式输出

365 阅读2分钟

大模型多轮对话 流式输出

下面这种EventSource 是一个浏览器 API,它允许你创建一个可以发出事件的对象。new EventSource 构造函数创建了一个新的 EventSource,是传统的SSE实现方法,这种方法默认是get请求,但是我们服务端需要的是POST请求,而且这种方法也不能设置header等参数,那么这种方法就不行啦

<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>SSE Example</title>
</head>

<body>
    <h1>Server-Sent Events Example</h1>
    <div id="messages"></div>

    <script>
        const evtSource = new EventSource('/events');
        const messages = document.getElementById('messages');

        evtSource.onmessage = function(event) {
            const newElement = document.createElement("p");
            const eventObject = JSON.parse(event.data);
            newElement.textContent = "Message: " + eventObject.message + " at " + eventObject.timestamp;
            messages.appendChild(newElement);
        };
    </script>
</body>
</html>

不过我们可以借助fetch-event-source这个库就可以像发起fetch请求一样发起服务器单向通信请求。 相对于传统的 EventSource API它具有实现POST请求、自定义头部和请求体的灵活性,满足各种复杂需求以及提供 onopenonmessageonclose 和 onerror 回调,允许精细化管理整个请求生命周期。

安装与使用

npm install @microsoft/fetch-event-source

然后我们可以在自己的工程里面单独封装一个用于流式输出的api文件

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

// SSE post请求
const controller = new AbortController();
const signal = controller.signal;
/*
 * url 接口地址
 * params 参数
 * sCB 成功回调
 * eCB 失败回调
*/
export const sseRequest = (baseUrl: string, obj: any, sCB: Function, eCB: Function) => {
  return fetchEventSource(`${baseUrl}/nlpd_servers/streaming_request`, {
    method: "POST",
    signal: signal,
    headers: {
      "Content-Type": "application/json",
      // Accept: "*/*",
      Accept: "text/event-stream",
    },
    body: JSON.stringify(obj),
    onmessage(msg) {
      sCB(msg);
    },
    onerror(err) {
      // 必须抛出错误才会停止
      eCB(err);
      throw err;
    },
    onclose() {
      console.log('关闭连接');
    }
  });
};

然后我们在可以在多轮对话页面调用api处

const successCallback = async (msg: any) => {
  console.log("msg", msg);
};

const errorCallback = (err: any) => {
  console.error("发生错误:", err);
};

// 调用 sseRequest 函数
await sseRequest(baseUrl.value, data, successCallback, errorCallback);

***注意 在发送消息时 服务端返回的数据应该符合以下图片中的规则:

image.png

同时还需要注意返回信息中的换行和空格符,因为在markdown文本转换的时候可能会因为他俩区分不开,导致意外的换行,所以最好和大模型工程师(Flask,FastAPI)(商量一下在返回数据的时候对空格和换行符转换一下,比如 "\xA"代表空格,"\xA\xB"代表换行