用LangChain快速构建基于“易速鲜花”本地知识库的智能问答系统学习笔记与思考题
问答系统运行效果展示
问题:易速鲜花晨会宣言是什么?
原文
回答
这个基于LangChain的问答系统实现了一个可以回答用户问题的流程,其实现流程可以分为以下几个步骤:
-
加载文档内容
系统首先从一个指定的文件夹(OneFlower
)中加载各种格式的文档,这些文档可能是PDF、DOCX、或TXT格式。为了支持多种格式的加载,代码使用了LangChain社区提供的三个Loader类:PyPDFLoader
:用于加载PDF文档。Docx2txtLoader
:用于加载DOCX文档。TextLoader
:用于加载纯文本文件。
每次从文件夹中读取一个文件时,代码会根据文件类型选择合适的Loader,读取文件内容并存储到
documents
列表中,后续步骤将基于这个列表进行内容切分和嵌入处理。 -
文档切分
为了让模型能够处理大文档内容并提高检索的精准度,系统将文档内容切分成小的文本块。在这里,代码使用RecursiveCharacterTextSplitter
类,将每篇文档切分为长度为200字符的小块,且每块之间有10字符的重叠。重叠的目的是防止内容在切分过程中丢失上下文,这样即便问题涉及到跨块的内容,模型仍然能获取到完整的信息。完成切分后,切分后的文档块将被存储到
chunked_documents
变量中。 -
嵌入与向量存储
系统将每个文本块嵌入到一个向量空间中,以便于基于向量的检索。在这部分,代码实现了一个自定义的嵌入类DoubaoEmbeddings
:DoubaoEmbeddings
类继承自LangChain的Embeddings
类。该类通过一个API接口(如OpenAI的API)将每个文本块转化为一个高维向量。- 类中定义了两个方法:
embed_query
用于生成单个文本的向量,embed_documents
用于批量生成多个文本的向量。 - 嵌入过程依赖于
Ark
客户端来调用外部API(例如OpenAI的嵌入模型)。api_key
和API的基础URL由环境变量获取。
生成的嵌入向量将被存储在Qdrant向量数据库中。Qdrant是一种向量存储数据库,支持基于向量的高效检索和管理。以下是存储的具体方法:
vectorstore = Qdrant.from_documents( documents=chunked_documents, embedding=DoubaoEmbeddings(model=os.environ["EMBEDDING_MODELEND"]), location=":memory:", collection_name="my_documents", )
此代码将切分后的文档和其嵌入向量存储在Qdrant的一个内存数据库中,并使用指定的
collection_name
来组织数据。 -
检索链配置
系统需要一个检索器和问答链来完成问题的回答任务。以下是相关组件的配置:MultiQueryRetriever
:它是一个多查询检索器,可以生成多个相似的查询来找到最相关的文档块。retriever_from_llm
会基于向量数据库找到与用户问题最相关的文档块。ChatOpenAI
:这部分使用OpenAI的GPT-3.5模型,作为语言模型来生成最终的回答。模型的行为可以通过调节温度参数来控制,这里设为temperature=0
以获得更确定性的回答。RetrievalQA
链:RetrievalQA
是一个LangChain中定义的问答链,结合了检索器和语言模型。系统先通过retriever_from_llm
找到相关文档块,再使用GPT-3.5来生成基于这些块的答案。
-
问答系统UI
最后,通过Flask框架实现了一个Web界面,允许用户在网页上输入问题。流程如下:app.route("/")
定义了系统的主页面路由。home()
函数中接收用户的问题,调用RetrievalQA
链得到回答,并将结果传递到模板文件index.html
中进行展示。- 最后,
app.run()
运行Flask服务器,将应用部署到本地地址,用户可以通过浏览器访问和使用这个问答系统。
使用Flask框架,系统提供了简单的问答UI,易于用户输入问题和查看结果。
使用Chroma替代Qdrant向量数据库
LangChain支持多种向量数据库,Chroma是其中之一,可以通过以下步骤替换Qdrant实现该问答系统:
-
安装Chroma
首先安装Chroma库:pip install chromadb
-
替换Qdrant为Chroma
Chroma的使用方式与Qdrant类似,因此可以直接替换Qdrant.from_documents
部分:from langchain_community.vectorstores import Chroma # 使用Chroma创建向量存储 vectorstore = Chroma.from_documents( documents=chunked_documents, embedding=DoubaoEmbeddings(model=os.environ["EMBEDDING_MODELEND"]), collection_name="my_documents", )
-
集成到现有检索流程
Chroma也支持.as_retriever()
方法,因此检索和问答链的配置不需要改变。直接使用vectorstore.as_retriever()
即可完成与Qdrant类似的检索操作。
使用 Hugging Face 的 google/flan-t5-xl
模型替代 GPT-3.5
为了使用 Hugging Face 提供的 google/flan-t5-xl
开源模型替代 GPT-3.5,可以按照以下步骤进行修改:
-
安装Hugging Face Transformers库
通过以下命令安装Transformers库:pip install transformers
-
加载 Hugging Face 模型
替换掉ChatOpenAI
,使用 Hugging Face 的google/flan-t5-xl
模型。以下是加载模型的代码:from transformers import AutoModelForSeq2SeqLM, AutoTokenizer import torch # 加载 Hugging Face 的 Flan-T5 模型和 Tokenizer model_name = "google/flan-t5-xl" tokenizer = AutoTokenizer.from_pretrained(model_name) model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
-
定义回答生成函数
由于Flan-T5是一个生成式模型,我们可以定义一个generate_answer
函数来生成回答:def generate_answer(question): inputs = tokenizer(question, return_tensors="pt") outputs = model.generate(inputs.input_ids, max_length=200, num_beams=4, early_stopping=True) answer = tokenizer.decode(outputs[0], skip_special_tokens=True) return answer
-
修改Flask应用中的问答逻辑
在Flask应用的home()
函数中,替换调用RetrievalQA
链的部分。因为不再使用GPT-3.5模型,可以直接调用generate_answer
函数:@app.route("/", methods=["GET", "POST"]) def home(): if request.method == "POST": question = request.form.get("question") result = generate_answer(question) # 调用 Hugging Face 模型生成回答 return render_template("index.html", result=result) return render_template("index.html")