用LangChain快速构建基于“易速鲜花”本地知识库的智能问答系统学习笔记与思考题

28 阅读5分钟

用LangChain快速构建基于“易速鲜花”本地知识库的智能问答系统学习笔记与思考题

问答系统运行效果展示

问题:易速鲜花晨会宣言是什么?

原文

image.png

回答

image.png

这个基于LangChain的问答系统实现了一个可以回答用户问题的流程,其实现流程可以分为以下几个步骤:

  1. 加载文档内容
    系统首先从一个指定的文件夹(OneFlower)中加载各种格式的文档,这些文档可能是PDF、DOCX、或TXT格式。为了支持多种格式的加载,代码使用了LangChain社区提供的三个Loader类:

    • PyPDFLoader:用于加载PDF文档。
    • Docx2txtLoader:用于加载DOCX文档。
    • TextLoader:用于加载纯文本文件。

    每次从文件夹中读取一个文件时,代码会根据文件类型选择合适的Loader,读取文件内容并存储到documents列表中,后续步骤将基于这个列表进行内容切分和嵌入处理。

  2. 文档切分
    为了让模型能够处理大文档内容并提高检索的精准度,系统将文档内容切分成小的文本块。在这里,代码使用RecursiveCharacterTextSplitter类,将每篇文档切分为长度为200字符的小块,且每块之间有10字符的重叠。

    重叠的目的是防止内容在切分过程中丢失上下文,这样即便问题涉及到跨块的内容,模型仍然能获取到完整的信息。完成切分后,切分后的文档块将被存储到chunked_documents变量中。

  3. 嵌入与向量存储
    系统将每个文本块嵌入到一个向量空间中,以便于基于向量的检索。在这部分,代码实现了一个自定义的嵌入类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来组织数据。

  4. 检索链配置
    系统需要一个检索器和问答链来完成问题的回答任务。以下是相关组件的配置:

    • MultiQueryRetriever:它是一个多查询检索器,可以生成多个相似的查询来找到最相关的文档块。retriever_from_llm会基于向量数据库找到与用户问题最相关的文档块。
    • ChatOpenAI:这部分使用OpenAI的GPT-3.5模型,作为语言模型来生成最终的回答。模型的行为可以通过调节温度参数来控制,这里设为temperature=0以获得更确定性的回答。
    • RetrievalQA链:RetrievalQA是一个LangChain中定义的问答链,结合了检索器和语言模型。系统先通过retriever_from_llm找到相关文档块,再使用GPT-3.5来生成基于这些块的答案。
  5. 问答系统UI
    最后,通过Flask框架实现了一个Web界面,允许用户在网页上输入问题。流程如下:

    • app.route("/")定义了系统的主页面路由。
    • home()函数中接收用户的问题,调用RetrievalQA链得到回答,并将结果传递到模板文件index.html中进行展示。
    • 最后,app.run()运行Flask服务器,将应用部署到本地地址,用户可以通过浏览器访问和使用这个问答系统。

    使用Flask框架,系统提供了简单的问答UI,易于用户输入问题和查看结果。

使用Chroma替代Qdrant向量数据库

LangChain支持多种向量数据库,Chroma是其中之一,可以通过以下步骤替换Qdrant实现该问答系统:

  1. 安装Chroma
    首先安装Chroma库:

    pip install chromadb
    
  2. 替换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",
    )
    
  3. 集成到现有检索流程
    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,可以按照以下步骤进行修改:

  1. 安装Hugging Face Transformers库
    通过以下命令安装Transformers库:

    pip install transformers
    
  2. 加载 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)
    
  3. 定义回答生成函数
    由于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
    
  4. 修改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")