流式输出是什么

流式输出指的是服务器持续地将数据推送到客户端,而不是一次性发送完毕。 这种模式下,连接一旦建立,服务器就能实时地发送更新给客户端。在客户端的前端界面中可以以打字机的效果显示出来,从感知上减少了用户的等待时间,提升用户体验。

如何使得llm的回答流式返回

首先我们使用langchain封装一个LLM,我们这里以ZHIPUAI为例,我们可以在Integrations中找到Zhipu AI的API文档👇🏻:

Zhipu API文档

1
2
3
4
5
6
7
8
9
from langchain_community.chat_models import ChatZhipuAI


# 模型的封装
llm = ChatZhipuAI(
model="glm-4",
temperature=0.5,
streaming = True, # 在这里将streaming设置为true
)

然后只需通过下面的方法就可以使大模型的回答在终端以打字机的方式显现出来:

1
2
3
4
if __name__ == "__main__":
user_input = input("Enter your message: ")
for chunk in llm.stream(user_input):
print(chunk.content,flush=True)

但是这样的话会在每小块回答都自动换行,那是因为默认的end参数为换行符,我们只需要将end设置为""就可以使输出在同一行啦。如果想看得更加清楚,可以将end设置为"|"

现在后端的部分实现了,我们需要将数据送到前端去,我们的框架是Flask,在APP.py里我们写一个这样的函数:

1
2
3
4
5
6
7
@app.route('/send_message', methods=['POST'])
def send_message():
data = request.json
message = data['message'] # 获取用户发送的消息

# 生成流式回复
return Response(RAG_stream(message, history_messages), mimetype='text/plain')

其中调用的RAG_Stream函数的逻辑如下:

1
2
3
4
5
def RAG_stream(input):
chunks = []
for chunk in llm.stream(input):
if chunk.content:
yield f"{chunk.content}".encode('utf-8')

然后我们就需要在前端来接收这些数据,并且把他们流式地打印出来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<template>
<p>
{{chatMessage.message}}
</p>
</template>

<script>
export default{
data(){
return {
chatMessages:'',
response:'',
},
methods:{
async sendMessage() {
this.controller = new AbortController();
try {
const response = await fetch('http://localhost:5000/send_message', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('token')}` // 添加token
},
body: JSON.stringify({ message: "testMsg" }),
signal: this.controller.signal
});
const reader = response.body.getReader();

const decoder = new TextDecoder();

while (true) {
if (this.isStopped) break;
const { done, value } = await reader.read();
if (done) break;
this.response += decoder.decode(value, { stream: true });

this.$nextTick(() => {
this.scrollToBottom();
});
}
} catch (error) {
console.error('Error:', error);
}
},
}
}
}
</script>

这样,流式传输的基本逻辑就已经完成了。