如何为-AI-搜索选择-5-个最相关的文档
如何为 AI 搜索选择 5 个最相关的文档
原文:
towardsdatascience.com/how-to-select-the-5-most-relevant-documents-for-ai-search/
根据丰富 LLM 上下文与元数据的我的上一篇文章,我将写出这篇文章的主要目标:
我的目标是强调你如何获取和过滤 AI 搜索中最相关的文档。

这张图展示了传统的 RAG 流程。你从用户查询开始,使用嵌入模型对其进行编码。然后,你将这个嵌入与整个文档语料库的预计算嵌入进行比较。通常,文档被分成块,它们之间有一些重叠,尽管一些系统也只处理整个文档。在计算嵌入相似度后,你只保留最相关的 K 个文档,其中 K 是你自己选择的一个数字,通常在 10 到 20 之间。根据语义相似度获取最相关文档的步骤是今天文章的主题。在获取最相关文档后,你将它们与用户查询一起输入到 LLM 中,LLM 最后返回一个响应。图片由作者提供。
目录
-
为什么最优文档检索很重要?
-
传统方法
-
嵌入相似度
-
关键词搜索
-
-
获取更多相关文档的技术
-
召回率:获取更多相关文档
-
上下文检索
-
获取更多片段
-
为召回率重排序
-
-
精确度:过滤掉无关文档
-
为精确度重排序
-
LLM 验证
-
-
-
提高文档检索的益处
-
摘要
为什么最优文档检索很重要?
真正理解文档检索步骤为何对任何 RAG 管道如此关键非常重要。为了理解这一点,你还必须对 RAG 管道中的流程有一个大致的了解:
-
用户输入他们的查询
-
查询被嵌入,并计算查询与每个单独文档(或文档片段)之间的嵌入相似度
-
我们根据嵌入相似度检索最相关的文档。
-
最相关的文档(或片段)被输入到 LLM 中,并提示它根据提供的片段回答用户问题。

这张图突出了嵌入相似度的概念。在左侧,你有用户查询,“总结租赁协议”。这个查询被嵌入到文本下面的向量中。此外,在上中部的顶部,你有可用的文档语料库,在这个例子中是四个文档,所有这些文档都有预先计算的嵌入。然后我们计算查询嵌入与每个文档之间的相似度,并得出一个相似度。在这个例子中,K=2,所以我们向我们的 LLM 输入两个最相关的文档进行问答。图由作者提供。
现在有几个管道方面很重要。例如:
-
你使用哪种嵌入模型
-
你使用哪种 LLM 模型
-
你检索多少文档(或片段)
然而,我会争辩说,可能没有哪个方面比文档选择更重要。这是因为如果没有正确的文档,无论你的 LLM 有多好,或者你检索了多少片段,答案很可能是错误的。
模型可能使用稍微差一点的嵌入模型或稍微旧一点的 LLM。然而,如果你没有检索到正确的文档,你的 RAG 管道将无法工作。
传统方法
我首先会了解一些今天仍在使用的传统方法,主要使用嵌入相似度或关键词搜索。
嵌入相似度
使用嵌入相似度来检索最相关文档是目前的首选方法。这是一个在大多数用例中相当可靠的方法。使用嵌入相似度检索文档的 RAG 正如我上面所描述的那样。
关键词搜索
关键词搜索也常用于检索相关文档。传统的做法,如 TF-IDF 或 BM25,至今仍被成功使用。然而,关键词搜索也有其弱点。例如,它仅基于精确匹配来检索文档,当无法进行精确匹配时,这会引发问题。
因此,我想讨论一些你可以用来改进你的文档检索步骤的其他技术。
检索更多相关文档的技术
在本节中,我将讨论一些更高级的技术来获取最相关的文档。我将本节分为两部分。第一部分将涵盖优化文档检索以提高召回率,即从可用的文档语料库中尽可能多地获取相关文档。另一部分子节讨论如何优化精度。这意味着确保你获取的文档实际上对用户查询是正确且相关的。
召回:获取更多相关文档
我将讨论以下技术:
-
上下文检索
-
获取更多片段
-
重新排序
上下文检索

此图突出了上下文检索的流程。该流程包含与传统的 RAG 流程类似的基本元素,包括用户提示、向量数据库(DB)以及向 LLM 提示最相关的 K 个片段。然而,上下文检索还引入了一些新的元素。首先是 BM25 索引,其中所有文档(或片段)都为 BM25 搜索进行了索引。每次进行搜索时,我们都可以快速索引查询并按照 BM25 获取最相关的文档。然后,我们从 BM25 和语义相似度(向量数据库)中保留最相关的 K 个文档,并将这些嵌入组合起来。最后,我们像往常一样,将最相关的文档以及用户查询一起输入 LLM,并接收响应。图由作者提供。
上下文检索是 Anthropic 在 2024 年 9 月引入的一种技术。他们的文章涵盖了两个主题:向文档片段添加上下文以及将关键词搜索(BM25)与语义搜索相结合以获取相关文档。
为了向文档添加上下文,他们会对每个文档片段进行提示,给定的 LLM 根据片段和整个文档,重新编写片段以包含给定片段的信息和整个文档中的相关上下文。
例如,如果你有一个分为两个片段的文档。其中第一个片段包含重要的元数据,如地址、日期、位置和时间,而另一个片段包含关于租赁协议的信息。LLM 可能会重新编写第二个片段,以包含租赁协议和第一个片段中最相关的部分,在这种情况下是地址、位置和日期。
Anthropic 在其文章中也讨论了将语义搜索和关键词搜索相结合,本质上使用这两种技术获取文档,并采用优先级方法来组合从每种技术检索到的文档。
获取更多片段
获取更多相关文档的一个更简单的方法是简单地获取更多的片段。你获取的片段越多,获取相关片段的可能性就越高。然而,这有两个主要缺点:
-
你可能会得到更多不相关的片段(影响召回)
-
你将增加提供给你的 LLM 的标记数量,这可能会对 LLM 的输出质量产生负面影响
召回率重排
重排也是一种强大的技术,可以在检索与用户查询相关的文档时用来提高精确度和召回率。在基于语义相似度检索文档时,你会为所有块分配一个相似度分数,通常只保留最相似的 K 个块(K 通常在 10 到 20 之间,但根据不同的应用而有所不同)。这意味着重排器应尝试将相关文档放在最相关的 K 个文档中,同时将无关文档排除在相同的列表之外。我认为 Qwen Reranker 是一个好的模型;然而,也有许多其他重排器。
精确度:过滤掉无关文档
-
重排
-
LLM 验证
精确度重排
如上一节关于召回率的讨论所述,重排器也可以用来提高精确度。重排器通过将相关文档添加到最相关的文档的前 K 列表中来增加召回率。另一方面,重排器通过确保无关文档不进入最相关的文档前 K 列表来提高精确度。
LLM 验证
利用 LLM 判断块(或文档)的相关性也是一种强大的技术,可以用来过滤掉无关的块。你可以简单地创建一个如下所示的功能:
def is_relevant_chunk(chunk_text: str, user_query: str) -> bool:
"""
Verify if the chunk text is relevant to the user query
"""
prompt = f"""
Given the provided user query, and chunk text, determine whether the chunk text is relevant to answer the user query.
Return a json response with {
"relevant": bool
}
<user_query>{user_query}</user_query>
<chunk_text>{chunk_text}</chunk_text>
"""
return llm_client.generate(prompt)
然后你将每个块(或文档)通过这个函数,并只保留被 LLM 判断为相关的块或文档。
这种技术有两个主要的缺点:
-
LLM 成本
-
LLM 响应时间
你将发送大量的 LLM API 调用,这不可避免地会带来显著的成本。此外,发送这么多查询将花费时间,这会增加你的 RAG 管道的延迟。你应该平衡快速响应用户的需求。
改进文档检索的好处
在你的 RAG 管道中改进文档检索步骤有许多好处。以下是一些例子:
-
更好的 LLM 问答性能
-
减少幻觉
-
更经常能够正确回答用户的查询
-
实质上,这使得 LLM 的工作变得更简单
总体而言,你的问答模型在成功回答的用户查询数量方面将得到提升。这是我在评估你的 RAG 系统后推荐的指标,你可以在我的关于使用自动 LLM 评估评估五百万份文档的文章中了解更多关于 LLM 系统评估的内容。
减少幻觉也是一个极其重要的因素。幻觉是我们面临的最重要的问题之一。它们之所以有害,是因为它们降低了用户对问答系统的信任,这使得他们不太可能继续使用你的应用程序。然而,确保 LLM 既接收相关文档(精确度),又最大限度地减少无关文档的数量(召回率),对于减少 RAG 系统产生的幻觉数量是有价值的。
减少无关文档(精确度),也避免了上下文膨胀(上下文中的过多噪音)或甚至上下文中毒(在文档中提供错误信息)的问题。
摘要
在这篇文章中,我讨论了如何改进你的 RAG 管道的文档检索步骤。我首先讨论了我认为文档检索步骤是 RAG 管道中最重要的一部分,你应该花时间优化这一步骤。此外,我还讨论了传统 RAG 管道如何通过语义搜索和关键词搜索检索相关文档。继续讨论,我讨论了你可以利用的技术来提高检索文档的精确度和召回率,例如上下文检索和 LLM 块验证技术。
👉 我的免费电子书和网络研讨会:
👉 在社交平台上找到我:
📩 订阅我的通讯
🧑💻 取得联系
✍️ Medium

浙公网安备 33010602011771号