03LangChain实战课 - “易速鲜花”内部员工知识库问答系统

120 阅读6分钟

我正在参加「豆包MarsCode AI练中学体验活动」详情请看:掘金小册上线 AI练中学功能 | 你的 AI 编程助教喊你免费领小册啦!

LangChain实战课 - “易速鲜花”内部员工知识库问答系统

项目背景与目标

“易速鲜花”作为一个大型在线鲜花销售平台,面临着内部知识分散、更新不及时等问题。为了解决这些问题,我们计划开发一个基于内部知识手册的“Doc-QA”系统,即文档问答系统,利用LangChain框架处理员工手册中的问题,提供精准答案。

开发框架与核心机制

整个框架分为三个部分:数据源、大模型应用(LLM App)、用例。核心实现机制是数据处理管道(Pipeline),具体流程包括:

  1. Loading(加载):文档加载器将文档加载为LangChain可读格式。
  2. Splitting(分割):文本分割器将文档切分为指定大小的块。
  3. Storage(存储):将分割好的文档块以嵌入形式存储到向量数据库中。
  4. Retrieval(检索):应用程序从存储中检索分割后的文档。
  5. Output(输出):将问题和相似的嵌入片传递给语言模型(LLM),生成答案。

数据的准备和载入

我们首先使用LangChain中的document_loaders来加载各种格式的文本文件。以下是代码示例:

import os
from langchain.document_loaders import PyPDFLoader, Docx2txtLoader, TextLoader

os.environ["OPENAI_API_KEY"] = '你的OpenAI API Key'

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())

文本的分割

接下来,我们将加载的文本分割成更小的块,以便进行嵌入和向量存储。代码示例如下:

from langchain.text_splitter import RecursiveCharacterTextSplitter

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

向量数据库存储

我们将分割后的文本转换成嵌入形式,并存储在向量数据库中。代码示例如下:

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",
)

相关信息的获取

当内部文档存储到向量数据库之后,我们需要根据问题和任务来提取最相关的信息。我们创建一个聊天模型,并实例化一个RetrievalQA链。代码示例如下:

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

logging.basicConfig()
logging.getLogger('langchain.retrievers.multi_query').setLevel(logging.INFO)

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)

生成回答并展示

最后,我们创建一个Flask应用来接收用户的问题,并生成相应的答案。代码示例如下:

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)

HTML网页的关键代码如下:

<body>
    <div class="container">
        <div class="header">
            <h1>易速鲜花内部问答系统</h1>
            <img src="{{ url_for('static', filename='flower.png') }}" alt="flower logo" width="200">
        </div>
        <form method="POST">
            <label for="question">Enter your question:</label><br>
            <input type="text" id="question" name="question"><br>
            <input type="submit" value="Submit">
        </form>
        {% if result is defined %}
            <h2>Answer</h2>
            <p>{{ result.result }}</p>
        {% endif %}
    </div>
</body>

总结

通过这个项目,我们学习了如何使用LangChain框架来构建一个基于文档的问答系统。我们了解了文档的加载、分割、存储、检索和输出的整个流程,并实际操作了代码。这个系统不仅提高了内部知识的可访问性和更新效率,也展示了LangChain框架的强大功能。

思考题

  1. 简述基于文档的QA系统的实现流程
  2. 使用Chroma实现任务
  3. 使用HuggingFace的google/flan-t5-x1模型代替GPT-3.5完成这个任务

思考题回答

1. 简述基于文档的QA系统的实现流程

基于文档的QA系统实现流程大致如下:

  • 数据准备:首先,收集并整理“易速鲜花”内部的知识文档,这些文档可能包括PDF、Word和TXT格式的文件。

  • 文档加载:使用LangChain提供的文档加载器(Document Loaders),将不同格式的文档转换成可读的文本格式,并存储在列表中。

  • 文本分割:将加载的文档文本分割成小块,每块大约200个字符,以便于后续的嵌入和存储。

  • 嵌入与存储:利用大模型将每个文本块转换成嵌入向量,并存储到向量数据库中,这里使用的是Qdrant。

  • 信息检索:当用户提出问题时,系统将问题也转换成向量,并在向量数据库中检索与问题最相关的文档块。

  • 生成回答:将检索到的文档块和原始问题一起输入到语言模型中,由模型生成答案。

  • 展示答案:最后,将生成的答案展示给用户,完成整个问答流程。

2. 使用Chroma实现任务

使用Chroma作为向量数据库来实现这个任务是可行的。Chroma是一个开源的向量数据库,支持高维数据的存储和近似最近邻搜索。以下是使用Chroma实现的基本步骤:

  • 安装Chroma:首先需要安装Chroma及其Python客户端库。

  • 配置Chroma:设置Chroma的配置参数,如维度、距离度量等。

  • 生成嵌入:使用OpenAI的Embedding模型为文档块生成嵌入向量。

  • 存储嵌入:将生成的嵌入向量存储到Chroma数据库中。

  • 检索嵌入:当接收到用户问题时,将问题转换为向量,并在Chroma中检索最相似的文档块。

  • 集成到LangChain:将Chroma作为向量存储和检索的后端,集成到LangChain的Pipeline中。

代码层面,需要替换原有的Qdrant相关代码为Chroma的API调用,确保数据的存储和检索可以在Chroma中正确执行。

3. 使用HuggingFace的google/flan-t5-x1模型代替GPT-3.5完成这个任务

使用HuggingFace提供的开源模型google/flan-t5-x1代替GPT-3.5也是可行的。以下是大致步骤:

  • 安装HuggingFace库:确保安装了Transformers库,这是HuggingFace提供的用于加载和使用预训练模型的库。

  • 加载模型:使用Transformers库加载google/flan-t5-x1模型。

  • 调整问答系统:将问答系统中原来调用GPT-3.5的部分替换为调用加载的flan-t5-x1模型。

  • 模型微调:如果可能,对flan-t5-x1模型进行微调,使其更好地适应“易速鲜花”的特定领域知识。

  • 集成到LangChain:确保模型可以接收问题并生成答案,然后集成到LangChain的Pipeline中。

代码层面,需要替换原有的ChatOpenAI模型实例化为HuggingFace的模型实例,并确保模型的输入输出接口与LangChain的其他组件兼容。