如何实现LLM流式输出

82 阅读2分钟

前言

我们在使用chatgpt这种LLM对话产品的时候,一般和LLM对话返回的结果一般都是一段一段的返回给我们的,而不是一整个直接返回给我们,为什么会出现这种情况呢?赶快来看看吧!

原因分析

我们向LLM提出一个问题,LLM需要分析传给它的数据,并且还要进行概率计算,最终把一系列高概率结果返回给我们用户。

我们用户接收的是来自服务器的数据,而服务器传输数据是一段一段的传给我们的,并不是一下子把数据传输给我们。但是我们前端该怎么实现这样的效果呢?

我们一般都是收集用户的询问问题,然后发送给服务器让它们去处理。如果就这么直接的处理的话,难免要等待响应的结果。但是,随着等待的时间较长,用户端得不到响应的话,用户也会不耐烦,降低了他们的体验。

那么这一切的根源在哪呢?

const url='XXXXX'

async function getResponse(content){
    // 发起请求
    const resq=await fetch(url,{
        method:'POST',
        headers:{
            'Content-Type':'application/json',
        },
        body:JSON/stringify({content})
    })
    // 解析转换为纯文本
    const text=await resq.text()
    console.log(text)
}

耗时主要在哪?

要想知道花费时间主要在哪,我们就需要对这两个await的作用比较清楚。

我们先来看看流程图

image.png

我们客户端最先收服务器的一定是响应头,当用户端接收到响应头后,第一个await就马上结束了。所以说,主要花费的时间就是在第二个await上。而且响应头的内容较少,基本上不怎么花时间。我们第二个await等待的就是那一个个响应体。等全部响应体过来后,第二个await就结束了。

所以,我们对第二个await进行处理,不能一直等到所有的响应体过来。我们应该流式读取,客户端和服务器响应的时候,服务器像水流一样把数据返回给客户端,即服务器端过来多少客户端读多少。

...
const reader = resp.body.getReader()
const decoder = new TextDecoder()
while(1){
    // 此处等待,不会等到所有返回,有多少读多少
    const [done,value] = await reader.read()
    if(done){
        break
    }
    const txt = decoder.decode(value)
    // 只需把读到的内容渲染回页面即可
}

Ending

以上内容就是流式读取的解析了。