使用langchain与你自己的数据对话(二):向量存储与嵌入_langchain chat with your data

之前我以前完成了“使用langchain与你自己的数据对话(一):文档加载与切割这篇文章,没有阅读的朋友可以先阅读一下,今天我们来继续讲解第三门课:向量存储与嵌入。

Langchain在实现与外部数据对话的功能时需要经历下面的5个阶段,它们分别是:Document Loading->Splitting->Storage->Retrieval->Output,如下图所示:

在上一篇博客:文档加载与切割)中我已经介绍了如何使用Langchain来加载外部的文档,以及如何切割文档,之所以要对文档做加载与切割的操作,是因为外部数据类型和属性有所不同,比如外部数据可能是pdf, text, 网页,youtube视频等,要读取不同类型的外部数据我们就需要有专门的Loader来加载这些数据,所以我们就需要各种类型的文档加载器,当数据被加载器加载以后,接下来我们需要做文档的切割,这是因为外部数据的体量可能比较大,如pdf文档可能会有几十页,几百页的内容,所以我们需要将文档内容按一点尺寸(chunk_size)均匀的切成小块(chunks), 在上一篇博客中我们介绍了几种Langchain常用的文档切割器如RecursiveCharacterTextSplitter, CharacterTextSplitter,TokenTextSplitter,MarkdownHeaderTextSplitter等,其中Langchain默认使用RecursiveCharacterTextSplitter切割器。当文档被切割以后,加下来就到了嵌入(Embeddings)和向量存储(vectorstores)的环节,如下图所示:

所谓的向量存储是指被切割的文档需要经过向量化操作以后存储到向量数据库的过程,因为大型语言模型(LLM)无法理解文字信息(只能理解数字),所以我们必须对文字信息进行编码,这里说的编码就是只嵌入(Embeddings), 嵌入操作可以将文本转换成数字编码并以向量的形式存储在向量数据库中,如下图所示:

当文档被切割成块(chunks)后,每一个块都会经嵌入操作后转换成向量并存储在向量数据库中,当用户对文档内容提出问题时,用户的问题也会经嵌入操作后被转换成向量并与向量数据库中的所有向量做相似度比较,最后找出与问题最相关的n个向量,如下图所示:

当找到与用户问题最相关的n个向量以后,这些向量会被还原成原始文本,然后将用户的问题和这些文本信息发送给LLM, LLM会针对用户的问题对这些文本内容做提炼和汇总,最后给出正确合理的答案,如下图所示:

整个与文档对话的过程大致就是这样,下面我们来实操一下上面的嵌入和向量存储的过程,不过首先我们还是需要做一下些基础性工作,比如设置一下openai的api key:

import os
import openai
import sys
sys.path.append('../..')

from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file

openai.api_key  = os.environ['OPENAI_API_KEY']

Document Loading & Splitting

接下来我们首先来实现文档的加载和切割,这里我们会加载一组吴恩达老师著名的机器学习课程cs229的pdf讲义稿:

from langchain.document_loaders import PyPDFLoader

# Load PDF
loaders = [
    # Duplicate documents on purpose - messy data
    PyPDFLoader("docs/cs229_lectures/MachineLearning-Lecture01.pdf"),
    PyPDFLoader("docs/cs229_lectures/MachineLearning-Lecture01.pdf"),
    PyPDFLoader("docs/cs229_lectures/MachineLearning-Lecture02.pdf"),
    PyPDFLoader("docs/cs229_lectures/MachineLearning-Lecture03.pdf")
]
docs = []
for loader in loaders:
    docs.extend(loader.load())

需要说明一下的是这里我们加载了2篇相同的pdf文档:Lecture01.pdf,之所以要加载两篇相同的pdf文档,是为了后面我们需要做一些测试看看当文档内容相同的时候LLM的表现。当文档完成加载以后,下面我们就需要对文档进行切割,首先我们需要创建一个文档切割器RecursiveCharacterTextSplitter:

# Split
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size = 1500,
    chunk_overlap = 150
)

这里关于参数chunk_size ,和chunk_overlap 的含义在文档加载与切割这篇博客中已经详细说明过了,这里不再赘述。当文档切割器创建完成以后,我们可以开始切割文档的操作:

#切割文档
splits = text_splitter.split_documents(docs)

#查看切割后文档的数量
print(len(splits))

这里我们看到切割后的文档长度是209,也就是说所有的pdf文档被切割成了209块(chunks),我们可以查看其中的某一块的文档内容:

splits[0]

我们看到被切换的文档块中包含了文档的内容(page_content)和元数据(metadata),在元数据中记录了文档的位置和该块内容所在的页数。那么现在在splits中就包含了209个这样的文档块。

Embeddings

所谓的嵌入(Embeddings)是一种文本的编码的方法,它可以一段文字转换成一定长度的一组向量,下面我们来做一下简单的embedding测试:

from langchain.embeddings.openai import OpenAIEmbeddings
embedding = OpenAIEmbeddings()


sentence1 = "我喜欢小狗。"
sentence2 = "我喜欢小动物。"
sentence3 = "我今天心情很差。"

embedding1 = embedding.embed_query(sentence1)
embedding2 = embedding.embed_query(sentence2)
embedding3 = embedding.embed_query(sentence3)

这里我们有三句简单的中文句子,前两句表达人和动物之间的关系,第三句表达人的心情,所以前两句的含义应该比较相似,后第三句和前两句的含义完全不同,下面我们可以通过计算两个向量的点积来得到两个向量的相似度:

np.dot(embedding1, embedding2)

np.dot(embedding1, embedding3)

np.dot(embedding2, embedding3)

我们可以看到embedding1与embedding2之间有较高的相似性达到了0.94,而embedding3与embedding1和embedding2的相似度只都只有0.8以下,这说明第一句和第二句话有较高的相似度。下面我们看一下经过embedding操作以后的结果是怎么样的:

print(embedding1)

这里我们看到经过embdding操作后生成的向量是一个python的list, 其中包含了很多数字,下面我们再看一下这个embdding的长度:

print(len(embedding1))

这里我们可以看到经过embdding操作以后生成的向量的长度是1536,也就是说由1536个数字来表示了被embdding的这句文本,我们也可以看成是由1536个维度来表示这句文本。

向量数据库

当我们知道了Embedding的原理以后,接下来我们来介绍一种向量数据库Chroma,Chroma 是开源嵌入(Embedding)数据库。Chroma 通过为大型语言模型(LLM)提供可嵌入的知识、事实和技能,让构建大型语言模型(LLM)的应用程序变得更加容易,如下图所示:

接下来我们来实际操作创建向量数据库的过程,并且将生成的向量数据库保存在本地。当我们在创建Chroma数据库时,我们需要传递如下参数:

  • documents: 切割好的文档对象
  • embedding: embedding对象
  • persist_directory: 向量数据库存储路径
from langchain.vectorstores import Chroma

#向量数据库保存位置
persist_directory = 'docs/chroma/'

#创建向量数据库
vectordb = Chroma.from_documents(
    documents=splits,
    embedding=embedding,
    persist_directory=persist_directory
)


#查看向量数据库中的文档数量
print(vectordb._collection.count())

这里我们看到向量数据库中存储这209个向量,这和我们之前切割文档后的splits 中的数量是一至的,这说明原来209个文档块已经被转换成了209个向量并且被保存在了Chroma数据库中。

相似度搜索(Similarity Search)

当文档被切割并经embedding操作后转换成向量存储到Chroma数据库中后,我们可以对Chroma数据库中的向量进行相似度的比较,也就是我们可以模拟用户提出问题,然后去Chroma执行相似内容搜索,并返回与问题相似度较高的文本内容:

question = "is there an email i can ask for help"

docs = vectordb.similarity_search(question,k=3)

#打印文档数量
print(len(docs))

这里我们要求向量数据库对问题进行相似度搜索,找出和问题最相关的3个(k=3)文档。下面我们查看其中的一个文档的内容:

docs[0].page_content

我们看到第一篇文档中包含了"email"这个单词,这和我们的问题显然是相关的。接下来我们来实现向量数据库的持久化:

vectordb.persist()

执行了persist()操作以后向量数据库才真正的被保存到了本地,下次在需要使用该向量数据库时我们只需要从本地加载数据库即可,无需再根据原始文档来生成向量数据库了。

失败的应用场景

虽然有了向量数据库,基本上可以让我们轻松完成 80% 的相似性搜索任务。但也存在一些失败的场景,比如下面的例子:

question = "what did they say about matlab?"

docs = vectordb.similarity_search(question,k=5)

这里我们要求向量数据库搜索5个和问题相关的答案,但是大家还记得之前我们在创建文档加载器时加载了两篇相同的文档(Lecture01.pdf),所以现在向量数据库中应该有重复的向量,因此如果当用户的问题和Lecture01.pdf中的内容相关时,向量数据库会返回重复的内容:

docs[0]

docs[1]

这两我们看到docs[0]和docs[1]的内容是完全一样的,这是因为我们之前加载了重复的文档(Lecture01.pdf)所导致的。如何避免让向量数据库返回重复的内容,我们将在下一篇博客中讨论这个问题,下面我们再看一种失败的场景,这里我们要求向量数据库在第三篇原始文档()中搜索相关答案:

question = "what did they say about regression in the third lecture?"

docs = vectordb.similarity_search(question,k=5)

for doc in docs:
    print(doc.metadata)


从上面的返回结果中我们看到,虽然我们要求向量数据库只能从第三篇文档中搜索相关答案,但是从返回结果的元数据中我们看到第一篇(Lecture01.pdf)和第二篇(Lecture02.pdf)的内容也在其中,这与我们的要求(问题)相违背,因为我们只要求搜索第三篇文档(Lecture03.pdf)即可。这似乎说明向量数据库并没有很好的理解问题的语义。下面我们查看一下返回的最后一个文档的内容(Lecture01.pdf):

print(docs[4].page_content)

这里我们看到docs[4]对应的是Lecture01.pdf中的第8页的内容,其中也包含了“regression”,这和我们的问题相关。

关于如何避免上述失效的应用场景,我们将会在下一篇博客中进行讨论。

总结

今天我们学习了嵌入和向量数据库的基本原理,并且对嵌入(Embeddings)和开源数据库Chroma进行了实际的操作,并观察了它们的返回结果,同时我们还发现了两种Chroma数据库相似搜索失效的场景。关于如何避免产生失效的结果我们将在下一篇文章中进行讨论。

如何学习大模型

现在社会上大模型越来越普及了,已经有很多人都想往这里面扎,但是却找不到适合的方法去学习。

作为一名资深码农,初入大模型时也吃了很多亏,踩了无数坑。现在我想把我的经验和知识分享给你们,帮助你们学习AI大模型,能够解决你们学习中的困难。

我已将重要的AI大模型资料包括市面上AI大模型各大白皮书、AGI大模型系统学习路线、AI大模型视频教程、实战学习,等录播视频免费分享出来,需要的小伙伴可以扫取。

一、AGI大模型系统学习路线

很多人学习大模型的时候没有方向,东学一点西学一点,像只无头苍蝇乱撞,我下面分享的这个学习路线希望能够帮助到你们学习AI大模型。

在这里插入图片描述

二、AI大模型视频教程

在这里插入图片描述

三、AI大模型各大学习书籍

在这里插入图片描述

四、AI大模型各大场景实战案例

在这里插入图片描述

五、结束语

学习AI大模型是当前科技发展的趋势,它不仅能够为我们提供更多的机会和挑战,还能够让我们更好地理解和应用人工智能技术。通过学习AI大模型,我们可以深入了解深度学习、神经网络等核心概念,并将其应用于自然语言处理、计算机视觉、语音识别等领域。同时,掌握AI大模型还能够为我们的职业发展增添竞争力,成为未来技术领域的领导者。

再者,学习AI大模型也能为我们自己创造更多的价值,提供更多的岗位以及副业创收,让自己的生活更上一层楼。

因此,学习AI大模型是一项有前景且值得投入的时间和精力的重要选择。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/783107.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【智能制造-11】X型焊枪和C型焊枪

手工焊枪分为X型焊枪和C型焊枪两种。 X焊枪中,气缸活塞杆与活动枪臂体之间以轴连接,气缸活塞做直线运动,焊枪臂绕转轴摆动,进行焊接。 C型焊枪中,气缸活塞杆与活动枪臂联动,进行直线往复运动,进…

简单实现联系表单Contact Form自动发送邮件

如何实现简单Contact Form自动邮件功能?怎样简单设置? 联系表单不仅是访客与网站所有者沟通的桥梁,还可以收集潜在客户的信息,从而推动业务的发展。AokSend将介绍如何简单实现一个联系表单,自动发送邮件的过程&#x…

声明一个类模板,利用它分别实现两个整数、浮点数和字符的比较,求出大数和小数

在之前的文章中曾介绍了函数模板,对于功能相同而数据类型不同的一些函数,不必定义各个函数,可以定义一个可对任何类型变量进行操作的函数模板,在调用函数时,系统会根据实参的类型,取代函数模板中的类型参数…

应用层协议原理——因特网提供的运输服务

我们已经考虑了计算机网络能够一般性地提供的运输服务。现在我们要更为具体地考察由因特网提供的运输服务类型。因特网(更一般的是TCP/IP网络)为应用程序提供两个运输层协议,即UDP和TCP。当软件开发者为因特网创建一个新的应用时,首先要做出的决定是&…

游戏AI的创造思路-技术基础-决策树(2)

上一篇写了决策树的基础概念和一些简单例子,本篇将着重在实际案例上进行说明 目录 8. 决策树应用的实际例子 8.1. 方法和过程 8.1.1. 定义行为 8.1.2. 确定属性 8.1.3. 构建决策树 8.1.4. 实施行为 8.1.5. 实时更新 8.2. Python代码 8. 决策树应用的实际例子…

大模型网信办备案全网最详细说明【+流程+附件】

根据目前公开的国内大模型算法备案统计来看,首批境内深度合成服务算法备案清单,总共通过41家,14家互联网大厂和独角兽企业成功申报算法备案32个,6家新兴互联网公司成功申报算法备案9个,仅占比21.9%。 第二批境内…

Python标准库常用模块的典型用法介绍与案例

目录 1. os模块 典型用法 案例 2. sys模块 典型用法 案例 3. datetime模块 典型用法 案例 4. re模块 典型用法 案例 5. json模块 典型用法 案例 6. random模块 典型用法 案例 7. collections模块 典型用法 案例 总结 Python作为一门功能强大的编…

控件-ProgressBar

常用属性 1.android:max:进度条的最大值 2. android: progress:进度条已完成进度值 3. android: indeterminate:如果设置成true,则进度条不精确显示进度 4.style"?android:attr/progressBarStyleHorizontal"水平进度条 案例 进度条加载

探索TXE、TC、RXNE标志位在串口通信中的轮询与中断应用

浅谈一下STM32串口中断之TXE,TC,RXNE标志位 之前做一个项目,用到了串口中断,但是对TXE、TC和RXNE标志位的作用和使用方法不是很清楚,导致在调试过程中遇到了一些问题。通过查阅相关资料和实际操作,我对这三个标志位有了更深入的了…

Python酷库之旅-第三方库Pandas(010)

目录 一、用法精讲 22、pandas.read_hdf函数 22-1、语法 22-2、参数 22-3、功能 22-4、返回值 22-5、说明 22-6、用法 22-6-1、数据准备 22-6-2、代码示例 22-6-3、结果输出 23、pandas.HDFStore.put方法 23-1、语法 23-2、参数 23-3、功能 23-4、返回值 23-5…

【数据分析】Pandas_DataFrame读写详解:案例解析(第24天)

系列文章目录 一、 读写文件数据 二、df查询数据操作 三、df增加列操作 四、df删除行列操作 五、df数据去重操作 六、df数据修改操作 文章目录 系列文章目录前言一、 读写文件数据1.1 读写excel文件1.2 读写csv文件1.3 读写mysql数据库 二、df查询数据操作2.1 查询df子集基本方…

2.5 C#视觉程序开发实例1----CamManager实现模拟相机采集图片

2.5 C#视觉程序开发实例1----CamManager实现模拟相机采集图片 1 目标效果视频 CamManager 2 CamManager读取本地文件时序 3 BD_Vision_Utility添加代码 3.0 导入链接库 BD_OperatorSets.dllSystem.Windows.Forms.dllOpencvSharp 3.1 导入VisionParam中创建的文件Util_FileO…

乡村振兴指数与其30个原始变量数据(Shp/Dta/Excel格式,2000-2022年)

数据简介:这份数据是我国各地级市乡村振兴指数与其30各原始变量数据并对其进行地图可视化表达。城镇化是当今中国社会经济发展的必由之路。当前我国城镇化处于发展的关键时期,但城镇化发展的加快却是一把双刃剑,为何要如此形容呢?因为当前城…

【04】微服务通信组件Feign

1、项目中接口的调用方式 1.1 HttpClient HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 Http 协议的客户端编程工具包,并且它支持 HTTP 协议最新版本和建议。HttpClient 相比传统 JDK 自带的 URLConnectio…

科研绘图系列:R语言径向柱状图(Radial Bar Chart)

介绍 径向柱状图(Radial Bar Chart),又称为雷达图或蜘蛛网图(Spider Chart),是一种在极坐标系中绘制的柱状图。这种图表的特点是将数据点沿着一个或多个从中心向外延伸的轴来展示,这些轴通常围绕着一个中心点均匀分布。 特点: 极坐标系统:数据点不是在直角坐标系中展…

AI时代还需要产品经理吗?需要什么样的?

在人工智能技术迅速发展的今天,我们不禁要思考,产品经理这个角色是否仍然重要?AI时代是否还需要他们? 很明确的说,需要!为什么呢? 首先,我们必须认识到,AI虽然具有强大…

如何理解李彦宏说的“不要卷模型,要卷应用”

如何理解李彦宏说的“不要卷模型,要卷应用” “大家不要卷模型,要卷应用”这句话的意思是,呼吁行业不要把过多的精力和资源投入到模型的研发竞争中,而是应该更加注重基于模型的应用开发。 李彦宏提出这一观点的原因主要有以下几点…

容联云发布容犀大模型应用,重塑企业“营销服”|WAIC 2024

7月6日,在2024世界人工智能大会上,容联云成功举办主题为“数智聚合 产业向上”的生成式应用与大模型商业化实践论坛。 论坛上,容联云发布了容犀智能大模型应用升级,该系列应用包括容犀Agent Copilot、容犀Knowledge Copilot、容犀…

PHP星座微信小程序系统源码

🌟每日星运,尽在掌握!星座微信小程序,你的专属星空指南✨ 🌈 一、每日运势,精准推送 想知道今天的你运势如何?星座微信小程序来告诉你!🔮 每天醒来,打开小程…

排座椅【详细代码题解】

[NOIP2008 普及组] 排座椅 题目描述 上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情。不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来之后,只有有限的 D D D 对同学上课时…