AI教程 2025年01月17日
0 收藏 0 点赞 230 浏览 1265 个字
摘要 :

面向开发者的LLM入门教程-向量数据库检索: 检索(Retrieval) 在构建检索增强生成 (RAG) 系统时,信息检索是核心环节。检索模块负责对用户查询进行分析,从知识库中快速……

哈喽!伙伴们,我是小智,你们的AI向导。欢迎来到每日的AI学习时间。今天,我们将一起深入AI的奇妙世界,探索“面向开发者的LLM入门教程-向量数据库检索”,并学会本篇文章中所讲的全部知识点。还是那句话“不必远征未知,只需唤醒你的潜能!”跟着小智的步伐,我们终将学有所成,学以致用,并发现自身的更多可能性。话不多说,现在就让我们开始这场激发潜能的AI学习之旅吧。

面向开发者的LLM入门教程-向量数据库检索

面向开发者的LLM入门教程-向量数据库检索:

检索(Retrieval)

在构建检索增强生成 (RAG) 系统时,信息检索是核心环节。检索模块负责对用户查询进行分析,从知识库中快速定位相关文档或段落,为后续的语言生成提供信息支持。检索是指根据用户的问题去向量数据库中搜索与问题相关的文档内容,当我们访问和查询向量数据库时可能会运用到如下几种技术:

· 基本语义相似度(Basic semantic similarity)
· 最大边际相关性(Maximum marginal relevance,MMR)
· 过滤元数据
· LLM辅助检索

面向开发者的LLM入门教程-向量数据库检索

使用基本的相似性搜索大概能解决你80%的相关检索工作,但对于那些相似性搜索失败的边缘情况该如何解决呢?这一章节我们将介绍几种检索方法,以及解决检索边缘情况的技巧,让我们一起开始学习吧!

向量数据库检索

本章节需要使用 lark 包,若环境中未安装过此包,请运行以下命令安装:

!pip install -Uq lark

1.相似性检索(Similarity Search)

以我们的流程为例,前面课程已经存储了向量数据库( VectorDB ),包含各文档的语义向量表示。首先将上节课所保存的向量数据库( VectorDB )加载进来:

from langchain.vectorstores import Chroma
from langchain.embeddings.openai import OpenAIEmbeddings
persist_directory_chinese = ‘docs/chroma/matplotlib/’
embedding = OpenAIEmbeddings()
vectordb_chinese = Chroma(
persist_directory=persist_directory_chinese,
embedding_function=embedding
)
print(vectordb_chinese._collection.count())

27

下面我们来实现一下语义的相似度搜索,我们把三句话存入向量数据库Chroma中,然后我们提出问题让向量数据库根据问题来搜索相关答案:

texts_chinese = [
“””毒鹅膏菌(Amanita phalloides)具有大型且引人注目的地上(epigeous)子实体
(basidiocarp)”””,
“””一种具有大型子实体的蘑菇是毒鹅膏菌(Amanita phalloides)。某些品种全白。”””,
“””A. phalloides,又名死亡帽,是已知所有蘑菇中最有毒的一种。”””,
]

我们可以看到前两句都是描述的是一种叫“鹅膏菌”的菌类,包括它们的特征:有较大的子实体,第三句描述的是“鬼笔甲”,一种已知的最毒的蘑菇,它的特征就是:含有剧毒。对于这个例子,我们将创建一个小数据库,我们可以作为一个示例来使用。

smalldb_chinese = Chroma.from_texts(texts_chinese, embedding=embedding)

100%|██████████| 1/1 [00:00<00:00, 1.51it/s]

下面是我们对于这个示例所提出的问题:

question_chinese = “告诉我关于具有大型子实体的全白色蘑菇的信息”

现在,让针对上面问题进行相似性搜索,设置 k=2 ,只返回两个最相关的文档。

smalldb_chinese.similarity_search(question_chinese, k=2)

[Document(page_content=’一种具有大型子实体的蘑菇是毒鹅膏菌(Amanita phalloides)。某些品
种全白。’, metadata={}),
Document(page_content=’毒鹅膏菌(Amanita phalloides)具有大型且引人注目的地上
(epigeous)子实体(basidiocarp)’, metadata={})]

我们现在可以看到,向量数据库返回了 2 个文档,就是我们存入向量数据库中的第一句和第二句。这里我们很明显的就可以看到 chroma 的 similarity_search(相似性搜索) 方法可以根据问题的语义去数据库中搜索与之相关性最高的文档,也就是搜索到了第一句和第二句的文本。但这似乎还存在一些问题,因为第一句和第二句的含义非常接近,他们都是描述“鹅膏菌”及其“子实体”的,所以假如只返回其中的一句就足以满足要求了,如果返回两句含义非常接近的文本感觉是一种资源的浪费。下面我们来看一下max_marginal_relevance_search 的搜索结果。

2.解决多样性:最大边际相关性(MMR)

最大边际相关模型 (MMR,Maximal Marginal Relevance) 是实现多样性检索的常用算法。

面向开发者的LLM入门教程-向量数据库检索

MMR 的基本思想是同时考量查询与文档的相关度,以及文档之间的相似度。相关度确保返回结果对查询高度相关,相似度则鼓励不同语义的文档被包含进结果集。具体来说,它计算每个候选文档与查询的相关度,并减去与已经选入结果集的文档的相似度。这样更不相似的文档会有更高的得分。

总之,MMR 是解决检索冗余问题、提供多样性结果的一种简单高效的算法。它平衡了相关性和多样性,适用于对多样信息需求较强的应用场景。

我们来看一个利用 MMR 从蘑菇知识库中检索信息的示例。首先加载有关蘑菇的文档,然后运行 MMR算法,设置 fetch_k 参数,用来告诉向量数据库我们最终需要 k 个结果返回。fetch_k=3 ,也就是我们最初获取 3 个文档,k=2 表示返回最不同的 2 个文档。

smalldb_chinese.max_marginal_relevance_search(question_chinese,k=2, fetch_k=3)

[Document(page_content=’一种具有大型子实体的蘑菇是毒鹅膏菌(Amanita phalloides)。某些品
种全白。’, metadata={}),
Document(page_content=’A. phalloides,又名死亡帽,是已知所有蘑菇中最有毒的一种。’,
metadata={})]

这里我们看到 max_marginal_relevance_search(最大边际相关搜索) 返回了第二和第三句的文本,尽管第三句与我们的问题的相关性不太高,但是这样的结果其实应该是更加的合理,因为第一句和第二句文本本来就有着相似的含义,所以只需要返回其中的一句就可以了,另外再返回一个与问题相关性弱一点的答案(第三句文本),这样似乎增强了答案的多样性,相信用户也会更加偏爱

还记得在上一节中我们介绍了两种向量数据在查询时的失败场景吗?当向量数据库中存在相同的文档时,而用户的问题又与这些重复的文档高度相关时,向量数据库会出现返回重复文档的情况。现在我们就可以运用Langchain的 max_marginal_relevance_search 来解决这个问题:

我们首先看看前两个文档,只看前几个字符,可以看到它们是相同的。

question_chinese = “Matplotlib是什么?”
docs_ss_chinese = vectordb_chinese.similarity_search(question_chinese,k=3)

print(“docs[0]: “)
print(docs_ss_chinese[0].page_content[:100])
print()
print(“docs[1]: “)
print(docs_ss_chinese[1].page_content[:100])

docs[0]:
第⼀回:Matplotlib 初相识
⼀、认识matplotlib
Matplotlib 是⼀个 Python 2D 绘图库,能够以多种硬拷⻉格式和跨平台的交互式环境⽣成出版物质量的
图形,⽤来绘制各种

docs[1]:
第⼀回:Matplotlib 初相识
⼀、认识matplotlib
Matplotlib 是⼀个 Python 2D 绘图库,能够以多种硬拷⻉格式和跨平台的交互式环境⽣成出版物质量的
图形,⽤来绘制各种

这里如果我们使用相似查询,会得到两个重复的结果,读者可以自己尝试一下,这里不再展示。我们可以使用 MMR 得到不一样的结果。

docs_mmr_chinese =
vectordb_chinese.max_marginal_relevance_search(question_chinese,k=3)

当我们运行 MMR 后得到结果时,我们可以看到第一个与之前的相同,因为那是最相似的。

print(docs_mmr_chinese[0].page_content[:100])

第⼀回:Matplotlib 初相识
⼀、认识matplotlib
Matplotlib 是⼀个 Python 2D 绘图库,能够以多种硬拷⻉格式和跨平台的交互式环境⽣成出版物质量的图形,⽤来绘制各种

但是当我们进行到第二个时,我们可以看到它是不同的。

它在回应中获得了一些多样性。

print(docs_mmr_chinese[1].page_content[:100])

By Datawhale 数据可视化开源⼩组
© Copyright © Copyright 2021.y轴分为左右两个,因此 tick1 对应左侧的轴; tick2 对应右侧的轴。
x轴分为上下两个

从以上结果中可以看到,向量数据库返回了 2 篇完全不同的文档,这是因为我们使用的是 MMR 搜索,它把搜索结果中相似度很高的文档做了过滤,所以它保留了结果的相关性又同时兼顾了结果的多样性。

3.解决特殊性:使用元数据

关于失败的应用场景我们还提出了一个问题,是询问了关于文档中某一讲的问题,但得到的结果中也包括了来自其他讲的结果。这是我们所不希望看到的结果,之所以产生这样的结果是因为当我们向向量数据库提出问题时,数据库并没有很好的理解问题的语义,所以返回的结果不如预期。要解决这个问题,我们可以通过过滤元数据的方式来实现精准搜索,当前很多向量数据库都支持对 元数据(metadata) 的操作:

metadata 为每个嵌入的块(embedded chunk)提供上下文。

question_chinese = “他们在第二讲中对Figure说了些什么?”

现在,我们以手动的方式来解决这个问题,我们会指定一个元数据过滤器 filter

docs_chinese = vectordb_chinese.similarity_search(
question_chinese,
k=3,
filter={“source”:”docs/matplotlib/第二回:艺术画笔见乾坤.pdf”}
)

接下来,我们可以看到结果都来自对应的章节

for d in docs_chinese:
print(d.metadata)

{‘source’: ‘docs/matplotlib/第二回:艺术画笔见乾坤.pdf’, ‘page’: 9}
{‘source’: ‘docs/matplotlib/第二回:艺术画笔见乾坤.pdf’, ‘page’: 10}
{‘source’: ‘docs/matplotlib/第二回:艺术画笔见乾坤.pdf’, ‘page’: 0}

当然,我们不能每次都采用手动的方式来解决这个问题,这会显得不够智能。下一小节中,我们将展示通过LLM来解决这个问题。

4.解决特殊性:在元数据中使用自查询检索器(LLM辅助检索)

在上例中,我们手动设置了过滤参数 filter 来过滤指定文档。但这种方式不够智能,需要人工指定过滤条件。如何自动从用户问题中提取过滤信息呢?

LangChain提供了SelfQueryRetriever模块,它可以通过语言模型从问题语句中分析出:
1. 向量搜索的查询字符串(search term)
2. 过滤文档的元数据条件(Filter)

以“除了维基百科,还有哪些健康网站”为例,SelfQueryRetriever可以推断出“除了维基百科”表示需要过滤的条件,即排除维基百科的文档。

它使用语言模型自动解析语句语义,提取过滤信息,无需手动设置。这种基于理解的元数据过滤更加智能方便,可以自动处理更复杂的过滤逻辑。

掌握利用语言模型实现自动化过滤的技巧,可以大幅降低构建针对性问答系统的难度。这种自抽取查询的方法使检索更加智能和动态。

其原理如下图所示:

面向开发者的LLM入门教程-向量数据库检索

下面我们就来实现一下LLM辅助检索:

from langchain.llms import OpenAI
from langchain.retrievers.self_query.base import SelfQueryRetriever
from langchain.chains.query_constructor.base import AttributeInfo

llm = OpenAI(temperature=0)

这里我们首先定义了 metadata_field_info_chinese ,它包含了元数据的过滤条件 source 和 page , 其中 source 的作用是告诉 LLM 我们想要的数据来自于哪里, page 告诉 LLM 我们需要提取相关的内容在原始文档的哪一页。有了 metadata_field_info_chinese 信息后,LLM会自动从用户的问题中提取出上中的 Filter 和 Search term 两项,然后向量数据库基于这两项去搜索相关的内容。下面我们看一下查询结果:

metadata_field_info_chinese = [
AttributeInfo(
name=”source”,
description=”The lecture the chunk is from, should be one of
`docs/matplotlib/第一回:Matplotlib初相识.pdf`, `docs/matplotlib/第二回:艺术画笔见乾
坤.pdf`, or `docs/matplotlib/第三回:布局格式定方圆.pdf`”,
type=”string”,
),
AttributeInfo(
name=”page”,
description=”The page from the lecture”,
type=”integer”,
),
]

document_content_description_chinese = “Matplotlib 课堂讲义”
retriever_chinese = SelfQueryRetriever.from_llm(
llm,
vectordb_chinese,
document_content_description_chinese,
metadata_field_info_chinese,
verbose=True
)

question_chinese = “他们在第二讲中对Figure做了些什么?”

当你第一次执行下一行时,你会收到关于predict_and_parse已被弃用的警告。 这可以安全地忽略。

docs_chinese = retriever_chinese.get_relevant_documents(question_chinese)

/root/autodl-tmp/env/gpt/lib/python3.10/sitepackages/langchain/chains/llm.py:275: UserWarning: The predict_and_parse method
is deprecated, instead pass an output parser directly to LLMChain.
warnings.warn(

query=’Figure’ filter=Comparison(comparator=,
attribute=’source’, value=’docs/matplotlib/第二回:艺术画笔见乾坤.pdf’) limit=None

打印可以看到查询结果,基于子查询检索器,我们检索到的结果都是在第二回的文档中:

for d in docs_chinese:
print(d.metadata)

{‘source’: ‘docs/matplotlib/第二回:艺术画笔见乾坤.pdf’, ‘page’: 9}
{‘source’: ‘docs/matplotlib/第二回:艺术画笔见乾坤.pdf’, ‘page’: 10}
{‘source’: ‘docs/matplotlib/第二回:艺术画笔见乾坤.pdf’, ‘page’: 0}
{‘source’: ‘docs/matplotlib/第二回:艺术画笔见乾坤.pdf’, ‘page’: 6}

5.其他技巧:压缩

在使用向量检索获取相关文档时,直接返回整个文档片段可能带来资源浪费,因为实际相关的只是文档的一小部分。为改进这一点,LangChain提供了一种“ 压缩 ”检索机制。其工作原理是,先使用标准向量检索获得候选文档,然后基于查询语句的语义,使用语言模型压缩这些文档,只保留与问题相关的部分。例如,对“蘑菇的营养价值”这个查询,检索可能返回整篇有关蘑菇的长文档。经压缩后,只提取文档中与“营养价值”相关的句子。

面向开发者的LLM入门教程-向量数据库检索

从上图中我们看到,当向量数据库返回了所有与问题相关的所有文档块的全部内容后,会有一个Compression LLM来负责对这些返回的文档块的内容进行压缩,所谓压缩是指仅从文档块中提取出和用户问题相关的内容,并舍弃掉那些不相关的内容。

from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor
def pretty_print_docs(docs):
print(f”n{‘-‘ * 100}n”.join([f”Document {i+1}:nn” + d.page_content for i,
d in enumerate(docs)]))
llm = OpenAI(temperature=0)
compressor = LLMChainExtractor.from_llm(llm) # 压缩器
compression_retriever_chinese = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=vectordb_chinese.as_retriever()
)
# 对源文档进行压缩
question_chinese = “Matplotlib是什么?”
compressed_docs_chinese =
compression_retriever_chinese.get_relevant_documents(question_chinese)
pretty_print_docs(compressed_docs_chinese)

Document 1:
Matplotlib 是⼀个 Python 2D 绘图库,能够以多种硬拷⻉格式和跨平台的交互式环境⽣成出版物质量的
图形,⽤来绘制各种静态,动态,交互式的图表。
———————————————————————————
——————-
Document 2:
Matplotlib 是⼀个 Python 2D 绘图库,能够以多种硬拷⻉格式和跨平台的交互式环境⽣成出版物质量的
图形,⽤来绘制各种静态,动态,交互式的图表。

在上面的代码中我们定义了一个 LLMChainExtractor ,它是一个压缩器,它负责从向量数据库返回的文档块中提取相关信息,然后我们还定义了 ContextualCompressionRetriever ,它有两个参数:base_compressor 和 base_retriever,其中 base_compressor 是我们前面定义的 LLMChainExtractor的实例,base_retriever是早前定义的 vectordb 产生的检索器。

现在当我们提出问题后,查看结果文档,我们可以看到两件事。
1. 它们比正常文档短很多
2. 仍然有一些重复的东西,这是因为在底层我们使用的是语义搜索算法。

从上述例子中,我们可以发现这种压缩可以有效提升输出质量,同时节省通过长文档带来的计算资源浪费,降低成本。上下文相关的压缩检索技术,使得到的支持文档更严格匹配问题需求,是提升问答系统效率的重要手段。读者可以在实际应用中考虑这一技术。

面向开发者的LLM入门教程-结合各种技术
面向开发者的LLM入门教程-结合各种技术:结合各种技术 为了去掉结果中的重复文档,我们在从向量数据库创建检索器时,可以将搜索类型...

嘿,伙伴们,今天我们的AI探索之旅已经圆满结束。关于“面向开发者的LLM入门教程-向量数据库检索”的内容已经分享给大家了。感谢你们的陪伴,希望这次旅程让你对AI能够更了解、更喜欢。谨记,精准提问是解锁AI潜能的钥匙哦!如果有小伙伴想要了解学习更多的AI知识,请关注我们的官网“AI智研社”,保证让你收获满满呦!

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.ai-blog.cn/2810.html

相关推荐
01-27

Kimi神级写作指令-充当正则表达式生成器的提示词: 正则表达式是不是让你又爱又恨?想匹配特定文本…

427
01-27

Kimi神级写作指令-充当数学家的提示词: 数学计算是不是让你头大?复杂的表达式、繁琐的步骤,是不…

230
01-27

Kimi神级写作指令-充当全栈软件开发人员的提示词: 想开发一个Web应用程序,却不知道从何下手?或…

230
01-27

Kimi神级写作指令-充当对弈棋手的提示词: 喜欢下棋但找不到对手?或者想提升棋艺却苦于没有合适的…

230
01-27

Kimi神级写作指令-作为专业DBA的提示词: 数据库查询是不是让你头大?写SQL语句时总是担心性能不够…

230
01-27

Kimi神级写作指令-作为项目经理的提示词: 项目管理是不是让你头大?进度拖延、任务混乱、团队沟通…

230
01-27

Kimi神级写作指令-作为 IT 专家的提示词: 电脑蓝屏、软件崩溃、网络连接失败……这些技术问题是不是…

230
01-27

Kimi神级写作指令-担任 SVG 设计师的提示词: 你是不是经常需要一些简单的图像素材,但又不想打开…

230
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力原创内容

快速提升站内名气成为大牛

扫描二维码

手机访问本站