游乐游手机版
首页/AI热点日报/热点详情

吴恩达课程:大模型检索增强生成的向量数据库检索优化

类型:热点整理2026-06-28
前言 上一期我们聊完了文本数据的加载、切分,以及如何把这些碎片向量化并存入向量数据库。做完这些,前期的数据处理工作就算告一段落了——后续哪怕需要载入更多数据,重复相同的流程就行。在上节课最后,我们简单试了试用 similarity_search 在向量数据库里检索相关数据,这节课就来深入展开这部分内

前言

上一期我们聊完了文本数据的加载、切分,以及如何把这些碎片向量化并存入向量数据库。做完这些,前期的数据处理工作就算告一段落了——后续哪怕需要载入更多数据,重复相同的流程就行。在上节课最后,我们简单试了试用 similarity_search 在向量数据库里检索相关数据,这节课就来深入展开这部分内容。

吴恩达DeepLearning.AI课程系列 - 大模型检索增强生成(四):向量数据库中的检索优化

说到检索(Retrieval),除了最基础的 similarity_search(通过计算查询向量和所有候选文档向量的相似度来匹配),其实还有不少其他玩法,比如 Maximum Marginal Relevance(MMR,最大边际相关性)、利用 Metadata(元数据)进行过滤,以及 LLM Aided Retrieval(大模型辅助检索)等。下面就来逐一拆解。

Similarity Search 方法详解

Similarity Search(相似度搜索) 是向量数据库里最基础的检索方式。它的逻辑很直接:把用户的查询转成一个向量,然后跟数据库里所有文档向量算相似度,挑出最接近的那些。常用的相似度度量包括余弦相似度欧氏距离等,这些方法能有效衡量两个向量在高维空间里的“距离”。

打个比方,用户搜“深度学习的基本概念”,系统就会把这句话向量化,然后跟库里的向量比较,返回最匹配的文档片段。这种方法的优点就是简单直观,适合快速找到高度相关的结果。

不过,单纯依赖相似度搜索有一个明显的短板:结果容易缺乏多样性。因为它只盯着“跟查询像不像”,完全不管结果之间是不是重复或者相似过头。在一些需要覆盖多个不同方面的场景下,光靠相似度可能不够用——这时候就需要 Maximum Marginal Relevance (MMR) 这类方法登场,在相关性和多样性之间找到平衡。

Maximum Marginal Relevance 方法详解

在很多信息检索任务里,“最相似”并不总是最优答案。尤其是当用户的需求涉及多个侧面时,只挑最相似的那几个结果,很容易导致信息重复。为了解决这个问题,Maximum Marginal Relevance (MMR) 应运而生。它的核心思路是:在保证相关性的同时,尽量让返回的结果之间差异更大,从而提供更全面的信息。

MMR 方法的原理与动机

举个例子,用户问“Tell me about all-white mushrooms with large fruiting bodies”。如果只按相似度搜,很可能返回几个高度相似甚至重复的答案——虽然每个都跟查询相关,但并没有覆盖不同角度。MMR 要做的就是:不让结果扎堆,而是让它们互相补充

MMR 的思想本质上是“既要又要”:既要跟用户的问题高度相关,又要让结果之间有足够多的差异。这样一来,用户既能得到直接回答,又能看到不同维度的信息,比如具体细节和大局概述。

MMR 算法的工作流程

MMR 的具体流程可以通过下面的图来理解,这里逐步拆解一下主要步骤:

  1. 查询向量存储(Query the Vector Store):先把用户的查询转成向量,去向量库里匹配。每个文档片段都对应一个向量(通常由嵌入模型生成)。
  2. 选择最相似的 fetch_k 个响应:从库里挑出与查询最相似的前 k 个结果(基于余弦相似度等)。这一步保证了基础的相关性。
  3. 在这些候选里选 k 个最具多样性的结果:接着,MMR 会从刚选出的最相似结果中,再挑出 k 个彼此差异最大的。计算每对候选结果之间的相似度,偏好那些“不太像”的,从而增加信息覆盖面。

MMR 通过一个权重参数 λ 来调节相关性与多样性之间的比重。当 λ 接近 1 时,更偏向相似性;接近 0 时,更偏向多样性。实际应用时可以根据场景灵活调整。

MMR 的实际应用

MMR 在信息检索和推荐系统里用得很广,特别适合那些需要广泛覆盖信息的场景。比如搜索某个主题时,MMR 能同时返回具体细节和整体概述,帮助用户对这个主题形成更完整的理解。其实本质上它还是基于 similarity_search 的,只不过像大语言模型调整 temperature 一样,通过增加随机性来让结果更丰富——毕竟人类交流时也从来不会只有“最优解”这一种答案。

利用元数据提高检索精确度:基于自查询检索器的方法

在检索过程中,如何提高精度,尤其是在面对大量复杂文档时,是个关键问题。前面的 similarity_searchMaximum Marginal Relevance 已经能帮我们找到相似的文档,但有时仅靠相似度还不够精确,特别是当用户的查询带有明确的限定条件时。这时候元数据(Metadata)就派上用场了。

元数据是与每个文本片段绑定的上下文信息,比如来源文档、页码、作者、时间戳等。利用这些信息,可以精准限定检索范围。举个例子:当用户问“第三讲中提到的回归分析内容是什么”,我们当然不希望返回其他讲次的结果。很多向量数据库支持在检索时直接对元数据进行过滤,从而大幅提升准确性。

具体来说,对于上面那个问题,可以在 similarity_search 时加入一个过滤条件,比如指定 source 为 "docs/cs229_lectures/MachineLearning-Lecture03.pdf",这样就能确保只从第三讲的文档里找,不会被其他讲次干扰。

实战演练

接下来进入动手环节,看看如何在代码里实现这些检索方法。环境版本如下:

langchain                0.3.0
langchain-community      0.3.0
pypdf                    5.0.0
openai                   1.47.0
beautifulsoup4           4.12.3
chromadb                 0.5.15

首先,需要运行上一期(大模型检索增强生成(三):向量数据库及嵌入)的代码,在指定位置生成一个 Chroma 数据库。看到文件生成即表示数据库创建成功。

新建一个 retrieval.py 文件,写入以下代码来验证数据库是否正常。如果能打印出文档数量,就说明一切正常。

from langchain_community.embeddings import BaichuanTextEmbeddings
from langchain_chroma import Chroma

persist_directory = r'D:\langchain'
embeddings = BaichuanTextEmbeddings(baichuan_api_key="sk-xxx")  # 填入上期内容的百川 API Key

vectordb = Chroma(
    persist_directory=persist_directory,
    embedding_function=embeddings
)
print(vectordb._collection.count())

Similarity Search(相似度搜索)

先试试最基础的方法——Similarity Search。在刚才的代码基础上加上以下内容,向向量数据库提问:“大语言模型是怎么推理的?”

question = "大语言模型是怎么推理的?"
docs_ss = vectordb.similarity_search(question, k=2)
print(docs_ss[0].page_content[:100])
print(docs_ss[1].page_content[:100])

输出的结果与推理确实相关,第一部分是“现代循环神经网络”的目录结构,第二部分是“注意力机制”的目录结构。

# 第一部分
9. 现代循环神经网络
9.1. 门控循环单元(GRU)
9.2. 长短期记忆网络(LSTM)
9.3. 深度循环神经网络
9.4. 双向循环神经网络
9.5. 机器翻译与数据集
9.6. 编码器-解

# 第二部分
10. 注意力机制
10.1. 注意力提示
10.2. 注意力汇聚:Nadaraya-Watson 核回归
10.3. 注意力评分函数
10.4. Bahdanau 注意力
10.5. 多头注意力

Maximum Marginal Relevance (MMR)

接下来换成 MMR 试试效果:

question = "大语言模型是怎么推理的?"
docs_mmr = vectordb.max_marginal_relevance_search(question, k=2)
print(docs_mmr[0].page_content[:100])
print(docs_mmr[1].page_content[:100])

输出结果有点意思。终端先弹了一个警告,说默认请求 20 条结果,但数据库里总共才 18 条。而且虽然第一部分内容跟之前一样,第二部分却变成了一堆大学名称,跟推理完全无关——从这里能看出,加了随机性后,效果未必会更好

# 警告
Number of requested results 20 is greater than number of elements in index 18, updating n_results = 18

# 第一部分
9. 现代循环神经网络
9.1. 门控循环单元(GRU)
9.2. 长短期记忆网络(LSTM)
9.3. 深度循环神经网络
9.4. 双向循环神经网络
9.5. 机器翻译与数据集
9.6. 编码器-解

# 第二部分
Vardhman Maha veer Open University     
      Vietnamese-German University    
      Vignana Jyothi Institute        

要消除这个警告,需要加一个参数 fetch_k=8。这个参数告诉 MMR 先从数据库里取前 8 个最相似的文档作为候选,然后再从这 8 个里挑出 k=2 个多样性最好的结果。

docs_mmr = vectordb.max_marginal_relevance_search(question, k=2, fetch_k=8)
print(docs_mmr[0].page_content[:100])
print(docs_mmr[1].page_content[:100])

再次运行,警告消失了,但结果跟之前差不多。

9. 现代循环神经网络
9.1. 门控循环单元(GRU)
9.2. 长短期记忆网络(LSTM)
9.3. 深度循环神经网络
9.4. 双向循环神经网络
9.5. 机器翻译与数据集
9.6. 编码器-解
Vardhman Maha veer Open University     
      Vietnamese-German University    
      Vignana Jyothi Institute        

通过调整 fetch_k 的值,可以控制随机性的强弱。试试 fetch_k=2

docs_mmr = vectordb.max_marginal_relevance_search(question, k=2, fetch_k=2)
print(docs_mmr[0].page_content[:100])
print(docs_mmr[1].page_content[:100])

结果跟 Similarity Search 完全一样——因为候选池只有 2 个,MMR 没有多样化的空间,只能照单全收。

9. 现代循环神经网络
9.1. 门控循环单元(GRU)
9.2. 长短期记忆网络(LSTM)
9.3. 深度循环神经网络
9.4. 双向循环神经网络
9.5. 机器翻译与数据集
9.6. 编码器-解

10. 注意力机制
10.1. 注意力提示
10.2. 注意力汇聚:Nadaraya-Watson 核回归
10.3. 注意力评分函数
10.4. Bahdanau 注意力
10.5. 多头注意力

再试试 fetch_k=3

docs_mmr = vectordb.max_marginal_relevance_search(question, k=2, fetch_k=3)
print(docs_mmr[0].page_content[:100])
print(docs_mmr[1].page_content[:100])

结果有了变化:第二部分变成了书籍的目录(包括前言、安装、符号等)。因为候选池里出现了一个不同角度的文档,为了满足多样性要求,MMR 强行把这块内容塞进了结果。

9. 现代循环神经网络
9.1. 门控循环单元(GRU)
9.2. 长短期记忆网络(LSTM)
9.3. 深度循环神经网络
9.4. 双向循环神经网络
9.5. 机器翻译与数据集
9.6. 编码器-解
参考文献
Table Of Contents

前言
安装
符号

1. 引言
2. 预备知识
2.1. 数据操作
2.2. 数据预处理
2.3. 线性代数
2.4.

从这个实验可以看出,在 MMR 里调整 fetch_k 等参数可以控制输出的随机性和多样性。用得好,能显著提升检索效果。

元数据(Metadata)

更进一步,我们可以利用元数据做更精确的搜索。先看看数据库里有哪些元数据:

all_docs = vectordb.similarity_search("", k=18)  # 用空查询获取所有文档
for i, doc in enumerate(all_docs):
    print(f"Document {i+1} metadata: {doc.metadata}")

输出显示,所有文档的元数据都一样,因为都来自同一个网页链接:

"metadata": {
    "source": "https://zh.d2l.ai/",
    "language": "en",
    "title": "《动手学深度学习》 — 动手学深度学习 2.0.0 documentation",
}

为了演示元数据过滤,可以往数据库里添加另一个来源的文档。在上一期代码的基础上加上以下内容(注意运行前最好删掉原有数据库,否则会重复添加):

new_loader = WebBaseLoader("https://www.deeplearning.ai/")
new_docs = new_loader.load()
new_splits = text_splitter.split_documents(new_docs)
vectordb.add_documents(new_splits)
print(f"更新后的文档数量: {vectordb._collection.count()}")

运行后,文档数量从 18 变成了 20,说明新网页提供了两个片段。再次查看元数据,会发现多了两条来自 https://www.deeplearning.ai/ 的记录。

Document 8 metadata: {'description': 'DeepLearning.AI | Andrew Ng | Join over 7 million people...', 'source': 'https://www.deeplearning.ai/', ...}
Document 18 metadata: {'description': '...', 'source': 'https://www.deeplearning.ai/', ...}

现在,就可以通过指定 source 来过滤检索了:

question = "大语言模型是怎么推理的?"
docs_meta = vectordb.similarity_search(question, k=1, filter={"source": "https://www.deeplearning.ai/"})
print(docs_meta[0].page_content[:100])

结果只返回了 DeepLearning.AI 网页里的内容,与其他来源完全隔离。

prevnextIn Collaboration WithprevnextThe largest weekly AI newsletterWhat matters in AI right nowOct

本门课完整代码展示

main.py —— 前期准备

from langchain_community.document_loaders import WebBaseLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.embeddings import BaichuanTextEmbeddings
from langchain_chroma import Chroma

loader = WebBaseLoader("https://zh.d2l.ai/")
docs = loader.load()

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size = 1500,
    chunk_overlap = 150
)
splits = text_splitter.split_documents(docs)
print(len(splits))

embeddings = BaichuanTextEmbeddings(baichuan_api_key="sk-83842453061e34d80b392edba11f62fe")

persist_directory = r'D:\langchain'

vectordb = Chroma.from_documents(
    documents=splits,
    embedding=embeddings,
    persist_directory=persist_directory
)
print(vectordb._collection.count())

# 添加新文档
new_loader = WebBaseLoader("https://www.deeplearning.ai/")
new_docs = new_loader.load()
new_splits = text_splitter.split_documents(new_docs)
vectordb.add_documents(new_splits)
print(f"更新后的文档数量: {vectordb._collection.count()}")

retrieval.py —— 检索方法

from langchain_community.embeddings import BaichuanTextEmbeddings
from langchain_chroma import Chroma

persist_directory = r'D:\langchain'
embeddings = BaichuanTextEmbeddings(baichuan_api_key="sk-83842453061e34d80b392edba11f62fe")

vectordb = Chroma(
    persist_directory=persist_directory,
    embedding_function=embeddings
)

# question = "大语言模型是怎么推理的?"
# docs_ss = vectordb.similarity_search(question, k=2)
# print(docs_ss[0].page_content[:100])
# print(docs_ss[1].page_content[:100])

# docs_mmr = vectordb.max_marginal_relevance_search(question, k=2, fetch_k=3)
# print(docs_mmr[0].page_content[:100])
# print(docs_mmr[1].page_content[:100])

# all_docs = vectordb.similarity_search("", k=20)
# for i, doc in enumerate(all_docs):
#     print(f"Document {i+1} metadata: {doc.metadata}")

question = "大语言模型是怎么推理的?"
docs_meta = vectordb.similarity_search(question, k=1, filter={"source": "https://www.deeplearning.ai/"})
print(docs_meta[0].page_content[:100])

总结

这篇文章深入探讨了向量数据库中几种精准检索的方法:从基础的相似度搜索,到能平衡相关性与多样性的 Maximum Marginal Relevance (MMR),再到利用 元数据 进行精确过滤,以及结合 大语言模型 实现智能检索的思路。相似度搜索提供最直接的匹配,MMR 则通过调整参数让结果更丰富多样,而元数据过滤让我们能定向锁定特定来源的内容。实际应用中,根据场景灵活组合这些方法,才能让检索效果真正“聪明”起来。

来源:https://www.53ai.com/news/knowledgegraph/2025010414762.html

相关热点

继续查看同栏目近期热点。

延伸阅读

补充最近整理过的热点入口。