我们希望做一个流式输出的后端,然后让前端去捕获这个流式输出,并且在聊天界面中流式输出。 首先构造流式输出引擎。 然后生成responsestream,这个responsestream里面有一个生成器,叫做responsegen。我们可以像列表一样去迭代这个生成器,然后取出生成的文本。 这样我们就可以在Jupyter的界面看到流式输出了。 我们也可以做一个后端,可以用FastAPI来做。这是一个新的python web框架,性能很强悍。 我们先来安装一下这个框架: 在Jupyter的格子中输入以下内容。 框架都很小,很快就安装好。 下面我们来改造一下,用fastapi做成http接口。
我们希望做一个流式输出的后端,然后让前端去捕获这个流式输出,并且在聊天界面中流式输出。
首先构造流式输出引擎。
# 构造流式输出引擎 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/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函数了。这个函数需要一个参数,是字符串形式的。
本教程配了一个chat.html 文件,如果后端用fastapi配置好了,浏览器http://127.0.0.1/stream_chat?param=你是谁?也能有内容了,就可以在本地电脑双击打开这个chat.html 文件进行对话聊天。
好了,现在我们可以从零搭建起一个RAG应用了。未来我们可以一起搭建起一套开源的 To B的RAG系统。这个RAG系统也叫wow-rag,目前计划采用的技术栈是:
前端:TS + Vue3 + Element Plus
后端:FastAPI
大模型框架:Llama-index
大模型:自塾自封装One-API服务
数据库:Qdrant
我们计划不依赖于docker。只有一个zip包,解压后双击就部署完成。
我们计划做成五个套餐版本,分别是: