LangChain快速搭建的实战项目
*详细的学习文档第二弹!上一期,我们简单了解了一下LangChain框架,并尝试调用了zhipuAI,接下来,让我们用一个实战项目进行具体的了解! * 内部员工知识库问答系统
[“易速鲜花”作为一个大型在线鲜花销售平台,有自己的业务流程和规范,也拥有针对员工的SOP手册。新员工入职培训时,会分享相关的信息。但是,这些信息分散于内部网和HR部门目录各处,有时不便查询;有时因为文档过于冗长,员工无法第一时间找到想要的内容;有时公司政策已更新,但是员工手头的文档还是旧版内容。] 来源:LangChain 实战课 - 掘金小册 - 掘金小册 (juejin.cn)
下面描述了实现这个知识库文档的整体框架
核心实现机制: 这个项目的核心实现机制是下图所示的数据处理管道(Pipeline)。
具体流程分为下面5步。
- Loading:文档加载器把Documents 加载为以LangChain能够读取的形式。
- Splitting:文本分割器把Documents 切分为指定大小的分割,我把它们称为“文档块”或者“文档片”。
- Storage:将上一步中分割好的“文档块”以“嵌入”(Embedding)的形式存储到向量数据库(Vector DB)中,形成一个个的“嵌入片”。
- Retrieval:应用程序从存储中检索分割后的文档(例如通过比较余弦相似度,找到与输入问题类似的嵌入片)。
- Output:把问题和相似的嵌入片传递给语言模型(LLM),使用包含问题和检索到的分割的提示生成答案。
准备和载入
的内部资料包括 pdf、word 和 txt 格式的各种文件,下载链接
[文档库链接] github.com/huangjia201…
LangChain中的document_loaders来加载各种格式的文本文件。
在这一步中,我们从 pdf、word 和 txt 文件中加载文本,然后将这些文本存储在一个列表中。(注意:可能需要安装PyPDF、Docx2txt等库)
pip install pypdf
pip install docx2txt
import os
import getpass
if not os.getenv("ZHIPUAI_API_KEY"):
os.environ["ZHIPUAI_API_KEY"] = getpass.getpass("Enter your ZhipuAI API key: ")
# 1. 导入 Document Loaders,用于加载不同格式的文档
from langchain_community.document_loaders import PyPDFLoader # 用于加载 PDF 文件
from langchain_community.document_loaders import Docx2txtLoader # 用于加载 DOCX 文件
from langchain_community.document_loaders import TextLoader # 用于加载 TXT 文件
# 指定文档的存放目录
base_dir = 'E:\mathProject\LangChainPy\OneFlower' # 注意使用双反斜杠或原始字符串以避免转义问题
documents = [] # 初始化一个空列表,用于存储加载的文档
# 遍历指定目录中的所有文件
for file in os.listdir(base_dir):
# 构建完整的文件路径
file_path = os.path.join(base_dir, file)
# 检查文件后缀,根据文件类型选择合适的加载器
if file.endswith('.pdf'): # 如果文件是 PDF 格式
loader = PyPDFLoader(file_path) # 创建 PDF 加载器实例
documents.extend(loader.load()) # 加载文档并将内容添加到 documents 列表中
elif file.endswith('.docx'): # 如果文件是 DOCX 格式
loader = Docx2txtLoader(file_path) # 创建 DOCX 加载器实例
documents.extend(loader.load()) # 加载文档并将内容添加到 documents 列表中
elif file.endswith('.txt'): # 如果文件是 TXT 格式
loader = TextLoader(file_path) # 创建 TXT 加载器实例
documents.extend(loader.load()) # 加载文档并将内容添加到 documents 列表中
文本的分割
接下来需要将加载的文本分割成更小的块,以便进行嵌入和向量存储。这个步骤中,我们使用 LangChain中的RecursiveCharacterTextSplitter 来分割文本。
plain复制代码AI练中学# 2.Split 将Documents切分成块以便后续进行嵌入和向量存储
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=10)
chunked_documents = text_splitter.split_documents(documents)
现在,我们的文档被切成了一个个200字符左右的文档块。这一步,是为把它们存储进下面的向量数据库做准备。
[词嵌入] 词嵌入(Word Embedding)是自然语言处理和机器学习中的一个概念,它将文字或词语转换为一系列数字,通常是一个向量。简单地说,词嵌入就是一个为每个词分配的数字列表。这些数字不是随机的,而是捕获了这个词的含义和它在文本中的上下文。因此,语义上相似或相关的词在这个数字空间中会比较接近。 举个例子,通过某种词嵌入技术,我们可能会得到: "国王" -> [1.2, 0.5, 3.1, ...] "皇帝" -> [1.3, 0.6, 2.9, ...] "苹果" -> [0.9, -1.2, 0.3, ...] 从这些向量中,我们可以看到“国王”和“皇帝”这两个词的向量在某种程度上是相似的,而与“苹果”这个词相比,它们的向量则相差很大,因为这两个概念在语义上是不同的。 词嵌入的优点是,它提供了一种将文本数据转化为计算机可以理解和处理的形式,同时保留了词语之间的语义关系。这在许多自然语言处理任务中都是非常有用的,比如文本分类、机器翻译和情感分析等。
[向量数据库] 向量数据库,也称为矢量数据库或者向量搜索引擎,是一种专门用于存储和搜索向量形式的数据的数据库。在众多的机器学习和人工智能应用中,尤其是自然语言处理和图像识别这类涉及大量非结构化数据的领域,将数据转化为高维度的向量是常见的处理方式。这些向量可能拥有数百甚至数千个维度,是对复杂的非结构化数据如文本、图像的一种数学表述,从而使这些数据能被机器理解和处理。然而,传统的关系型数据库在存储和查询如此高维度和复杂性的向量数据时,往往面临着效率和性能的问题。因此,向量数据库被设计出来以解决这一问题,它具备高效存储和处理高维向量数据的能力,从而更好地支持涉及非结构化数据处理的人工智能应用。 ---- 引自LangChain 实战课 - 掘金小册 - 掘金小册 (juejin.cn)
向量数据库存储
LangChain中支持很多向量数据库,这里我们选择的是开源向量数据库Qdrant。(注意,需要安装qdrant-client)
安装Qdrant
打开官网Qdrant - Vector Database - Qdrant
点击Get Started
自行登录
按照提示创建你的账户,拿到api key
点击Access Database
建议按照教程学习一段时间,然后我们进行下一步。
Qdrant内存存储使用
这次我们先使用内存进行存储
设置 ZHIPUAI_API_KEY 环境变量,在之前我们已经使用过
import getpass
import os
if not os.getenv("ZHIPUAI_API_KEY"):
os.environ["ZHIPUAI_API_KEY"] = getpass.getpass("Enter your ZhipuAI API key: ")
实例化
现在我们可以实例化我们的模型对象并生成聊天完成,你可以单独测试一下
from langchain_community.embeddings import ZhipuAIEmbeddings
embeddings = ZhipuAIEmbeddings(
model="embedding-3",
# With the `embedding-3` class
# of models, you can specify the size
# of the embeddings you want returned.
# dimensions=1024
)
没问题后,这里直接将完整代码给大家,参考修改学习
import os
import getpass
if not os.getenv("ZHIPUAI_API_KEY"):
os.environ["ZHIPUAI_API_KEY"] = getpass.getpass("Enter your ZhipuAI API key: ")
# 1.Load 导入Document Loaders
from langchain_community.document_loaders import PyPDFLoader
from langchain_community.document_loaders import Docx2txtLoader
from langchain_community.document_loaders import TextLoader
# 2.Split 将Documents切分成块以便后续进行嵌入和向量存储
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 3.Store 将分割嵌入并存储在矢量数据库Qdrant中
from langchain_community.vectorstores import Qdrant
from langchain_community.embeddings import ZhipuAIEmbeddings
# 加载Documents
def load_documents(base_dir):
# 文档的存放目录
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())
else :
print(f"Unsupported file type: {file}")
continue
text_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=10)
chunked_documents = text_splitter.split_documents(documents)
return chunked_documents
# 2.Split 将Documents切分成块以便后续进行嵌入和向量存储
base_dir = 'E:\mathProject\LangChainPy\OneFlower'
chunked_documents = load_documents(base_dir)
vectorstore = Qdrant.from_documents(
documents=chunked_documents, # 以分块的文档
embedding=ZhipuAIEmbeddings(), # 用ZhipuAI的Embedding Model做嵌入
location=":memory:", # in-memory 存储
collection_name="my_documents",)
使用了智谱AI作为嵌入,代码提示缺少相关的包自行根据提示下载
目前,所有内部文档,都以“文档块嵌入片”的格式被存储在向量数据库里面了。那么,我们只需要查询这个向量数据库,就可以找到大体上相关的信息了。
本次的教程就到这里啦,你可以使用上一节的知识来询问这个ai,看看是否成功传递了文档的内容. 接下来,将会更新 ##获取相关信息的过程##以及模型IO