鲜花知识库问答系统——基本LangChain框架实践 | 豆包MarsCode AI刷题

42 阅读5分钟

项目介绍

  • 项目名称: “易速鲜花”内部员工知识库问答系统。
  • 项目目标: 开发一套基于各种内部知识手册的“Doc-QA”系统,利用LangChain框架处理从员工手册中产生的各种问题。

问题分析

整个流程分为加载、切分、存储、检索和问答功能实现几大环节。

1. 数据准备和载入

  • 文件加载: 使用LangChain的document_loaders模块加载PDF、Word和TXT文件。根据文件扩展名选择合适的加载器(如PyPDFLoaderDocx2txtLoaderTextLoader),并将加载的文本内容存储在一个列表中。

2. 文本分割

  • 分割方法: 使用LangChain的RecursiveCharacterTextSplitter工具将加载的文档内容分割成小块(例如200字符左右),以便后续进行嵌入和向量存储。

3. 向量数据库存储

  • 嵌入和存储: 使用OpenAI的OpenAIEmbeddings生成文本的嵌入,然后将这些嵌入存储在Qdrant向量数据库中。向量数据库用于高效存储和检索高维向量数据。

4. 相关信息获取

  • 检索方法: 使用余弦相似度从向量数据库中检索与用户输入问题最相关的文档片段。余弦相似度用于比较向量的方向相似性,适用于文本数据的处理。

5. 生成回答并展示

  • UI实现: 使用Flask创建一个Web应用来接收用户输入的问题,并调用之前创建的RetrievalQA链来生成答案。RetrievalQA链结合了检索器和大语言模型(如GPT-3.5),检索器从向量数据库中找到相关文档片段,然后大语言模型生成最终答案。最后,通过Flask应用将答案渲染并展示在前端页面上。

思考题

基于文档的QA系统的实现流程

1. 加载 (Loading)

目的: 将不同格式的文档(如PDF、Word、TXT)转换为可以被LangChain处理的文本格式。

实现:

  • 使用LangChain提供的document_loaders模块来处理不同类型的文件。
  • PyPDFLoader用于处理PDF文件。
  • Docx2txtLoader用于处理Word文件。
  • TextLoader用于处理纯文本文件。

代码示例:

from langchain.document_loaders import PyPDFLoader, Docx2txtLoader, TextLoader

base_dir = './OneFlower'
documents = []

for file in os.listdir(base_dir):
    file_path = os.path.join(base_dir, file)
    if file.endswith('.pdf'):
        loader = PyPDFLoader(file_path)
        documents.extend(loader.load())
    elif file.endswith('.docx'):
        loader = Docx2txtLoader(file_path)
        documents.extend(loader.load())
    elif file.endswith('.txt'):
        loader = TextLoader(file_path)
        documents.extend(loader.load())

2. 分割 (Splitting)

目的: 将加载的文档分割成较小的文本块,以便于后续的嵌入和检索。

实现:

  • 使用LangChain的RecursiveCharacterTextSplitter工具。
  • 设置合适的chunk_sizechunk_overlap参数。

代码示例:

from langchain.text_splitter import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=10)
chunked_documents = text_splitter.split_documents(documents)

3. 嵌入和存储 (Embedding and Storage)

目的: 将分割后的文本块转换为向量形式,并存储在向量数据库中。

实现:

  • 使用OpenAI的OpenAIEmbeddings生成文本嵌入。
  • 使用Qdrant向量数据库存储嵌入。

代码示例:

from langchain.vectorstores import Qdrant
from langchain.embeddings import OpenAIEmbeddings

vectorstore = Qdrant.from_documents(
    documents=chunked_documents,
    embedding=OpenAIEmbeddings(),
    location=":memory:",
    collection_name="my_documents",
)

4. 检索 (Retrieval)

目的: 根据用户输入的问题,从向量数据库中检索相关的文本块。

实现:

  • 使用余弦相似度比较问题和文档嵌入。
  • 使用LangChain的MultiQueryRetriever工具。

代码示例:

from langchain.chat_models import ChatOpenAI
from langchain.retrievers.multi_query import MultiQueryRetriever
from langchain.chains import RetrievalQA

llm = ChatOpenAI(model_name="gpt-3.5-turbo", temperature=0)
retriever_from_llm = MultiQueryRetriever.from_llm(retriever=vectorstore.as_retriever(), llm=llm)
qa_chain = RetrievalQA.from_chain_type(llm, retriever=retriever_from_llm)

5. 生成回答 (Output)

目的: 将检索到的相关文档块和用户问题传递给大语言模型,生成最终的答案。

实现:

  • 使用Flask创建一个Web应用来接收用户输入。
  • 调用qa_chain生成答案并渲染到前端页面。

代码示例:

from flask import Flask, request, render_template

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def home():
    if request.method == 'POST':
        question = request.form.get('question')
        result = qa_chain({"query": question})
        return render_template('index.html', result=result)
    return render_template('index.html')

if __name__ == "__main__":
    app.run(host='0.0.0.0', debug=True, port=5000)

使用Chroma向量数据库实现任务

安装Chroma客户端

pip install chromadb

修改存储部分代码

from langchain.vectorstores import ChromaDB
from langchain.embeddings import OpenAIEmbeddings

chromadb_client = ChromaDBClient()
chromadb_database = chromadb_client.get_or_create_database("my_documents")

for doc in chunked_documents:
    embedding = OpenAIEmbeddings().embed_text(doc)
    chromadb_database.add_documents([{"text": doc, "embedding": embedding}])

使用google/flan-t5-x1代替GPT-3.5

安装HuggingFace模型

pip install transformers

修改模型部分代码

from transformers import AutoModelForCausalLM, AutoTokenizer

model_name = "google/flan-t5-x1"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)

llm = ChatOpenAI(model=model, tokenizer=tokenizer, temperature=0)

详细分析

1. 加载 (Loading)

  • 目的: 将不同格式的文档转换为文本格式,以便后续处理。
  • 实现: 使用LangChain的document_loaders模块,根据文件扩展名选择合适的加载器。
  • 代码: 通过遍历目录中的文件,使用相应的加载器读取文件内容并存储在列表中。

2. 分割 (Splitting)

  • 目的: 将长文本分割成较小的块,以便于嵌入和检索。
  • 实现: 使用RecursiveCharacterTextSplitter工具,设置合适的块大小和重叠量。
  • 代码: 遍历所有文档,将其分割成指定大小的文本块。

3. 嵌入和存储 (Embedding and Storage)

  • 目的: 将文本块转换为向量形式,并存储在向量数据库中。
  • 实现: 使用OpenAI的OpenAIEmbeddings生成文本嵌入,使用Qdrant存储嵌入。
  • 代码: 遍历所有分割后的文本块,生成嵌入并存储在Qdrant数据库中。

4. 检索 (Retrieval)

  • 目的: 根据用户输入的问题,从向量数据库中检索相关的文本块。
  • 实现: 使用余弦相似度比较问题和文档嵌入,使用MultiQueryRetriever工具。
  • 代码: 实例化大语言模型和检索器,创建RetrievalQA链。

5. 生成回答 (Output)

  • 目的: 将检索到的相关文档块和用户问题传递给大语言模型,生成最终的答案。
  • 实现: 使用Flask创建Web应用,接收用户输入并调用qa_chain生成答案。
  • 代码: 创建Flask应用,定义路由处理用户请求,渲染答案到前端页面。

使用Chroma向量数据库

  • 安装: 使用pip安装Chroma客户端。
  • 修改: 使用ChromaDBClient创建数据库,遍历文档块生成嵌入并存储。

使用google/flan-t5-x1代替GPT-3.5

  • 安装: 使用pip安装transformers库。
  • 修改: 使用AutoModelForCausalLM和AutoTokenizer加载指定的模型,实例化ChatOpenAI。

可以尝试按照以上步骤进行大致的实现。