wow-rag—task5:流式部署
我们希望做一个流式输出的后端,然后让前端去捕获这个流式输出,并且在聊天界面中流式输出。
首先构造流式输出引擎。
# 构造流式输出引擎
query_engine = index.as_query_engine(
streaming=True,
similarity_top_k=3,
llm=llm)
然后生成response_stream,这个response_stream里面有一个生成器,叫做response_gen。我们可以像列表一样去迭代这个生成器,然后取出生成的文本。
response_stream = query_engine.query("请写一篇1000字的文章论述法学专业就业前景")
for text in response_stream.response_gen:
print(text,end="")
这样我们就可以在Jupyter的界面看到流式输出了。
我们也可以做一个后端,可以用FastAPI来做。这是一个新的python web框架,性能很强悍。
我们先来安装一下这个框架:
在Jupyter的格子中输入以下内容。
%pip install fastapi
%pip install uvicorn
框架都很小,很快就安装好。
下面我们来改造一下,用fastapi做成http接口。
新建一个Jupyter notebook的格子,填入以下代码:
import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
app = FastAPI()
app.add_middleware(CORSMiddleware,allow_origins=["*"])
@app.get('/stream_chat')
async def stream_chat(param:str = "你好"):
async def generate():
# 我们假设query_engine已经构建完成
response_stream = query_engine.query(param)
for text in response_stream.response_gen:
yield text
return StreamingResponse(generate(), media_type='text/event-stream')
if __name__ == '__main__':
config = uvicorn.Config(app, host='0.0.0.0', port=5000)
server = uvicorn.Server(config)
await server.serve()
可以看到,这里的关键的关键在于yield语句的使用以及用一个generate函数构建Response。
然后在前端我们就可以愉快地接收了。
当然也可以新建一个python文件,填入以下代码:
import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
app = FastAPI()
app.add_middleware(CORSMiddleware,allow_origins=["*"])
@app.get('/stream_chat')
async def stream_chat(param:str = "你好"):
def generate():
# 我们假设query_engine已经构建完成
response_stream = query_engine.query(param)
for text in response_stream.response_gen:
yield text
return StreamingResponse(generate(), media_type='text/event-stream')
if __name__ == '__main__':
uvicorn.run(app, host='0.0.0.0', port=5000)
可以看到在jupyter的格子中运行的代码与在py文件中运行的代码的区别仅仅在于if __name__ == '__main__':
之后的代码。这是因为Jupyter是一个交互式的环境,它会在每个单元格中运行代码,而不是在一个独立的程序中运行。因此,当我们在Jupyter中运行一个程序时,它会在一个新的进程中运行,而不是在当前进程中运行。这就是为什么我们在Jupyter中运行的代码需要在if __name__ == '__main__':
之后的代码中用uvicorn.Server启动服务器。而在py文件中运行的代码则不需要。
我们甚至可以直接在浏览器地址栏里输入:
http://127.0.0.1:5000/stream_chat?param=你是谁?
然后浏览器页面就会出现流式输出。
我们也可以把它封装到一个js函数中
async function fetchStream(param) {
const url = `http://127.0.0.1:5000/stream_chat?param=${encodeURIComponent(param)}`;
const response = await fetch(url);
const reader = response.body.getReader();
while (true) {
const { value, done } = await reader.read();
if (done) {
// 如果没有更多的数据可读,退出循环
statusvue.isTalking=false;
break;
}
// 处理接收到的数据
const text = new TextDecoder("utf-8").decode(value);
console.log(text)
}
}
然后我们就可以在想要用到地地方调用这个fetchStream函数了。这个函数需要一个参数,是字符串形式的。