LangChain实战课:学习构建智能问答系统 | 豆包MarsCode AI 刷题

210 阅读8分钟

这是一篇菜鸟的学习笔记~

本文详细介绍了如何使用LangChain构建一个基于"易速鲜花"本地知识库的智能问答系统。

- 问答系统的实现框架:数据源+大模型应用+用例(回答窗口)

数据源有多种类型,主要包括非结构化数据(PDF文件)、结构化数据(SQL数据库)和代码(Python或Java程序)。大模型应用则是使用人工智能大模型作为核心,生成回答用户问题的内容,具体可以利用大模型创建问答系统或聊天机器人等实用工具。

核心实现机制分为五步:

  1. 将文档内容转换为程序可以处理和分析的格式,使其成为可读取和操作的数据结构。这一步骤涉及使用适当的加载器来解析不同类型的文档,如PDF、Word文档或纯文本文件,并将其内容提取为可供后续处理的形式。
  2. 将文档分割成指定尺寸的小块或片段,以便于后续处理和分析。这个步骤对于大型文档尤为重要,因为它能够确保每个片段都包含足够的上下文信息,同时又不会过于冗长,从而提高后续处理的效率和准确性。
  3. 把文档块以嵌入的形式存储到向量数据库,以便系统能够在大量数据中高效找到与给定查询向量相似的文档块,然后可以被用来进行各种下游任务,例如信息检索、推荐系统或自然语言处理任务。
  4. 检索嵌入的信息片,通过对比输入问题与已存储嵌入片之间的相似度。在计算出相似度后,系统将根据相似度得分对所有嵌入片进行排序。得分越高的嵌入片表示与输入问题越相似,系统将优先返回这些高相似度的片段,提升信息检索的智能化和实用性。
  5. 生成回答。

五模块具体说明

数据的载入

使用PyPDFLoader、Docx2txtLoader、TextLoader载入不同格式的文档,这些加载器能够处理各种类型的文本文件,使系统能够从多种来源获取信息。

分割文本

使用RecursiveCharacterTextSplitter来分割文本,这是一种高效的文本分割方法。其中,chunk_size参数定义了每个分块的最大字符数,确保每个块不会过大;而chunk_overlap参数则指定了相邻分块之间重叠的字符数,这有助于保持上下文的连贯性。通过调整这两个参数,我们可以灵活地控制文本分割的粒度和连贯性,从而为后续的处理和分析提供更好的基础。

text_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=10)
向量数据库的存储(Qdrant)

该系统使用Qdrant作为向量数据库,这一步骤涉及到词嵌入和向量数据库的概念的概念。

词嵌入

将词语转换为数字向量,捕捉词的含义和上下文,语义相近的词在向量空间中距离较近。例如: "国王" -> [1.2, 0.5, 3.1, ...] "皇帝" -> [1.3, 0.6, 2.9, ...] "苹果" -> [0.9, -1.2, 0.3, ...] 这种表示方法使计算机能理解和处理文本,保留词语间的语义关系,广泛应用于自然语言处理任务、翻译和情感分析等。

向量数据库

存储和搜索向量形式数据的数据库。在机器学习和人工智能应用中,特别是处理非结构化数据时,常将数据转化为高维向量。这些向量可能有数百至数千个维度,是对复杂数据的数学表述。传统关系型数据库在处理高维向量数据时效率低下,因此开发了向量数据库,以高效存储和处理高维向量数据,更好地支持非结构化数据处理的人工智能应用。

非结构化数据

所有格式的办公文档、文本、图片、XML、HTML、各类报表、图像和音频/视频信息等。

对比问题与文档信息

信息提取的核心原理是将用户提出的问题转化为向量形式,随后与向量数据库中存储的各个文档向量进行比较和匹配。这一过程涉及复杂的数学运算和相似度计算,旨在从海量数据中快速定位并提取出与问题最相关的信息。通过这种方法,系统能够高效地识别出最接近用户查询意图的内容,从而为后续的问答或信息检索任务奠定基础。这种基于向量的信息提取方式不仅提高了检索的准确性,还大大提升了处理大规模非结构化数据的效率。

  • 欧式距离:这是一种测量向量间距离的方法,源自于我们熟悉的二维平面上两点间的直线距离概念。在高维空间中,欧氏距离的计算方法是将两个向量各个对应维度的差值平方后求和,然后对这个和取平方根。这种方法不仅适用于二维或三维空间,还可以扩展到任意维度的向量空间。欧氏距离的计算结果直观地反映了两个向量在空间中的实际距离,因此在许多应用中被广泛使用。(关注距离长短,提供了向量间物理距离的直观度量)
  • 余弦相似度:这是一种用于衡量向量之间方向相似性的重要指标。它的计算结果范围在-1到1之间,具有特殊的数学意义。当两个向量的余弦相似度值越接近1,就意味着这两个向量在高维空间中的方向越接近,即它们所代表的数据或概念越相似。相反,如果余弦相似度接近-1,则表示两个向量方向相反,而接近0则表示两个向量近乎正交,即没有明显的相似性。(主要关注向量方向的相似程度,而非向量的绝对大小)
  1. 导入必要的库
import logging
from langchain_openai import ChatOpenAI
from langchain.retrievers.multi_query import MultiQueryRetriever
from langchain.chains import RetrievalQA 
  • logging:用于日志记录,在调试或监控代码运行状态时很有用。
  • ChatOpenAI:这是 LangChain 库中用于调用 OpenAI 大语言模型的类。
  • MultiQueryRetriever:LangChain 中的多查询检索器,可以生成多种查询以检索相关文档。
  • RetrievalQA:这是 LangChain 中的一个问答链工具,用于结合检索器和大语言模型实现问答功能。
  1. 配置日志
logging.basicConfig()
logging.getLogger("langchain.retrievers.multi_query").setLevel(logging.INFO)
  • logging.basicConfig() 设置基本的日志配置。
  • setLevel(logging.INFO) 日志级别设置为 INFO,用于输出信息级别及以上的日志,这对调试和监控有帮助。
  1. 实例化 ChatOpenAI 模型
llm = ChatOpenAI(model=os.environ["LLM_MODELEND"], temperature=0)
  • model=os.environ["LLM_MODELEND"]:通过环境变量获取 OpenAI 模型的名称。
  • temperature=0:设置模型的回答温度为 0(即确定性),确保每次回答一致。
  1. 创建 MultiQueryRetriever 实例
retriever_from_llm = MultiQueryRetriever.from_llm(retriever=vectorstore.as_retriever(), llm=llm)
  • retriever=vectorstore.as_retriever():假设 vectorstore 是一个向量存储对象,通过 .as_retriever() 方法将其转为检索器。
  • llm=llm:将上一步创建的 ChatOpenAI 实例传递给 MultiQueryRetriever,使其可以生成多种查询,增加检索结果的相关性。
  1. 创建 RetrievalQA 链
qa_chain = RetrievalQA.from_chain_type(llm, retriever=retriever_from_llm)
  • RetrievalQA.from_chain_type:使用指定的模型(llm)和检索器(retriever_from_llm)实例化一个问答链。
  • qa_chain:这个对象能够接收一个问题,利用检索器找到相关文档,然后用模型生成基于文档的回答。
  • 输出回答 使用Flask框架来构建一个简单的web应用程序,该应用能够接收用户输入的问题,并利用我们之前构建的问答系统生成相应的答案。这种方法不仅能够为用户提供一个直观的界面来与系统进行交互,还能够实时处理用户的查询并返回相关的信息。

具体而言,Flask应用将包含一个表单,允许用户输入他们的问题。当用户提交问题时,服务器会调用我们的问答链来处理这个问题,然后将生成的答案返回给用户。这种交互式的方式使得用户能够方便地利用我们构建的知识库来获取所需的信息。

总结

总体上说就是采用 LangChain 库构建了一个功能强大的问答系统(RetrievalQA 链)。该系统结合了先进的大语言模型(如 OpenAI 的 GPT-3.5)和高效的检索工具(MultiQueryRetriever),能够从向量数据库中精准检索相关信息。这种创新的组合不仅提高了信息检索的准确性,还能基于检索到的信息生成高质量、上下文相关的回答。系统的设计充分利用了大语言模型的自然语言理解能力和 MultiQueryRetriever 的多角度查询策略,确保了问答过程的全面性和深度。这种方法显著提升了系统处理复杂查询的能力,使其能够应对各种难度的问题,并提供详细、准确的回答。