检索增强生成简易指南-全-
检索增强生成简易指南(全)
原文:
zh.annas-archive.org/md5/0ae5c3e21bf3980e558f5938d3586d4e译者:飞龙
前言
机器如何理解人类意图一直是我深感兴趣的主题。虽然我在 2007 年开始踏上 AI 和机器学习之旅,但直到 2016 年初,在构建一个虚拟数据分析师时,我对自然语言处理(NLP)产生了浓厚的兴趣。当谷歌在 2018 年发布 BERT 时,我坚信 NLP 正站在革命的边缘。
在 2022 年,随着 OpenAI 的 GPT-3 系列模型 text-davinci-002 的发布,我决定加入基于生成式 AI 的内容营销平台 Yarnit,构建应用的 AI 核心。我们的使命是创建一个平台,企业内容营销团队能够以高速、大规模和低成本生成营销资产——社交媒体帖子、博客、电子邮件等等,并且具有更高的准确性。很快,很明显,没有将品牌特定知识和对专有数据的访问纳入其中的生成模型无法有效地实现这一点。这一认识引导我探索检索增强生成(RAG)。
大型语言模型(LLMs)往往无法满足用户期望。虽然它们在存储和生成知识方面非常有效,但它们也容易产生幻觉——自信但错误的输出。这就是 RAG 提供突破的地方,它允许 LLMs 在生成响应之前检索相关、实时和事实信息。RAG 的美丽之处在于其概念简单性与实施细节的微妙结合。RAG 在克服 LLMs 核心限制方面的变革潜力,使得研究人员和实践者都保持着高度的兴趣。
当我开始研究 RAG 时,它还是一个相对未开发的领域。正式的学习资源很少,大部分知识都散布在博客、社交媒体帖子、研究论文和讨论论坛中。我在社交媒体平台和博客文章中分享了许多自己的发现。最终,将所有这些学习成果整合成一本综合书籍的想法逐渐成形。
为了创建一个简单、实用的资源,为构建基于大型语言模型(LLM)的应用的技术专业人士提供帮助,我在 2024 年中期开始着手编写这本书。随着时间的推移,它已经发展成一本关于检索增强生成(RAG)的基础指南,涵盖了广度和深度,同时通过清晰的解释和简单的 Python 代码确保了实际应用。
我坚信,RAG 是任何与 AI 应用工作的人必备的技能,而掌握它需要坚实的概念基础。这本书就是为了提供这样的基础而设计的。编写这本书是一次极其丰富的经历,我在其中学到了很多。我希望你们会发现它既启发人心又有趣味。
第一章:LLMs 和 RAG 的需求
本章涵盖
-
LLMs 的局限性和 RAG 的需求
-
RAG 基础知识
-
RAG 的流行用例
在短时间内,大型语言模型(LLMs)在现代语言处理任务和自主 AI 代理中得到了广泛应用。OpenAI 的 GPT、Anthropic 的 Claude、Google 的 Gemini 和 Meta 的 Llama 系列是值得注意的 LLMs,它们被集成到各种平台和技术中。检索增强生成(RAG)在 LLM 应用中发挥着关键作用,通过提高响应的准确性和相关性。根据 Grand View Research(mng.bz/BzKg),到 2023 年,全球 RAG 市场规模估计约为 10 亿美元,预计年增长率为 44.7%,这使得它成为增长最快的 AI 方法之一。
本书旨在揭示 RAG 及其应用的概念。章节逐一介绍 RAG 的定义、设计、实现、评估和演变。为了开篇,本章首先强调了 LLMs 的局限性以及需要像 RAG 这样的方法。然后介绍了 RAG 的概念,并逐步构建定义。本章最后列出了 RAG 带来的流行用例。
到本章结束时,你将获得对 RAG 系统组件进行更深入探索的基础知识。此外,你还应该
-
对 RAG 的定义要有深刻的理解。
-
理解 LLMs 的局限性和对 RAG 的需求。
-
准备深入了解 RAG 系统的组成部分。
2022 年 11 月 30 日将被铭记为人工智能领域的一个分水岭时刻。这是 OpenAI 发布 ChatGPT 的那一天,全世界都被它迷住了。ChatGPT 成为有史以来最快达到百万用户的 APP。在接下来的 12 个月里,对之前鲜为人知的术语如生成 AI 和 LLMs 的兴趣急剧上升(见图 1.1)。

AI 生成的内容可能是不正确的。(图片来源:trends.google.com)
图 1.1 “生成 AI”和“大型语言模型”的 Google 趋势图,时间范围从 2022 年 11 月到 2024 年 11 月。来源:作者根据trends.google.com的数据创建。
随着 ChatGPT 等平台的使用激增,LLMs 的弱点被暴露出来。
1.1 LLMs 的诅咒和 RAG 的概念
驱动 ChatGPT、Ask Gemini 和类似应用的 LLMs 已被证明可以存储知识。你可以向它们提问,它们往往会以看似正确的答案回应。然而,尽管它们在生成文本方面具有前所未有的能力,但它们的回答并不总是准确的。经过更仔细的观察,你可能会注意到 LLMs 的回应受到次优信息和固有的记忆限制的困扰。
为了理解局限性,我们将使用一个简单的例子。那些熟悉这项美妙运动板球的人会记得,2023 年男子 ODI 板球世界杯锦标赛在 2023 年举行。澳大利亚板球队获得了冠军。现在,想象你正在与 ChatGPT 互动,你问,“谁赢得了 2023 年板球世界杯?”实际上,你是在与 GPT-4o 或 o1 LLM 互动,这是 OpenAI 开发和维护的,为 ChatGPT 提供动力。在本章的前几节中,为了简单起见,我们将交替使用 ChatGPT 和 LLMs 这两个术语。所以,你提出问题,很可能会得到如图 1.2 所示的回答。

图 1.2 ChatGPT (GPT 3.5) response to the question, “Who won the 2023 Cricket World Cup?” Source: Screenshot of the author’s account on chat.openai.com.
ChatGPT does not have any memory of the 2023 Cricket World Cup, and it tells you to check the information from other sources. This is not ideal, but at least ChatGPT is honest in its response. The same question asked again might also provide a factually inaccurate result. Look at the response in figure 1.3. ChatGPT falsely responds that India was the winner of the tournament.

图 1.3 An example of hallucination. ChatGPT’s (GPT 3.5) inaccurate response to the question, “Who won the 2023 cricket World Cup?” Source: Screenshot of the author’s account on chat.openai.com.
这是有问题的。尽管 ChatGPT 没有关于 2023 年板球世界杯的记忆,但它仍然以一种看似自信的语气生成答案,但这是不准确的。这被称为“幻觉”,并且已经成为 LLMs 的主要批评点。
备注:在 2023 年 9 月,ChatGPT 的“使用 Bing 浏览”功能被引入,允许 ChatGPT Plus 用户从网络获取实时信息,以提供更准确和更新的回答。这是应用程序的一个功能,通过代理搜索和检索机制启用。底层 LLM 本身并不具有最新的信息。
许多用户将 LLM 视为信息来源,作为 Google Search 的替代品。在我们的例子中,我们也期待 ChatGPT(GPT 3.5 模型)能回答这个简单的问题。为什么 LLM 无法满足这一期望?
1.1.1 LLMs are not trained for facts
通常,LLMs 可以被视为一种下一个标记(大致上,下一个单词)预测模型。它们是学习了大量人类生成文本数据集的机器学习模型,寻找统计模式以复制类似人类的语言能力。
为了简化,首先想象模型被展示了一个句子,例如“老师教学生。”然后,我们隐藏这个句子的最后几个词(即,“教学生”),并询问模型下一个词应该是什么。模型应该学会预测下一个词是“教”,然后是“the”,以此类推。有各种方法来教授模型,包括因果语言模型(CLM)和掩码语言模型(MLM)。图 1.4 展示了这两种技术背后的理念。
训练数据可以包含数十亿种不同类型的句子。下一个标记(或词)是从训练数据中观察到的概率分布中选择。有不同方法和手段从已经计算过概率的标记中选择下一个标记。粗略地说,你可以假设词汇表中的所有词都计算了概率,并从中选择了一个高概率的词。图 1.5 展示了我们例子“老师 ____”的概率分布。选择“teaches”这个词是因为它的概率最高。其他词也可能被选中。
在这种情况下,模型只是在尝试按顺序预测一个词。LLMs 如何能够从它们训练的数据中存储知识,并以连贯和可理解的语言呈现这些知识(在大多数情况下)几乎是一种魔法。这种能力得益于一种基于称为“transformers”的注意力机制的神经网络架构。transformers 架构的细微差别以及从头开始构建 LLMs 是一个广泛的研究领域。这超出了本书的范围,但鼓励你了解更多关于 LLM 训练和 transformers 的信息。
返回到 LLMs 的局限性,它们的训练过程引入了三个主要的特点缺点。

图 1.4 两种标记预测技术:CLM 和 MLM。在 CLM 方法中,模型根据前面的标记预测下一个标记。在 MLM 中,模型根据前面的和后面的标记预测掩码标记。

图 1.5 “老师”之后的词语概率分布示意图
知识截止日期
训练一个 LLM 是一个昂贵且耗时的过程。训练一个 LLM 需要大量的数据,可能需要几周甚至几个月。因此,LLMs 训练的数据并不总是最新的。例如,OpenAI 的旗舰模型 GPT-4.1,于 2025 年 4 月发布,其知识只到 2024 年 6 月 1 日。在此知识截止日期之后发生的事件对模型是不可用的。
幻觉
观察发现,大型语言模型(LLM)有时会提供事实错误的信息。(我们可以在本章开头提到的 2023 年板球世界杯的例子中看到这一点。)尽管这些信息在事实上是错误的,但 LLM 的回答听起来却非常自信且合法。这种被称为“自信地撒谎”的特征,即幻觉,已被证明是 LLM 最大的批评之一。幻觉的原因可以追溯到 LLM 作为一个下一标记预测模型,它会从分布中选择最可能的单词。
知识限制
正如您已经看到的,LLM 已经在来自各种来源的大量数据上进行了训练,包括开放的互联网。然而,它们对非公开信息一无所知。LLM 没有在内部公司文件、客户信息、产品文档、机密人员信息等方面的信息上进行过训练。因此,不能期望 LLM 对任何关于它们的问题做出回应。
这种特征引发了关于这项技术普遍采用和价值的重要问题。但如果这些限制是 LLM 本质及其训练过程固有的,那么这是否意味着 LLM 作为技术不可用?
完全不是!现在让我们继续了解像 RAG 这样的方法是如何解决问题的。
1.1.2 什么是 RAG?
回想一下我们用来开始这次讨论的问题:“2023 年板球世界杯的获胜者是谁?”我们能做些什么来改善这个回答?
即使 ChatGPT 没有这个信息,世界(即互联网)对 2023 年板球世界杯的信息没有不确定性。如果你不知道,简单的谷歌搜索就会告诉你 2023 年板球世界杯的获胜者。关于 2023 年板球世界杯的维基百科文章(图 1.6)在开头部分就准确提供了这些信息。如果有一种方法可以告诉 LLM 关于这篇文章的维基百科信息。
你可能会问,我们如何将这个信息给 ChatGPT?答案是相当简单的。我们只需将这段文本连同我们的问题一起粘贴(见图 1.7)。
就这样!ChatGPT 现在给出了正确的答案。它能够理解我们提供的额外信息,提炼关于锦标赛获胜者的信息,并给出精确且事实准确性的回答。
这个例子可能看起来很幼稚,但以过于简化的方式,它说明了 RAG 的基本概念。让我们回顾一下我们在这里做了什么。我们理解这个问题是关于 2023 年板球世界杯的获胜者。我们搜索了关于这个问题的信息,并确定了维基百科作为信息来源。然后我们复制了这些信息,并将其与原始问题一起传递给了 ChatGPT(以及它背后的 LLM)。从某种意义上说,我们增加了 ChatGPT 的知识。作为一种技术,

图 1.6 2023 年板球世界杯的维基百科文章。来源:mng.bz/yN4J。

图 1.7 ChatGPT(GPT 3.5)对问题的响应,增加了外部上下文。来源:作者在 chat.openai.com 的账户截图)。
RAG 以编程方式做同样的事情。它通过提供先前未知的信息来克服 LLM 的局限性,从而增强系统的整体记忆。
正如其名所示,“检索增强生成”(RAG)可以通过以下三个步骤来解释:
-
它从 LLM 外部的数据源(在我们的例子中是维基百科)检索相关信息。
-
它通过添加外部信息来增强LLM 的输入。
-
最后,LLM 生成的结果更加准确。
RAG 的简单定义,如图 1.8 所示,可以如下所示:
检索增强生成是从外部来源检索相关信息的技术,通过将外部信息添加到 LLM 的输入中,从而使得 LLM 能够生成一个上下文相关、可靠且事实准确的反应。

图 1.8 RAG(简单定义):信息检索、查询增强以及使用 LLM 生成形成 RAG 的三个焦点
我们迄今为止所看到的例子过于简化。我们手动搜索外部信息,而且搜索仅针对这个问题。在实践中,所有这些过程都是自动化的,这使得系统可以扩展到各种查询和数据源。我们现在将进一步阐述这个想法。
1.2 RAG 的新颖性
主要思想是为 LLM 提供额外的上下文或知识。本质上,这意味着创建一个具有三个主要目标的 ChatGPT 类似系统:
-
使 LLM 能够响应最新信息。
-
使大型语言模型(LLM)能够响应事实准确的信息。
-
使 LLM 了解专有信息。
可以使用不同的技术来实现这些目标。可以从头开始训练一个新的 LLM,其中包括新的数据。也可以使用额外的数据对现有模型进行微调。然而,这两种方法都需要大量的数据和计算资源。此外,定期用新信息更新模型成本高昂。
RAG 是一种更便宜、更有效、更动态的技术,用于实现三个目标。LLM 以最新和事实准确的信息响应,并且它们了解专有信息,因此没有知识空白。
1.2.1 RAG 的发现
在一篇题为“用于知识密集型 NLP 任务的检索增强生成”(arxiv.org/abs/2005.11401)的论文中,帕特里克·刘易斯和他的合著者探讨了 RAG 模型的配方,这些模型结合了用于语言生成的预训练“参数”和“非参数”记忆。让我们关注一下“参数”和“非参数”这两个术语。
在机器学习的术语中,参数指的是模型在训练过程中学习的模型权重或变量。简单来说,它们是模型调整以执行分配任务的设置或配置。对于语言生成,大型语言模型(LLMs)经过数十亿参数的训练(据传闻 GPT 4 模型拥有超过 1000 亿参数,最大的 Llama 3 模型有 4050 亿参数)。LLM 保留其训练信息的能力完全基于其参数。因此,可以说 LLMs 在其参数中存储了事实信息。LLM 的内部记忆被称为“参数记忆”。参数记忆是有限的,它取决于参数的数量,并且是 LLM 所训练数据的一个因素。
相反,我们可以向 LLM 提供其参数记忆中不存在的信息。在板球世界杯的例子中,我们看到当我们向 ChatGPT 提供外部来源的信息时,它能够摆脱幻觉。这种对 LLM 来说是外部信息但可以提供给 LLM 的信息被称为“非参数”。如果我们能够根据需要从外部来源收集信息并将其与 LLM 一起使用,它就形成了系统的“非参数”记忆。在上述论文中,刘易斯和他的合著者存储了维基百科数据,并使用检索器访问信息。他们证明了这种 RAG 方法在生成更具体、多样和事实性的语言方面优于仅参数的基线。我们将在第三章和第四章中讨论向量数据库和检索器。
到 2025 年,RAG 已成为 LLM 领域最常用的技术之一。随着非参数记忆的加入,LLM 的回答更加贴近事实。让我们讨论 RAG 的优势。
1.2.2 RAG 如何帮助?
随着非参数记忆的引入,LLM 不再局限于其内部知识。至少从理论上讲,我们可以得出结论,这种非参数记忆可以扩展到我们想要的程度。它可以存储任何数量的专有文档或数据,并访问各种来源,如内网和公开互联网。从某种意义上说,通过 RAG,我们打开了将无限知识添加到 LLM 的可能性。创建这种非参数记忆或知识库总需要一些努力,我们将在稍后详细探讨。第三章专门讨论非参数知识库的创建。
由于克服了参数化内存有限的挑战,RAG 还增强了用户对 LLM 响应的信心。RAG 的三个优点如下:
-
深度上下文意识—添加的信息有助于 LLM 生成上下文适当的响应,用户可以相对更有信心。例如,如果非参数化内存包含有关特定公司产品的信息,用户可以确信 LLM 将从提供的来源生成有关这些产品的响应,而不是从其他地方。
-
来源引用—除了上下文意识外,由于信息是从已知来源检索的,这些来源可以在响应中引用。这使得响应更加可靠,因为用户可以选择从来源验证信息。
-
较少的幻觉—通过上下文意识,LLM 响应中出现事实不准确性的倾向大大减少。在 RAG 系统中,LLM 的幻觉更少。
我们已经看到了一个简单的 RAG 定义。现在让我们扩展这个定义:
生成式检索增强是通过对显式非参数化内存的访问来增强 LLM 参数化内存的方法论方法,检索器可以从其中检索相关信息,将信息增强到提示中,然后将提示传递给 LLM,以使 LLM 能够生成上下文相关、可靠且事实准确的响应。
这个定义在图 1.9 中得到了说明。
RAG 在 LLM 驱动的应用的传播和接受中起到了催化剂的作用。在结束本章并进入 RAG 系统的设计之前,让我们看看一些 RAG 被采用的流行用例。

人工智能生成的内容可能是错误的。
图 1.9 RAG 通过创建对非参数化内存的访问来增强 LLM 的参数化内存。
1.3 流行的 RAG 应用场景
RAG 不仅仅是一个理论概念,它是一种与 LLM 技术本身一样流行的技术。软件开发商自 2018 年 Google 发布 BERT 以来就开始使用语言模型。如今,有成千上万的应用程序使用 LLM 来解决语言密集型任务。每当您遇到使用 LLM 的应用程序时,它通常会在某种形式下拥有一个内部 RAG 系统。常见应用将在以下章节中描述。
1.3.1 搜索引擎体验
传统搜索结果以按相关性排序的页面链接列表形式显示。现代搜索引擎整合 RAG,将实时信息检索与生成式答案相结合。谷歌的搜索生成体验(SGE)通过相关结果和引文增强查询。基于 AI 的搜索引擎,如 Perplexity.ai 和 ChatGPT 的搜索,建立在 RAG 框架之上,该框架检索最新的网络信息,然后生成带有来源的响应。通过将答案建立在实时结果之上,这些搜索引擎提供了比独立 LLM 更准确、有来源支持的答案。
1.3.2 个性化营销内容生成
最广泛的应用 LLM 可能是内容生成。内容创作工具使用 RAG 来根据当前数据和用户特定上下文定制营销文案。例如,Yarnit 使用 RAG 根据最新信息和用户输入生成营销文案、博客文章和其他内容类型。在撰写文本的同时,Yarnit 可以引入新鲜事实或趋势材料,确保输出内容的相关性和事实性。通过在生成时引入正确的信息(例如,品牌风格指南或最新统计数据),这些平台能够产生与受众产生共鸣的个性化、品牌化的营销内容。
1.3.3 实时事件解说
想象一个体育赛事或新闻事件。检索器可以通过 API 连接到实时更新/数据,并将这些信息传递给 LLM 以创建虚拟解说员。这些还可以通过文本到语音模型进行增强。一个典型的例子是 IBM 的 Watson AI 在美网上的应用——它通过引入实时比赛数据和数千篇新闻文章来生成音频和文本形式的网球解说。这种 RAG 方法允许 Watson 在叙述时提及球员统计数据、交锋记录和比赛亮点,从而即时创建基于事实的解说。在金融市场,供应商正在做类似的事情——彭博社的 AI 驱动工具使用 RAG 将他们的洞察建立在最新的专有数据上。彭博社的平台明确采用 RAG 框架,以确保任何生成式输出(市场摘要、交易员查询的答案等)都是基于最新的权威内容,而不是仅仅基于模型的记忆。
1.3.4 对话式代理
使用 RAG,LLM 可以被定制为产品/服务手册、领域知识、指南等,并可作为支持代理,解决用户投诉和问题。这些代理还可以根据查询的性质将用户路由到更专业的代理。几乎所有的基于 LLM 的网站或内部工具的聊天机器人都使用了 RAG。Intercom 的 Fin AI 代理是一个值得注意的例子——它被特别设计为具有“定制和增强”的 RAG 架构,可以从公司的支持内容中生成答案。像 Zendesk 这样的支持平台通过检索帮助中心文章来回答客户查询,遵循类似的模式。行业观察家指出,这些公司使用基本的 RAG 快速检索相关的支持文档,并从中生成定制的响应。
1.3.5 文档问答系统
如前所述,LLM(大型语言模型)的一个局限性是它们无法访问专有非公开信息,例如产品文档、客户档案以及特定于组织的类似信息。一旦能够访问这些专有文档,RAG(检索增强生成)系统就变成了一种智能 AI 系统,能够回答有关组织的所有问题。例如,在法律领域,研究人员强调,特定领域的 RAG 能够使法律研究工具提供更加细致和可靠的答案。一个法律问答系统可以检索相关案例法或法规,并将这些内容输入到 LLM 中回答问题,确保答案引用了正确的先例。这种技术是诸如 ROSS Intelligence 等产品核心,旨在通过从法律数据库中检索段落来回答律师的查询,然后生成答案。更普遍地,企业知识管理正在被 RAG 所改变——公司不再依赖于 LLM 有限的训练数据,而是可以配备 AI 助手即时搜索内部文档、维基或手册。
1.3.6 虚拟助手
虚拟个人助手,如 Siri、Alexa 等,开始使用 LLM 来增强用户体验。结合 RAG 提供的更多用户行为上下文,这些助手将变得更加个性化。例如,亚马逊下一代 Alexa 集成了检索技术,因此它能够回答超出其核心训练的信息。通过将检索到的事实添加到语音助手答案中,RAG 帮助虚拟助手如 Alexa 和 Google Assistant 为用户查询提供更加准确和最新的答案。
1.3.7 AI 驱动的研发
人工智能代理在法律和金融等研究密集型领域越来越受欢迎。RAG 被广泛用于检索和分析案例法,以协助律师。许多投资组合管理公司正在引入 RAG 系统,以分析大量文件来研究投资机会。ESGReveal 是由阿里巴巴集团的研究人员开发的一个框架,它使用 RAG 从企业报告中提取和评估环境、社会和治理(ESG)数据。
1.3.8 社交媒体监控和情感分析
分析社交媒体数据洪流是 RAG 适用的另一个任务。例如,Brandwatch 这样的社交媒体监听平台使用生成式 AI 从数百万条帖子中总结趋势和情感,但他们将这些总结建立在底层数据之上。Brandwatch 的系统扫描超过 1 亿个来源,然后其生成式 AI 集成将数据转换为用户易于理解的摘要。
1.3.9 新闻生成和内容编辑
新闻机构一直在使用 RAG 来自动化和协助新闻写作,同时保持准确性。例如,路透社提供了一种解决方案,将受信任的新闻数据输入到生成模型中,以便它们产生基于事实的输出。通过使用路透社的实时新闻源作为检索来源,一个 AI 系统可以生成新闻摘要或用最新的核实事实来回答问题。路透社声称,这种方法通过 RAG 系统从最新的路透社故事中提取可信事实,保持了答案的可靠性和准确性。美联社(AP)在自动化新闻方面也是一个先驱:AP 多年来一直使用模板和数据来自动生成体育综述和收益报告,现在,随着生成式 AI 的出现,他们正在用 LLMs 增强这些系统。多亏了 RAG,一个 AI 作家可以摄取比分数据或财务结果,然后生成一篇可读的文章,将每个陈述都建立在提供的数据之上。
这些只是少数精选示例。RAG 在其他领域如客户支持自动化、金融市场洞察、医疗诊断、法律文件起草、学习系统和供应链优化等方面也得到了广泛的应用。
这章介绍了 RAG 概念。RAG 通过向系统提供非参数化知识库的访问,克服了 LLMs(大型语言模型)的限制,从而解决这些挑战。在下一章中,我们基于对 RAG 的基础理解,通过研究其设计中的不同组件,迈出了理解 RAG 系统构建的第一步。
摘要
-
RAG 通过提供访问外部信息来增强 LLMs 的记忆能力。
-
LLMs 是训练在大量文本数据上以生成类似人类文本的下一词(或标记)预测模型。
-
LLMs 面临着知识截止日期和仅基于公共数据进行训练的挑战。它们也容易生成事实错误的信息(即,产生幻觉)。
-
RAG 通过整合非参数记忆克服了 LLM 的限制,并提高了响应的上下文意识和可靠性。
-
RAG 的常见应用场景包括搜索引擎、文档问答系统、对话机器人、个性化内容生成、虚拟助手等等。
第二章:RAG 系统和它们的设计
本章涵盖
-
RAG 系统的概念和设计
-
索引管道概述
-
生成管道概述
-
对 RAG 评估的初步了解
-
对 RAG 操作堆栈的概述
第一章探讨了检索增强生成(RAG)背后的核心原则以及它解决的大语言模型(LLM)挑战。要构建一个 RAG 系统,需要组装几个组件。这个过程包括创建和维护系统的非参数记忆,或知识库。另一个管道通过将提示发送到 LLM 并从中接受响应来促进实时交互,其中检索和增强步骤位于中间。评估是另一个关键组件,确保系统的有效性和准确性。所有这些组件都由操作堆栈的各个层级支持。
第二章讨论了 RAG 系统的设计,检查涉及的步骤和需要两个不同的管道。我们将创建知识库的管道称为“索引管道”。允许与 LLM 进行实时交互的另一个管道将被称为“生成管道”。我们将讨论它们的各个组件,如数据加载、嵌入、向量存储、检索器等。此外,我们将了解如何进行 RAG 系统的评估,并介绍为这些系统提供动力的 RAG 操作(RAGOps)堆栈。
本章将介绍将在后续章节中详细讨论的各种组件。到第二章结束时,你将深入理解 RAG 系统的组件,并准备好深入研究不同的组件。到本章结束时,你应该
-
能够理解 RAG 系统设计的几个组成部分。
-
为更深入地探索索引管道——生成管道、RAG 评估方法和 RAGOps 堆栈做好准备。
2.1 RAG 系统看起来是什么样子?
到目前为止,我们已经了解到 RAG 是使用 LLM 来解决其用例的系统的一个关键组件。但是,这个系统是什么样的呢?为了说明,让我们回顾一下第一章开头使用的例子(“2023 年板球世界杯冠军是谁?”)并概述我们采取的步骤,以使 ChatGPT 能够为我们提供准确的回答。
第一步是提出问题本身:“2023 年板球世界杯冠军是谁?”随后,我们手动在互联网上搜索可能包含问题答案信息的来源。我们找到了一个(在我们的例子中是维基百科)并从中提取了一段相关的段落。随后,我们将相关的段落添加到我们的原始问题中,将问题和检索到的段落一起粘贴到 ChatGPT 的提示中,并得到了一个事实正确的回答:“澳大利亚赢得了 2023 年板球世界杯。”
这个过程可以提炼为五个步骤,我们的系统需要促进所有这些步骤:
-
用户提出问题。
-
系统搜索与输入问题相关的信息。
-
从输入问题中检索或获取与信息相关的信息,并将其添加到输入问题中。
-
这个问题和信息被传递给一个大型语言模型(LLM)。
-
LLM 以上下文答案的形式响应。
如果你还记得,我们已经在第一章中描述了这一过程。让我们在图 2.1 的上下文中可视化这一过程。这个工作流程将被称为“生成管道”,因为它生成答案。

图 2.1 生成管道覆盖了五个 RAG 步骤。从查询到响应的旅程涉及搜索和检索、增强和生成。
这个管道允许与 LLM 进行实时上下文交互。当然,创建生成管道所需的五个步骤中都有一些复杂性。需要就检索器和 LLM 的选择做出一些决定。提示语的构建也会影响响应的质量。我们将在第三章讨论提示语的构建。在建立这个生成管道之前,我们首先必须解决一个关键的前置步骤。为此,需要回答一些关于信息外部来源的关键问题。我们还需要提前知道在哪里查找,然后与所有这些不同的来源建立连接:
-
信息外部来源的位置在哪里?
-
是开放的互联网吗?还是公司内部数据存储中有一些文档?信息是否存在于某些第三方数据库中?我们想要使用多个来源的信息吗?
-
为什么这很重要?
-
-
源信息性质是什么?
-
这些是 Word 文档还是 PDF 文件?访问信息是通过 API 进行的吗?响应格式是 JSON 吗?我们将在一个文档中找到答案,还是信息分布在多个文档中?
-
为什么这很重要?
-
我们还需要了解数据存储的格式和性质,以便能够从源文件中提取信息。
当数据存储在多个来源,如互联网和内部数据湖时,系统必须连接到每个来源,以各种格式搜索相关信息,并根据原始查询对其进行组织。每次提问时,都需要重复连接、提取和解析的过程。来自不同来源的信息可能导致事实上的不一致,这些不一致需要实时解决。搜索所有信息可能非常耗时。因此,这将被证明是一个高度次优、不可扩展的过程,可能无法产生期望的结果。如果来自不同来源的信息
-
收集在一个单独的位置。
-
存储在单一格式中。
-
将其分解成小块的信息。
统一知识库的需求源于外部数据源的不同性质。为了满足这一需求,我们需要采取一系列步骤来创建和维护一个结构良好的知识库。这又是一个五步的过程:
-
连接到之前确定的外部来源。
-
从文档中提取文档并解析文本。
-
将长篇文本分解成更小、更易于管理的部分。
-
将这些小部分转换成合适的格式。
-
存储这些信息。
这些步骤,这些步骤有助于创建这个知识库,构成了索引管道。索引管道如图 2.2 所示。
除了创建知识库外,索引管道在维护和更新它以保持其相关性和准确性方面也起着至关重要的作用。在索引管道创建知识库之前,生成管道没有地方可以搜索信息。是索引管道为生成管道的后续操作奠定了基础。因此,设置索引管道是在激活生成管道之前。
这些管道共同构成了 RAG 系统的骨架,使用户能够无缝交互,并交付上下文相关的响应。图 2.3 显示了索引和生成管道共同工作,形成 RAG 系统的骨架。
我们已经建立了一个包含两个管道的 RAG 系统的流程。从概念上讲,这是完整的流程。然而,为了构建用于现实世界的系统,还需要更多的组件。下一节将重新构想这个流程以及其他考虑因素,并为 RAG 系统设计一个方案。

图 2.2 覆盖创建 RAG 知识库步骤的索引管道。这包括连接到源,解析,分割,转换和存储信息。

图 2.3 索引和生成管道共同构成一个 RAG 系统。索引管道是一个离线过程,而生成管道则促进与知识库的实时交互。
2.2 RAG 系统的设计
我们看到了 RAG 系统是如何通过索引和生成管道创建的。这两个管道本身也包含几个部分。像所有软件应用一样,生产就绪的 RAG 系统需要的不仅仅是基本组件。我们需要考虑准确性、可观察性、可扩展性和其他重要因素。本书详细讨论了这些组件。图 2.4 展示了 RAG 系统的一个大致布局。除了索引和生成组件外,我们还将添加基础设施、安全、评估等层。

图 2.4 生产就绪的 RAG 系统组件
让我们看看 RAG 系统的主要组件。前四个组件完成了索引管道:
-
数据加载组件—连接到外部源,提取和解析数据
-
数据拆分组件—将大块文本拆分成更小、更易于管理的部分
-
数据转换组件—将文本数据转换为更合适的格式
-
存储组件—存储数据以创建系统的知识库
下面的三个组件完成了生成管道:
-
检索器—负责从存储中搜索和获取信息
-
LLM 设置—负责生成对输入的响应
-
提示管理—允许增强检索到的信息以匹配原始输入
评估组件在部署前后测量系统的准确性和可靠性。监控组件跟踪 RAG 系统的性能并帮助检测故障。其他组件包括缓存,有助于存储先前生成的响应以加快类似查询的检索;护栏,以确保符合政策、法规和社会责任;以及安全,以保护 LLM 免受如提示注入、数据中毒等攻击。所有层都由服务基础设施支持。
所有这些组件都由一个中央编排层管理和控制,该层负责它们的交互和顺序。它提供了一个统一的接口来管理和监控工作流程和过程。
在我们深入探讨后续章节之前,以下章节提供了这些组件的概述。
2.3 索引管道
我们讨论了索引管道如何促进实时生成管道中使用的知识库的创建。从实际应用的角度来看,索引管道是一个离线或异步管道。这意味着当用户提问时,索引管道不会实时激活。相反,它预先创建知识库并在预定义的时间间隔更新它。索引管道由四个主要组件组成,如图 2.5 所示。

图 2.5 索引管道的四个组件有助于知识库的创建。
让我们更深入地探讨每个部分:
-
数据拆分(文本拆分**)——*将文本拆分成更小的片段可以增强系统高效处理和分析信息的能力。在自然语言处理(NLP)术语中,这些较小的片段通常被称为“块”。将大型文本文档拆分成更小块的过程称为“分块”。我们将在第三章中讨论分块的需求和各种分块策略。
-
数据转换(嵌入**)——*在 RAG 系统中,文本数据必须转换为数值格式,以便进行搜索和检索计算。有几种实现这种转换的方法。从所有实际目的来看,一种称为“嵌入”的数据格式最适合搜索和检索。你将在第三章中了解更多关于嵌入和不同嵌入模型的内容。
-
数据存储——*一旦数据以所需格式(嵌入)准备好,就需要将其存储在持久(永久)内存中,以便实时生成管道在用户提问时随时访问数据。数据存储在称为“向量数据库”的专用数据库中,这些数据库最适合搜索和检索嵌入。第三章将探讨各种向量数据库及其对 RAG 系统的适用性影响因素。
你是否总是需要索引管道?
离线索引管道通常用于构建大量数据的知识库,以便重复使用(例如,许多企业文档、手册等)。然而,在某些情况下,生成管道连接到第三方 API 以接收与用户问题相关的信息。
例如,想象一个为寻求基于天气预报的旅行建议的用户构建的应用程序。该应用程序的一个重要组成部分将是获取用户位置的天气详情。假设系统使用第三方 API 服务,当提供输入中的位置时,可以响应位置天气详情。然后,这些天气信息被传递给 LLM 以生成建议。
这个应用程序也可以被视为一个 RAG 系统。但有一个区别。这个系统将搜索和检索操作外包给了第三方 API。数据由第三方维护。对于此类系统,不需要构建索引管道,因为搜索和检索发生在系统之外。另一个例子是要求用户输入外部信息的应用程序,如文档摘要器。这里的搜索操作外包给了用户。
因此,那些使用增强外部信息到提示中但并不一定自行搜索和检索信息的系统,无需创建知识库,因此,没有索引管道。有些人可能会争论,这样的系统根本就不是 RAG 系统。
2.4 生成管道
在索引管道建立的基础上,生成管道促进了 RAG 系统的实时交互。正是生成管道促进了系统中的检索、增强和生成。当用户提问时,生成管道处理查询,检索相关信息,并生成响应——这一切都不需要用户直接与底层索引管道交互。生成管道由三个组件启用,如图 2.6 所示。

图 2.6 生成管道的三个组件使得 RAG 系统的实时查询-响应过程成为可能。
让我们更详细地考虑这些内容:
-
检索器—这可能是整个系统中最关键的部分。使用高级搜索算法,检索器扫描知识库,根据用户的查询识别和检索最相关的信息。整个系统的总体有效性在很大程度上依赖于检索器的准确性。此外,搜索是一个计算密集型操作,可能需要时间。因此,检索器也对系统的总体延迟做出了重大贡献。我们将在第四章和第六章中讨论不同的检索器和检索策略。
-
提示管理—一旦检索器检索到相关信息,就需要将其与原始用户查询结合或增强。乍一看,这似乎是一个简单的任务。然而,提示的构建对生成响应的质量有重大影响。这个组件也属于提示工程的范围。我们将在第四章中探讨不同的提示和提示管理策略。
-
LLM 设置—最后,LLM 负责生成最终响应。RAG 系统可能依赖于多个 LLM。LLM 可以是已经预训练并通常可用的基础模型,例如 Meta 或 Mistral 的,或者通过管理服务,如 OpenAI 或 Anthropic。LLM 也可以针对特定任务进行微调。微调涉及在特定数据集或任务上训练现有的 LLM,以提高性能和适应性,用于专用应用。在罕见的情况下,开发者可能决定训练他们自己的 LLM。我们将在第四章中深入讨论 LLM。
2.5 评估和监控
索引和生成管道从使用角度完成了系统。有了这两个管道,至少在理论上,用户可以开始与系统交互并获得响应。然而,在这种情况下,我们没有系统质量的衡量标准。系统是否运行准确,或者它仍然容易产生幻觉?检索器检索到的信息是否与查询最相关?为了回答这些问题,我们必须建立一个评估框架。这个框架有助于在系统发布之前评估其质量,然后进行持续监控和改进。
建立在 LLMs 的进步之上,RAG 代表了 NLP 领域的一项最新创新。相关性分数、召回率和精确度等指标通常用于评估 RAG 系统的有效性。TruEra 提出的 RAG 指标三元组(mng.bz/Mw22)提供了一个直观的框架,用于全面评估。它从三个维度来审视 RAG 评估,如图所示。
图 2.7。
工作流程涉及在每个步骤之间进行检查——提示、上下文和答案。让我们更仔细地看看:

AI 生成的内容可能是错误的。](../Images/CH02_F07_Kimothi.png)
图 2.7 TruEra 提出的 RAG 评估的三元组。RAG 评估的三个关键维度是查询、上下文和响应。
-
在检索到的信息(上下文)和用户查询(提示)之间——检索器搜索和检索的信息是否与用户提出的问题最相关?检索到不相关信息的结果是,无论 LLM 有多好,如果增强的信息不好,响应将不会是最优的。
-
在最终响应(答案)和检索到的信息(上下文)之间——在生成响应时,LLM 是否考虑了所有检索到的信息?即使
-
尽管 RAG 旨在减少幻觉,但系统仍可能忽略检索到的信息。这有几个原因,将在后续章节中讨论。
-
在最终响应(答案)和用户查询(提示)之间——最终响应是否与用户最初提出的问题相符?为了评估系统的整体有效性,需要评估最终响应与原始问题的相关性。
有几个指标有助于评估这三个维度中的每一个。对于某些指标,需要一个基准数据集。基准数据集通过将生成的响应与人工整理的参考进行比较,为评估 RAG 系统的准确性和有效性提供了一个基准。我们将在第五章中更深入地探讨这些指标和基准数据集。
在实时操作期间对指标进行持续评估可以识别系统难以准确回答的查询类型。还可以从用户那里收集对生成的响应的定性反馈。
2.6 RAGOps 堆栈
RAG 以及基于 LLM 的应用正在由一个不断发展的操作堆栈提供支持。各种提供商提供基础设施组件,例如数据存储平台、模型托管服务和应用程序编排框架。该基础设施可以理解为几个层次:
-
数据层—用于处理和存储以嵌入形式的数据的工具和平台
-
模型层—提供专有或开源 LLM 的提供商
-
提示层—提供提示维护和评估的工具
-
评估层—提供 RAG 评估指标的工具和框架
-
应用编排—促进系统不同组件调用的框架
-
部署层—提供部署 RAG 应用的云提供商和平台
-
应用层—RAG 应用的托管服务
-
监控层—提供对 RAG 应用持续监控的平台
第七章探讨了支持 RAG 系统的各种基础设施层。
2.7 缓存、安全护栏和其他层
最后,还有一些在 RAG 系统中经常使用的其他组件。这些组件解决了系统延迟、监管和道德合规等问题。
-
缓存—缓存是将某些数据存储在缓存内存中以实现更快检索的过程。LLM 缓存与常规缓存略有不同。LLM 对查询的响应存储在语义缓存中。下次提出类似查询时,将检索缓存中的响应,而不是将查询通过完整的 RAG 管道发送。这种方法通过减少响应时间、LLM 推理成本和 LLM 服务负载来提高系统性能。
-
安全护栏—对于几个用例,在实践中,将有一组输出需要生成的边界。安全护栏是在系统中添加的预定义规则集,以符合政策、法规和道德指南。
-
安全—LLM 和基于 LLM 的应用已经见证了新的威胁,例如提示注入、数据中毒、敏感信息泄露等。随着威胁的发展,安全基础设施也需要发展以解决关于 RAG 系统安全和数据隐私的担忧。
RAGOps 也在快速发展。日志记录和跟踪、模型版本控制和反馈层是 RAGOps 堆栈的一些组件。
本章概述了 RAG 系统的主要组件,包括索引和生成管道、评估和监控以及服务基础设施。通过理解这些组件,你现在已经准备好在后续章节中深入探讨每个组件以及 RAG 系统的复杂性。在下一章中,我们将开始构建索引管道,以创建我们 RAG 系统的知识库。
摘要
-
一个 RAG 启用系统由两个主要管道组成:索引管道和生成管道。
-
索引管道负责创建和维护知识库,这包括数据加载、文本分割、数据转换(嵌入)以及在向量数据库中的数据存储。
-
生成管道通过检索信息、增强查询和使用大型语言模型(LLM)生成响应来管理实时交互。
-
评估和监控是评估系统性能的关键组件,涵盖了检索信息与查询之间的相关性、最终响应与检索信息之间的相关性,以及最终响应与原始查询之间的相关性。
-
RAG 系统的服务基础设施包括数据、模型、提示、评估、应用编排、部署、应用托管和监控等层。
-
为了提高性能、确保合规性和应对潜在威胁,通常会采用额外的组件,如缓存、安全网和安全措施。
第三章:索引管道:为 RAG 创建知识库
本章涵盖
-
数据加载
-
文本拆分或分块
-
将文本转换为嵌入
-
在向量数据库中存储嵌入
-
使用 LangChain 的 Python 示例
在第二章中,我们讨论了检索增强生成(RAG)系统的主要组件。您可能还记得,索引管道创建了 RAG 应用的知识库或非参数记忆。在开始与大型语言模型(LLM)的实时用户交互之前,需要设置索引管道。
本章详细阐述了索引管道的四个组件。我们首先讨论数据加载,这涉及到连接到源、提取文件和解析文本。在这个阶段,我们介绍了一个称为 LangChain 的框架,它在 LLM 应用开发者社区中越来越受欢迎。接下来,我们详细阐述数据拆分或分块的需求,并讨论分块策略。嵌入是 AI 和 ML 世界中的一个重要设计模式。我们详细探讨了嵌入及其在 RAG 环境中的相关性。最后,我们探讨了一种新的存储技术——向量存储以及促进其发展的数据库。
到本章结束时,您应该对如何创建知识库(或 RAG 应用程序的参数外记忆)有一个稳固的理解。我们还用 Python 代码片段丰富了本章内容,以便那些有兴趣的人可以尝试亲手开发索引管道。
到本章结束时,您应该
-
了解如何从来源中提取数据。
-
深入了解文本分块策略。
-
学习嵌入是什么以及它们是如何被使用的。
-
掌握向量存储和向量数据库的知识。
-
对设置索引管道有端到端的知识。
3.1 数据加载
本节重点介绍索引管道的第一阶段。您将了解数据加载器、元数据信息和数据转换器。
构建 RAG 系统(或非参数记忆)的知识库的第一步是从其原始位置获取数据。这些数据可能是 Word 文档、PDF 文件、CSV、HTML 等形式。此外,数据可能存储在文件、块或对象存储中,在数据湖、数据仓库中,甚至在可以通过开放互联网访问的第三方来源中。从原始位置获取数据的过程称为数据加载。从一系列来源加载文档可能是一个复杂的过程。因此,建议提前记录所有来源和文件格式。
在深入之前,让我们从一个简单的例子开始。如果你还记得,在第一章中,我们使用维基百科作为关于 2023 年板球世界杯信息来源。当时,我们复制了文章的开头段落并将其粘贴到 ChatGPT 提示窗口中。现在,我们将不再手动操作,而是通过一个名为 LangChain 的非常流行的框架来连接到维基百科并提取数据。本章和本书中的代码可以在 Python 笔记本上运行,并在本书的 GitHub 仓库中提供(mng.bz/a9DJ)。
注意 LangChain 是一个由 Harrison Chase 开发的开源框架,于 2022 年 10 月发布。它用 Python 和 JavaScript 编写,旨在用于构建使用 LLMs 的应用程序。除了适合 RAG 之外,LangChain 也适合构建聊天机器人、文档摘要器、合成数据生成等应用场景。随着时间的推移,LangChain 已经与 LLM 提供商(如 OpenAI、Anthropic 和 Hugging Face)、各种向量存储提供商、云存储系统(如 AWS、Google、Azure)以及新闻、天气等 API 建立了集成。尽管 LangChain 受到了一些批评,但它仍然是开发者的一个良好起点。
安装 LangChain
要使用pip安装 LangChain(在本章中我们将使用版本 0.3.19),请运行
%pip install langchain==0.3.19
langchain-community包包含第三方集成。LangChain 会自动安装它,但如果它不起作用,你也可以使用pip单独安装它:
%pip install langchain-community
现在你已经安装了 LangChain,我们将使用它连接到维基百科并从关于 2023 年板球世界杯的页面中提取数据。为此任务,我们将使用langchain-community包中的document_loaders库的AsyncHtmlLoader函数。要运行AsyncHtmlLoader,我们必须安装另一个名为 bs4 的 Python 包:
#Installing bs4 package
%pip install bs4==0.0.2 --quiet
#Importing the AsyncHtmlLoader
from langchain_community.document_loaders import AsyncHtmlLoader
#This is the URL of the Wikipedia page on the 2023 Cricket World Cup
url="https://en.wikipedia.org/wiki/2023_Cricket_World_Cup"
#Invoking the AsyncHtmlLoader
loader = AsyncHtmlLoader (url)
#Loading the extracted information
html_data = loader.load()
代码中的data变量现在存储了来自维基百科页面的信息。
print(data)
这里是输出(为了节省空间,大量文本被替换为句点。)
>>[Document(page_content='<!DOCTYPE html>\n<html class="client-nojs vector-feature-language-in-header-enabled………………………………………………………………………………………………….of In the knockout stage, India and Australia beat New Zealand and South Africa respectively to advance to the final, played on 19 November at <a href="/wiki/Narendra_Modi_Stadium" title="Narendra Modi Stadium">Narendra Modi Stadium</a>. Australia won by 6 wickets, winning their sixth Cricket World Cup title………………………………………………… "datePublished":"2013-06-29T19:20:08Z","dateModified":"2024-05-01T05:16:34Z","image":"https:\\/\\/upload.wikimedia.org\\/wikipedia\\/en\\/e\\/eb\\/2023_CWC_Logo.svg","headline":"13th edition of the premier international cricket competition"}</script>\n</body>\n</html>', metadata={'source': 'https://en.wikipedia.org/wiki/2023_Cricket_World_Cup', 'title': '2023 Cricket World Cup - Wikipedia', 'language': 'en'})]
变量data是一个包含两个元素的文档列表:page_content和metadata。page_content包含从 URL 获取的文本。你会注意到文本以及相关信息还包括换行符(\n)和其他 HTML 标签;然而,metadata包含另一个重要的数据方面。
元数据是关于数据的信息(例如,类型、来源和目的)。这可以包括数据摘要;数据创建的方式;谁创建了它以及为什么;创建时间;以及数据的大小、质量和状况。在检索阶段,元数据信息非常有用。此外,它还可以用于解决由于时间顺序或来源可能出现的冲突信息。在先前的例子中,在从 URL 提取数据时,维基百科已经在元数据信息中提供了来源、标题和语言。对于许多数据来源,您可能需要添加元数据。
通常,需要对源数据进行“清理”。我们例子中的数据有很多换行符和 HTML 标签,这需要一定程度的清理。我们将尝试使用来自langchain-community包中的document_transformers库的Html2TextTransformer函数清理我们提取的网页数据。对于Html2TextTransformer,我们还需要安装另一个名为html2text的包。
#Install html2text
%pip install html2text==2024.2.26 –quiet
#Import Html2TextTransformer
from langchain_community.document_transformers import Html2TextTransformer
#Assign the Html2TextTransformer function
html2text = Html2TextTransformer()
#Call transform_documents
html_data_transformed = html2text.transform_documents(data)
print(html_data_transformed[0].page_content)
现在的page_content输出已经没有任何 HTML 标签,只包含网页上的文本:
>>Jump to content Main menu Main menu move to sidebar hide Navigation * Main page * Contents * Current events * Random article * About Wikipedia * Contact us * Donate Contribute………….In the knockout stage, India and Australia beat New Zealand and South Africa respectively to advance to the final, played on 19 November at Narendra Modi Stadium. Australia won by 6 wickets, winning their sixth Cricket World Cup title…… * This page was last edited on 1 May 2024, at 05:16 (UTC). * Text is available under the Creative Commons Attribution-ShareAlike License 4.0; additional terms may apply. By using this site, you agree to the Terms of Use and Privacy Policy. Wikipedia® is a registered trademark of the Wikimedia Foundation, Inc., a non-profit organization. * Privacy policy * About Wikipedia * Disclaimers * Contact Wikipedia * Code of Conduct * Developers * Statistics * Cookie statement * Mobile view *
由于我们已经移除了数据的 HTML 部分,文本现在更加连贯。可以进行进一步的清理,例如删除特殊字符和其他不必要的信息。数据清理还会消除重复。在数据加载阶段,还可以包括对敏感信息的掩码,如 PII(个人信息标识符)或公司机密。在某些情况下,可能还需要进行事实核查。
我们数据来源是维基百科(更确切地说,是一个指向维基百科页面的网址),格式是 HTML。来源也可以是其他存储位置,如 AWS S3、SQL/NoSQL 数据库、Google Drive、GitHub,甚至是 WhatsApp、YouTube 和其他社交媒体网站。同样,数据格式可以是.doc、.pdf、.csv、.ppt、.eml 等。大多数情况下,您将能够使用已经内置了源和格式集成的框架,如 LangChain。有时,您可能需要构建自定义连接器和加载器。
虽然数据加载可能看起来很简单(毕竟,它只是连接到源并提取数据),但添加元数据、文档转换、掩码和类似的细微差别增加了这一步骤的复杂性。为了获得最佳结果,建议进行数据源的先进规划、格式审查和元数据信息的整理。
我们现在已经迈出了构建我们的 RAG 系统第一步。数据加载过程可以进一步细分为四个子步骤,如图 3.1 所示:

AI 生成的内容可能是不正确的。](../Images/CH03_F01_Kimothi.png)
图 3.1 索引管道数据加载组件的四个子步骤
-
连接到数据源。
-
从文件中提取文本。
-
审查和更新元数据信息。
-
清理或转换数据。
我们现在已经从源数据中获取了数据,并将其清理到一定程度。我们加载的这个维基百科页面本身就有超过 8,000 个单词。想象一下,如果我们有多个文档,单词的数量会有多少。为了有效地管理信息,我们采用了一种称为数据拆分的方法,这将在下一节中讨论。
3.2 数据拆分(分块)
将长文本分解成可管理的片段称为数据拆分或分块。本节讨论为什么需要分块以及不同的分块策略。我们还使用 LangChain 的功能来展示几个示例。
3.2.1 分块的优势
在上一节中,我们从 URL(一个维基百科页面)加载数据并提取了文本。这是一篇大约有 8,000 个单词的长文本。当涉及到克服在 LLM 应用中使用长文本的主要限制时,分块提供了以下三个优势:
-
LLM 的上下文窗口—由于技术的固有性质,LLM 一次可以处理的标记(大致相当于单词)数量是有限的。这包括提示(或输入)中的标记数量以及完成(或输出)中的标记数量。一个 LLM 一次可以处理的标记总数限制被称为“上下文窗口大小”。如果我们传递的输入超过了上下文窗口大小,LLM 会选择忽略超过大小的所有文本。因此,非常重要的是要小心处理传递给 LLM 的文本数量。在我们的例子中,一篇有 50,000 个单词的文本将无法与上下文窗口较小的 LLM 很好地工作。解决这个问题的方式是将文本分解成更小的部分。
-
中间丢失问题—即使在那些具有较长的上下文窗口的 LLM 中(例如,Anthropic 的 Claude 3 上下文窗口高达 200,000 个标记),观察到准确读取信息的问题。已经注意到,如果相关信息位于提示的中间部分,准确性会急剧下降。通过只传递相关信息给 LLM 而不是整个文档,可以解决这个问题。
-
搜索的便利性—这本身并不是 LLM 的问题,但观察到大量文本更难进行搜索。当我们使用检索器(回想一下第二章中引入的生成管道)时,搜索较小的文本片段会更有效率。
定义:标记是自然语言处理(NLP)任务中使用的根本语义单元。标记可以假设是单词,但有时,一个单词可以由多个标记组成。OpenAI 建议一个标记由四个字符或 0.75 个单词组成。标记很重要,因为大多数专有 LLM 的定价是基于标记使用的。
3.2.2 分块过程
分块过程可以分为三个步骤,如图 3.2 所示:
-
将较长的文本分割成紧凑、有意义的单元(例如,句子或段落)。
-
将较小的单元合并成较大的块,直到达到特定的尺寸。之后,这个块被视为一个独立的文本段。
-
在创建新的块时,将前一个块的一部分包含在新块的开始处。这种重叠是必要的,以保持上下文的连续性。
这个过程也被称为“从小到大”的分块。

图 3.2 数据分块过程
3.2.3 分块方法
虽然将文档分割成块听起来像是一个简单的概念,但在执行分块时可以采用多种方法。以下两个方面的差异存在于不同的分块方法中:
-
文本分割的方式
-
测量块的大小
固定大小块分块
一种非常常见的方法是预先确定块的大小和块之间的重叠量。以下两种方法属于 固定大小块分块 类别:
- 按字符分割——在这里,我们指定一个特定的字符,例如换行符
\n或特殊字符*,以确定文本应该如何分割。每当遇到这个字符时,文本就会被分割成单元。块的大小以字符数来衡量。我们必须选择块的大小或每个块中需要的字符数。我们还可以选择两个块之间需要重叠的字符数。我们将通过一个示例来查看,并使用来自langchain.text_splitters的CharacterTextSplitter方法演示这种方法。为此,我们将从上一节中加载并转换的维基百科文档存储在变量html_data_transformed中。
#import libraries
from langchain.text_splitters import CharacterTextSplitter
#Set the CharacterTextSplitter parameters
text_splitter = CharacterTextSplitter(
separator="\n", #The character that should be used to split
chunk_size=1000, #Number of characters in each chunk
chunk_overlap=200, #Number of overlapping characters between chunks
)
#Create Chunks
chunks=
text_splitter.create_documents(
[html_data_transformed[0].page_content]
)
#Show the number of chunks created
print(f"The number of chunks created : {len(chunks)}")
>>The number of chunks created: 67
这种方法创建了 64 个块。但重叠部分如何?让我们随机检查两个块,比如说,块 4 和块 5。我们将比较两个连续块的最后 200 个字符
将块 4 与块 5 的前 200 个字符合并:
chunks[4].page_content[-200:]
>> 'on was to be played from 9 February to 26 March\n2023.[3][4] In July 2020 it was announced that due to the disruption of the\nqualification schedule by the COVID-19 pandemic, the start of the tournament'
chunks[5].page_content[:200]
>> '2023.[3][4] In July 2020 it was announced that due to the disruption of the\nqualification schedule by the COVID-19 pandemic, the start of the tournament\nwould be delayed to October.[5][6] The ICC rele'
比较两个输出,我们可以观察到两个连续块之间存在重叠。
按字符分割是一种简单而有效的方法来创建块。这是任何人都应该尝试的第一个分块方法。然而,有时在指定的长度内创建块可能不可行。这是因为需要分割文本的字符的顺序出现相隔甚远。为了解决这个问题,采用了递归方法。
- 递归按字符分割—这种方法与按字符分割类似,但不是指定单个字符进行分割,而是指定一个字符列表。该方法最初尝试根据第一个字符创建块。如果无法使用第一个字符创建指定大小的块,它将使用下一个字符进一步分解块到所需的大小。这种方法确保块主要在指定的大小内创建。这种方法适用于通用文本。你可以使用 LangChain 中的
RecursiveCharacterTextSplitter来使用这种方法。RecursiveCharacterTextSplitter的唯一区别在于,我们不需要在分隔符参数separator=``"``\n``"中传递单个字符,而是需要传递一个列表separators= [``"``\n\n``"``,``"``\n``"``,"``.``"``,""``]。
在固定大小分块中考虑的另一个角度是使用标记。如本节开头所示,标记是 NLP 的基本单位。它们可以粗略地理解为单词的代理。所有 LLM 都以标记的形式处理文本。因此,使用标记来确定块的大小也是有意义的。这种方法被称为按标记分割方法。在这里,分割仍然基于字符,但块的大小和重叠由标记的数量而不是字符的数量决定。
注意:标记化器用于从文本片段中创建标记。标记与单词略有不同。例如,“I’d like that!”有三个单词;然而,在 NLP 中,此文本可能被解析为五个标记,即“ I”,“‘d”,“like”,“that”,“!”。不同的 LLM 使用不同的方法来创建标记。OpenAI 使用 tiktoken 标记器为 GPT3.5 和 GPT4 模型创建标记;Meta 的 Llama2 使用 Hugging Face 的 transformers 库中的 LLamaTokenizer。你还可以在 Hugging Face 上探索其他标记化器。NLTK 和 spaCy 是一些其他流行的库,可以用作标记化器。
要使用按标记分割的方法,你可以在RecursiveCharacterTextSplitter和CharacterTextSplitter类中使用特定方法,例如使用 OpenAI 的 tiktoken 标记器创建具有 10 个标记重叠的 100 个标记块,可以使用RecursiveCharacterTextSplitter.from_tiktoken_encoder(encoding="cl100k_base", chunk_size=100, chunk_overlap=10),或者使用来自 Hugging Face 的另一个标记器创建相同大小的块,可以使用CharacterTextSplitter.from_``huggingface_tokenizer(tokenizer, chunk_size=100, chunk_overlap=10)`。
固定大小分块的限制在于它没有考虑文本的语义完整性。换句话说,忽略了文本的意义。它在数据本质上均匀的场景中效果最好,例如基因序列和服务手册,或者结构统一的报告,如调查问卷。
专用分块
块分割的目标是将有意义的数据放在一起。如果我们处理的是 HTML、Markdown、JSON 或甚至计算机代码形式的数据,那么根据结构而不是固定大小来分割数据更有意义。块分割的另一种方法是考虑提取和加载数据的格式。例如,Markdown 文件是根据标题组织的,用 Python 或 Java 等编程语言编写的代码是根据类和函数组织的,同样,HTML 是根据标题和部分组织的。对于这些格式,可以采用专门的块分割方法。LangChain 提供了MarkdownHeaderTextSplitter、HTMLHeader-TextSplitter和RecursiveJsonSplitter等类,用于这些格式。
这里是一个使用HTML-SectionSplitter. 分割 HTML 文档的简单代码示例。我们使用相同的维基百科文章作为 HTML 页面的来源。我们首先根据部分分割输入数据。HTML 中的部分被标记为<h1>、<h2>、<table>等。可以假设一个结构良好的 HTML 文档将包含类似的信息。这有助于我们创建包含类似信息的块。要使用HTMLSectionSplitter库,我们必须安装另一个名为lxml的 Python 包:
#Installing lxml
%pip install lxml==5.3.1 --quiet
# Import the HTMLHeaderTextSplitter library
from langchain_text_splitters import HTMLSectionSplitter
# Set URL as the Wikipedia page link
url="https://en.wikipedia.org/wiki/2023_Cricket_World_Cup"
loader = AsyncHtmlLoader (url)
html_data = loader.load()
# Specify the header tags on which splits should be made
sections_to_split_on=[
("h1", "Header 1"),
("h2", "Header 2"),
("table ", "Table"),
("p", "Paragraph")
]
# Create the HTMLHeaderTextSplitter function
splitter = HTMLSectionSplitter(sections_to_split_on)
# Create splits in text obtained from the URL
Split_content = splitter.split_text(html_data[0].page_content)
专门块分割的优势在于块的大小不再受固定宽度的限制。这个特性有助于保留数据的固有结构。因为块的大小根据结构而变化,所以这种方法有时也被称为自适应块分割。在结构化场景中,如客户评论或患者记录,数据长度可能不同,但理想情况下应在同一个块中,专门块分割效果很好。
在上一个示例中,让我们看看创建了多少个块:
len(split_content)
>> 231
这种方法从 URL 中为我们提供了 231 个块。块分割方法不必是互斥的。我们可以进一步使用固定大小的块分割方法,如RecursiveCharacterTextSplitter,对这些 231 个块进行分割。
from langchain.text_splitter import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
separators=["\n\n","\n","."]
chunk_size=1000, chunk_overlap=100,
)
final_chunks = text_splitter.split_documents(split_content)
让我们看看这种技术组合创建了多少个块:
len(chunks)
>> 285
通过首先从 URL 中分割 HTML 数据,然后使用专门的块分割方法,接着使用固定大小方法,总共创建了 285 个块。这比仅使用固定大小方法(我们在上一节中看到的是“按字符分割”给我们带来了 67 个块)要多。
你可能想知道拥有更多分块和最佳数量的优势。不幸的是,对此并没有直接的答案。拥有许多分块(因此分块尺寸更小)意味着分块中的信息是精确的。这在向 LLM 提供准确信息时是有利的。相比之下,通过将数据分割成小块,你可能会失去更大文档的整体主题、思想和连贯性。这里的任务是找到一个平衡点。在我们简要地审视一种考虑文本意义以进行分块并旨在创建超级上下文分块的方法之后,我们将讨论更多的分块策略。
语义分块
这个想法,由 Greg Kamradt 提出,质疑了先前分块方法的两个方面。
-
为什么我们应该有一个预定义的固定大小的分块?
-
为什么分块方法没有考虑内容的实际意义?
为了解决这些问题,一种通过查看句子之间的语义相似度(或意义相似度)的方法被称为语义分块。它首先创建由三个句子组成的小组,然后合并意义相似的小组。为了找出意义的相似度,这种方法使用嵌入(我们将在下一节讨论嵌入)。这仍然是一种实验性的分块技术。在 LangChain 中,你可以使用来自langchain_experimental.text_splitter库的SemanticChunker类。见图 3.3,以了解不同分块方法的示例。

图 3.3 分块方法
随着 LLM 和生成式 AI 空间的快速发展,分块方法也在变得更加复杂。简单的分块方法预先确定分块的大小和按字符分割。稍微复杂一点的技术是按标记分割数据。专门的方法更适合不同的数据格式。实验技术,如语义分块和代理分块,正在引领分块空间的进步。现在,让我们考虑一个重要的问题:如何选择分块方法。
3.2.4 选择分块策略
我们已经看到有许多分块方法可用。在创建索引管道的过程中,选择哪种分块方法(即是否使用单一方法或多种方法)是一个经常出现的问题。没有指导方针或规则来回答这个问题。然而,你正在开发的应用程序的一些特性可以指导你走向一个有效的策略。
内容的性质
你正在处理的数据类型可以作为数据块化策略的指南。如果你的应用程序使用特定格式的数据,如代码或 HTML,建议使用专门的数据块化方法。不仅如此,无论你是在处理长文档,如白皮书和报告,还是短形式内容,如社交媒体帖子、推文等,也可以指导数据块大小和重叠限制。如果你使用的信息来源多样化,那么你可能需要针对不同的来源使用不同的方法。
用户查询的预期长度和复杂性
你的 RAG 系统可能收到的查询的性质也决定了数据块化策略。如果你的系统预期一个简短且直接的查询,那么与长且复杂的查询相比,你的块大小应该不同。在某些情况下,将长查询与短块匹配可能效率低下。同样,短查询与大型块匹配可能产生部分不相关的结果。
结果。
应用和用例需求
你正在解决的使用案例的性质也可能决定最佳的数据块化策略。对于直接问答系统,较短的块可能用于精确的结果,而对于摘要任务,较长的块可能更有意义。如果你的系统需要的结果作为另一个下游应用程序的输入,这也可能影响数据块化策略的选择。
嵌入模型
我们将在下一节中讨论嵌入。目前,你可以记下某些嵌入模型在特定尺寸的数据块上表现更好。
在本节中,我们已经详细讨论了数据块化。从理解数据块化的需求和优势到不同的数据块化方法和数据块化策略的选择,你现在已经准备好从不同的来源加载数据并将它们分割成最佳尺寸。记住,数据块化不是一个过于复杂的任务,大多数数据块化方法都会有效。然而,你将不得不根据观察到的结果评估和改进你的数据块化策略。
现在数据已经被分割成可管理的尺寸,我们需要存储它,以便稍后可以检索出来用于生成管道。我们需要确保这些数据块可以有效地搜索以匹配用户查询。结果发现,一种数据模式对于此类任务是最有效的。这种模式被称为“嵌入”。让我们在下一节中探讨嵌入及其在 RAG 系统中的应用。
部分。
3.3 数据转换(嵌入)
计算机在其核心上执行数学计算。数学计算是在数字上进行的。因此,为了使计算机处理任何类型的非数值数据,如文本或图像,它必须首先将其转换为数值形式。
3.3.1 嵌入是什么?
嵌入 是数据科学、机器学习和人工智能领域非常有用的设计模式。嵌入是数据的向量表示。作为一个一般定义,嵌入是将数据转换成 n-维矩阵的数据。单词 embedding 是单词的向量表示。我通过使用三个单词作为例子来解释嵌入:dog, bark, 和 fly。
备注:在物理学和数学中,向量是一个具有大小和方向的物体,就像空间中的箭头一样。箭头的长度是数量的量级,箭头所指的方向是数量的方向。物理学中此类数量的例子有速度、力、加速度等等。在计算机科学和机器学习中,向量的概念是数据的抽象表示,这种表示是一个数字数组或列表。这些数字代表数据特征或属性。在自然语言处理(NLP)中,向量可以表示文档、句子,甚至单词。数组或列表的长度是向量中的维度数。一个二维向量将有两个数字,一个三维向量将有三个数字,一个 n-维向量将有 n 个数字。
让我们通过给三个单词分配一个数字来理解嵌入:Dog = 1,Bark = 2,Fly = 6,如图 3.4 所示。我们选择这些数字是因为单词 dog 更接近于单词 bark,而远离单词 fly。

图 3.4 单词在一维向量中
一维向量并不是很好的表示方式,因为我们无法准确绘制无关的单词。在我们的例子中,我们可以绘制出单词 fly 和 bark(都是动词),它们相距很远,而 bark 更接近于狗,因为狗会吠叫。但是,我们如何绘制像 love 或 red 这样的单词呢?为了准确表示所有单词,我们需要增加维度的数量。见图 3.5。

图 3.5 2D 向量空间中的单词
嵌入模型的目的是将单词(或句子/段落)转换为 n-维向量,使得在意义上相似的单词(或句子/段落)在向量空间中彼此靠近。见图 3.6。

图 3.6 嵌入过程将数据(如文本)转换为向量并压缩输入信息,从而产生一个针对训练数据的特定嵌入空间。
一个嵌入模型可以使用 Word2Vec、GloVe、FastText 或 BERT 等嵌入算法在预处理文本数据的语料库上训练:
-
Word2Ve**c—Word2Vec 是由 Google 的研究人员开发的一种基于浅层神经网络的学习词嵌入的模型。它是最早的嵌入技术之一。
-
GloV**e—全球词表示向量是由斯坦福大学的研究人员开发的无监督学习技术。
-
FastTex**t—FastText 是 Facebook AI Research 开发的 Word2Vec 的扩展。它特别适用于处理拼写错误和罕见单词。
-
ELM**o—由 Allen Institute for AI 的研究人员开发的 Embeddings from Language Models。ELMo 嵌入已被证明可以改善问答和情感分析任务的性能。
-
BERT—由 Google 的研究人员开发的基于 Transformer 架构的模型。通过考虑双向上下文,它提供了上下文化的词嵌入,在各种 NLP 任务上实现了最先进的性能。
在某些用例中,训练定制的嵌入模型可能是有益的,其中范围有限。训练一个泛化良好的嵌入模型可能是一项费力的练习。收集和预处理文本数据可能很繁琐。训练过程也可能变得计算成本高昂。
3.3.2 常见的预训练嵌入模型
对于任何正在构建 RAG 系统的人来说,好消息是一旦创建了嵌入,它们也可以跨任务和领域泛化。有各种专有和开源的预训练嵌入模型可供使用。这也是嵌入在机器学习应用中流行度激增的原因之一。
-
OpenAI 的嵌入模型—ChatGPT 和 GPT 系列 LLM 背后的公司 OpenAI 也提供了三个嵌入模型:
-
text-embedding-ada-002于 2022 年 12 月发布。它具有 1536 维的维度,这意味着它将文本转换为 1536 维的向量。
-
text-embedding-3-small是 2024 年 1 月发布的最新 1536 维小嵌入模型。它相对于 ada-002 模型的灵活性在于用户可以根据自己的需求调整维度的尺寸。
-
text-embedding-3-large是与 text-embedding-3-small 模型一起发布的 3072 维大型嵌入模型。它是 OpenAI 迄今为止性能最好的模型。
OpenAI 模型是闭源的,可以通过 OpenAI API 访问。它们的价格基于所需的嵌入输入令牌的数量。
-
-
Google 的 Gemini 嵌入模型—text-embedding-004(最后更新于 2024 年 4 月)是 Google Gemini 提供的模型。它提供弹性嵌入尺寸高达 768 维,可以通过 Gemini API 访问。
-
Voyage A**I—这些嵌入模型由 Claude 系列 LLM 的提供者 Anthropic 推荐。Voyage 提供几种嵌入模型,例如
-
voyage-large-2-instruct 是一个成为嵌入模型领导者的 1024 维嵌入模型。
-
voyage-law-2 是一个针对法律文件优化的 1024 维模型。
-
voyage-code-2 是一个针对代码检索优化的 1536 维模型。
-
voyage-large-2 是一个针对检索优化的 1536 维通用模型。
Voyage AI 在收费使用嵌入模型之前提供了一些免费令牌。
-
-
Mistral AI embedding**s——Mistral 是 Mistral 和 Mixtral 等 LLM 背后的公司。他们提供了一种名为 mistral-embed 的 1024 维嵌入模型,这是一个开源嵌入模型。
-
Cohere embedding**s——Cohere,Command、Command R 和 Command R + LLMs 的开发者,也提供了一系列嵌入模型,这些模型可以通过 Cohere API 访问。其中一些是
-
embed-english-v3.0 是一个仅适用于英语嵌入的 1024 维模型。
-
embed-english-light-v3.0 是 embed-english 模型的轻量版本,具有 384 维。
-
embed-multilingual-v3.0 提供了超过 100 种语言的跨语言支持。
-
这五种模型绝非推荐,而仅仅是一份流行的嵌入模型的列表。除了这些提供商之外,几乎所有的 LLM 开发者,如 Meta、TII 和 LMSYS,也提供预训练的嵌入模型。一个可以查看所有流行嵌入模型的地方是 Hugging Face 上的 MTEB(大规模文本嵌入基准)排行榜(huggingface.co/spaces/mteb/leaderboard)。MTEB 基准比较了在分类、检索、聚类等任务上的嵌入模型。你现在已经知道了嵌入是什么,但为什么它们有用呢?让我们通过一些用例的例子来讨论这个问题。
3.3.3 嵌入应用案例
嵌入之所以如此受欢迎,是因为它们有助于建立单词、短语和文档之间的语义关系。在搜索或文本匹配的最简单方法中,我们使用关键词,如果关键词匹配,我们就可以将匹配的文档作为搜索结果展示。然而,这种方法在搜索时未能考虑语义关系或词语的含义。通过使用嵌入,我们可以克服这个挑战。
相似度是如何计算的
我们讨论了嵌入是单词或句子的向量表示。相似的文本片段彼此靠近。彼此的接近度是通过向量空间中点的距离来计算的。最常用的相似度度量之一是余弦相似度。余弦相似度是两个向量之间角度的余弦值。回想一下三角学,平行线的余弦值(即角度 = 0°)为 1,直角的余弦值(即 90°)为 0。相反方向的余弦值(即角度 = 180°)为-1。因此,余弦相似度介于-1 和 1 之间,其中不相关的术语值接近 0,相关的术语值接近 1。意义相反的术语具有-1 的值。见图 3.7。

图 3.7 2D 向量空间中向量的余弦相似度
另一种相似度的度量是两个向量之间的欧几里得距离。接近的向量具有较小的欧几里得距离。可以使用以下公式进行计算:
距离 (A, B) = sqrt((A[i]-B[i])²),
其中 i 是 n 维向量的第 i 个维度
嵌入的不同用例
这里展示了嵌入的不同用例:
-
文本搜索—在知识库中搜索正确的文档片段是 RAG 系统的一个关键组成部分。嵌入用于计算用户查询和存储文档之间的相似度。
-
聚类—将相似数据分类在一起以在数据中找到主题和组可以获得有价值的见解。嵌入用于将相似的文本片段分组在一起,例如,找出客户评论中的共同主题。
-
机器学习—高级机器学习技术可用于解决各种问题,如分类和回归。为了将文本数据转换为数值特征,嵌入证明是一种非常有价值的技巧。
-
推荐引擎—产品特征之间的较短距离意味着更大的相似度。使用嵌入进行产品和用户特征可以用于推荐相似产品。
由于我们专注于 RAG 系统,因此我们在此检查使用嵌入进行文本搜索——找到与用户查询最接近的文档片段。让我们继续我们的 2023 年板球世界杯维基百科页面的例子。在上一个部分,我们使用专业和固定宽度的组合创建了 67 个片段。现在我们将看到如何为每个片段创建嵌入。我们将看到如何使用开源以及专有嵌入模型。
这里是使用 Hugging Face 通过开源嵌入模型 all-MPnet-base-v2 创建嵌入的代码示例:
# Import HuggingFaceEmbeddings from embeddings library
from langchain_huggingface import HuggingFaceEmbeddings
# Instantiate the embeddings model. The embeddings model_name can be changed as desired
embeddings =
HuggingFaceEmbeddings(
model_name="sentence-transformers/all-mpnet-base-v2"
)
# Create embeddings for all chunks
hf_embeddings =
embeddings.embed_documents(
[chunk.page_content for chunk in final_chunks]
)
#Check the length(dimension) of the embedding
len(hf_embeddings [0])
>> 768
此模型创建维度为 768 的嵌入。hf_embeddings列表由 285 个列表组成,每个列表包含每个片段的 768 个数字。图 3.8 显示了所有片段的嵌入空间。

图 3.8 使用 all-MiniLM-l6-v2 模型为维基百科页面块创建的嵌入。
同样,我们可以使用 OpenAI 托管的私有模型,如 text-embedding-3-small 模型。唯一的前提是获取 API 密钥并在 OpenAI 上设置账单账户。
# Install the langchain openai library
%pip install langchain-openai==0.3.7 --quiet
# Import OpenAIEmbeddings from the library
from langchain_openai import OpenAIEmbeddings
# Set the OPENAI_API_KEY as the environment variable
import os
os.environ["OPENAI_API_KEY"] = <YOUR_API_KEY>
# Instantiate the embeddings object
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
# Create embeddings for all chunks
openai_embeddings =
embeddings.embed_documents(
[chunk.page_content for chunk in chunks]
)
#Check the length(dimension) of the embedding
len(openai_embedding[0])
>> 1536
text-embedding-3-small 模型为相同维度的块创建嵌入,维度为 1536。
可用的嵌入模型有很多,每天都有新的模型被添加。嵌入的选择可能由某些因素决定。让我们看看几个因素。
3.3.4 如何选择嵌入?
有几个主要因素会影响你选择嵌入的决定。
用例
你的应用程序用例可能决定了你选择的嵌入。MTEB 排行榜对每个嵌入模型在七个用例中的表现进行了评分:分类、聚类、成对分类、重排序、检索、语义文本相似性和摘要。在撰写本书时,Salesforce 开发的SFR-Embedding-Mistral模型在检索任务中表现最佳。
成本
成本是另一个需要考虑的重要因素。为了创建知识库,你可能需要为数千份文档创建嵌入,从而产生数百万个标记。
嵌入是强大的数据模式,在寻找文本之间的相似性方面最为有效。在 RAG 系统中,嵌入在搜索和检索与用户查询相关的数据中起着关键作用。一旦创建了嵌入,它们需要存储在持久内存中以便实时访问。为了存储嵌入,一种新的数据库类型,称为向量数据库,变得越来越流行。
3.4 存储(向量数据库)
现在我们已经到达索引管道的最后一步。数据已经被加载、分割并转换为嵌入。为了重复使用这些信息,我们需要将其存储在内存中,以便按需访问。
3.4.1 向量数据库是什么?
数据库的演变可以追溯到计算机的早期阶段。数据库是有组织的集合,旨在易于访问、管理和更新。例如,MySQL 这样的关系型数据库将结构化数据组织成行和列。MongoDB 这样的 NoSQL 数据库擅长处理非结构化和半结构化数据。Neo4j 这样的图数据库针对查询图数据进行了优化。同样,向量数据库是为了处理高维向量而构建的。这些数据库专门用于索引和存储向量嵌入,以实现快速语义搜索和检索。
除了有效地存储高维向量数据外,现代向量数据库还提供传统功能,如可伸缩性、安全性、多租户、版本控制和管理工作,等等。然而,向量数据库的独特之处在于提供基于欧几里得距离或余弦相似度的相似搜索。它们还采用专门的索引技术。
3.4.2 向量数据库的类型
向量数据库最初是一种专门的数据库产品,但受到存储向量数据需求增长的推动,所有主要的数据库提供商都增加了向量索引功能。我们可以将今天可用的流行向量数据库分为六大类。
-
向量索引**—这些库专注于索引和搜索的核心功能。它们不支持数据管理、查询处理或接口。它们可以被视为一个基本的向量数据库。向量索引的例子包括 Facebook AI Similarity Search (FAISS)、Non-Metric Space Library (NMSLIB)、Approximate Nearest Neighbors Oh Yeah (ANNOY)、Scalable Nearest Neighbors (ScaNN)等。
-
专门的向量数据库**—这些数据库专注于高维向量支持的核心功能,如索引、搜索和检索(例如向量索引),同时也提供数据库功能,如数据管理、可扩展性、安全性、可伸缩性、非向量数据支持等。专门的向量数据库的例子包括 Pinecone、ChromaDB、Milvus、Qdrant、Weaviate、Vald、LanceDB、Vespa 和 Marqo。
-
搜索平台**—Solr、Elastic Search、Open Search 和 Apache Lucene 是传统的文本搜索平台和引擎,专为全文搜索构建。它们现在已将向量相似搜索能力添加到现有的搜索能力中。
-
SQL 数据库的向量功能**—Azure SQL、Postgres SQL(pgvector)、SingleStore 和 CloudSQL 是传统的 SQL 数据库,现在已经增加了向量数据处理能力。
-
NoSQL 数据库的向量功能**—与 SQL 数据库一样,NoSQL 数据库如 MongoDB 也增加了向量搜索功能。
-
具有向量功能的图数据库**—例如 Neo4j,通过增加向量功能,也开辟了新的可能性。
LangChain 支持使用向量索引,例如 FAISS。要使用 FAISS,我们首先必须安装faiss-cpu库。我们将使用第 3.2 节中已创建的块和第 3.3 节中使用的 OpenAI 嵌入:
# Install FAISS-CPU
%pip install faiss-cpu==1.10.0 --quiet
# Import FAISS class from vectorstore library
from langchain_community.vectorstores import FAISS
from langchain_community.docstore.in_memory import InMemoryDocstore
# Import OpenAIEmbeddings from the library
from langchain_openai import OpenAIEmbeddings
# Set the OPENAI_API_KEY as the environment variable
import os
os.environ["OPENAI_API_KEY"] = <YOUR_API_KEY>
# Chunks from Section 3.3
Final_chunks=final_chunks
# Instantiate the embeddings object
embeddings=OpenAIEmbeddings(model="text-embedding-3-small")
# Instantiate the FAISS object
vector_store = FAISS(
embedding_function=embeddings,
index=index,
docstore=InMemoryDocstore(),
index_to_docstore_id={},
)
# Add the chunks
vector_store.add_documents(documents=final_chunks)
# Check the number of chunks that have been indexed
vector_store.index.ntotal
>> 285
使用此代码,285 个数据块已转换为向量嵌入,这些嵌入存储在 FAISS 向量索引中。FAISS 向量索引也可以使用vector_store.save_local(folder_path,index_name)和FAISS.load_local(folder_path,index_name)函数保存到内存中。现在让我们简要地看看如何使用向量存储。我们将从本书开始就一直在询问的原始问题: “2023 年板球世界杯的冠军是谁?”
# Original Question
query = "Who won the 2023 Cricket World Cup?"
# Ranking the chunks in descending order of similarity
docs = vector_store.similarity_search(query)
# Printing one of the top-ranked chunk
print(docs[0].page_content)
相似性搜索按相似度降序排列块,这意味着与查询最相似的块将排在顶部。在先前的例子中,我们可以观察到关于世界杯决赛的块已经被排在
在顶部。
FAISS 是一个简化版的高性能向量索引,适用于许多应用。ChromaDB 是另一个用户友好的向量数据库,已经获得了广泛认可。Pinecone 提供托管服务和定制化。Milvus 在相似性搜索方面声称有更高的性能,而 Qdrant 提供了先进的过滤系统。现在我们将讨论一些关于如何选择最适合您需求的向量数据库的要点。
3.4.3 选择向量数据库
所有向量数据库都提供相同的基本功能,但每个数据库也声称具有差异化的价值。您的选择应受您用例的细微差别与数据库的价值主张相匹配的影响。在评估和实施向量数据库时,以下是一些需要考虑的事项:
-
准确性与速度—某些算法更准确但速度较慢。必须根据应用需求在搜索准确性和查询速度之间取得平衡。评估向量数据库时,这些参数将变得很重要。
-
灵活性与性能—向量数据库为用户提供定制化。虽然这可能有助于您根据特定需求定制数据库,但更多的定制可能会增加开销并减慢系统速度。
-
本地存储与云存储—评估本地存储速度和访问与云存储优势(如安全性、冗余和可扩展性)之间的权衡。
-
直接访问与 API—确定是否需要通过直接库进行紧密集成控制,或者是否需要像 API 这样的易于使用的抽象更适合您的用例。
-
简单性与高级功能—比较高级算法优化、查询功能和索引与您的用例所需的复杂性和对简单性的需求之间的比较。
-
成本—虽然您可能在完全托管的解决方案中产生常规成本,但如果管理不善,自托管可能更昂贵。
我们现在已经完成了一个文档的端到端索引。我们继续使用相同的问题(“2023 年板球世界杯谁赢了?”)和相同的外部来源——2023 年板球世界杯的维基百科页面(mng.bz/yN4J)。在本章中,我们从程序化加载这个维基百科页面开始,提取 HTML 文档,然后解析 HTML 文档以提取。之后,我们使用一种专业和固定宽度的分块方法将文本分成小块。我们使用 OpenAI 的 text-embedding-003-large 模型将这些块转换为嵌入。最后,我们将嵌入存储到 FAISS 向量索引中。我们还看到了如何使用这个向量索引上的相似性搜索帮助我们检索相关块。
当使用多种方法和策略对来自不同来源的不同格式的多个文档进行索引时,我们可以将所有信息以向量嵌入的形式存储,为我们的 RAG 系统创建一个非参数化知识库。
这就结束了我们对索引管道的讨论。到现在为止,您必须已经对索引管道的四个组成部分有了坚实的理解,并准备好为 RAG 系统构建知识库。
在下一章中,我们将使用这个知识库通过生成管道实时响应用户查询。
摘要
数据加载
-
从原始位置获取数据的过程称为数据加载,包括以下四个步骤:连接到源、提取和解析文本、审查和更新元数据以及清理和转换数据。
-
从一系列来源加载数据可能是一个复杂的过程。务必提前规划好所有来源和加载器。
-
LangChain 提供了多种数据加载器可供使用。
-
将长文本分解成可管理的尺寸称为数据拆分或分块。
-
分块解决了 LLM 的上下文窗口限制问题,减轻了长提示中丢失在中间的问题,并使搜索和检索更容易。
-
分块过程涉及将较长的文本划分为小单元,将小单元合并成块,并在块之间包含重叠以保持上下文连续性。
-
分块可以是固定大小、专用(或自适应)或语义的。不断有新的分块方法被引入。
-
您选择的分块策略应基于内容的性质、预期用户查询的长度和复杂性、应用用例以及所使用的嵌入模型。
-
分块策略可以包括多种方法。
数据转换
-
为了处理,文本需要转换为数值格式。
-
嵌入是数据的向量表示(单词、句子、文档等)。
-
嵌入算法的目标是在向量空间中将相似的数据点放置在彼此附近。
-
可用几种预训练的、开源和专有嵌入模型供使用。
-
嵌入模型使相似度搜索成为可能。嵌入可以用于文本搜索、聚类、机器学习模型和推荐引擎。
-
嵌入的选择在很大程度上取决于用例和成本影响。
-
向量数据库旨在高效地存储和检索高维向量数据,如嵌入。
-
向量数据库基于距离度量,如余弦相似度,提供相似度搜索。
-
除了相似度搜索之外,向量数据库还提供传统服务,如可扩展性、安全性、版本控制和类似服务。
-
独立的向量索引、专门的向量数据库或具有附加向量能力的传统产品(如搜索平台、SQL 和 NoSQL 数据库)都可以提供向量功能。
-
准确性、速度、灵活性、存储、性能、简单性、访问性和成本是影响选择向量数据库的一些因素。
第四章:生成管道:生成上下文 LLM 响应
本章涵盖
-
检索器和检索方法
-
使用提示工程技术进行增强
-
使用 LLM 进行生成
-
Python 中 RAG 管道的基本实现
在第三章中,我们讨论了通过索引管道创建知识库,即检索增强生成(RAG)应用的非参数记忆。为了使用这个知识库进行准确和上下文相关的响应,我们需要创建一个包含检索、增强和生成步骤的生成管道。
本章详细阐述了生成管道的三个组成部分。我们首先讨论检索过程,这主要涉及在知识库的向量数据库中搜索存储的嵌入,并返回与用户输入查询密切匹配的文档列表。你还将了解检索器及其检索算法的概念。接下来,我们转向增强步骤。在此阶段,了解与 RAG 一起使用的不同提示工程框架也是有益的。最后,作为生成步骤的一部分,我们讨论了 LLM 生命周期的一些阶段,例如使用基础模型与监督微调、不同大小的模型,以及在 RAG 环境中开源与专有模型。在这些步骤中,我们还强调了不同方法的优缺点。
到本章结束时,你将具备对 RAG 系统两个基础管道的理解。你也应该准备好构建一个基本的 RAG 系统。
到本章结束时,你应该
-
了解 RAG 中使用的几个检索器。
-
理解使用提示工程进行增强。
-
了解 LLM 在 RAG 环境中的使用细节。
-
对设置基本 RAG 系统有端到端的知识。
在深入探讨每个组件之前,让我们先对生成管道进行一个概述。
4.1 生成管道概述
回想一下第二章中介绍的生成管道。当用户提供输入时,生成管道负责提供上下文响应。检索器从知识库中搜索最合适的信息。用户问题通过这些信息进行增强,并作为输入传递给 LLM 以生成最终响应。这个过程如图 4.1 所示。
生成管道涉及三个过程:检索、增强和生成。检索过程负责从知识库中检索与用户查询相关的信息。增强是将检索到的信息与用户查询相结合的过程。生成是最后一步,LLM 根据增强的提示生成响应。本章详细讨论了这三个过程。
4.2 检索
检索是指从大量语料库或知识库中查找和提取相关信息的过程。正如你在第三章中看到的,来自各种来源的信息被解析、分块并以嵌入的形式存储在向量数据库中。这些存储的嵌入有时也被称为文档,知识库由几卷文档组成。本质上,检索是一个搜索问题,旨在找到与输入查询最匹配的文档。
通过一个称为检索器的组件来搜索知识库并检索正确的文档。简单来说,检索器接受查询作为输入,并返回一个匹配文档的列表作为输出。这个过程如图 4.2 所示。你可以想象检索是一个关键步骤,因为检索到的信息质量直接影响最终生成的输出质量。

图 4.1 包含三个组件(即检索、增强和生成)的生成管道概述

图 4.2 检索器在知识库中搜索并返回最相关的文档。
我们在第三章构建索引管道时已经讨论了嵌入。使用嵌入,我们可以找到与用户查询匹配的文档。嵌入是检索可以发生的一种方法。还有其他方法,花些时间了解不同类型的检索方法和它们计算结果的方式是值得的。
本节首先讨论了检索算法及其在 RAG(检索增强生成)环境中的重要性。在 RAG 系统中,可以使用一种或多种检索方法来构建检索组件。接下来,我们将探讨一些可以直接通过框架(例如 LangChain)使用的预构建检索器的例子。这些检索器与数据库、云服务提供商或第三方信息源等服务集成。最后,我们将通过在 LangChain 中使用 Python 构建一个非常简单的检索器来结束本节。我们还将继续使用这个例子来展示增强和生成步骤,以便在本章结束时,我们有一个完整的生成管道实现。
注意第三章讨论了索引以及如何将数据转换为数值形式以便以后检索信息。你可能还记得我们在 3.3 节中详细讨论了嵌入。由于我们以嵌入的形式存储了数据,为了检索这些数据,我们也必须在嵌入的搜索上工作。因此,检索过程与索引过程紧密耦合。我们用于索引的任何东西,我们也将用于检索。
4.2.1 检索方法的进展
信息检索,或称 IR,是搜索的科学。无论你是在文档中搜索信息还是搜索文档本身,它都属于信息检索的范畴。信息检索在计算机科学中有着丰富的历史,始于 19 世纪初约瑟夫·玛丽·雅卡尔发明的雅卡尔织机,这是第一个能够读取穿孔卡的设备。从那时起,信息检索从简单的搜索和检索发展到高度复杂的搜索和检索。布尔检索是一种基于关键词的简单搜索(就像你在浏览器或文字处理器的搜索栏中按下 CTRL/CMD + F 时遇到的搜索),其中使用布尔逻辑根据单词的存在或不存在来匹配文档与查询。如果文档包含查询中的确切术语,通常结合 AND、NOT 和 OR 运算符,则会检索文档。"词袋模型" (BoW) 在 NLP 的早期阶段被广泛使用。它创建了一个包含文档中所有单词的词汇表,作为一个向量,表示每个单词的存在或不存在。考虑两个句子:"The cat sat on the mat" 和 "The cat in the hat。" 词汇表是 [``"``the``"``, "``cat``"``, "``in``"``, "``hat``"``, "``on``"``, "``mat``"``],而第一个句子表示为向量 [2, 1, 1, 1, 0, 0],而第二个句子是 [2, 1, 0, 0, 1, 1]。虽然简单,但它忽略了上下文、意义和单词的顺序。
其中一些,尽管在机器学习和信息检索领域很受欢迎,但由于各种原因,在 RAG 的上下文中并不合理。为了我们的目的,我们关注在 RAG 中使用的一些流行的检索技术。
术语频率-逆文档频率
术语频率-逆文档频率 (TF-IDF) 是一种用于评估单词在文档中相对于文档集合(语料库)的重要性的一种统计度量。它将更高的权重分配给在文档中频繁出现但在语料库中不频繁出现的单词。图 4.3 阐述了如何计算单语元搜索词的 TF-IDF。

图 4.3 根据搜索词计算 TF-IDF 以对文档进行排名
LangChain 还提供了一个 TF-IDF 的抽象实现,使用来自 langchain_community 的检索器,它反过来又使用 scikit-learn:
# Install or Upgrade Scikit-learn
%pip install –-upgrade scikit-learn
# Import TFIDFRetriever class from retrievers library
from langchain_community.retrievers import TFIDFRetriever
# Create an instance of the TFIDFRetriever with texts
retriever = TFIDFRetriever.from_texts(
["Australia won the Cricket World Cup 2023",
"India and Australia played in the finals",
"Australia won the sixth time having last won in 2015"]
)
# Use the retriever using the invoke method
result=retriever.invoke("won")
# Print the results
print(result)
TF-IDF 不仅可用于单语元,也可用于短语(n-gram)。然而,即使 TF-IDF 通过强调独特单词来改进简单的搜索方法,它仍然缺乏对上下文和单词顺序的考虑,这使得它对于像 RAG 这样的复杂任务不太适用。
最佳匹配 25
最佳匹配 25(BM25)是一种用于根据每个文档中出现的查询术语对文档进行排名的高级概率模型。它是概率信息检索模型家族的一部分,被认为是经典 TF-IDF 模型的进步。BM25 带来的改进是它调整了文档的长度,这样较长的文档不会得到不公平的高分。图 4.4 展示了 BM25 的计算过程。

AI 生成的内容可能是不正确的。](../Images/CH04_F04_Kimothi.png)
图 4.4 BM25 也考虑了文档的长度。
与 TF-IDF 类似,LangChain 也使用rank_bm25包提供了一个 BM25(具体来说是 Okapi BM25)的抽象实现:
# Install or Upgrade rank_bm25
%pip install –-upgrade rank_bm25
# Import BM25Retriever class from retrievers library
from langchain_community.retrievers import BM25Retriever
# Create an instance of the TFIDFRetriever with texts
retriever = BM25Retriever.from_texts(
["Australia won the Cricket World Cup 2023",
"India and Australia played in the finals",
"Australia won the sixth time having last won in 2015"]
)
# Use the retriever using the invoke method
result=retriever.invoke("Who won the 2023 Cricket World Cup?")
# Print the results
print(result)
对于长查询而不是单个关键词,计算查询中每个词的 BM25 值,查询的最终 BM25 值是所有词值的总和。BM25 是传统信息检索(IR)中的一个强大工具,但它仍然无法捕捉到 RAG 应用所需的查询和文档的完整语义意义。BM25 通常在 RAG 中用于快速初始检索,然后使用更强大的检索器重新排序结果。我们将在第六章学习重新排序,届时我们将讨论 RAG 的高级策略。
静态词嵌入
如 Word2Vec 和 GloVe 之类的静态嵌入将词表示为连续向量空间中的密集向量,基于上下文捕捉语义关系。例如,“king” − “man” + “woman”近似于“queen”。这些嵌入可以捕捉到 BoW、TF-IDF 和 BM25 所遗漏的细微差别,如相似性和类比。然而,尽管它们提供了更丰富的表示,但它们仍然缺乏完整的上下文理解,并且在处理多义词(具有多个意义的词)方面有限。这里的“静态”一词强调了词的向量表示不会随着输入查询中词的上下文而改变。
上下文嵌入
由 BERT 或 OpenAI 的文本嵌入模型生成,上下文嵌入为查询和文档生成高维、上下文感知的表示。这些基于 transformers 的模型捕捉深层的语义意义和关系。例如,关于“apple”的查询将检索讨论苹果这种水果或苹果科技公司的文档,具体取决于输入查询。图 4.5 展示了静态嵌入和上下文嵌入之间的差异。上下文嵌入在信息检索(IR)中代表了一个重大进步,为 RAG 任务提供了必要的上下文和理解。尽管计算密集,上下文嵌入在 RAG 中是最广泛使用的检索器。第 3.3.2 节中讨论的嵌入模型示例是上下文嵌入。
TF-IDF 和 BM25 等方法使用基于频率的计算来对文档进行排序。在嵌入(静态和上下文)中,排序是基于相似度分数。相似度通常使用文档向量之间角度的余弦值来计算。我们在第 3.3.3 节中讨论了余弦相似度计算。图 4.6 说明了使用嵌入进行检索的过程。
其他检索方法
虽然所讨论的方法在讨论中最为流行,但还有其他方法可供选择。这些方法代表了更近期的进展和专门的方法,如果你想要深入了解信息检索的世界,这些方法是非常好的参考:
-
学习稀疏检索—使用神经网络生成稀疏、可解释的表示(例如:SPLADE,DeepCT,和 DocT5Quer)
-
密集检索—将查询和文档编码为密集向量以进行语义匹配(例如:密集段落检索器 [DPR],ANCE,RepBERT)

图 4.5 静态嵌入与上下文嵌入的比较
-
混合检索—结合稀疏和密集方法以实现平衡的效率和效果(例如:ColBERT,COIL)
-
交叉编码检索—直接使用转换器模型比较查询-文档对(例如:基于 BERT 的重排序器)
-
基于图的检索—使用图结构来建模文档之间的关系(例如:TextGraphs,用于信息检索的图神经网络)
-
量子启发检索—将量子计算原理应用于信息检索(例如:量子语言模型 [QLM])
-
神经信息检索模型—包含各种基于神经网络的信息检索方法(例如:NPRF [神经 PRF],KNRM [基于核的神经网络排序模型])

图 4.6 基于嵌入的检索技术中的相似度计算和结果排序
表 4.1 列出了不同检索器的优缺点。虽然上下文嵌入是开始使用 RAG 所需了解的唯一内容,但熟悉其他检索器对于进一步探索以及当你想要提高检索器性能的情况是有用的。正如我们讨论的,在 LangChain 中使用scikit-learn检索器实现 TF-IDF 和rank_bm25检索器实现 BM25,还有许多其他使用上述提到的方法之一的方法。我们将在下一节中查看一些流行的例子。
表 4.1 RAG 不同检索技术的比较
| 技术 | 关键特性 | 优点 | 缺点 | 适用于 RAG |
|---|---|---|---|---|
| 布尔检索 | 使用逻辑运算符的精确匹配 | 简单、快速、精确 | 有限的相关性排名;无部分匹配 | 低:过于僵化 |
| 词袋模型 | 无序的词频计数 | 简单直观 | 忽略词序和上下文 | 低:缺乏语义理解 |
| TF-IDF | 基于文档和语料库频率的词权重 | 比词袋模型改进的相关性排名 | 仍然忽略语义和词关系 | 低-中等:比词袋模型好但有限;用于混合检索 |
| BM25 | 具有长度归一化的高级排名函数 | 性能稳健;行业标准 | 语义理解有限 | 中等:简单 RAG 的良好基线;用于混合检索。 |
| 静态嵌入 | 固定的密集向量表示 | 捕获一些语义关系 | 与上下文无关;在多义性处理上有限 | 中等:引入基本语义 |
| 上下文嵌入 | 考虑上下文的密集表示 | 丰富的语义理解;处理多义性 | 计算密集 | 高:出色的语义捕获 |
| 学习到的稀疏检索器 | 神经网络生成的稀疏表示 | 高效、可解释且具有一定的语义理解 | 可能会错过一些语义关系 | 高:平衡效率和语义 |
| 密集检索器 | 查询和文档的密集向量匹配 | 强大的语义匹配 | 计算密集;可解释性较低 | 高:非常适合 RAG 中的语义搜索 |
| 混合检索器 | 稀疏和密集方法的组合 | 平衡效率和有效性 | 实现和调整复杂 | 高:适用于各种 RAG 需求的多面手 |
| 跨编码检索器 | 直接查询-文档比较 | 非常准确的相关性评估 | 极其计算密集 | 中-高:非常适合 RAG 中的重排序 |
| 基于图的检索器 | 文档关系的图结构 | 捕获数据中的复杂关系 | 可能复杂于构建和查询 | 中-高:适用于 RAG 中的结构化数据 |
| 受量子启发的检索器 | 信息检索中的量子计算概念 | 处理复杂查询的潜力 | 新兴领域;实际效益尚未完全证明 | 低-中等:有潜力但尚未成熟 |
| 神经信息检索模型 | 适用于信息检索的各种神经网络方法 | 灵活;可以捕获复杂模式 | 通常需要大量训练数据;可能是黑盒 | 高:适用于各种 RAG 场景的适应性 |
4.2.2 流行检索器
开发者可以根据一种或多种检索方法的组合来构建他们的检索器。检索器不仅用于 RAG,还用于各种与搜索相关的任务。
对于 RAG,LangChain 提供了许多集成,其中 TF-IDF、嵌入和相似性搜索、以及 BM25 等算法已被抽象为供开发者使用的检索器。我们已经看到了 TF-IDF 和 BM25 的例子。以下章节中描述了一些其他流行的检索器。
向量存储和数据库作为检索器
向量存储可以作为检索器使用,从而免除开发者计算查询向量嵌入并按相似度和排名结果的责任。FAISS 通常与上下文嵌入模型一起用于检索。其他向量数据库如 PineCone、Milvus 和 Weaviate 通过结合嵌入等密集检索方法和 BM25 和 SPLADE 等稀疏方法提供混合搜索功能。
云服务提供商
云服务提供商 Azure、AWS 和 Google 也提供了他们的检索器。与 Amazon Kendra、Azure AI Search、AWS Bedrock、Google Drive 和 Google Vertex AI Search 的集成为开发者提供了在规模上执行向量、关键词和混合查询信息检索的基础设施、API 和工具。
网络信息资源
与信息资源如维基百科、arXiv 和 AskNews 的连接提供了从这些来源的优化搜索和检索。你可以在官方 LangChain 文档中查看这些检索器和其他更多内容(mng.bz/gm4R)
这是对检索器世界的简要介绍。如果你觉得信息有点复杂,你总是可以随时回过头来再看。在这个阶段,对上下文嵌入的理解就足够了。上下文嵌入是基本 RAG 管道中最受欢迎的技术,我们现在将使用 OpenAI 嵌入创建一个简单的检索器。
4.2.3 简单检索器实现
在我们进入生成管道的下一步之前,让我们看看一个简单的检索器示例。在第三章中,我们正在为 2023 年板球世界杯的维基百科页面进行索引。如果你还记得,我们使用了 OpenAI 的嵌入来编码文本,并使用 FAISS 作为向量索引来存储嵌入。我们还把 FAISS 索引存储在本地目录中。现在让我们重用这个索引:
# Install the langchain openai library
%pip install langchain-openai==0.3.7
# Import FAISS class from vectorstore library
from langchain_community.vectorstores import FAISS
# Import OpenAIEmbeddings from the library
from langchain_openai import OpenAIEmbeddings
# Set the OPENAI_API_KEY as the environment variable
import os
os.environ["OPENAI_API_KEY"] = <YOUR_API_KEY>
# Instantiate the embeddings object
embeddings=OpenAIEmbeddings(model="text-embedding-3-small")
# Load the database stored in the local directory
vector_store=FAISS.load_local(
folder_path="../../Assets/Data",
index_name="CWC_index",
embeddings=embeddings,
allow_dangerous_deserialization=True
)
# Original Question
query = "Who won the 2023 Cricket World Cup?"
# Ranking the chunks in descending order of similarity
retrieved_docs = vector_store.similarity_search(query, k=2)
这个similarity_search()函数返回一个按分数排序的匹配文档列表。这个分数是查询与文档之间相似度的量化,因此被称为相似度分数。在这个例子中,使用了向量索引的内置相似度搜索功能进行检索。作为我们在第 4.2.2 节讨论的检索器之一,向量存储本身充当了检索器。K=2告诉函数检索前两个文档。这是 RAG 系统生成管道中检索器最基本实现,检索方法是通过嵌入实现的。我们使用了 OpenAI 的 text-embedding-3-small。FAISS 根据这些嵌入计算相似度分数。
检索器是 RAG 系统的骨架。检索器的质量对生成输出的质量有很大影响。在本节中,你学习了关于 vanilla 检索方法的内容。在设计生产级系统时,会使用多种策略。我们将在第六章中了解这些高级策略。现在,我们已经了解了检索器,接下来我们将进入下一个重要步骤——增强。
4.3 增强技术
检索器检索与用户查询最相关的信息(或文档)。但是,接下来怎么办?我们如何使用这些信息?答案是相当直观的。如果你还记得第一章的讨论,LLM 的输入是自然语言提示。检索器检索到的信息也应该以自然语言提示的形式发送给 LLM。将用户查询和检索到的信息结合起来的这个过程被称为增强。
RAG 中的增强步骤主要属于提示工程领域。提示工程可以定义为向 LLM 提供指令以实现预期结果的技术。提示工程的目标是通过构建提示,在 LLM 对预期结果(s)的响应中实现准确性和相关性。乍一看,增强似乎很简单——只需将检索到的信息添加到查询中。然而,一些细微的增强技术有助于提高生成结果的品质。见图 4.7 简单增强的示例。

图 4.7 简单增强是将用户查询与检索到的文档结合起来发送给 LLM。
4.3.1 RAG 提示工程技术
提示工程作为一个学科,有时被认为过于简单,不足以被称为工程。你可能听说过这样的话,“英语是新的编程语言。”与 LLM 的交互确实是在自然语言中进行的。然而,同样真实的是,编程的原则不是代码所写的语言,而是机器被指令的逻辑。考虑到这一点,让我们考察不同的逻辑方法,这些方法可以用来增强用户查询与检索到的信息。
上下文提示
为了理解简单的增强技术,让我们回顾第一章。回忆我们的例子“谁赢得了 2023 年板球世界杯?”我们复制了维基百科文章的摘录。这个摘录是检索到的信息。然后我们将这些信息添加到提示中,并提供了额外的指令——“仅根据以下提供的上下文回答。”图 4.8 展示了这个例子。
通过添加这个指令,我们已经设置了我们的生成过程只关注提供的信息,而不是 LLM 的内部知识(或参数化知识)。这是一种简单的增强技术,也被称为上下文提示。请注意,指令可以以任何语言结构给出。例如,我们可以在提示的开头添加指令,例如,“在以下背景下回答问题,谁赢得了 2023 年板球世界杯。信息:<维基百科摘录>。”我们也可以在提示的末尾重申指令——“请记住,只根据提供的背景回答问题,不要从任何其他来源获取信息。”
控制生成提示
有时,信息可能不在检索到的文档中。这种情况发生在知识库中的文档没有与用户查询相关的任何信息时。检索器可能仍然检索到一些与用户查询最接近的文档。在这些情况下,幻觉的可能性增加,因为 LLM 仍然会尝试遵循回答问题的指令。为了避免这种情况,添加了一个额外的指令,告诉 LLM 如果检索到的文档没有适当的信息来回答用户问题(类似于“如果问题不能根据提供的情况回答,就说我不知道。”),则不要回答。在 RAG 的上下文中,这种技术特别有价值,因为它确保了模型的响应基于检索到的信息。如果相关信息尚未检索到或不在知识库中,模型被指示承认这种信息缺失,而不是尝试生成一个可能是不正确的答案。”

AI 生成的内容可能是不正确的。](../Images/CH04_F09_Kimothi.png)
图 4.8 信息通过添加指令增强到原始问题中。
少样本提示
观察到,当生成响应时,LLM 相当好地遵循提示中提供的示例。如果你想生成的内容以特定的格式或风格呈现,建议提供一些示例。在 RAG 中,当在提示中提供检索到的信息时,我们也可以指定某些示例,以帮助引导生成过程,使其以我们需要的方式使用检索到的信息。这种技术被称为少样本提示。在这里,“shot”指的是提示中给出的示例。图 4.9 展示了包含两个示例的提示。

AI 生成的内容可能是不正确的。](../Images/CH04_F09_Kimothi.png)
图 4.9 RAG 上下文中少样本提示的示例
你可能会遇到诸如 单次提示 或 两次提示 等术语,它们用给出的示例数量替换了“少量”一词。相反,当没有给出示例,并且期望 LLM 正确回答时,该技术也称为 零次提示。
思维链提示
观察到引入中间推理步骤可以提高 LLM 在需要复杂推理的任务(如算术、常识和符号推理)中的性能。在 RAG 的上下文中也可以应用这一点。这被称为 思维链,或 CoT,提示。在图 4.10 中,我要求 ChatGPT 根据检索到的信息分析两个团队的表现。

图 4.10 推理任务的思维链(CoT)提示
CoT 提示方法还可以与少量提示技术相结合,在最终问题之前提供少量推理示例。创建这些示例是一项劳动密集型任务。在 auto-CoT 中,示例也是使用 LLM 创建的。
其他高级提示技术
提示工程正变得越来越复杂。持续的研究不断提出提示技术的改进。要深入了解提示工程,让我们来看看以下一些技术:
-
自洽性——虽然 CoT 在 CoT 提示中使用单个推理链,但自洽性旨在采样多个不同的推理路径,并使用它们各自的生成结果来得出最一致的答案。
-
生成式知识提示——这种技术通过动态构建相关的知识链,使用模型的潜在知识来加强推理,探索基于提示的知识生成理念。
-
思维树提示——这种技术维护一个可探索的思维树结构,其中包含旨在解决问题的连贯的中间思维步骤。
-
自动推理和工具使用(ART)——ART 框架自动将模型生成与工具使用交织在一起,用于复杂的推理任务。ART 使用演示来分解问题并集成工具,而无需特定于任务的脚本。
-
自动提示工程师(APE)——APE 框架自动生成和选择最佳指令以引导模型。它使用大型语言模型(LLM)根据输出演示合成任务候选提示解决方案。
-
主动提示——主动提示通过涉及查询、不确定性分析、人工标注和增强推理的过程,动态调整语言模型以适应特定任务的提示。
-
ReAct 提示—ReAct 集成了用于并发推理轨迹和特定任务操作的 LLM,通过与外部工具交互进行信息检索,从而提高性能。当与 CoT 结合时,它最优地利用内部知识和外部信息,增强 LLM 的可解释性和可靠性。
-
递归提示—递归提示将复杂问题分解为子问题,通过按顺序使用提示来解决它们。这种方法有助于在数学问题或问答等任务中的组合泛化,模型基于前一步的解决方案构建。
表 4.2 总结了不同的提示技术。增强的提示工程是一个不断发展的学科。需要注意的是,在为 RAG 应用编写提示时,有很大的创意空间。有效的提示对生成的输出有显著影响。你使用的提示类型将很大程度上取决于你的用例和知识库中信息的性质。
表 4.2 增强提示技术的比较
| 技术 | 描述 | 关键优势 | 最佳用例 | 复杂度 |
|---|---|---|---|---|
| 上下文提示 | 将检索到的信息添加到提示中,并指示关注提供的上下文 | 确保关注相关信息 | 一般 RAG 查询 | 低 |
| 控制生成提示 | 当信息不可用时,指示模型说“我不知道” | 降低幻觉风险 | 当准确性至关重要时 | 低 |
| 少样本提示 | 在提示中提供示例以指导响应格式和风格 | 提高输出一致性和格式遵循 | 当需要特定输出格式时 | 中等 |
| 思维链 (CoT) 提示 | 引入中间推理步骤 | 提高复杂推理任务的表现 | 需要逐步分析的复杂查询 | 中等 |
| 自洽性 | 样本多个不同的推理路径 | 提高答案的一致性和准确性 | 具有多种可能推理方法的任务 | 高 |
| 生成知识提示 | 动态构建相关的知识链 | 使用模型的潜在知识 | 需要广泛知识应用的任务 | 高 |
| 思维树提示 | 维护一个可探索的思维步骤树结构 | 允许更全面的解决问题 | 复杂的多步问题解决 | 高 |
| 自动推理和工具使用 (ART) | 交错模型生成与工具使用 | 提高问题分解和工具集成 | 需要外部工具使用的任务 | 非常高 |
| 自动提示工程师 (APE) | 自动生成和选择最优指令 | 优化特定任务的提示 | 复杂任务的提示优化 | 非常高 |
| 活跃提示 | 动态适应特定任务的 LMs 提示 | 提高特定任务的性能 | 需要自适应提示的任务 | 高 |
| ReAct 提示 | 将推理痕迹与特定任务的操作集成 | 提高性能和可解释性 | 需要推理和操作的任务 | 高 |
| 递归提示 | 将复杂问题分解为子问题 | 有助于组合泛化 | 复杂、多步骤问题 | 高 |
在上一节中,我们已经构建了一个简单的检索器。现在,我们将使用一个简单的上下文提示和受控生成执行增强。
4.3.2 简单增强提示的创建
在 4.2.3 节中,我们能够使用 OpenAI 嵌入实现一个基于 FAISS 的检索器。现在,我们将利用这个检索器并创建增强提示:
# Import FAISS class from vectorstore library
from langchain_community.vectorstores import FAISS
# Import OpenAIEmbeddings from the library
from langchain_openai import OpenAIEmbeddings
# Set the OPENAI_API_KEY as the environment variable
import os
os.environ["OPENAI_API_KEY"] = <YOUR_API_KEY>
# Instantiate the embeddings object
embeddings=OpenAIEmbeddings(model="text-embedding-3-small")
# Load the database stored in the local directory
vector_store=FAISS.load_local(
folder_path="../../Assets/Data",
index_name="CWC_index",
embeddings=embeddings,
allow_dangerous_deserialization=True
)
# Original Question
query = "Who won the 2023 Cricket World Cup?"
# Ranking the chunks in descending order of similarity
retrieved_docs = vector_store.similarity_search(query, k=2)
# Selecting the first chunk as the retrieved information
retrieved_context= retrieved_docs[0].page_content
# Creating the prompt
augmented_prompt=f"""
Given the context below, answer the question.
Question: {query}
Context : {retrieved_context}
Remember to answer only based on the context provided and not from any other source.
If the question cannot be answered based on the provided context, say I don't know.
"""
增强步骤完成后,我们现在可以发送提示到 LLM 以生成期望的结果。你将学习 LLMs 如何生成文本以及生成的细微差别。
4.4 生成
生成是此流程的最终步骤。虽然 LLMs 可以在之前的任何步骤中使用,但生成步骤完全依赖于 LLM。最受欢迎的 LLMs 是由 OpenAI、Anthropic、Meta、Google、Microsoft 和 Mistral 等开发人员开发的。虽然文本生成是 LLMs 的核心能力,但我们现在看到的多模态模型可以处理图像、音频和文本。同时,研究人员正在开发更快、更小的模型。
在本节中,我们将讨论有助于为你的 RAG 系统选择语言模型的因素。然后,我们将继续使用我们迄今为止构建的检索器和增强提示的例子,并通过添加生成步骤来完成它。
4.4.1 LLMs 的分类及其对 RAG 的适用性
截至 2024 年 6 月,有超过一百种 LLMs 可供使用,每周都有新的 LLMs 出现。那么,我们如何决定为我们的 RAG 系统选择哪个 LLM 呢?为了展示决策过程,让我们讨论可以将 LLMs 广泛分类的三个主题:
-
它们是如何被训练的
-
如何访问它们
-
它们的大小
我们将讨论这些主题下的 LLMs,并了解可能影响 LLM 选择的因素。
原始模型与微调模型
训练 LLM 需要大量的数据和计算资源。LLM 的训练是通过无监督学习过程完成的。所有现代 LLMs 都是自回归模型,并且被训练来生成序列中的下一个标记。这些庞大的预训练 LLMs 也被称为基础模型。
你可能会问的问题是,如果 LLMs 只是预测序列中的下一个标记,我们如何能够向这些模型提问和聊天呢?答案是所谓的监督微调,或称SFT。
监督微调是一种用于适应预训练语言模型以特定任务或行为(如问答或聊天)的过程。它涉及在标记数据集上进一步训练预训练的基础模型,其中模型学习将输入映射到特定的期望输出。您从一个预训练模型开始,为目标任务准备一个标记数据集,并在该数据集上训练模型,这将调整模型参数以在目标任务上表现更好。图 4.11 给出了 SFT 过程的概述。

图 4.11 监督微调是一种分类模式训练过程。
尽管基础模型在广泛的任务中具有很好的泛化能力,但在某些用例中,需要微调模型。例如,法律和医疗保健等特定领域的领域适应性、针对分类和命名实体识别(NER)等特定任务的优化以及对话式 AI、个性化等用例,在这些情况下,您可能会观察到微调模型表现更好。
在 RAG(阅读理解生成)的背景下,选择基础模型和微调模型时,应考虑以下标准:
-
*领域特定性**—基础模型具有更广泛的知识,可以处理更广泛的主题和查询,适用于通用 RAG 系统。如果您的 RAG 应用是特定的(例如,处理患者记录或重型机械的说明书),您可能会发现针对特定领域微调模型可以提高性能。
-
*检索集成**—如果您发现您正在使用的基模型没有很好地整合检索到的信息,那么一个训练有素以更好地利用信息的微调模型可以导致生成质量更高。
-
*部署速度**—基础模型可以快速部署,因为不需要额外的训练。要微调模型,您需要花费时间来收集训练数据和模型的实际训练。
-
*响应定制—为了生成特定格式或自定义风格元素(如语气或词汇)的结果,经过微调的模型可能比基础模型更好地满足要求。
-
*资源效率**—微调模型需要更多的存储和计算资源。根据部署规模,微调模型的成本可能更高。
-
*道德一致性**—微调模型允许更好地控制响应,以符合道德准则,甚至某些隐私方面。
标准的总结见表 4.3。
表 4.3 选择基础模型和微调模型的标准
| 标准 | 更好的适用性 | 说明 |
|---|---|---|
| 领域特定性 | 微调模型 | 适用于特定应用(例如,患者记录和说明书)的性能更好 |
| 检索集成 | 微调模型 | 可以训练以更好地利用检索到的信息 |
| 部署速度 | 基础模型 | 无需额外训练即可快速部署 |
| 响应定制 | 微调模型 | 更好地遵守特定格式、风格、语气或词汇要求 |
| 资源效率 | 基础模型 | 需要更少的存储和计算资源 |
| 道德一致性 | 微调模型 | 允许更好地控制对道德指南和隐私的响应 |
微调模型可以更好地控制你的 RAG 系统,但它们成本较高。还存在过度依赖检索以及 RAG 性能与大型语言模型固有能力之间的潜在权衡。因此,是否使用基础模型或微调一个取决于你希望实现哪些改进、数据的可用性、成本以及其他权衡。一般建议从基础模型开始实验,然后逐步过渡到监督微调以提高性能。
开源模型与专有模型
软件开发和分发代表了两种根本不同的方法:开源软件与专有软件。大型语言模型的世界也不例外。一些大型语言模型开发者,如 Meta 和 Mistral,已经公开了模型权重,以促进合作和社区驱动的创新。相比之下,像 OpenAI、Anthropic 和 Google 这样的先驱者则保持了模型的封闭性,提供支持、托管服务和更好的用户体验。
对于 RAG 系统,开源模型提供了定制的灵活性、部署方法和透明度,但需要必要的基础设施来维护模型。专有模型提供商可能对于大量使用来说成本更高,但提供定期更新、易用性、可扩展性和更快的发展,以及其他方面。一些专有模型提供商,如 OpenAI,已经预建了 RAG 功能。您选择哪种类型的模型可能取决于以下一些标准:
-
定制化—开源大型语言模型通常被认为更适合定制化,例如与自定义检索机制的深度集成。开源大型语言模型还允许更好的微调控制。专有模型的定制仅限于 API 功能。
-
易用性—然而,专有模型的使用要容易得多。一些模型,如 OpenAI、Cohere 和类似的产品,提供了优化的、预构建的 RAG 解决方案。
-
部署灵活性—开源模型可以根据您的偏好进行部署(私有云、本地),而专有模型由提供商管理。这也影响到数据安全和隐私。现在大多数专有模型提供商都提供多种部署选项。
选项。
-
成本——开源 LLMs 可能伴随着前期基础设施成本,而私有模型则是基于使用量定价。长期成本和查询量是选择开源和私有模型时需要考虑的因素。大规模部署可能更倾向于使用开源模型。
开源和私有模型在 RAG(检索和生成)之间的选择取决于部署规模、特定领域需求、集成需求以及检索和生成过程中定制的重要性等因素。除此之外,知识更新的需求、透明度、可扩展性、数据结构、合规性等因素将决定模型的选择。讨论的总结见表 4.4
表 4.4 开源和私有模型选择标准
| 标准 | 更好的适用性 | 说明 |
|---|---|---|
| 定制化 | 开源 | 允许与自定义检索机制更深入地集成,并更好地控制微调 |
| 易用性 | 私有 | 提供优化、预构建的 RAG 解决方案,通常更容易使用 |
| 部署灵活性 | 开源 | 可以部署在私有云或本地,提供更多选项 |
| 大规模部署的成本 | 开源 | 尽管前期有基础设施成本,但对于大规模部署可能更具成本效益 |
| 数据安全和隐私 | 开源 | 提供对数据的更多控制,尽管一些私有模型现在提供各种部署选项 |
| 定期更新和支持 | 私有 | 通常提供定期更新和更好的支持 |
混合方法也不被排除。在原型验证阶段,私有模型可能适合快速实验。
这里有一些流行的私有模型示例:
-
OpenAI 的 GPT 系列 (
platform.openai.com/docs/models) -
Anthropic 的 Claude 系列 (
www.anthropic.com/claude) -
Google 的 Gemini 系列 (
mng.bz/eBnJ) -
Cohere 的 Command R 系列 (
cohere.com/command)
一些开源模型是
-
Meta 的 Llama 系列 (
llama.meta.com/) -
Mistral (
docs.mistral.ai/getting-started/models/)
模型大小
大型语言模型(LLMs)有多种大小,通常按它们包含的参数数量来衡量。模型的大小极大地影响了其能力以及资源需求。
较大的模型包含数十亿甚至数万亿的参数。这些模型在推理能力、语言理解和更广泛的知识方面表现出色。它们可以生成更连贯的文本,其回答在上下文中更准确。然而,这些较大的模型在计算、存储和能源需求方面显著较高。
参数规模在数百万或数十亿的小型模型提供了诸如更快的推理时间、更低的资源使用量和更容易在边缘设备或资源受限环境中部署等好处。研究人员和开发者继续探索实现大型模型性能的同时,使用更小和更高效架构的方法。
对于一个 RAG 系统,以下方面应进行评估:
-
资源限制—小型模型具有远低于大型模型的资源使用量。可以使用更小的模型构建轻量级的 RAG 应用,实现更快的推理。
models.
-
推理能力—在资源限制的另一端是模型的语言处理能力。大型模型更适合复杂推理任务,并能处理检索信息中的歧义。因此,小型模型将严重依赖检索信息的质量。
-
部署选项—大型模型的大小使得它们难以部署在边缘设备上。这是小型模型提供的灵活性,使得 RAG 应用能够部署到广泛的设备和环境中。
-
上下文处理—由于拥有更长的上下文窗口,大型模型可能在整合 RAG 系统中的检索信息方面表现得更好。大型模型在处理多样化查询方面也更为出色,而小型模型则难以处理域外查询。在 RAG 系统中,大型模型可能在处理多样或不可预测的查询类型时表现更佳。
实际上,大多数 RAG 应用都是基于大型模型构建的。然而,从长期采用和应用技术的角度来看,小型模型更有意义。各种因素总结在表 4.5 中。
表 4.5 选择小型和大型模型的标准
| 标准 | 更好的适用性 | 说明 |
|---|---|---|
| 资源限制 | 小型模型 | 资源使用量更低;适合轻量级 RAG 应用 |
| 推理能力 | 大型模型 | 更适合复杂推理任务和处理检索信息中的歧义 |
| 部署选项 | 小型模型 | 更灵活;可以部署在边缘设备和资源受限的环境中 |
| 上下文处理 | 大型模型 | 更擅长整合检索到的多个信息片段;更长的上下文窗口 |
| 查询多样性 | 大型模型 | 更好地处理多样和不可预测的查询类型 |
| 推理速度 | 小型模型 | 更快的推理时间;适合需要快速响应的应用 |
流行的小型语言模型示例包括:
-
Microsoft 的 Phi-3 (
azure.microsoft.com/en-us/products/phi-3) -
Google 的 Gemma (
ai.google.dev/gemma)
在你的 RAG 系统中,选择 LLM 是一个核心考虑因素,需要密切注意并反复迭代。你系统的性能可能需要通过实验和调整 LLM 的选择来适应。
LLM 的列表几乎已经无穷无尽。这对开发者和企业来说意味着这项技术已经真正实现了民主化。虽然所有 LLM 都有其独特的提案和架构,但在实际应用中,有各种各样的选择可供选择。简单的 RAG 应用可能依赖于单个 LLM 提供商,但对于更复杂的应用,多 LLM 策略可能更有益。
我们实现了一个简单的检索器并创建了一个增强提示。在本章的最后部分,我们通过创建生成步骤来总结管道。
4.4.2 完成 RAG 管道:使用 LLM 进行生成
我们使用 FAISS 和 OpenAI 嵌入构建了一个简单的检索器,并创建了一个简单的增强提示。现在我们将使用 OpenAI 的最新模型 GPT-4o 来生成响应:
# Import FAISS class from vectorstore library
from langchain_community.vectorstores import FAISS
# Import OpenAIEmbeddings from the library
from langchain_openai import OpenAIEmbeddings
# Set the OPENAI_API_KEY as the environment variable
import os
os.environ["OPENAI_API_KEY"] = <YOUR_API_KEY>
# Instantiate the embeddings object
embeddings=OpenAIEmbeddings(model="text-embedding-3-small")
# Load the database stored in the local directory
vector_store=FAISS.load_local(
folder_path="../../Assets/Data",
index_name="CWC_index",
embeddings=embeddings,
allow_dangerous_deserialization=True
)
# Original Question
query = "Who won the 2023 Cricket World Cup?"
# Ranking the chunks in descending order of similarity
retrieved_docs = vector_store.similarity_search(query, k=2)
# Selecting the first chunk as the retrieved information
retrieved_context= retrieved_docs[0].page_content
# Creating the prompt
augmented_prompt=f"""
Given the context below, answer the question.
Question: {query}
Context : {retrieved_context}
Remember to answer only based on the context provided and not from any other source.
If the question cannot be answered based on the provided context, say I don't know.
"""
# Importing the OpenAI library from langchain
from langchain_openai import ChatOpenAI
# Instantiate the OpenAI LLM
llm = ChatOpenAI(
model="gpt-4o-mini",
temperature=0,
max_tokens=None,
timeout=None,
max_retries=2
)
# Make the API call passing the augmented prompt to the LLM
response = llm.invoke (
[("human",augmented_prompt)]
)
# Extract the answer from the response object
answer=response.content
print(answer)
就这样。我们已经构建了一个生成管道,尽管是一个非常简单的管道。现在它可以从知识库中检索信息并生成与所提问题相关且基于知识库的答案。尝试提出不同的问题以查看管道的泛化能力如何。
现在我们已经涵盖了生成管道的三个步骤——检索、增强和生成。在了解了索引管道(在第三章中介绍)和生成管道之后,你现在已经准备好创建一个基本的 RAG 系统。我们迄今为止讨论的内容可以被称为天真 RAG 实现。天真 RAG 可能会受到不准确性的影响。它可能在正确检索和排序信息方面效率低下。LLM 可能会忽略检索到的信息并仍然进行幻觉。为了讨论和解决这些挑战,在第六章中,我们检查了允许更复杂和性能更好的 RAG 系统的先进策略。
但在之前,系统评估的问题出现了。它是否在预期的线上生成响应?LLM 是否仍在进行幻觉?在尝试提高系统性能之前,我们需要能够衡量和基准测试它。这就是我们在第五章要做的。我们将探讨评估指标和流行的 RAG 基准。
摘要
检索
-
检索是从知识库中根据用户查询找到相关信息的过程。这是一个匹配文档与输入查询的搜索问题。
-
RAG 的流行检索方法包括
-
TF-IDF(词频-逆文档频率**)——相对于语料库的词在文档中的重要性统计量。可以使用 LangChain 的 TFIDFRetriever 实现。
-
BM25(最佳匹配 25**)——一种高级概率模型,是 TF-IDF 的改进。它调整文档长度,可以使用 LangChain 的 BM25Retriever 实现。
-
静态词嵌入**s——将词表示为密集向量(例如,Word2Vec,GloVe)并捕获语义关系,但缺乏完整的上下文理解。
-
上下文嵌入—由 BERT 或 OpenAI 的文本嵌入等模型产生。它们提供上下文感知表示,尽管计算密集,但在 RAG 中应用最广泛。
-
高级检索方法—包括学习稀疏检索、密集检索、混合检索、交叉编码检索、基于图的检索、量子启发检索和神经信息检索模型。
-
-
大多数高级实现将包括混合方法。
-
向量存储和数据库(例如,FAISS、PineCone、Milvus、Weaviate)、云服务提供商解决方案(例如,Amazon Kendra、Azure AI Search、Google Vertex AI Search)和网页信息资源(例如,Wikipedia、Arxiv、AskNews)是 LangChain 提供的流行检索器集成之一。
-
检索器的选择取决于准确性、速度和与索引方法的兼容性等因素。
增强功能
-
增强将用户查询与检索信息相结合,为 LLM 创建提示。
-
提示工程对于有效增强至关重要,旨在提高 LLM 响应的准确性和相关性。
-
RAG 的关键提示工程技术包括
-
上下文提示—在指令中添加检索信息,以关注提供的内容。
-
受控生成提示—指示 LLM 在信息不足时承认缺乏知识。
-
少样本提示—提供示例以指导 LLM 的响应格式或风格。
-
思维链(CoT)提示—为复杂任务引入中间推理步骤。
-
高级技术包括自洽性、生成知识提示和思维树。
-
-
增强技术的选择取决于任务复杂性、期望的输出格式和 LLM 能力。
生成
-
生成是最终步骤,其中 LLM 根据增强的提示生成响应。
-
大型语言模型(LLMs)可以根据它们的训练方式、访问方式和参数数量进行分类。
-
监督微调(SFT)改进了上下文使用和领域优化,增强了连贯性,并使源归因成为可能;然而,它也带来了成本、过度依赖检索的风险以及与 LLM 固有能力的潜在权衡。
-
开源和专有 LLMs 之间的选择取决于定制需求、长期成本和数据敏感性。
-
较大的模型在推理、语言理解和更广泛的知识方面具有优势,并能生成更连贯和上下文准确的响应,但需要高计算和资源需求。较小的模型允许更快的推理、更低的资源使用,并且更容易部署在边缘设备或资源受限的环境中,但它们不具备大型模型相同级别的语言理解能力。
-
流行的大型 LLMs 包括来自 OpenAI、Anthropic、Google 等公司的产品,开源模型可通过 Hugging Face 等平台获得。
-
LLM 的选择取决于性能要求、资源限制、部署环境和数据敏感性等因素。
-
为 RAG 系统选择 LLM 需要仔细考虑、实验,并根据性能进行可能的调整。
第五章:RAG 评估:准确性、相关性和忠实度。
本章涵盖
-
评估 RAG 管道的需求和需求。
-
RAG 评估的指标、框架和基准。
-
RAG 评估的当前局限性和未来发展方向。
第三章和第四章讨论了使用索引和生成管道开发检索增强生成(RAG)系统的进展。RAG 承诺减少幻觉,并将大型语言模型(LLM)的响应基于提供的环境,这是通过为系统创建一个非参数化记忆或知识库,然后从中检索信息来实现的。
本章介绍了评估 RAG 系统功能良好程度的方法。我们需要确保两个 RAG 管道的组件按预期运行。在较高层次上,我们需要确保检索到的信息与输入查询相关,并且 LLM 生成的响应基于检索到的环境。为此,随着时间的推移已经开发出几个框架。在这里,我们讨论了一些流行的框架以及它们计算的指标。
评估还有第二个方面。虽然框架允许计算指标,但如何确保你的 RAG 管道比其他开发者开发的管道表现更好?评估不能孤立进行。为此,已经建立了一些基准。这些基准评估了 RAG 系统在预设数据上的表现,如问答集,以便对不同 RAG 管道进行准确比较。这些基准帮助开发者评估他们的系统与其他开发者开发的系统相比的性能。
最后,像 RAG 技术一样,RAG 评估的研究仍在进行中。当前评估参数集中仍存在一些局限性。我们讨论了这些局限性以及 RAG 评估未来发展的想法。
到本章结束时,你应该
-
了解 RAG 评估的基本原理。
-
了解 RAG 评估的流行框架、指标和基准。
-
理解局限性和最佳实践。
-
能够在 Python 中评估 RAG 管道。
为了让 RAG 实现将 LLM 响应基于数据的承诺,你需要超越简单的索引、检索、增强和生成实现。我们将在第六章中讨论这些高级策略。然而,要改进某物,你首先需要衡量其性能。RAG 评估有助于为你设置 RAG 系统性能的基线,然后你可以对其进行改进。首先,我们来看 RAG 系统评估的基本方面。
5.1 RAG 评估的关键方面
构建一个 PoC RAG 管道并不特别复杂。通过简短的培训和验证一组有限的示例即可实现。然而,为了增强其鲁棒性,在准确反映生产用例的数据集上进行彻底测试是必不可少的。RAG 管道可能会出现自己的幻觉。这可能是由于
-
检索器未能检索到完整上下文,或者检索到了无关的上下文。
-
尽管提供了上下文,但大型语言模型(LLM)并没有考虑它。
-
LLM 从上下文中选择无关信息而不是回答查询。
检索和生成是两个需要从评估角度特别关注的过程。这是因为这两个步骤会产生可评估的输出。(虽然索引和增强会影响输出,但它们不会产生可测量的结果)。以下是关于这两个过程我们需要问自己的几个问题:
-
从知识库中检索上下文的效果如何?
-
它是否与查询相关?
-
存在多少噪声(无关信息)?
-
生成的响应有多好?
-
响应是否基于提供的上下文?
-
响应是否与查询相关?
你可以问更多类似的问题来评估你的 RAG 系统的性能。当代研究已经发现某些评分来评估 RAG 系统的质量和能力。以下几节将讨论三个主要的质量评分和四种主要能力。
5.1.1 质量评分
在 RAG 评估的讨论中,有三个质量评分维度很常见。它们衡量检索和生成的质量:
-
上下文相关性—这个维度评估检索到的信息或上下文与用户查询的相关性。它计算从知识库中检索上下文的精确度和召回率等指标。
-
答案忠实度(也称为扎根性**)—这个维度评估系统生成的答案是否使用了检索到的信息。
-
答案相关性—这个维度评估系统生成的答案与原始用户查询的相关性。
我们将在第 5.2 节讨论这些评分是如何计算的。
5.1.2 必需的能力
质量评分对于衡量 RAG 系统的检索和生成组件表现如何非常重要。在整体层面上,RAG 系统应该具备某些关键能力:
-
噪声鲁棒性—假设 RAG 系统存储的知识库中的信息被完美整理以回答可能提出的问题是不切实际的。很可能一个文档与用户查询相关,但没有任何有意义的答案信息。RAG 系统从相关文档中分离出这些噪声文档的能力被称为噪声鲁棒性。
-
负拒绝—本质上,LLMs 总是生成文本。知识库中的文档可能没有关于用户查询的信息。RAG 系统在没有相关信息时不给出答案的能力被称为负拒绝。
-
信息整合—为了对用户查询给出全面的答案,很可能需要从多个文档中检索信息。系统从多个文档中吸收信息的能力被称为信息整合。
-
反事实鲁棒性—有时知识库中的信息本身可能是不准确的。一个高质量的 RAG 系统应该能够解决这个问题,并拒绝检索到的信息中的已知错误。这种能力被称为反事实鲁棒性。
噪声鲁棒性是检索组件应该具备的能力,而其他能力大多与生成组件相关。
除了这些,延迟是另一个经常提到的能力。尽管它是一个非功能性需求,但在生成 AI 应用中却非常关键。延迟是用户查询和响应之间的延迟。你可能已经注意到,LLMs 在生成最终响应之前有相当大的延迟。再加上检索和增强的任务,延迟肯定会增加。因此,重要的是要监控你的 RAG 系统从用户输入到响应所需的时间。
伦理考量也是生成 AI 应用的前沿。对于某些 RAG 应用,测量系统响应中的偏差和毒性的程度很重要。这也会受到知识库中底层数据的影响。虽然这并不是 RAG 特有的,但评估输出中的偏差和毒性是很重要的。
另一个需要检查的方面是系统的鲁棒性,即其处理不同类型查询的能力。一些查询可能很简单,而另一些可能涉及复杂的推理。一些查询可能需要比较两块信息,而另一些可能涉及复杂的后处理,如数学计算。当我们讨论第 5.4 节中的基准 CRAG 时,我们将探讨一些查询类型。
最后,重要的是要提到,这些是接近 RAG 核心技术层面的分数和能力。毕竟,RAG 是一种解决最终用例的手段。因此,你可能需要为你的 RAG 系统构建特定用例的评估标准。例如,问答系统可能使用精确匹配(EM)或 F1 分数作为指标,而摘要服务可能使用 ROUGE 分数。使用 RAG 的现代搜索引擎可能会考虑用户交互指标、源归属的准确性以及类似指标。
这就是评估 RAG 管道背后的主要思想。我们之前讨论的质量分数和能力需要被衡量和基准化。RAG 评估的两个关键推动者是框架和基准。
框架是设计用来促进评估的工具,提供评估过程和数据生成的自动化。它们通过提供一个结构化的环境来测试 RAG 系统的不同方面,从而简化评估过程。它们是灵活的,可以适应不同的数据集和指标。我们将在第 5.3 节讨论流行的评估框架。
基准是标准化的数据集及其评估指标,用于衡量 RAG 系统的性能。基准为比较不同的 RAG 方法提供了一个共同基础。它们通过考虑一组固定的任务及其评估标准来确保评估的一致性。例如,HotpotQA 侧重于多跳推理和检索能力,使用精确匹配和 F1 分数等指标。
基准用于建立性能基准并识别特定任务或领域中的优势/劣势。我们将在第 5.4 节讨论一些基准及其特性。
开发者可以使用框架将评估集成到他们的开发过程中,并使用基准来比较他们的开发与既定标准。框架和基准都计算关注检索和 RAG 质量分数的指标。我们将在下一节开始讨论指标,然后再讨论流行的基准和框架。
5.2 评估指标
指标量化了对 RAG 系统性能的评估。我们将评估指标分为两大类:
-
在信息检索任务中常用的检索指标
-
随着 RAG 应用的增加而演变的 RAG 特定指标
值得注意的是,还有一些针对自然语言生成的特定指标,如 BLEU、ROUGE 和 METEOR,它们侧重于流畅性,并衡量相关性和语义相似度。它们在分析和基准化 LLMs 性能方面发挥着重要作用。本书讨论了针对检索和 RAG 的特定指标。
5.2.1 检索指标
RAG 的检索组件可以独立评估,以确定检索器在满足用户查询方面的表现如何。主要的检索评估指标包括准确度、精确度、召回率、F1 分数、平均倒数排名(MRR)、平均平均精度(MAP)和归一化折现累积增益(nDCG)。
准确度
准确度通常定义为在考察的总案例中,正确预测(包括真阳性和真阴性)的比例。在信息检索的背景下,它可以解释为

尽管准确度是一个简单直观的指标,但它不是检索的主要指标。在一个大型知识库中,大多数文档通常与任何给定的查询无关,这可能导致误导性高的准确度分数。它不考虑检索结果的排名。
Precision
回收率关注检索结果的品质。它衡量检索到的文档中与用户查询相关的比例。它回答了这样的问题:“在所有检索到的文档中,有多少是相关的?”

更高的精确度意味着检索器表现良好,主要检索到相关文档。
Precision@k
Precision@k 是精确度的一个变体,它衡量在检索到的前‘k’个结果中相关文档的比例。它特别重要,因为它关注的是顶部结果,而不是所有检索到的文档。对于 RAG 来说,它很重要,因为只有顶部结果最有可能被用于增强。例如,如果你限制你的 RAG 系统只使用前五个检索到的文档进行上下文增强,Precision@5 将是计算该指标的度量:

其中‘k’是一个选择的截止点。Precision@5 为 .8 意味着在顶部五个检索到的文档中,有四个是相关的。
Precision@k 也用于比较系统,当不同系统检索到的结果总数可能不同时。然而,局限性在于‘k’的选择可能是任意的,并且这个指标不会超出选择的‘k’。
回收率
回收率关注检索器提供的覆盖率。它衡量从语料库中所有相关文档中检索到的相关文档的比例。它回答了这样的问题:“在所有相关文档中,有多少被检索到了?”

注意,与精确度不同,计算回收率需要先了解相关文档的总数。在具有大量文档的知识库中的大规模系统中,这一要求可能具有挑战性。
与精确度一样,回收率也不考虑检索文档的排名。它也可能具有误导性,因为检索知识库中的所有文档将导致完美的回收率值。图 5.1 可视化了各种精确度和回收率场景。

图 5.1 精确度和回收率
F1 分数
F1 分数是精确度和回收率的调和平均数。它提供了一个平衡检索器质量和覆盖率的单一指标:

该方程式使得 F1 分数惩罚任何得分低的变量;只有当召回率和精确度值都很高时,才能得到高 F1 分数。这意味着分数不能由单个变量正偏斜。图 5.2 说明了 F1 分数如何平衡精确度和召回率。

图 5.2 F1 分数平衡了精确度和召回率。精确度和召回率的中间值比一个非常高而另一个非常低的值得到的 F1 分数要高。
F1 分数提供了一个单一、平衡的度量,可以用来轻松比较不同的系统。然而,它不考虑排名,并且对精确度和召回率给予相同的权重,这可能并不总是理想的。
平均倒数排名
平均倒数排名,或 MRR,在评估相关文档排名时特别有用。它测量列表中第一个相关文档的排名的倒数。MRR 在查询集上计算:

其中 N 是查询总数,ranki 是第 i 个查询的第一个相关文档的排名。
MRR 在你想了解系统如何快速找到相关文档并考虑结果排名时特别有用。然而,由于它没有考虑第一个相关结果之外的内容,当多个相关结果都很重要时,它可能没有用。图 5.3 展示了平均倒数排名的计算方法。

图 5.3 MRR 考虑了排名,但没有考虑所有文档。
均值平均精度
均值平均精度,或 MAP,是一个度量,它结合了不同“k”截止水平的精确度和召回率,即顶部结果的截止数。它计算一个称为平均精度的度量,然后对所有查询进行平均:

其中 Ri 是查询 i 的相关文档数,Precision@k 是截止“k”处的精确度,rel@k 是一个二进制标志,表示排名 k 的文档的相关性。
均值平均精度是所有 N 个查询的平均精度:

MAP 提供了一种在召回率水平上的单一质量度量。当结果排序很重要但计算复杂时,它非常合适。让我们看看图 5.4 中的 MAP 计算示例。

图 5.4 MAP 考虑了所有检索到的文档,并为更好的排名给出更高的分数
归一化折现累积增益
标准化折现累积增益(nDCG)通过考虑相关文档在结果列表中的位置并给予较早出现的相关文档更高的分数来评估排名质量。它在文档具有不同相关度级别的场景中特别有效。为了计算折现累积增益(DCG),检索列表中的每个文档都被分配一个相关性分数 rel,以及一个折扣因子减少文档的权重,随着其排名位置的上升:

其中 reli 是文档在位置 I 的分级相关性,IDCG 是理想 DCG,即完美排名的 DCG。
nDCG 是实际 DCG 与 IDCG 的比率:

图 5.5 展示了 nDCG 计算的示例。

图 5.5 nDCG 处理文档中的相关度级别,并惩罚错误的排名。
nDCG 是一个复杂的指标,计算起来很复杂。它需要文档具有相关性分数,这可能导致主观性,折扣因子的选择对值有显著影响,但它考虑了文档中不同级别的相关性,并给予排名较高的项目更高的权重。
检索系统不仅用于 RAG,还用于各种其他应用领域,如网络和搜索引擎、电子商务产品搜索和个性化推荐、社交媒体广告检索、归档系统、数据库、虚拟助手等。检索指标有助于评估和改进性能,以有效满足用户需求。表 5.1 总结了不同的检索指标。
表 5.1 检索指标
| 指标 | 衡量内容 | 优点 | 用例 | 考虑事项 |
|---|---|---|---|---|
| Accuracy | 检索的整体正确性 | 容易理解;包括真实负例 | 平衡数据集的一般性能 | 在不平衡数据集中可能具有误导性;不考虑排名 |
| Precision | 检索结果的品质 | 容易理解和计算 | 通用检索质量评估 | 不考虑排名或检索的完整性 |
| Precision@k | 前 k 个检索结果的品质 | 专注于 RAG 中最相关的结果 | 仅使用前 k 个结果进行增强 | 根据你的 RAG 系统使用情况选择 k |
| Recall | 相关文档的覆盖率 | 衡量检索的完整性 | 评估是否遗漏了重要信息 | 需要知道语料库中所有相关文档 |
| F1-score | 精确率和召回率的平衡 | 结合质量和覆盖率的单一指标 | 通用检索性能 | 可能会模糊精确率和召回率之间的权衡 |
| 平均倒数排名(MRR) | 快速找到相关文档的速度 | 强调快速找到至少一个相关结果 | 当找到一个好结果就足够时 | 当需要多个相关结果时不太有用 |
| 平均平均精度(MAP) | 不同召回率水平的精度 | 考虑精度和排名 | 对排名检索结果的全面评估 | 计算和解释更复杂 |
| 标准化折现累积增益(nDCG) | 带有分级相关性的排名质量 | 考虑不同程度的相关性和排名 | 当文档具有不同级别的相关性时 | 需要对文档进行相关性评分 |
并非所有检索指标都适用于评估。通常,为了可解释性,更复杂的指标会被忽视。这些指标的使用取决于你在系统性能演变过程中的改进阶段。例如,一开始你可能只是试图提高精确度,而在一个进化的阶段,你可能正在寻找更好的排名。
虽然这些指标主要关注检索,但一些指标是专门为 RAG 应用创建的。这些指标专注于第 5.1 节中讨论的三个质量评分。
5.2.2 RAG 特定指标
用于评估 RAG 应用的三个质量评分是语境相关性、答案相关性和答案忠实度。这些评分具体回答以下三个问题:
-
信息检索是否与用户查询相关?
-
生成的答案是否基于检索到的信息?
-
生成的答案是否与用户查询相关?
让我们来看看这些评分中的每一个。
语境相关性
语境相关性评估检索到的文档与原始查询的相关程度。关键方面包括主题一致性、信息有用性和冗余。存在人类评估方法和语义相似度度量来计算语境相关性。
该指标被检索增强生成评估(RAGAs)框架采用(将在第 5.3 节中进一步讨论)。检索到的上下文应只包含与查询或提示相关的信息。对于语境相关性,估计一个指标 S,其中 S 是检索上下文中与回答查询或提示相关的句子数量:

图 5.6 是高语境和低语境相关性的一个示例。

图 5.6 语境相关性评估检索信息的相关程度
与查询的相关性。
相关句子的数量有时也会根据每个句子与查询的相似度得分之和进行定制。语境相关性确保生成组件可以访问适当的信息。
答案忠实度
答案忠诚度是衡量响应在检索到的上下文中事实基础的程度的指标。忠诚度确保响应中的事实不与上下文矛盾,并且可以追溯到源头。它还确保 LLM 没有产生幻觉。在 RAGAs 框架中,忠诚度首先识别响应中提出的声明数量,并计算这些声明在上下文中存在的比例:

让我们看看图 5.7 中的例子

图 5.7 答案忠诚度评估生成的响应与检索到的上下文之间的接近程度。
忠诚度并非衡量事实准确性的完整指标,它仅评估对上下文的扎根程度。忠诚度的逆指标是幻觉率,它可以计算出响应中生成的声明在检索到的上下文中不存在的比例。
与忠诚度相关的另一个相关指标是覆盖率。覆盖率衡量上下文中相关声明的数量,并计算生成的响应中存在的相关声明的比例。它衡量检索到的段落中的相关信息包含在生成的答案中的程度:

答案相关性
与上下文相关性度量检索到的上下文与查询的相关性一样,答案相关性是衡量响应与查询相关程度的一个指标。此指标侧重于关键方面,例如系统理解查询的能力、响应与查询的相关性以及响应的完整性。
在 RAGAs 中,对于此指标,为初始查询或提示生成一个响应。为了计算分数,然后提示 LLM 多次生成针对生成的响应的问题。然后计算这些问题和原始问题之间的平均余弦相似度。其概念是,如果答案正确地回答了初始问题,LLM 应该能够从中生成与原始问题匹配的问题:

其中 N 是 LLM 生成的查询数量。
注意,答案相关性不是一个衡量真实性的指标,而只是一个衡量相关性的指标。响应可能或可能不是事实准确的,但它可能是相关的。图 5.8 是答案相关性计算的说明。你能找到相关性不高的原因吗?(提示:答案可能包含一些无关的事实。)答案相关性确保 RAG 系统能够提供有用且适当的响应,从而提高用户满意度和系统的实用价值。
权衡和其他考虑因素
这三个指标及其导数构成了 RAG 质量评估的核心。此外,这些指标相互关联,有时还涉及权衡。高上下文相关性通常会导致更高的忠实度,因为系统可以访问更多相关信息。然而,高忠实度并不总是保证高答案相关性。一个系统可能忠实于检索到的段落中的信息,但未能直接回答查询。在不考虑忠实度的情况下优化答案相关性可能会导致看似合适的响应,但包含幻觉或错误信息。
我们在本节中讨论了许多指标。有效解释这些指标对于性能提升至关重要。作为 RAG 系统的创建者,您应该使用这些指标来与其他类似系统进行比较。您还可以观察一致的趋势,以识别您系统的优势和劣势。低精确度高召回率的系统可能表明您的系统检索了大量文档,您可能需要使检索器更加选择性地检索。低精确度低召回率的系统指出检索存在根本问题,您可能需要重新评估索引管道本身。低 MAP 或低上下文相关性分数可能表明存在相同的问题。同样,低 MRR 或低 nDCG 值可能表明检索器的排名算法存在问题。为了解决低答案忠实度或低答案相关性,您可能需要改进您的提示或微调 LLM。

图 5.8 答案相关性是通过计算原始问题和合成问题之间的余弦相似度的平均值来计算的。
也可能存在一些需要您权衡的权衡。提高精确度通常会降低召回率,反之亦然。高度相关但简短的上下文可能导致答案不完整,而高答案忠实度有时可能以牺牲答案相关性为代价。
每个指标相对的重要性将取决于您的用例和用户需求。您可能需要包括针对您的下游用例特定的其他指标,例如用于衡量简洁性的摘要,以及用于强调对话连贯性的聊天机器人。
开发者可以从头开始编写这些指标并将其集成到他们 RAG 系统的开发和部署过程中。然而,您会发现现成的评估框架非常方便。我们将在下一节讨论三个流行的框架。
人工评估和真实数据
我们在本节中讨论的大多数指标都涉及相关文档的概念。例如,精确度是检索到的相关文档数量除以检索到的总文档数量。出现的问题是,一个人如何确定一个文档是相关的?
简单的答案是采用人工评估方法。主题专家查看文档并确定相关性。人工评估引入了主观性,因此,人工评估是由专家小组而不是个人进行的。但人工评估在规模和成本方面存在限制。
任何可以可靠地建立相关性的数据都变得极其有用。地面实据是已知为真实或正确的信息。在 RAG 和生成式 AI 领域,地面实据是一组准备好的提示-上下文-响应或问题-上下文-响应示例,类似于监督机器学习中的标记数据。为您的知识库创建的地面实据数据可以用于评估您的 RAG 系统。
如何创建地面实据数据?这可以被视为一次性的练习,其中一组专家创建这些数据。然而,从文档中手动生成数百个 QCA(问题-上下文-答案)样本可能是一个耗时且劳动密集型的任务。此外,如果知识库是动态的,地面实据数据也需要更新。由人类创建的问题可能面临达到全面评估所需复杂性的挑战,这可能会影响评估的整体质量。
LLMs(大型语言模型)可以用来解决这些挑战。合成数据生成使用 LLMs 从知识库中的文档生成多样化的问题和答案。LLMs 可以被提示创建问题,如简单问题、多上下文问题、条件问题、推理问题等,使用知识库中的文档作为上下文。
5.3 框架
框架为 RAG 评估提供了一个结构化的方法。它们可以用来自动化评估过程。一些框架甚至超越了这一点,并帮助生成合成地面实据数据。虽然新的评估框架仍在不断推出,但这里我们讨论两个流行的框架:
-
RAGAs(检索增强生成评估)
-
ARES(自动 RAG 评估系统)
5.3.1 RAGAs
Retrieval-Augmented Generation Assessment(RAGAs,检索增强生成评估),是由 Exploding Gradients 开发的一个框架,它评估 RAG 系统的检索和生成组件,而不依赖于大量的人工标注。RAGAs
-
通过合成生成一个可用于评估 RAG 管道的测试数据集。
-
使用指标来衡量管道的性能。
-
监控生产中的应用质量。
我们将继续以 2023 年板球世界杯的维基百科页面为例,但首先使用 RAGAs 创建一个合成测试数据集,然后使用 RAGAs 指标来评估我们在第三章和第四章中创建的 RAG 管道的性能。
合成测试数据集生成(地面实据)
第 5.2 节指出,为了计算评估 RAG 管道质量的评估指标,需要真实数据。虽然这些数据可以手动整理,但 RAGAs 提供了从知识库中的文档生成此数据集的功能。
RAGAs 使用一个 LLM 来完成这项工作。它分析知识库中的文档,并使用 LLM 从知识库的片段中生成种子问题。这些问题基于知识库中的文档片段。这些片段作为问题的上下文。另一个 LLM 用于生成这些问题的答案。这就是它如何根据知识库中的文档生成问题-上下文-答案数据的方式。RAGAs 还有一个进化模块,它创建更难的问题(例如,多上下文、推理和条件)以进行更全面的评估。图 5.9 说明了使用 RAGAs 生成合成数据的过程。

图 5.9 使用 RAGAs 生成合成真实数据
为了评估我们的 RAG 管道,让我们像在第三章中做的那样重新创建 Wikipedia 页面的文档。请注意,为了继续以下代码,我们不得不安装前几章中使用的包:
#Importing the AsyncHtmlLoader
from langchain_community.document_loaders import AsyncHtmlLoader
#This is the URL of the Wikipedia page on the 2023 Cricket World Cup
url="https://en.wikipedia.org/wiki/2023_Cricket_World_Cup"
#Instantiating the AsyncHtmlLoader
loader = AsyncHtmlLoader (url)
#Loading the extracted information
html_data = loader.load()
from langchain_community.document_transformers import Html2TextTransformer
#Instantiate the Html2TextTransformer function
html2text = Html2TextTransformer()
#Call transform_documents
html_data_transformed = html2text.transform_documents(html_data)
html_data_transformed包含 Wikipedia 页面的必要文档格式。我们将使用 RAGAs 库从这些文档生成数据集。为此,我们首先需要安装 RAGAs 库:
%pip install ragas== 0.2.13
# Import necessary libraries
from ragas.llms import LangchainLLMWrapper
from ragas.embeddings import LangchainEmbeddingsWrapper
from ragas.testset import TestsetGenerator
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
# Instantiate the models
generator_llm =
LangchainLLMWrapper(
ChatOpenAI(model="gpt-4o-mini")
)
generator_embeddings =
LangchainEmbeddingsWrapper(
OpenAIEmbeddings(model="text-embedding-3-small")
)
# Create the TestsetGenerator
generator =
TestsetGenerator(
llm=generator_llm,
embedding_model=generator_embeddings
)
# Call the generator
testset =
generator.generate_with_langchain_docs
(
html_data_transformed,
test_size=20,
)
我们创建的testset包含基于我们文档的 20 个问题,以及问题所基于的文档片段和真实答案。数据集的截图显示在图 5.10 中。

图 5.10 使用 RAGAs 生成的合成测试数据
我们将使用这个数据集来评估我们的 RAG 管道。
重新创建 RAG 管道
从创建的测试数据集中,我们使用问题和真实答案信息。我们将问题传递给我们的 RAG 管道并生成答案。我们将这些答案与真实答案进行比较,以计算评估指标。首先,我们重新创建我们的 RAG 管道。再次强调,为了继续编写代码,我们不得不安装前几章中使用的包:
# Import FAISS class from vectorstore library
from langchain_community.vectorstores import FAISS
# Import OpenAIEmbeddings & ChatOpenAI from the library
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
def rag_function(query, db_path, index_name):
# Instantiate the embeddings object
embeddings=OpenAIEmbeddings(model="text-embedding-3-small")
# Load the database stored in the local directory
db=FAISS.load_local(
folder_path=db_path,
index_name=index_name,
embeddings=embeddings,
allow_dangerous_deserialization=True
)
# Ranking the chunks in descending order of similarity and selecting the top 2 queries
retrieved_docs = db.similarity_search(query, k=2)
# Keeping text of top 2 retrieved chunks
retrieved_context=[ retrieved_docs[0].page_content
+retrieved_docs[1].page_content]
# Creating the prompt
augmented_prompt=f"""
Given the context below, answer the question.
Question: {query}
Context : {retrieved_context}
Remember to answer only based on the context
provided and not from any other source.
If the question cannot be answered based
on the provided context, say I don't know.
"""
# Instantiate the LLM
llm = ChatOpenAI(
model="gpt-4o-mini",
temperature=0,
max_tokens=None,
timeout=None,
max_retries=2
)
# Create message to send to the LLM
messages=[("human",augmented_prompt)]
# Make the API call passing the message to the LLM
response = llm.invoke(messages)
# Extract the answer from the response object
answer=response.content
return retrieved_context, answer
我们可以尝试这个管道来生成答案。
# Location of the stored vector index created by the indexing pipeline
db_path='../../Assets/Data'
# User Question
query="Who won the 2023 cricket world cup?"
# Index Name
index_name="CWC_index"
# Calling the RAG function
rag_function(query, db_path, index_name)
现在我们有了 RAG 管道函数,我们可以使用合成的这些问题来评估这个管道。
评估
我们首先使用我们的 RAG 管道对合成测试数据集中的问题生成答案。然后,我们将这些答案与真实答案进行比较。我们首先生成答案:
# Create Lists for Questions and Ground Truths from testset
sample_queries =
dataset.to_pandas()['user_input'].to_list()
expected_responses=
dataset.to_pandas()['reference'].to_list()
# Iterate through the testset to generate responses to questions
dataset_to_eval=[]
for query, reference in zip(sample_queries,expected_responses):
# Call the RAG function
rag_context, rag_answer=rag_function(query,db_path,index_name)
# Create a dictionary of question, answer, context, and ground truth
dataset_to_eval.append(
{
"user_input":query,
"retrieved_contexts":relevant_docs,
"response":response,
"reference":reference
}
)
对于 RAGAs,评估集需要以Dataset格式:
# Import the EvaluationDataset library
from ragas import EvaluationDataset
evaluation_dataset = EvaluationDataset.from_list(dataset_to_eval)
现在我们有了完整的评估数据集,我们可以调用指标:
#Import all the libraries
from ragas import evaluate
from ragas.metrics import (
LLMContextRecall,
Faithfulness,
FactualCorrectness,
AnswerCorrectness,
ResponseRelevancy)
#Set the judge LLM for evaluation
evaluator_llm =
LangchainLLMWrapper(
ChatOpenAI(model="gpt-4o-mini")
)
# Calculate the metrics for the dataset
result = evaluate(
dataset=evaluation_dataset,
metrics=[
LLMContextRecall(),
Faithfulness(),
AnswerCorrectness(),
ResponseRelevancy(),
FactualCorrectness()],
llm=evaluator_llm)
您还可以查看 RAGAs 的官方文档以获取更多信息(docs.ragas.io/en/stable/)。RAGAs 计算一系列对评估 RAG 管道质量有用的指标。RAGAs 使用一个 LLM 来完成这个相对主观的任务。例如,为了计算给定问题-上下文-答案记录的忠实度,RAGAs 首先将答案分解成简单的陈述。然后,对于每个陈述,它会询问 LLM 该陈述是否可以从上下文中推断出来。LLM 会提供一个 0 或 1 的响应,并附上原因。这个过程会重复几次。最后,忠实度被计算为 LLM 判断为忠实(即 1)的陈述的比例。使用基于 LLM 的方法还计算了其他几个指标。这种在评估任务中使用 LLM 的方法也被称为LLM 作为评委方法。需要注意的是,这种评估的准确性也取决于作为评委使用的 LLM 的质量。
5.3.2 自动 RAG 评估系统
自动 RAG 评估系统,或 ARES,是由斯坦福大学和 Databricks 的研究人员开发的一个框架。与 RAGAs 类似,ARES 在评估中使用 LLM 作为评委的方法。两者都要求语言模型对给定查询的答案相关性、上下文相关性和忠实度进行分类。然而,也有一些不同之处:
-
RAGAs 依赖于发送给 LLM 进行评估的启发式提示。相比之下,ARES 使用语言模型训练一个分类器。
-
RAGAs 通过汇总 LLM 的响应来得出分数。ARES 使用一个名为预测增强推理(PPI)的框架为分数提供置信区间。
-
RAGAs 从文档中生成一个简单的合成问题-上下文-答案数据集用于评估。ARES 生成包含查询-段落-答案三元组的正负例的合成数据集。
ARES 需要比 RAGAs 更多的数据。要使用 ARES,您需要以下三个数据集:
-
领域内段落集——这是一组与被评估的具体领域相关的段落。这些段落应该适合生成查询和答案。在我们的案例中,它将是来自维基百科文章的文档。
-
人类偏好验证集——需要至少大约 150 个标注数据点。这个集合用于验证人类标注者对生成的查询-段落-答案三元组的关联性的偏好。
-
少量示例——至少需要五个领域内查询和答案的示例。这些示例有助于在合成数据生成过程中提示 LLMs。
对于人类偏好验证集的需求以及对语言模型进行分类的微调使得应用 ARES 更加复杂。ARES 的应用超出了本书的范围。然而,ARES 是一个鲁棒的框架。它提供了对系统性能的详细分析,包括统计置信区间,使其适合深入评估 RAG 系统。RAGAs 承诺在没有依赖人类标注的情况下实现更快的评估周期。有关 ARES 应用的更多详细信息,请参阅官方 GitHub 仓库(github.com/stanford-futuredata/ARES)。
虽然 RAGAs 和 ARES 已经获得了流行,但还有其他框架,如 TruLens、DeepEval 和 RAGChecker,这些框架也得到了 RAG 开发者的认可。
框架提供了一种标准化的方法来自动化评估您的 RAG 管道。您选择的评估框架应取决于您的用例需求。对于快速且易于理解的评估,RAGAs 可能是您的选择。对于跨多个领域和问题类型的鲁棒性,ARES 可能更适合。大多数专有服务提供商(向量数据库、LLMs 等)都有您可能使用的评估功能。您也可以开发自己的指标。
接下来,我们将探讨基准测试。基准测试用于比较相互竞争的 RAG 系统。
5.4 基准测试
基准测试提供了一种标准参考点,用于评估系统的质量和性能。RAG 基准测试是一组标准化任务和用于比较不同 RAG 系统在检索相关信息和生成准确响应效率的数据库。自 2023 年以来,随着 RAG 开始流行,基准测试的数量急剧增加,但在那之前就已经有用于问答任务的基准测试。例如,斯坦福问答数据集(SQuAD)、WikiQA、自然问题(NQ)和 HotpotQA 都是开放域问答数据集,主要使用精确匹配(EM)和 F1 分数等指标来评估检索组件。BEIR 或基准信息检索是一个基于 9 个信息检索任务和 19 个问答数据集的全面、异构基准。本节讨论了三个流行的 RAG 特定基准及其评估。
5.4.1 RGB
检索增强生成基准(RGB)在 2023 年 12 月的一篇论文中提出(arxiv.org/pdf/2309.01431)。它包含 600 个基础问题和 400 个附加问题,英语和中文各占一半。语料库是通过一个多步骤过程构建的,包括收集最近的新闻文章,使用 ChatGPT 生成问题和答案,通过 Google 的 API 检索相关网页,并使用密集检索模型选择最相关的文本片段。它是一个专注于 RAG 系统四个关键能力的基准:噪声鲁棒性、负拒绝、信息整合和反事实鲁棒性,如图 5.11 所示。
RGB 专注于以下指标进行评估:
-
准确性—用于噪声鲁棒性和信息整合。它基于生成的文本与正确答案的精确匹配。
-
拒绝率—用于负拒绝。它通过模型输出与特定拒绝短语的精确匹配来衡量。拒绝率也

图 5.11 RAG 系统所需的四种能力。来源:陈等人发表的《检索增强生成中的大型语言模型基准测试》,arxiv.org/pdf/2309.0143。
-
以确定响应是否包含拒绝信息。
-
错误检测率—用于反事实鲁棒性。它通过模型输出与特定错误检测短语的精确匹配来衡量,并使用 ChatGPT 进行评估。
-
错误纠正率—用于反事实鲁棒性。它衡量模型在识别错误后是否可以提供正确答案。
您可以使用 GitHub 仓库来实施 RGB (github.com/chen700564/RGB)。
多跳 RAG
由香港科技大学的研究人员整理的多跳 RAG 包含 2556 个查询,每个查询的证据分布在两到四份文档中。查询还涉及文档元数据,反映了在现实世界的 RAG 应用中常见的复杂场景。它包含四种类型的查询:
-
推理—跨多个来源综合信息(例如,哪份报告讨论了苹果的供应链风险——2019 年年度报告还是 2020 年年度报告?)
-
比较—比较不同来源的事实(例如,Netflix 或 Google 是否在 2023 年报告了更高的收入?)
-
时间性—分析事件的时序(例如,例如,苹果是在第五代 iPad Pro 发布前还是之后推出 AirTag 跟踪设备?)
-
空值—无法从知识库中回答的查询
完整的实现代码可在 github.com/yixuantt/MultiHop-RAG 找到。
CRAG
由 Meta 和 HKUST 精心制作的综合 RAG 基准(CRAG)是一个包含 4,409 个问答对和模拟 API 的实际问答基准,用于模拟网络和知识图谱(KG)搜索。它包含八个类型(简单、条件、比较问题、聚合问题、多跳问题、集合查询、后处理密集型问题和错误前提问题,如图 5.12 所示)的查询,涵盖五个领域(金融、体育、音乐、电影和开放领域)。
对于评估集中的每个问题,CRAG 使用四个类别之一对答案进行标记:
-
完美—响应正确回答了用户的问题,且不包含任何幻觉内容(评分为 +1)。
-
可接受—响应提供了对用户问题的有用答案,但可能包含一些不影响答案有用性的小错误(评分为 +0.5)。
-
缺失—响应是“我不知道”、“很抱歉我找不到...”,系统错误(如空响应)或系统请求澄清原始问题的请求(评分为 0)。
-
错误—响应提供了错误或不相关的信息来回答用户的问题(评分为 -1)。

图 5.12 CRAG 中的八种问题类型
对于自动评估,CRAG 将答案精确匹配到基准真实值时将其分类为完美。如果不匹配,则要求一个 LLM 进行分类。它使用了两个 LLM 评估器。您可以在 arxiv.org/pdf/2406.04744 上了解更多关于 CRAG 的信息。
其他值得注意的基准数据集包括专注于医疗信息的 MedRAG (github.com/Teddy-XiongGZ/MedRAG),专注于中文的 CRUD-RAG (arxiv.org/pdf/2401.17043),以及专注于联邦搜索的 FeB4RAG (arxiv.org/abs/2402.11891)。如果您正在开发一个以准确和上下文生成为核心主张的 LLM 应用程序,您将通过展示它在不同基准上的表现来展示您应用程序的质量。表 5.2 比较了不同的基准。
表 5.2 RAG 基准
| 基准 | 数据集 | 任务 | 指标 | 适用性 |
|---|---|---|---|---|
| SQuAD | 斯坦福问答数据集 | 开放域问答 | 精确匹配 (EM), F1-score | 一般问答任务,对理解准确性的模型评估 |
| 自然问题 | 真实 Google 搜索查询 | 开放域问答 | F1-score | 真实世界的问答,从大型语料库中检索信息 |
| 火锅问答 | 基于维基百科的问答 | 多跳问答 | EM, F1-score | 涉及多个文档、复杂推理任务的问答 |
| BEIR | 多个数据集 | 信息检索 | nDCG@10 | 多个领域的综合信息检索模型评估 |
| RGB | 新闻文章、ChatGPT 生成的问答 | 强健问答 | 准确率、拒绝率、错误检测率、错误纠正率 | RAG 系统的鲁棒性和可靠性 |
| 多跳 RAG | 香港科技大学整理的查询 | 复杂问答 | 各种 | 需要跨源综合的 RAG 应用 |
| CRAG | 多个来源(金融、体育、音乐等) | 事实问答 | 四类评估(完美、可接受、缺失和错误) | 使用不同问题类型评估事实问答 |
我们已经研究了帮助自动化计算评估指标和基准框架,这些基准框架能够实现不同实现和方法的比较。框架将帮助您提高系统的性能,而基准将有助于将其与其他市场上可用的系统进行比较。
然而,与任何不断发展的领域一样,有一些限制和挑战需要考虑。下一节将探讨这些限制,并讨论为解决这些问题而出现的最佳实践,以确保对 RAG 评估采取更全面和细致的方法。
5.5 限制和最佳实践
在用于 RAG 评估的框架和基准方面已经取得了很大的进展。评估的复杂性源于检索和生成组件之间的相互作用。在实践中,对人类判断的依赖很大,这些判断是主观的,难以扩展。以下是一些常见的挑战和一些指导方针,以帮助应对这些挑战。
缺乏标准化指标
对于评估 RAG 系统,没有共识认为哪些是最好的指标。对于检索,通常测量精确率、召回率和 F1 分数,但它们并不能完全捕捉生成响应的细微差别。同样,常用的生成指标如 BLEU、ROUGE 等也不能完全捕捉 RAG 所需的上下文意识。使用针对 RAG 的特定指标,如答案相关性、上下文相关性和忠实度进行评估,可以引入 RAG 评估所需的必要细微差别。然而,即使是这些指标,也没有标准的计算方法,每个框架都带来了自己的方法。
最佳实践:比较不同框架在 RAG 特定指标上的结果。有时,根据用例更改计算方法可能是合理的。
过度依赖 LLM 作为评判者
RAG 特定指标(在 RAGAs、ARES 等中)的评估依赖于使用一个 LLM 作为评判者。LLM 被提示或微调以将响应分类为相关或不相关。这增加了 LLM 执行此任务复杂性的程度。可能的情况是,LLM 在评判您特定的文档和知识库时可能不太准确。另一个问题是自我参照。如果评判 LLM 与您的系统中的生成 LLM 相同,您可能会得到更有利的结果。
最佳实践:从裁判 LLM 中抽取一些结果并评估这些结果是否与普遍理解的企业实践一致。为了避免自引用问题,请确保使用与生成 LLM 不同的裁判 LLM。如果你使用多个裁判 LLM 并汇总他们的结果,这也可能有所帮助。
缺乏用例主观性
大多数框架在评估时采用通用方法。它们可能无法捕捉与你用例相关的任务的主体性质(内容生成与聊天机器人、问答等)。
最佳实践:关注特定用例的指标来评估质量、连贯性、有用性和类似方面。在你的工作流程中结合人类判断,使用用户反馈、众包或专家评分等技术。
基准是静态的
大多数基准都是静态的,没有考虑到信息的演变性质。RAG 系统需要适应实时信息的变化,而这些变化目前还没有得到有效测试。缺乏对 RAG 模型如何随时间学习并适应新数据的评估。大多数基准都是领域无关的,这可能无法反映你特定领域的 RAG 系统的性能。
最佳实践:使用针对你领域定制的基准。基准的静态性质是有限的。不要过度依赖基准,并使用定期更新的数据来补充基准的使用。
可扩展性和成本
评估大规模 RAG 系统比评估基本的 RAG 管道更复杂。它需要大量的计算资源。基准和框架通常也不考虑如延迟和效率等对现实应用至关重要的指标。
最佳实践:在评估时,仔细采样测试用例。结合工作流程来衡量延迟和效率。
除了这些,你还应仔细考虑偏差和毒性等方面,重点关注信息整合和负面拒绝,这些框架评估得并不好。同时,也要关注这些评估框架和基准的演变。
在本章中,我们全面考察了评估指标、框架和基准,这些将帮助你评估你的 RAG 管道。我们使用了 RAGAs 来评估我们一直在构建的管道。
到目前为止,我们已经探讨了构建和评估一个简单的 RAG 系统。这也标志着本书的第二部分 2。你现在已经熟悉了使用索引管道创建 RAG 知识大脑,使用生成管道实现实时交互,以及使用框架和基准来评估你的 RAG 系统。
在下一部分,我们将转向讨论 RAG 系统的生产方面。在第六章中,我们将探讨改进 RAG 管道的策略和高级技术,这些也应反映在更好的评估指标中。在第七章中,我们将探讨使 RAG 在生产中成为可能的 LLMOps 堆栈。
摘要
RAG 评估基础
-
RAG 评估评估系统在提供的上下文中减少幻觉和地面响应的能力。
-
RAG 评估的三个关键质量分数是上下文相关性、答案忠实度和答案相关性。
-
RAG 系统所需的四个关键能力包括噪声鲁棒性、负拒绝、信息整合和反事实鲁棒性。
-
需要考虑的额外因素包括响应的延迟、鲁棒性、偏差和毒性。
-
应该开发定制化的特定用例指标来评估性能。
评估指标
-
检索指标包括精确率、召回率、F1 分数、平均倒数排名(MRR)、平均平均精度(MAP)和归一化折现累积增益(nDCG)。
-
准确率、精确率、召回率和 F1 分数不考虑结果的排名顺序。
-
RAG 特定指标关注上下文相关性、答案忠实度和答案相关性。
-
人工评估和真实数据在 RAG 评估中起着至关重要的作用。
评估框架
-
RAGAs 是一个易于实现的框架,可用于快速评估 RAG 管道。
-
ARES 采用更复杂的方法,包括分类器训练和置信区间计算。
基准
-
基准为比较特定任务上不同 RAG 实现提供了标准化的数据集和指标。
-
流行基准如 SQuAD、自然问题、HotpotQA 和 BEIR 专注于检索质量。
-
近期基准如 RGB、多跳 RAG 和 CRAG 从 RAG 的角度看更为全面。
-
基准关注 RAG 性能的不同方面,如多跳推理或特定领域。
局限性和最佳实践
-
RAG 评估的挑战包括缺乏标准化指标、过度依赖 LLM 作为评判者以及基准的静态性质。
-
最佳实践包括使用多个框架、结合特定用例指标和定期更新评估数据。
-
平衡自动化指标与人工判断,并考虑特定用例的要求至关重要。
-
RAG 评估领域正在发展,新的框架和基准不断涌现。
-
开发者应关注新进展并相应地调整评估策略。
第六章:RAG 系统进展:简单、高级和模块化 RAG
本章涵盖了
-
简单 RAG 方法局限性
-
高级 RAG 策略和技术
-
RAG 中的模块化模式
在本书的前两部分中,你学习了检索增强生成(RAG)的效用,以及基本 RAG 系统的开发和评估。我们讨论的基本或简单的 RAG 方法,在面向生产级系统时通常是不够的。
本章重点介绍 RAG 的更高级概念。我们首先回顾简单 RAG 方法的局限性和失败点。接下来,我们讨论检索、增强和生成阶段的失败。在 RAG 管道的不同阶段,将详细阐述解决这些失败点的先进策略和技术。
更好的知识库索引导致更好的 RAG 结果。我们将探讨一些基于简单索引管道构建的数据索引策略,以改善知识库的可搜索性。
在生成管道中,改进被分为三个阶段:检索前、检索和检索后。检索前技术侧重于操作和改进用户查询的输入。检索策略侧重于更好地匹配用户查询与知识库中的文档。最后,在检索后阶段,重点是使检索到的上下文与期望的结果对齐,并使其适合生成。
本章的最后部分讨论了一种模块化方法,该方法正在出现并试图在 RAG 系统中找到适用性。模块化方法是对基本 RAG 系统的架构增强。
注意,RAG 改进的策略和技术是广泛的,本章突出了一些流行的策略。本章穿插了代码示例,但如需更全面的辅助代码,请查看本书的源代码仓库。
到本章结束时,你应该
-
了解为什么简单的 RAG 方法不适合生产。
-
了解使 RAG 知识库更高效的索引策略。
-
了解一些流行的检索前、检索和检索后技术。
-
熟悉 RAG 的模块化方法。
RAG(检索增强生成)为各种人工智能应用提供动力。然而,在结果方面存在一定的不确定性。在将 RAG 应用于生产之前,需要解决检索中的不准确、上下文不连贯以及 LLM(大型语言模型)输出中的不连贯问题。在很短的时间内,研究人员和从业者已经尝试了创新技术来提高 RAG 系统的相关性和忠实度。但在我们探讨这些技术之前,了解为什么简单的 RAG 方法通常无法进入生产环境是很重要的。
6.1 简单 RAG 局限性
天真的 RAG 可以被认为是 RAG 的最早形式,它在 ChatGPT 发布和 LLM 技术兴起后变得流行。如我们所见,它遵循索引、检索、增强和生成的线性过程。这个过程属于“检索后读取”框架,这意味着有一个检索器检索信息,还有一个 LLM 读取这些信息以生成结果,如图 6.1 所示。

图 6.1 天真的 RAG 是一个顺序的“检索后读取”过程。
天真的 RAG 方法在三个阶段都存在缺陷:
-
检索—天真的检索通常观察到精度低,导致检索到不相关信息。它还有低召回率,这意味着相关信息被遗漏,导致结果不完整。
-
增强—当多个检索到的文档包含相似信息时,存在冗余和重复的真正可能性。此外,当信息来自不同的文档时,上下文变得不连贯。还有 LLM 上下文长度的问题,它会影响传递给 LLM 用于生成的检索上下文的数量。
-
生成—由于上游过程的不足,生成过程受到幻觉和生成内容缺乏根基的影响。LLM 在协调信息时面临挑战。毒性和偏见的问题也持续存在。有时也注意到 LLM 过度依赖检索到的上下文,并忘记从其自身的参数记忆中提取信息。
图 6.2 总结了这些缺陷。

图 6.2 天真 RAG 在过程中的每个阶段的缺陷
在过去几年中,进行了大量研究和实验来解决这些缺陷。早期方法包括预训练语言模型。还尝试了涉及 LLM 微调、嵌入模型和检索器的技术。这些技术需要训练数据和模型权重的重新计算,通常使用监督学习技术。由于本书是一本基础指南,我们将不会深入这些复杂的技术。
本章涵盖了在两个 RAG 管道的不同阶段使用的干预、技术和策略:索引和生成管道。尽管这样的干预措施种类繁多,但下文将突出一些更受欢迎的。
6.2 高级 RAG 技术
自从最早的天真 RAG 实验以来,RAG 的高级技术一直在不断涌现。我们可以从以下三个阶段来讨论这些技术:
-
检索前阶段—正如其名所示,可以在检索器开始行动之前采取某些干预措施。这大致涵盖两个方面:
-
索引优化——在知识库中存储文档的方式
-
查询优化——优化用户查询,使其更好地与检索和生成任务对齐
-
-
检索阶段——某些策略可以提高检索过程的召回率和精确率。这超出了第四章中讨论的底层检索算法的能力。
-
后检索阶段——一旦信息被检索出来,上下文可以进一步优化,以更好地与生成任务和下游 LLM 对齐。
在这三个阶段采用的技术,高级 RAG 过程遵循“重写然后检索然后重新排序然后阅读”的框架。增加了重写和重新排序的两个额外组件,并且与简单的 RAG 相比,检索组件得到了增强。这种结构在图 6.3 中展示。

图 6.3 高级 RAG 是一个重写-检索-重新排序-阅读的过程,与简单的检索-阅读 RAG 过程相比。
我们现在将逐一探索这些组件,从预检索阶段开始。
6.3 预检索技术
采用预检索技术的首要目标是促进更好的检索。我们注意到,简单 RAG 的检索阶段存在召回率和精确率低的问题——检索到了不相关信息,并且没有检索到所有相关信息。这主要可能由于以下两个原因:
-
知识库不适合检索。如果知识库中的信息不是以易于搜索的方式存储的,那么检索的质量将保持次优。为了解决这个问题,在索引管道中进行索引优化,以实现知识库的更有效存储。
-
检索器不完全理解输入查询。在生成式 AI 应用中,对用户查询的控制通常有限。用户提供的详细程度是主观的。检索器有时可能误解或不完全理解用户查询的上下文。查询优化解决了简单 RAG 的这一挑战方面。
索引和查询优化都在检索器被调用之前进行。这是唯一一个建议在索引和生成管道中采取干预的阶段。我们将探讨这些方面的几种技术。
6.3.1 索引优化
索引优化在索引管道中使用。索引优化的目标是建立知识库以实现更好的检索。以下是一些流行的策略。
块优化
第三章讨论了在索引管道中分块的重要性。将大型文档分成更小的段落对于检索和处理 LLMs 的上下文长度限制起着至关重要的作用。某些技术旨在实现更好的分块和高效的块检索,例如
-
块大小优化—块的大小对 RAG 系统的质量有显著影响。虽然大块提供了更好的上下文,但它们也携带了大量的噪声。然而,小块具有精确的信息,但可能会错过重要信息。例如,考虑一份 10,000 字的法律文件。如果我们将其分成 1,000 字的段落,每个块可能包含多个法律条款,这使得检索特定信息变得困难。相反,将其分成 200 字的段落可以更精确地检索单个条款,但可能会失去周围条款提供的上下文。通过实验块大小可以帮助找到准确检索的最佳平衡。处理时间也取决于块大小。因此,块大小对检索准确性、处理速度和存储效率有显著影响。理想的块大小因用例而异,并取决于平衡因素,如文档类型和结构、用户查询的复杂性和期望的响应时间。没有一种适用于所有情况的优化块大小的方法。通过实验和评估不同块大小在忠实度、相关性和响应时间(如第五章所述)等指标上的表现,可以帮助确定 RAG 系统的最佳块大小。块大小优化可能需要定期重新评估,因为数据或需求发生变化。
-
上下文丰富化块分割—这种方法将较大文档的摘要添加到每个块中,以丰富小块的上下文。这为 LLM 提供了更多上下文,而不会添加太多噪声。它还提高了检索准确性,并保持了块之间的语义连贯性。这个特性在需要更全面的信息视图的情况下特别有用。虽然这种方法增强了更广泛上下文的理解,但它增加了复杂性,并带来了更高的计算需求、增加的存储需求和可能的检索延迟。以下是如何使用 GPT-4o-mini、OpenAI 嵌入和 FAISS 进行上下文丰富化的一个示例:
from langchain_community.document_loaders #1
import AsyncHtmlLoader #1
from langchain_community.document_transformers #1
import Html2TextTransformer #1
url= #1
https://en.wikipedia.org/wiki/2023_Cricket_World_Cup #1
loader = AsyncHtmlLoader (url) #1
data = loader.load() #1
html2text = Html2TextTransformer() #1
document_text=data_transformed[0].page_content #1
#1
#1
summary_prompt = f"Summarize the given #2
document in a single paragraph\n #2
document: {document_text}" #2
from openai import OpenAI #2
client = OpenAI() #2
#2
response = client.chat.completions.create( #2
model="gpt-4o-mini", #2
messages= [ #2
{"role": "user", "content": summary_prompt} #2
] #2
) #2
#2
summary=response.choices[0].message.content #2
#2
from langchain_text_splitters import #3
RecursiveCharacterTextSplitter #3
text_splitter = RecursiveCharacterTextSplitter( #3
chunk_size=1000, #3
chunk_overlap=200) #3
chunks=text_splitter.split_text( #3
data_transformed[0].page_content #3
) #3
context_enriched_chunks = #4
[answer + "\n" + chunk for chunk in chunks] #4
embedding = OpenAIEmbeddings(openai_api_key=api_key) #5
vector_store = FAISS.from_texts( #5
context_enriched_chunks, #5
embedding #5
) #5
1 从维基百科页面加载文本
2 使用 GPT-4o-mini 模型生成文本摘要
3 使用递归字符分割器创建块
4 通过汇总数据丰富块
5 创建嵌入并将其存储在 FAISS 索引中
- 获取周围数据块**— 在这种技术中,数据块在细粒度级别上创建,例如在句子级别,当查询响应中找到相关文本块时,系统不仅检索该文本块,还检索周围的文本块。这使得搜索更加细粒度,并通过检索相邻的文本块进行上下文扩展。这在长篇内容如书籍和报告中很有用,其中信息跨越段落和章节流动。这种技术也给系统增加了处理成本和延迟。除此之外,相邻的文本块可能包含噪声,这可能导致相关性的稀释。
数据块优化是向更好的 RAG 系统迈出的有效一步。尽管它提出了诸如管理成本、系统延迟和存储效率等挑战,但优化数据块可以从根本上改善 RAG 系统的检索和生成过程。
元数据增强
定义元数据的一种常见方式是“关于数据的数据。”元数据描述其他数据。它可以提供诸如数据描述、创建时间、作者和类似信息。虽然元数据对于管理和组织数据很有用,但在 RAG 的背景下,元数据增强了数据的可搜索性。以下是一些元数据在提高 RAG 系统中的关键作用:
-
元数据过滤—添加诸如时间戳、作者、类别等元数据可以增强数据块。在检索时,可以在进行相似度搜索之前,首先通过相关元数据信息过滤数据块。这提高了检索效率并减少了系统中的噪声。例如,使用时间戳过滤器可以帮助避免知识库中的过时信息。如果用户搜索“最新的 COVID-19 旅行指南”,通过时间戳进行元数据过滤确保只检索最新的指南,避免过时信息。
-
元数据丰富—时间戳、作者、类别、章节、页码等是从文档中提取的常见元数据元素。然而,还可以构建更有价值的元数据项。这可以是通过对数据块提取标签来总结数据块。一个特别有用的技术是反向假设文档嵌入。这涉及使用语言模型生成每个文档或数据块可能回答的潜在查询。然后,将这些合成查询添加到元数据中。在检索过程中,系统将用户的查询与这些合成查询进行比较,以找到最相关的数据块。
元数据是提高检索系统准确性的强大工具。然而,在向数据块添加元数据时必须谨慎行事。设计元数据模式对于避免冗余和管理处理及存储成本至关重要。提供改进的相关性和准确性,元数据增强在当代 RAG 系统中变得极为流行。
索引结构
知识库的另一个重要方面是信息结构的良好程度。在简单的 RAG 方法中,文档/块没有结构化的顺序。然而,为了更有效的检索,一些索引结构已经变得流行且有效:
-
父子文档结构——在父子文档结构中,文档是按层次组织的。父文档包含总体主题或摘要,而子文档深入具体细节。在检索过程中,系统可以首先定位最相关的子文档,如果需要,然后参考父文档以获取更多上下文。这种方法提高了检索的精确度,同时保持了更广泛的上下文。同时,这种层次结构在内存需求和计算负载方面可能带来挑战。
-
知识图谱索引——知识图谱以实体和关系的方式结构化组织数据。使用知识图谱结构不仅增加了上下文理解,还使系统具备增强的推理能力和改进的可解释性。然而,知识图谱的创建和维护是一个昂贵的流程。由知识图谱驱动的 RAG,也称为 GraphRAG,是一种新兴的高级 RAG 模式,它已经在 RAG 性能方面展示了显著的改进。我们将在第八章中详细讨论 GraphRAG。
索引结构可能对索引优化检索有最大的影响。然而,它给系统带来了存储和内存负担,并影响了搜索时间性能。因此,在大型系统中建议优化索引结构,在这些系统中可以实现诸如 GraphRAG 和分层索引等概念的真实潜力。
注意:在前几章中,我们讨论过嵌入是 RAG 的关键组成部分。它们用于计算用户查询与知识库中存储的文档之间的语义相似度。通常可用的嵌入模型是在通用语言上训练的。当处理特定领域或专业内容时,这些模型可能不会产生良好的结果。微调嵌入模型可以让您优化特定领域或任务的向量表示,从而实现更精确的相关上下文检索。微调是一个稍微复杂的过程,因为它需要整理训练数据集和资源以重新计算嵌入模型。如果您处理的是与通用语言词汇不同的高度专业化的领域,您应该考虑为您的领域微调嵌入模型。
与索引管道一样,索引优化是一个周期性的过程,不会实时发生。索引优化的目标是设置知识库以更好地检索。同时,也要注意增加的计算、内存和存储需求所带来的额外复杂性。图 6.4 展示了索引优化知识库的说明性工作流程。

图 6.4 索引优化知识库的说明
6.3.2 查询优化
预检索技术的第二阶段是生成管道的一部分。这一阶段的目标是以一种使输入用户查询更适合检索任务的方式对其进行优化。以下章节中列出了一些流行的查询优化策略。
查询扩展
在查询扩展中,原始用户查询被丰富以检索更多相关信息。这有助于提高系统的召回率,并克服了用户查询不完整或非常简短所带来的挑战。以下是一些扩展用户查询的技术:
- 多查询扩展——在这种方法中,使用 LLM 生成原始查询的多个变体,并使用每个变体查询从知识库中搜索和检索片段。对于一个查询“气候变化如何影响北极熊?”多查询扩展可能会生成“全球变暖对北极熊的影响”,“气候变化对北极熊栖息地的后果是什么?”让我们看看使用 GPT 4o-mini 模型生成多查询的一个简单例子:
original_query="How does climate change affect polar bears?"
num=5
expansion_prompt=f"Generate {num} variations #1
of the following query: {original_query}. #1
Respond in JSON format." #1
from openai import OpenAI #2
client = OpenAI() #2
response = client.chat.completions.create( #2
model="gpt-4o-mini", #2
messages= [ #2
{"role": "user", "content": expansion_prompt} #2
], #2
response_format={ "type": "json_object" } #2
) #2
#2
expanded_queries=response.choices[0].message.content #3
1 为查询扩展构建提示
2 使用 GPT 4o-mini 生成扩展查询
3 从响应对象中提取文本
- 子查询扩展:子查询方法与多查询方法相当类似。在这种方法中,不是生成原始查询的变体,而是将复杂查询分解成更简单的子查询。这种方法受到最少到最多提示技术的启发,其中复杂问题被分解成更简单的子问题,并逐一解决。对同一查询——“气候变化如何影响北极熊?”的子查询扩展可能会生成“融化的海冰如何影响北极熊的狩猎和觅食行为?”以及“气候变化对北极熊的生理和健康有何影响?”子查询的方法与多查询的方法类似,除了对提示的修改:
sub_query_expansion_prompt=f" \
Break down the following \
query into {num} sub-queries targeting \
different aspects of the query: {original_query}. \
Respond in JSON format. "
- 回溯扩展——这个术语来自回溯提示方法,其中原始查询被抽象为更高层次的查询。在检索过程中,原始查询和抽象查询都用于获取片段。类似于上面的例子,一个抽象的回溯查询可能是“气候变化对北极生态系统有何生态影响?”以下是一个可以使用的提示示例:
step_back_expansion_prompt = f" \
Given the query: {original_query}, \
generate a more abstract, \
higher-level conceptual query. "
当多查询扩展在检索过程中生成原始查询的各种改写或同义词以扩大搜索范围时,子查询扩展将复杂查询分解成更简单、更组件化的查询以针对特定信息,而回溯扩展将查询抽象为更高层次的概念以捕捉更广泛的上下文。
查询扩展在实施此策略时也带来了一系列需要考虑的挑战。虽然查询扩展可以通过匹配更多文档来提高召回率,但它可能会降低精确度。需要仔细选择扩展词,以避免从原始查询中产生上下文漂移。过度扩展可能会分散对原始查询的注意力。尽管存在挑战,查询扩展已被证明是提高检索召回率和生成更多上下文感知响应的有效技术。
查询转换
与查询扩展相比,在查询转换中,检索不是在原始用户查询上进行的,而是在转换后的查询上进行的,这对于检索器来说更合适。
-
Rewrit**e——查询是从输入重写的。在许多现实世界的应用中,输入可能不是一个直接的查询或适合检索的查询。基于输入,可以训练一个语言模型将输入转换成一个可用于检索的查询。例如,用户的陈述“我无法从手机发送电子邮件”可以重写为“解决智能手机上电子邮件发送问题的故障排除步骤”,使其更适合检索。
-
HyD**E——假设文档嵌入,或 HyDE,是一种技术,其中语言模型首先在未访问知识库的情况下为用户的查询生成一个假设答案。然后使用这个生成的答案在知识库中的文档嵌入上执行相似性搜索,有效地检索与假设答案相似而不是查询本身的文档。以下是一个生成假设文档嵌入的示例:
# Original Query
original_query= #1
"How does climate change \ #1
affect polar bears?" #1
# Prompts for generating HyDE
system_prompt="You are an expert in \ #2
climate change and arctic life." #2
hyde_prompt=f"Generate an answer to the \ #2
question: {original_query}" #2
# Using OpenAI to generate a hypothetical answer
from openai import OpenAI #3
client = OpenAI() #3
response = client.chat.completions.create( #3
model="gpt-4o-mini", #3
messages= [ #3
{"role": "system", "content": system_prompt}, #3
{"role": "user", "content": hyde_prompt} #3
] #3
) #3
#3
hy_answer=response.choices[0].message.content #3
# Using OpenAI Embeddings to convert hyde into embeddings
embeddings = OpenAIEmbeddings( #4
model="text-embedding-3-large" #4
) #4
hyde = embeddings.embed_query(hy_answer) #4
1 原始查询
2 生成 HyDE 的提示
3 使用 OpenAI 生成一个假设答案
4 使用 OpenAI 嵌入将 HyDE 转换为嵌入
与查询扩展类似的一些挑战,如从原始查询中漂移和保持意图,也存在于查询转换策略中。有效的查询重写和转换可以增强系统的上下文感知能力。
Query routing
不同的查询可能需要不同的检索方法。根据意图、领域、语言、复杂性、信息来源等标准,需要对查询进行分类,以便它们可以遵循适当的检索方法。这是通过将用户查询路由到适当的流程来优化用户查询的想法。路由技术的类型包括:
-
意图分类——使用预训练的分类模型来对用户查询的意图进行分类,以选择适当的检索方法。这种技术的改进是基于提示的分类,其中不是使用预训练的分类器,而是提示一个 LLM 对查询进行分类。
-
元数据路由——在这种方法中,从用户查询中提取关键词和标签,然后对块元数据进行过滤,以缩小搜索范围。
-
语义路由——在这种方法中,用户查询与每个检索方法的预定义查询集进行匹配。无论用户查询与预定义查询之间的相似度最高,都调用该检索方法。
在客户支持聊天机器人中,查询路由确保技术查询被导向包含故障排除指南的数据库,而账单问题则被导向账户信息,从而提高用户满意度。
实施查询路由需要努力和技能。它引入了一个全新的预测组件,给过程带来了不确定性。因此,它必须精心设计。在处理源数据和查询类型变化时,查询路由是必不可少的。
尽管检索前策略和技术范围广泛且不断演变,但我们在本节中查看了一些最受欢迎和有效的技术。请注意,这些策略的适用性将取决于知识库中内容的性质和用例。然而,使用这些策略中的每一个都将导致 RAG 系统性能的渐进式提升。既然我们已经为更好的检索设置了知识库和用户查询,那么让我们在下一节讨论重要的检索策略。
6.4 检索策略
在检索前阶段进行干预,如果查询和知识库与检索算法很好地对齐,可以显著提高 RAG 系统的性能。我们在第四章讨论了许多检索算法。在本节中,我们关注可以采用以改善检索的策略。
6.4.1 混合检索
混合检索策略是生产级 RAG 系统的一个基本组成部分。它涉及结合检索方法以提高检索准确性。这可能意味着简单地使用基于关键词的搜索以及语义相似度。也可能意味着结合所有稀疏嵌入、密集嵌入向量和基于知识图谱的搜索。检索可以是所有这些方法的并集或交集,具体取决于精度和召回率的要求。它通常遵循一个加权的检索方法。图 6.5 显示了混合检索器查询图和向量存储。

图 6.5 混合检索器采用多种查询技术并合并结果。
6.4.2 迭代检索
与使用检索-生成线性过程不同,迭代检索策略根据原始查询和生成的文本反复搜索知识库,这使得系统可以通过根据初始结果细化搜索来收集更多信息。这在解决多跳或复杂查询时很有用。虽然有效,但迭代检索可能导致更长的处理时间,并可能在管理大量检索信息时引入挑战。例如,Iter-RetGen 等迭代检索方法已经展示了显著提高的性能,它是一种交替进行检索和生成步骤的迭代方法。
6.4.3 递归检索
递归检索策略建立在迭代检索的基础上,通过根据获得的结果迭代地转换查询。虽然初始查询用于检索块,但新的聚焦查询是基于这些块生成的。因此,它导致在文档块中找到分散信息的能力更强,并且响应更加连贯和具有上下文。迭代检索思维链(IRCoT)是一种递归检索技术,它将迭代检索与 CoT 提示相结合。
6.4.4 自适应检索
自适应检索也遵循重复检索周期的方法。在自适应检索策略中,一个 LLM 被启用以确定检索的最合适时机和内容。自适应检索的目的是使检索过程更加个性化,以适应用户和上下文。它应用于根据用户行为调整查询或根据用户表现调整检索等领域。FLARE 和 Self-RAG 是自适应检索的两个流行例子。Self-RAG 引入了“反思令牌”,使模型能够自我反思并决定何时需要额外的检索。FLARE(前瞻性主动检索增强生成)根据当前生成预测未来内容需求并主动检索相关信息。自适应检索是更广泛的代理人工智能趋势的一部分。代理人工智能指的是在任务过程中能够做出自主决策的人工智能系统,根据上下文调整其行为。在 RAG 的上下文中,代理 RAG 涉及动态决定何时以及如何检索信息的 AI 代理,从而增强了检索过程的灵活性和效率。代理人工智能是 RAG 中一个重要的新兴模式。我们将在第八章详细讨论代理 RAG。
图 6.6 比较了三种关注重复检索周期的检索策略。虽然递归和迭代方法需要一个阈值来跳出迭代,但在自适应方法中,一个判断模型根据需要决定检索和生成步骤。

图 6.6 迭代、递归和自适应检索结合了重复检索周期。来源:改编自 Gao 等人,2023 年 12 月 18 日。“大型语言模型的检索增强生成:综述。”
所有高级检索策略都会在计算复杂度方面引入开销,因此必须平衡准确性与系统的成本和延迟。
通过采用高级预检索技术和合适的检索策略,我们可以预期从知识库中检索到更丰富、更深入和更相关的上下文。即使检索到了相关上下文,LLM 也可能难以吸收所有信息。为了解决这个问题,在下一节中,我们将讨论一些检索后策略,这些策略有助于在将必要信息添加到提示之前对上下文进行整理。
6.5 检索后技术
即使块检索以预期的方式进行,仍然存在一个故障点。LLM 可能无法处理所有信息。这可能是由于冗余或上下文之间不连贯的性质等多种原因。在检索后阶段,重新排序和压缩的方法有助于为 LLM 提供更好的上下文以进行生成。
6.5.1 压缩
过长的上下文可能将噪声引入系统。这降低了 LLM 处理信息的能力。因此,查询可能持续出现幻觉和不相关的响应。在提示压缩中,语言模型被用来检测和删除不重要的和不相关的标记。除了使上下文更相关外,提示压缩还对成本和效率产生积极影响。提示压缩的另一个优点是能够减小提示的大小,使其适合 LLM 的上下文窗口。COCOM 是一种将上下文压缩成少量上下文嵌入的方法。同样,xRAG 是一种使用文档嵌入作为特征的方法。压缩可能导致信息丢失,因此需要在压缩和性能之间取得平衡。一个简单的提示来压缩长时间检索到的上下文是
compress_prompt = f" \
Compress the following document \
into a shorter version, \
retaining only the essential information: \
\n\n{document}"
重新排序
对所有检索到的文档进行重新排序确保了最相关的信息在生成步骤中得到优先考虑。它通过优先考虑对查询更合适的文档来细化检索结果,从而提高用于生成的信息的整体质量和准确性。重新排序还解决了在采用混合检索方法时优先级的问题,并提高了整体响应质量。常见的重新排序器包括多向量、学习排序(LTR)、基于 BERT 的,甚至混合重新排序器,都可以使用。Cohere Rerank 等专用 API 提供预训练模型,以实现高效的重新排序集成。
在本节中,我们讨论了在 RAG 管道的不同阶段使用的一些流行的先进 RAG 策略和技术。同时考虑这些技术的权衡也很重要。几乎任何高级技术都会给系统带来开销。这些开销可能以计算负载、系统延迟以及增加的存储和内存需求的形式出现。因此,这些技术需要针对特定用例进行性能与开销的评估。表 6.1 提供了迄今为止讨论的 12 种策略的总结。
表 6.1 带有其优势和局限性的高级 RAG 策略
| 策略 | 描述 | 利益 | 挑战 |
|---|---|---|---|
| 文档块优化 | 调整文档块以实现最佳大小和上下文 | 提高检索准确度、处理速度和存储 | 需要进行实验;最佳块大小因用例而异 |
| 元数据增强 | 通过添加额外的元数据来丰富数据块以提高过滤和可搜索性 | 提高检索效率;减少噪声 | 需要仔细的架构设计;管理处理成本 |
| 索引结构 | 以结构化格式组织数据以实现高效检索 | 提高检索的准确性和上下文 | 增加内存和计算负载 |
| 查询扩展 | 丰富用户查询以检索更多相关信息 | 提高召回率;克服简短查询 | 可能降低精确度;风险出现上下文漂移 |
| 查询转换 | 修改用户查询以提高检索的适用性 | 提高上下文意识;保持意图 | 可能出现误解;偏离原始查询 |
| 查询路由 | 根据分类将查询引导到适当的检索方法 | 通过将方法与查询类型匹配来提高检索 | 引入不确定性;需要精心制作 |
| 混合检索 | 结合多种检索方法(例如,关键词和语义) | 提高检索准确性和鲁棒性 | 增加复杂性;需要方法加权 |
| 迭代检索 | 基于初始结果和查询细化重复搜索 | 收集更全面的信息;细化搜索 | 更长的处理时间;管理更多数据 |
| 递归检索 | 基于获取的结果迭代地转换查询 | 找到分散的信息;提供连贯的响应 | 类似于迭代检索;可能增加负载 |
| 自适应检索 | LLM 决定在生成过程中何时以及检索什么 | 个性化且上下文感知的检索;动态适应 | 增加计算复杂性;属于代理人工智能的一部分 |
| 压缩 | 通过删除无关信息来减少上下文长度 | 适应 LLM 上下文窗口;减少噪声和成本 | 可能丢失重要信息;需要平衡 |
| 重新排序 | 重新排序检索到的文档以优先考虑相关性 | 提高响应质量;确保使用最相关的信息 | 需要额外的模型;可能引入开销 |
图 6.7 是采用高级技术后一代化管道的示例。

图 6.7 高级生成管道的示例
虽然这些高级策略和技术在提高性能方面非常有用,但 RAG 系统还需要提供定制和灵活性。这是因为随着数据和查询性质的变化,我们可能需要迅速采用不同的技术。下一节中讨论的模块化 RAG 方法旨在提供比传统 RAG 系统更大的架构灵活性。
6.6 模块化 RAG
人工智能系统正变得越来越复杂,需要更多可定制、灵活和可扩展的 RAG 架构。模块化 RAG 的出现是 RAG 系统演变中的飞跃。模块化 RAG 将传统的单体 RAG 结构分解为可互换的组件。这使得可以根据特定用例定制系统。模块化方法将模块化引入 RAG 组件,如检索器、索引和生成,同时也添加了更多模块,如搜索、内存和融合。我们可以将模块化 RAG 方法分为两部分:
-
作为灵活、可互换模块开发的 RAG 核心组件
-
用于增强检索、增强和生成核心功能的专用模块
6.6.1 核心模块
RAG 系统(即索引、检索、增强和生成)的核心组件,以及先进的检索前和检索后技术,在模块化 RAG 框架中组成灵活、可互换的模块。
-
索引模块——索引模块作为构建知识库的基础。通过模块化此组件,开发者可以选择各种嵌入模型以实现高级语义理解。根据可扩展性和性能需求,可以互换向量存储。此外,可以根据数据结构(无论是文本、代码还是多媒体内容)调整分块方法,确保检索的最佳索引。
-
检索模块——检索模块允许使用多种检索算法。例如,开发者可以在使用密集嵌入的语义相似度搜索和传统的基于关键词的搜索(如 BM25)之间切换。这种灵活性允许根据应用程序的具体要求定制检索方法,例如优先考虑速度、准确性或资源利用率。例如,客户支持聊天机器人可能在非高峰时段使用语义搜索以提高准确性,并在高峰时段切换到关键词搜索以处理增加的负载。模块化检索组件允许根据实时需求动态交换检索策略。
-
生成模块—在生成模块中,LLM 的选择是模块化的。开发者可以从 GPT-4 等用于复杂语言生成的模型或用于成本效益的小型模型中进行选择。此模块还处理提示工程,以引导 LLM 生成准确和相关的响应。
-
检索前模块—允许检索前技术的灵活性,以提高索引内容的质量和用户查询。
-
检索后模块—与检索前模块类似,此模块允许灵活实现检索后技术以精炼和优化检索到的上下文。
你可能会注意到前三个模块完成了原始 RAG 方法,而检索前和检索后模块的添加将原始 RAG 提升为高级 RAG 实现。也可以说,原始 RAG 是高级 RAG 的一个特殊(且有限)情况。
6.6.2 新模块
模块化的 RAG 框架引入了几个新组件,以增强原始和高级 RAG 方法检索和生成能力。其中一些组件/模块包括
-
搜索—搜索模块旨在对不同数据源进行搜索。它针对不同的数据源进行定制,旨在增加源数据以更好地生成响应。
-
融合—RAG 融合通过多查询方法克服了传统搜索系统的局限性。融合模块通过使用 LLM 将用户的查询扩展到多个、不同的视角来增强检索。然后,它对这些扩展查询进行并行搜索,通过重新排序和选择最相关的信息来融合结果,并呈现全面的答案。这种方法捕捉了显性和隐性信息,揭示了可能因单一查询而错过的更深入的见解。
-
记忆—记忆模块使用 LLM 的固有记忆,即其参数中编码的预训练知识。此模块使用 LLM 回忆信息,而无需显式检索,指导系统何时检索额外数据,何时依赖 LLM 的内部知识。它可以涉及使用反射令牌或提示等技术,鼓励模型进行内省并决定是否需要更多信息。例如,当回答有关历史事件的查询时,记忆模块可以决定依赖 LLM 关于第二次世界大战的知识来提供背景,仅检索所需的特定日期或数字。这种方法减少了不必要的检索并使用了模型的预训练知识。
-
路由—在 RAG 系统中,路由通过不同的数据源进行导航,为查询选择最佳路径,无论是涉及摘要、特定数据库搜索还是合并不同的信息流。
-
任务适配器—此模块使 RAG 能够适应各种下游任务,允许通过最小示例开发特定任务的端到端检索器,展示了处理不同任务的灵活性。任务适配器模块允许 RAG 系统针对特定任务(如摘要、翻译或情感分析)进行微调。通过结合少量特定任务的示例或提示,该模块调整检索和生成组件,以产生符合所需任务的输出,增强多功能性而无需大量重新训练。
您可能会观察到,高级 RAG 是模块化 RAG 框架中的一个特殊情况。您也之前看到,简单 RAG 是高级 RAG 的一个特殊情况。这意味着 RAG 方法(即简单、高级和模块化)不是竞争关系,而是渐进关系。您可以从尝试 RAG 的简单实现开始,然后过渡到更模块化的方法。图 6.8 显示了 RAG 系统的演变过程。

图 6.8 RAG 的简单、高级和模块化方法都是渐进的。简单 RAG 是高级 RAG 的一个子组件,而高级 RAG 又是模块化 RAG 的一个子组件。
在构建模块化 RAG 系统时,请记住每个模块都应该设计成可以独立工作。这需要定义清晰的输入和输出。除了独立的模块外,编排层应该灵活,以便混合和匹配模块。还应记住,模块化方法在过程中引入了复杂性。管理接口、依赖关系、配置和模块版本可能很复杂。确保模块之间的兼容性和一致性可能具有挑战性。独立和集体测试每个模块需要强大的评估策略。额外的模块也可能增加系统的延迟和推理成本。
尽管增加了复杂性,但 RAG 的模块化方法在大型 RAG 系统中仍然是处于领先地位的。它使得快速实验、高效优化以及新技术的无缝集成成为可能。通过提供混合和匹配不同模块的能力,模块化 RAG 使您能够构建更稳健、准确和多功能的人工智能解决方案。它还简化了维护、更新和可扩展性,使其成为管理复杂、不断发展的知识库的理想选择。
本节讨论了使用高级技术和模块化框架提高 RAG 性能。可以在索引和生成管道的不同阶段采取干预措施。RAG 的模块化方法使快速实验、灵活性和可扩展架构成为可能。您需要实验以找出有助于特定用例的技巧。同时,也要注意权衡。高级技术引入的复杂性会影响计算、内存和存储需求。
这是将 RAG 投入生产的一个方面。为了实现可接受的准确性和效率,RAG 系统需要高级技术。RAG 系统在生产中的其他推动因素是构成 RAG 堆栈骨干的工具和技术。在下一章中,我们将探讨这一技术基础设施,它使 RAG 系统成为可能。
摘要
纳维亚 RAG 的局限性
-
纳维亚 RAG 遵循简单的“检索然后阅读”过程。
-
这种方法存在精度低和检索不完整的问题。
-
检索通常会错过相关信息,并拉入不相关的内容。
-
在增强阶段,通常存在来自类似检索文档的冗余。
-
当从多个文档中获取时,上下文可能会变得不连贯。
-
生成阶段面临幻觉和有偏的输出。
-
模型可能会过度依赖检索数据,而忽略其内部知识。
高级 RAG 技术
-
高级 RAG 流程遵循“重写然后检索然后重新排序然后阅读”的框架,其中查询通过重写进行优化,检索通过增强以提高精度,结果通过重新排序以优先考虑相关性,并使用最相关的信息来生成最终响应。
-
预检索技术包括
-
索引优化—改善文档存储以提高可搜索性
-
分块优化—平衡块大小以避免丢失上下文或引入噪声
-
上下文丰富分块—为每个块添加摘要以改善检索
-
元数据增强—添加标签和元数据,如时间戳或类别,以实现更好的过滤
-
查询优化—通过扩展或重写用户查询来提高检索准确性
-
-
检索技术包括
-
混合检索—结合基于关键词和语义搜索
-
迭代检索—通过反复查询初始结果来细化搜索
-
递归检索—根据检索到的块生成新查询以收集更多相关信息
-
-
后检索技术包括
-
压缩—减少不必要的上下文以去除噪声并适应模型的上下文窗口
-
重新排序—重新排序检索到的文档以优先考虑最相关的文档
-
模块化 RAG 框架
-
核心模块包括
-
索引模块—允许灵活的嵌入模型和向量存储选项
-
检索模块—支持在密集型和基于关键词的检索方法之间切换
-
生成模块—根据复杂性和成本选择语言模型的灵活性
-
-
新模块包括
-
搜索模块—针对特定数据源进行定制搜索以获得更好的结果
-
融合模块—将用户查询扩展到多种形式,并组合检索结果以获得更深入的见解
-
内存模块—使用模型的内部知识来减少不必要的检索,仅在需要时检索
-
路由模块—动态选择处理不同类型查询的最佳路径
-
任务适配模块—适配系统以适应不同的下游任务,如摘要或翻译
-
权衡和最佳实践
-
高级技术可以提高 RAG 的准确性,但会增加复杂性。
-
如混合检索或重新排序等技术可能会增加计算成本和延迟。
-
模块化 RAG 提供灵活性,但需要仔细管理接口和模块兼容性。
-
独立和整体测试每个模块对于确保系统稳定性和性能很重要。
-
性能、成本和系统复杂性之间的权衡应仔细评估。
第七章:RAGOps 堆栈的演变
本章涵盖
-
RAG 系统的设计
-
可用于实现 RAG 系统的工具和技术
-
RAG 系统的生产最佳实践
到目前为止,我们已经讨论了检索增强生成 (RAG) 系统的索引管道、生成管道和评估。第六章还介绍了一些在构建生产级 RAG 系统时有用的高级策略和技术。这些策略有助于提高检索和生成的准确性,在某些情况下,还可以减少系统延迟。有了所有这些信息,你应该能够为你的用例构建一个 RAG 系统。第二章简要概述了 RAG 系统的设计。本章将详细阐述该设计。
RAG 系统由标准应用程序层以及特定于生成 AI 应用的层组成。这些层堆叠在一起,创建了一个健壮的 RAG 系统。
这些层由技术基础设施支持。我们深入探讨这些层以及流行的服务提供商提供的可用于构建 RAG 系统的技术和工具。一些提供商已经开始提供端到端管理的 RAG 解决方案,本章将简要介绍。
我们以一些关于将 RAG 系统投入生产的经验和最佳实践来结束本章。第七章也标志着本书第三部分的结束。
到本章结束时,你应该
-
理解 RAG (RAGOps) 堆栈中各层的细节。
-
熟悉众多服务提供商以及他们为 RAG 系统提供的工具和技术。
-
了解将 RAG 系统投入生产的一些陷阱和最佳实践。
与传统软件应用相比,RAG 系统包含许多额外的组件。向量存储和嵌入模型是索引管道的基本组件。知识图谱正变得越来越流行的索引结构。生成组件可以有不同的语言模型。此外,提示管理变得越来越复杂。RAG 和 LLM (大型语言模型) 应用程序的生产生态系统仍在演变,但早期的工具和设计模式已经出现。RAGOps 指的是在生产环境中部署、维护和优化 RAG 系统所涉及的操作实践、工具和流程。
7.1 RAGOps 堆栈的演变
本节描述了构建 RAG 系统所需的不同组件。这些层组合在一起形成了 RAG 的操作堆栈。我们还将利用这个机会来修订本书中讨论的 RAG 系统的工作流程。
应当注意的是,RAG,就像一般的生成式 AI 一样,是一项不断发展的技术,因此,操作堆栈也在不断演变。你可能会发现不同的定义和结构。本章提供了一个全面的视角,并从其对 RAG 系统的重要性角度讨论了组件。我们查看以下三个类别划分的层:
-
对 RAG 系统操作至关重要的关键层。如果这些层中的任何一个缺失或不完整,RAG 系统很可能会失败。
-
重要的层,对于系统的性能、可靠性和安全性至关重要。这些基本组件将系统提升到一个为用户提供价值的标准。
-
增强层,它提高了系统的效率、可扩展性和可用性。这些组件用于使 RAG 系统变得更好,并基于最终需求进行选择。
7.1.1 关键层
索引管道和生成管道(在第三章和第四章中详细讨论)构成了 RAG 系统的核心。图 7.1 展示了索引管道,它有助于为 RAG 系统创建知识库,以及生成管道,它使用知识库来生成上下文感知的响应。

图 7.1 索引和生成管道构成 RAG 系统的核心
形成这两个管道的层的层,是 RAGOps 堆栈的关键层。
数据层
数据层在为 RAG 创建和存储知识库方面发挥着关键作用。它负责从源系统中收集数据,将其转换为可用的格式,并存储以实现高效检索。以下是数据层的一些组件:
-
数据采集组件—它从数据库、内容管理系统、文件系统、API、设备甚至互联网等源系统中收集数据。数据可以批量或作为流式数据采集,具体取决于用例。对于数据采集,你选择的工具可能取决于数据量、数据源类型、采集频率、成本和设置简便性等因素。数据采集不仅限于 RAG,而是现代软件应用中的主流组件。AWS Glue、Azure Data Factory、Google Cloud Dataflow、Fivetran、Apache NiFi、Apache Kafka 和 Airbyte 等都是可用的工具。对于快速原型设计和概念验证(PoC),LangChain 和 LlamaIndex 等框架内置了可以帮助连接某些源并提取信息的函数。
-
数据转换组件—它将摄取的数据从原始形式转换为可用的形式。在索引管道中的核心过程是数据的分块。我们知道嵌入是 RAG 应用的首选格式,因为它使得应用语义搜索变得更容易。图结构在先进系统中越来越受欢迎。某些预处理步骤,如清理、去重、元数据丰富和敏感信息屏蔽,也是这一阶段的一部分。虽然数据量和转换的性质在任何数据转换步骤中都起着重要作用,但在 RAG 系统中它们尤其关键。在数据摄取步骤中提到的所有提取-转换-加载(ETL)工具,以及 Apache Spark 和 dbt 等工具,也允许转换。然而,如果我们只关注 RAG,Unstructured.io 专注于处理和转换非结构化数据,以便在 LLM 应用中使用。它提供开源库以及托管服务。从非结构化数据构建知识图谱已经从早期的语义网络和本体论发展到今天稳健的框架。
微软的 GraphRAG 是一个框架,它开创了使用 LLM 从文本中提取实体和关系的方法。
-
数据存储组件—它以允许快速高效检索的方式存储转换后的数据。我们讨论过,为了存储嵌入,向量数据库被广泛使用,因为它们在相似性搜索中效率很高。对于图结构,使用图数据库。大多数传统数据库提供商正在将向量搜索功能纳入其系统。成本、规模和速度是选择数据存储的主要驱动因素。我们在这本书中使用了 FAISS 这样的向量索引。Pinecone 是一个完全托管的云原生服务。Milvus、Qdrant 和 Chroma 是开源向量数据库之一。Weviate 是另一个具有基于 GraphQL 接口的知识图的数据库。Neo4j 是存储和查询图数据的领先图数据库。有关流行向量数据库的比较,请参阅
www.superlinked.com/vector-db-comparison。
从源系统通过摄取和转换组件流向数据存储,这些组件导致知识库的创建,如图 7.2 所示。

图 7.2 数据层:通过从源系统提取、转换和加载(ETL)数据来创建知识库
强大的数据层是高效 RAG 系统的基石。当需要微调模型时,数据层也很有用。我们将在本章稍后简要讨论这一功能。接下来,我们将探讨模型层,它包括用于将文本转换为向量的嵌入模型和用于生成的 LLM。
模型层
预测模型使生成式人工智能应用成为可能。一些模型由第三方提供,而另一些则需要定制训练或微调。生成快速且成本效益高的模型响应也是使用预测模型的一个重要方面。模型层包括以下三个组件:
-
模型库——它包含为应用选择的所有模型的列表。最受欢迎的模型是生成文本和其他能够生成图像、视频和音频的生成模型,即大型语言模型(LLMs)。我们在数据层中看到,原始文本被转换成向量嵌入,这是通过嵌入模型完成的。除此之外,还有其他在 RAG 系统中使用的模型:
-
嵌入模型用于将数据转换成向量格式。我们在第三章中详细讨论了嵌入模型。回想一下,嵌入模型的选择取决于领域、用例和成本考虑。OpenAI、Google 的 Gemini、Voyage AI 和 Cohere 等提供商提供了各种嵌入模型选择,通过 Hugging Face transformers 也可以使用大量开源嵌入模型。多模态嵌入将不同模态的数据映射到共享嵌入空间中。
-
基础模型或预训练的 LLMs 用于生成输出,以及用于评估和自适应任务,在这些任务中 LLMs 被用来判断。我们在第四章中讨论了 LLMs 作为生成管道的一部分。回想一下,OpenAI 的 GPT 系列、Google 的 Gemini 系列、Anthropic 的 Claude 系列和 Cohere 的 Command R 系列是流行的专有 LLMs。Meta 的 llama 系列和 Mistral 是开源模型,它们已经获得了流行。现在,大多数 LLMs 都包括多模态功能,并且正在不断进化。
-
任务特定模型是 RAG 非核心的机器学习模型,但在各种任务中非常有用。这些模型用于高级 RAG 管道。用于高效路由和意图检测的查询分类模型、用于检测元数据的实体识别(NER)模型、查询扩展模型、幻觉检测模型以及偏见和毒性调节模型是 RAG 系统中一些有用的任务特定模型示例。虽然任务特定模型通常需要定制训练,但 OpenAI、Hugging Face 和 Google 等提供商也提供这些服务。
-
-
模型训练和微调组件—此组件负责在自定义数据上构建自定义模型和微调基础模型。在第四章中,我们讨论了 LLM 的微调有时对于领域适应是必要的。微调也可以用于嵌入模型。此外,特定任务的模型可以在自定义数据上训练。此组件支持用于训练和微调模型的算法。对于训练数据,此组件与数据层交互,在数据层中可以创建和管理训练数据。还建议使用常规 MLOps 层来开发和维护模型。这可以通过 Hugging Face、AWS SageMaker、Azure ML 和类似平台实现。
-
推理优化组件—此组件负责快速且经济高效地生成响应,可以通过量化、批处理、KV(键值)缓存等方法实现。ONNX 和 NVIDIA TensorRT-LLM 是流行的框架,用于优化推理。
图 7.3 展示了模型层的不同组件。它显示了模型层如何帮助决定在 RAG 系统中使用哪些模型,促进模型的训练和微调,并优化模型以实现高效的服务。

图 7.3 模型层:模型库是存储所有为应用、模型训练和微调所选模型的仓库,模型训练和微调与数据层交互以获取训练数据和训练自定义模型,而推理优化组件负责高效地提供模型服务。
模型部署
此层负责使 RAG 系统对应用层可用。它处理模型的底层基础设施。它还确保模型可以可靠地访问。模型可以通过以下四种主要方法进行部署:
-
完全托管部署—这可以由像 OpenAI、Google、Anthropic 和 Cohere 这样的专有模型提供商提供,其中所有模型部署、服务和扩展的基础设施都由这些提供商管理和优化。AWS SageMaker、Google Vertex AI、Azure Machine Learning 和 Hugging Face 等服务提供平台,用于部署、服务和监控开源和自定义开发的模型。Amazon Bedrock 是另一种完全托管的服务,提供对各种基础模型(专有和开源)的访问,简化了模型访问和部署。
-
自托管部署—此类部署由云 VM 提供商(如 AWS、GCP、Azure)和硬件提供商(如 Nvidia)启用。在这种情况下,模型在私有云或本地部署,基础设施由应用开发者管理。Kubernetes 和 Docker 等工具广泛用于模型的容器化和编排,而 Nvidia Triton Inference Server 可以优化 Nvidia 硬件上的推理。
-
本地/边缘部署—涉及在本地硬件或边缘设备上运行模型的优化版本,确保数据隐私、降低延迟和离线功能。本地/边缘部署通常需要模型压缩技术,如量化修剪,以及针对资源受限环境定制的较小模型。ONNX、TensorFlow Lite 和 PyTorch Mobile 等工具使移动和嵌入式平台上的高效部署成为可能,而 GGML 和 NVIDIA TensorRT 支持 CPU 和 GPU 优化。GPT4All 是一个流行的开源解决方案,可以在笔记本电脑、物联网设备和边缘服务器等设备上本地运行量化 LLM,而不依赖于云基础设施。这些框架促进了低延迟、节能的执行,使 AI 在去中心化环境中变得可访问。
模型部署是一项相对复杂的任务,当进行自托管和本地/边缘部署时需要工程技能。图 7.4 说明了模型部署的三种方式。

图 7.4 模型部署层管理 RAG 系统中所有模型的托管和部署基础设施,以实现高效服务。
与数据和模型层一起,RAG 系统的最基本组件已经就绪。现在我们需要一个管理数据和模型之间协调的层。这是应用编排层的责任。
应用编排层
当我们听到“编排”这个词时,会想到一个音乐指挥在交响乐团中领导一群音乐家。应用编排层在某种程度上类似。它负责管理系统中其他层之间的交互。它是一个中央协调器,使数据、检索系统、生成模型和其他服务之间的通信成为可能。编排层的主要组件包括
-
查询编排组件—负责接收和编排用户查询。所有预处理查询优化步骤,如查询分类、扩展和重写,都由该组件编排。查询编排层可能协调与终端应用层接收输入,以及模型层访问用于查询优化的模型。该组件通常将处理后的查询传递给检索协调和生成协调组件。
-
检索协调组件——托管各种检索逻辑。根据查询编排模块的输入,它选择适当的方法(密集检索或混合检索)并与数据层交互。根据检索策略,它还可能根据是否调用了任何递归或自适应检索方法与模型层交互。
-
生成协调组件——接收来自前一个组件的查询和上下文,并协调所有检索后的步骤。其主要功能是与模型层交互并提示 LLM 生成输出。除了生成之外,所有检索后的步骤,如重新排序和上下文压缩,都由该组件协调。生成后的任务,如反思、事实核查和审查,也可以由生成组件协调。该组件还可以负责将输出传递到应用层。
这些是编排层的三个主要组件。还有两个额外的组件需要考虑:
-
多代理编排组件——用于处理多个代理的 RAG,其中多个代理处理特定任务。我们将在第八章中更深入地探讨代理 RAG。编排层负责管理代理交互和协调。
-
工作流自动化组件——有时用于管理不同组件之间数据流和移动。这个组件并非特定于 RAG 系统,但在数据产品中应用较为普遍。Apache Airflow 和 Dagster 是用于工作流自动化的流行工具。
图 7.5 展示了编排层组件与应用层交互的情况,应用层由模型部署和数据层支持。

图 7.5 应用编排层接受来自应用层用户查询,并将响应发送回应用层。
LangChain 和 LlamaIndex 是最常用的编排框架,用于开发 RAG 系统。它们为不同的组件提供了抽象。微软的 AutoGen 和 CrewAI 是多代理编排的即将推出的框架。
通过这四层(即数据、模型、模型部署和应用编排),关键的 RAG 系统就完整了。这个核心系统可以与终端软件应用层交互,该层作为 RAG 系统与用户之间的接口。虽然应用层通常是定制构建的,但 Streamlit、Vercel 和 Heroku 等平台因其托管应用而受到欢迎。图 7.6 总结了 RAGOps 堆栈的关键层。
现在你已经熟悉了堆栈的核心层,接下来让我们看看那些提高系统性能和可靠性的关键层。

图 7.6 核心 RAGOps 堆栈,其中数据、模型、模型部署和应用编排层与源系统和托管服务提供商交互,并与应用层协调以与用户接口
7.1.2 必要层
虽然关键层构成了堆栈的核心,但它们并不评估或监控系统。它们不测试提示策略,也不提供针对 LLMs(大型语言模型)漏洞的任何保护。这些层对于系统至关重要。
提示层
虽然编排层的生成协调组件可以简单地将用户查询和检索到的上下文组合起来,但糟糕的提示可能导致幻觉和低劣的结果。正确工程化和评估提示对于引导模型生成相关、有根据和准确的响应至关重要。这个过程通常涉及实验。开发者创建提示,观察结果,然后迭代提示以提高应用的有效性。这也需要跟踪和协作。Azure Prompt Flow、LangChain 表达式语言(LCEL)、Weights & Biases 提示和 PromptLayer 是可用于创建和管理提示的几个应用程序之一。
评估层
第五章详细讨论了 RAG 评估。定期评估检索准确性、上下文相关性、忠实度和答案相关性对于确保响应质量是必要的。TruEra 的 TruLens、Ragas 和 Weights & Biases 是常用的评估平台和框架。
监控层
持续监控确保 RAG 系统的长期健康。观察处理链的执行对于理解系统行为和识别故障点至关重要。评估提供给语言模型的信息的相关性和充分性也是至关重要的。除此之外,定期跟踪系统指标,如资源利用率、延迟和错误率,也是监控层的一部分。ARISE、RAGAS 和 ARES 是也用于监控的评估框架。TraceLoop、TruLens 和 Galileo 是提供监控服务的提供商的例子。
LLM 安全和隐私层
虽然安全和隐私是任何软件系统的特性,但在 RAG(检索增强生成)的背景下,还有其他方面需要考虑。RAG 系统依赖于存储在向量数据库中的大型知识库,这些数据库可能包含敏感信息。它们需要遵守所有数据隐私法规。AI 模型容易受到操纵和中毒的影响。提示注入是通过提示检索敏感信息的恶意攻击。应采用数据保护策略,如匿名化、加密和差分隐私。查询验证、清理和输出过滤有助于防止攻击。实施护栏、访问控制、监控和审计也是安全和隐私层的组成部分。
缓存层
缓存已成为任何基于 LLM 的应用程序的一个重要组成部分。这是因为生成式 AI 模型的高成本和固有的延迟。在添加检索层后,RAG 系统的成本和延迟进一步增加。控制这种增加的一种方法是对常见查询的响应进行缓存。原则上,缓存 LLM 响应就像在其他任何软件应用程序中缓存一样,但对于生成式 AI 应用程序来说,它变得更加重要。
这些基本层与关键层叠加在一起,创建了一个强大、准确且高性能的 RAG 系统。图 7.7 添加了基本层及其组件到关键 RAGOps 堆栈中。

图 7.7 向关键 RAGOps 堆栈添加基本层为用户应用程序构建了一个强大的 RAG 系统之路。
表 7.1 是 RAGOps 堆栈中关键和基本层的总结。
表 7.1 RAGOps 堆栈的关键和基本层
| 层 | 类别 | 描述 | 示例工具 |
|---|---|---|---|
| 数据层 | 关键层 | 负责通过从各种来源摄取、转换为嵌入或图结构以及存储以供检索来创建和存储知识库 | AWS Glue, Apache Kafka, FAISS, Pinecone, Neo4j, Weaviate, Milvus |
| 模型层 | 关键层 | 包含 RAG 中生成和检索所需的模型;包括用于向量生成的嵌入模型、用于文本生成的 LLM 以及用于查询分类、幻觉检测或重新排序的模型 | OpenAI, Hugging Face Transformers, Google Gemini, Llama, Anthropic |
| 模型部署 | 关键层 | 确保模型可访问、性能良好且可扩展;负责提供模型并优化推理以实现快速响应时间 | SageMaker, Vertex AI, NVIDIA Triton, Hugging Face |
| 应用编排层 | 关键层 | 管理层与服务之间的交互,确保查询通过检索和生成阶段流动,并协调检索方法和生成任务 | LangChain, Haystack, Dagster, Apache Airflow, AutoGen, CrewAI |
| 提示层 | 基本层 | 设计和维护输入查询以确保 LLM 生成相关、高质量输出;确保持续提示优化以避免幻觉并提高准确性 | Weights & Biases Prompts, Azure Prompt Flow |
| 评估层 | 基本层 | 评估检索和生成阶段的性能,确保输出相关、事实准确。 | TruLens by TruEra, Ragas, Weights & Biases |
| 监控层 | 基本层 | 持续监控 RAG 系统的性能、健康和资源使用情况;跟踪关键指标,如延迟、资源消耗和错误率,以确保系统稳定性。 | Prometheus, Grafana, TruLens, Galileo |
| LLM 安全与隐私层 | 必要 | 确保 RAG 系统遵守数据隐私法规,并防止提示注入或其他形式的 AI 操纵;实施加密、访问控制和安全措施等安全策略 | AWS KMS, Azure Key Vault, Prompt Injection Guards |
| 模型训练/微调层 | 必要 | 处理特定领域或任务的模型训练和微调;使用特定领域的数据集对嵌入或 LLM 等模型进行微调,确保在特定用例中表现更佳 | Hugging Face, AWS SageMaker, Google Vertex AI, Azure ML |
| 缓存层 | 必要 | 缓存频繁使用的查询和响应,以减少重复检索和生成任务相关的延迟和成本;确保常见查询的响应时间更快,并最小化重复任务的资源使用。 | Redis, Varnish, ElasticCache |
现在我们将简要地看看几个增强层,这些层不是强制性的,但可以进一步改进 RAG 系统。请注意,可能有多个增强层,并且它们应该根据用例需求定制。
7.1.3 增强层
增强层是 RAGOps 堆栈的可选部分,但根据用例环境,它们可以带来显著收益。它们关注系统的效率、可用性和可扩展性。以下描述了一些可能的层。
人工介入层
这一层在需要人类判断的情况下提供关键监督,特别是对于需要更高精度或伦理考虑的用例。它有助于减少模型幻觉和偏差。
成本优化层
RAG 系统可能会变得非常昂贵,特别是当进行多次 LLM 调用以实现高级技术、评估、安全措施和监控时。这一层有助于高效地管理资源,这对于大规模系统尤为重要。优化基础设施可以节省大量成本,但不是系统功能的关键。
可解释性和可理解性层
这一层有助于提供系统决策的透明度,对于需要问责制的领域(例如法律和医疗保健)尤为重要。然而,许多应用程序在没有监管的环境下仍然可以正常工作。
协作和实验层
这一层对于在开发和实验中工作的团队很有用,但对于系统运行来说不是关键。这一层提高了生产力和迭代改进。Weights & Biases 是一个流行的平台,它有助于跟踪实验。
应根据应用需求选择增强层。可能还有其他适合您用例的层。
管理 RAG 解决方案
如果没有先前的知识、预算或时间,构建 RAG 系统可能会很复杂。为了解决这些挑战,服务提供商提供管理 RAG 解决方案。
OpenAI 提供的文件搜索工具可以自动解析和分块您的文档,创建并存储嵌入,并使用向量和关键词搜索来检索相关内容以回答用户查询。AWS 提供的 Amazon Bedrock 知识库,为端到端 RAG 工作流程提供全面管理的支持。Azure AI,例如 OpenAI 文件搜索,提供索引和查询。Anthropic 提供的 Claude 项目允许用户上传文档并提供上下文以进行专注的对话。
几家其他提供商提供 RAG 作为服务,并能处理视频和音频转录、图像内容提取和文档解析。为了快速轻松地部署 RAG 解决方案,可以考虑使用托管服务提供商。
我们还讨论了几种服务提供商、工具和技术,您可以在开发 RAG 系统时使用。这些工具和技术的选择可能取决于诸如
-
可扩展性和性能需求—RAG 系统需要高效地处理大量数据,同时保持低延迟。随着数据规模的扩大或流量激增,系统必须保持高性能以确保快速响应时间。选择允许自动扩展和可变负载的云平台。对于高性能和可扩展的检索,选择能够处理数百万嵌入并具有低延迟搜索能力的向量数据库。使用推理优化工具可以帮助在生成阶段降低延迟。
-
与现有堆栈的集成—与您当前技术堆栈的无缝集成可以最小化中断并降低复杂性。如果您的系统已经在 AWS、GCP 或 Azure 上运行,使用与这些平台集成良好的服务可以简化开发和维护。选择与云提供商原生集成、提供强大 API 支持、并确保所选框架支持这些工具的工具可以非常有益。
-
成本效益—与传统的机器学习模型相比,大型语言模型(LLMs)需要更多的资源。即使使用按需付费的模型,成本也会随着规模的扩大而迅速增加。缓存和推理优化可以帮助管理成本。
-
领域适应性—RAG 系统通常需要适应特定行业或领域(例如医疗保健和法律)。除非使用特定领域的数据进行微调,否则预训练模型可能对特定用例并不完全有效。对于领域适应性,应选择易于微调的模型。也可以考虑现有的特定领域模型。
-
*供应商锁定约束**—由于生成式 AI 是一个不断发展的领域,使用单一供应商的专有工具或服务可能会导致供应商锁定,使得迁移到其他平台或根据需求变化调整你的技术栈变得困难。尽可能使用开源或互操作技术有助于保持灵活性。选择云无关或支持多云部署的工具,以减少对单一供应商的依赖。建议采用模块化架构,以便在不重新设计系统的情况下更换组件。
-
*社区支持**—强大的社区支持意味着可以访问资源、教程、故障排除和定期更新,这可以加速开发并减少调试时间。这对于 LLMs 和 RAG 等快速发展的领域尤其如此。拥有活跃社区的工具有助于提供频繁的更新、插件和第三方集成,如 Hugging Face、LangChain 等。
在了解关键、基本和增强层知识的基础上,你应该准备好搭建一个技术栈来构建你的 RAG 系统。现在让我们看看在构建和部署生产级 RAG 系统时需要考虑的一些常见陷阱和最佳实践。
7.2 生产最佳实践
尽管在设计规划 RAG 系统时付出了诚挚的努力,但在开发和部署过程中仍不可避免地会出现一些问题。尽管 RAG 仍处于起步阶段,但一些常见的失误和最佳实践的趋势已经显现。已有许多实验和经验从中得出,以使 RAG 系统有效运作。本节讨论了五种这样的实践:
-
*系统的延迟**—RAG 系统可能由于需要多个步骤:检索、重新排序和生成而引入延迟。高延迟会显著降低用户体验,尤其是在聊天机器人或交互式搜索引擎等实时应用中,这是因为每个组件都会增加处理时间。有效的查询分类和路由可以帮助优化延迟。在混合检索中,一种有用的方法是首先根据关键词或稀疏检索技术过滤嵌入,然后对过滤后的结果进行相似度搜索。这减少了计算相似度所需的时间,尤其是在大型知识库中。
-
*持续的幻觉**—尽管付出了最大努力,LLMs 仍可能继续生成事实错误或不相关于检索内容的响应。如果检索的数据模糊或不完整,这种情况可能会发生。可能需要后处理验证步骤来解决这些问题。一种常见的方法是将 RAG 系统调整为以推荐为导向,而不是以行动为导向。这意味着系统会循环一个人类进行验证和最终行动。
-
缺乏可扩展性规划—RAG 系统的早期原型在小数据集上通常表现良好,但随着数据量或并发用户数量的增长可能会遇到困难。具有自动扩展功能的托管向量数据库服务可以更容易地规划需求增长和计算需求。同样,自动扩展也可以用于整体应用程序,使用云原生解决方案,如 AWS Lambda。
-
领域适应性挑战—嵌入和语言模型可能在细分或特定领域工作不佳。此外,检索模型和语言模型可能并不总是很好地互补,导致结果不连贯或混乱。检索模型和大型语言模型通常独立开发和微调,这可能导致检索的内容与大型语言模型生成响应的方式不匹配。对于高度专业化的领域,同时微调检索和生成模型变得非常重要。
-
数据隐私和 PII 处理不足—由于训练数据中的偏差,预训练模型可能会生成包含敏感信息(例如,个人数据和机密细节)的内容。RAG 系统可能在响应中无意中泄露敏感信息或个人身份信息(PII),导致隐私泄露。数据泄露,也称为数据盗窃、外泄或出口,是数字世界中的主要威胁。解决方案是在预处理和后处理阶段使用 PII 掩码和数据编辑。确保遵守 GDPR 或 HIPAA 等隐私法规,并部署带有隐私过滤器的模型。
最佳实践列表持续演变。延迟和可扩展性对于管理用户体验和访问至关重要。确保无幻觉生成和数据安全对于系统的可靠性至关重要。表 7.2 总结了将 RAG 系统投入生产的挑战和潜在解决方案。
表 7.2 生产挑战和潜在解决方案
| 挑战 | 描述 | 解决方案 |
|---|---|---|
| 系统延迟 | RAG 系统由于检索、重新排序和生成步骤而增加延迟,影响实时性能。 | 使用查询分类、混合检索过滤和限制相似度搜索 |
| 持续的幻觉 | 由于数据模糊或不完整,大型语言模型可能会生成错误或不相关的响应。 | 添加后处理验证,并使系统基于人类验证的建议。 |
| 缺乏可扩展性规划 | 早期的 RAG 系统随着数据和用户负载的增长而难以扩展。 | 使用自动扩展的向量数据库和云解决方案,如 AWS Lambda。 |
| 领域适应性挑战 | 嵌入和大型语言模型在特定领域可能表现不佳,导致结果不连贯。 | 对特定用例微调检索和生成模型。 |
| 数据隐私和 PII 处理不当 | 模型可能暴露敏感数据或 PII,导致隐私问题。 | 应用 PII 掩码、数据编辑和隐私过滤器,确保符合法规。 |
在本章中,我们探讨了整体 RAGOps 堆栈,该堆栈使构建生产级 RAG 系统成为可能。你还了解了一些常用的工具和技术,以及一些最佳实践。这标志着我们对 RAGOps 堆栈的讨论结束。我们现在完成了本书的第三部分,这意味着你应该准备好构建 RAG 系统并将其投入生产。本书的最后一部分,我们将讨论 RAG-like 多模态能力的一些新兴模式,包括代理 RAG 和 graphRAG,以及对未来方向和持续学习的总结性评论。
摘要
-
RAGOps 堆栈是设计 RAG 系统的一种分层方法。
-
这些层被分为关键、基本和增强层。
-
关键层对于操作至关重要;基本层确保性能和可靠性;增强层提高效率、可扩展性和可用性。
关键层
-
数据层—负责收集、转换和存储知识库。AWS Glue、Azure Data Factory 和 Apache Kafka 等工具可进行数据收集。数据转换包括分块、元数据丰富和将数据转换为向量格式。FAISS、Pinecone 和 Neo4j 等工具用于存储嵌入和图数据。
-
模型层—包括用于生成的嵌入模型和 LLM。嵌入模型将文本转换为向量,选项包括 OpenAI、Google、Cohere 和 Hugging Face。基础模型(LLM)如 GPT、Claude 和 Llama 生成输出并评估任务。特定任务的模型处理专门的任务,如查询分类和偏差检测。
-
模型部署—管理 LLM 和嵌入模型的托管和提供。流行的平台包括 AWS SageMaker、Google Vertex 和 Hugging Face。推理优化通过量化、批处理等方法减少响应时间和成本。
-
应用编排层—协调不同组件之间的数据流:
-
查询编排处理查询分类和优化。
-
检索协调管理密集或混合搜索等检索方法。
-
生成协调处理提示生成和检索后的任务,如重新排序。
-
基本层
-
提示层—确保提示被精心设计,以引导 LLM 产生相关、准确的响应。LangChain 和 Azure Prompt Flow 等工具协助提示管理。
-
评估层—通过评估检索准确性、忠实度和上下文相关性来监控系统性能。TruLens 和 Ragas 等工具提供评估框架。
-
监控层—跟踪系统健康、资源使用和延迟。TraceLoop 和 Galileo 等平台提供监控服务。
-
LLM 安全和隐私层—保护免受数据泄露和提示注入攻击。应使用加密、匿名化和差分隐私等工具来保护敏感数据。
-
缓存层—缓存频繁生成的响应,以减少 RAG 系统中的成本和延迟。
增强层
-
人工介入层—增加人工监督以确保更高的准确性和道德决策。
-
成本优化层—降低基础设施成本,尤其是在大规模 RAG 系统中。
-
可解释性和可理解性层—提供对系统决策的透明度,这对于医疗保健和法律等领域至关重要。
-
协作和实验层—对基于团队的开发和持续改进很有用。
生产最佳实践
-
延迟—RAG 系统由于多个步骤常常引入延迟。使用如混合检索中的过滤等技巧可以帮助减少响应时间。
-
幻觉—LLMs 可能仍然会生成不正确的响应。后处理验证和人工介入系统有助于减轻这一问题。
-
可扩展性—早期原型可能难以扩展。具有自动扩展功能的托管向量数据库服务可以帮助规划增长。
-
领域适应性—嵌入和语言模型可能在利基领域表现不佳。对检索和生成模型进行微调是必要的。
-
数据隐私—模型可能泄露敏感信息。PII 掩码、加密和遵守数据法规对于保护用户数据至关重要。
第八章:图、多模态、代理式和其他 RAG 变体
本章涵盖
-
介绍 RAG 变体
-
知识图谱 RAG
-
多模态 RAG
-
代理式 RAG
-
其他 RAG 变体
本书的第一部分介绍了检索增强生成(RAG)及其背后的核心思想。第二部分处理了构建和评估基本 RAG 系统。第三部分将 RAG 超越了简单方法,讨论了高级技术和支持 RAG 系统的技术栈。本书的最后部分探讨了更多的 RAG 模式,并以一些最佳实践和一些进一步探索的领域结束我们的讨论。
第八章探讨了几个流行的 RAG 变体。这些变体将 RAG 的不同阶段(即索引、检索、增强和生成)适应特定的用例需求。本章首先讨论了这些变体的出现及其目的。然后我们继续讨论在应用 RAG 中取得显著成效的三个重要变体。这些是知识图谱增强型、多模态和代理式 RAG。我们还简要考察了其他对 RAG 在实际应用中的进化有显著贡献的 RAG 变体。我们讨论了每个变体的目的和动机。本章还分析了这些变体的工作流程、特性和技术细节,以及它们的优缺点。为了简化,这些变体的代码不包括在本章中,但可以在本书的代码仓库中找到。
到本章结束时,你应该
-
了解 RAG 变体的思想和动机。
-
深入理解图、多模态和代理式 RAG。
-
了解几个流行的 RAG 变体及其解决的用例。
对 RAG 的简单方法存在几个局限性,这些局限性影响了标准 RAG 系统的整体可用性。这些局限性从理解不同文档之间关系上的困难到处理各种数据类型,以及关于系统成本和效率的担忧。第六章讨论了几种检索前、检索和检索后的技术,如索引优化、查询优化、混合和迭代检索策略、压缩和重新排序,这些技术针对不同的局限性并提高了 RAG 系统的准确性。随着时间的推移,出现了一些结合了这些技术之一或多个的 RAG 模式,以解决特定的用例挑战。我们将它们称为 RAG 变体。
8.1 RAG 变体是什么,为什么我们需要它们?
依赖于 RAG 的应用程序每天都在扩展。其中一些应用程序不仅处理文本,还处理不同的数据模态,如图像、视频和音频。其他应用领域如医疗保健和金融,不准确的结果可能带来灾难性的影响。使用 LLMs 作为决策代理的新兴领域也使得 RAG 系统更加适应和智能。除了事实准确性外,实际的 RAG 应用还需要低延迟和低成本,以提升用户体验和采用率。随着 RAG 应用范围的扩大,需要专门化的 RAG 变体——称为 RAG 变体——来应对不同任务和数据类型中的独特挑战。
这些 RAG 变体是对标准 RAG 框架的适应性调整,扩展了其功能以满足多样化的复杂用例需求。通过采用先进的预检索、检索和后检索技术,这些变体增强了 RAG,使其具备处理多模态数据、提供更高准确性和更好的关系理解等能力。这些 RAG 变体的演变使得系统既灵活又具有领域意识。
虽然已经出现了几种 RAG 变体,但我们在接下来的几节中将深入讨论的三个变体已经获得了显著的关注:
-
*多模态 RAG——扩展了标准 RAG 的功能,使其超越文本数据,并整合了其他数据类型,如图像、视频和音频。这一特性使得系统能够从非文本文档中获取信息,并提供额外的上下文。
-
*知识图谱 RAG——将知识图谱整合到检索过程中。这一想法在第六章中作为改进索引结构的一部分被引入。知识图谱有助于建立实体之间的关系,提供更好的上下文,特别是在多跳查询中。
-
*代理 RAG——将 LLM 代理整合到 RAG 框架中。这些代理能够在 RAG 价值链的索引到生成过程中实现自主决策。同时,所有组件都适应用户查询。
除了这三个之外,我们还涉及到一些额外的变体,例如校正 RAG、自 RAG 等,但首先,我们从多模态开始讨论。
8.2 多模态 RAG
迄今为止,我们已经看到标准 RAG 系统在管理和检索文本数据以生成上下文感知和基于事实的响应方面是有效的。然而,企业数据范围超出了文本,还包括图像、音频和视频。当尝试解释非文本数据格式时,标准 RAG 系统显得力不从心。这就是多模态 RAG 变体的核心动机,它扩展了能力以支持更多数据格式。
8.2.1 数据模态
对于初学者来说,“模态”这个词可能有些令人困惑,尤其是在不同领域“模态”的含义各不相同。语法模态与说话者的态度表达相关,而治疗模态可能指医学中的治疗方法。在 RAG 和人工智能领域,模态指的是数据格式。文本是一种模态,图像是一种模态,视频和音频是不同的模态,我们还可以将表格和代码视为不同的模态。图 8.1 展示了某些数据模态,包括一些不太常见的,如基因组数据和 3D 数据。

图 8.1 不同数据模态的示例
因此,多模态 RAG 是标准 RAG 的扩展版本,具有处理多种数据模态的能力。在深入探讨多模态 RAG 的需求和架构细节之前,让我们思考一下需要多模态 RAG 的应用场景。
8.2.2 多模态 RAG 用例
有几个行业和功能需要 RAG 的多模态变体,例如
-
医学诊断——诊断助手可以与包括医疗历史(以文本形式)、实验室结果(以表格形式)和诊断图像(如 X 光片、MRI 等)在内的患者记录一起工作,以及包括图表、图表或显微镜图像的研究和论文。当患者前来咨询时,这个助手可以为医生提供全面的分析。
-
投资分析——与包含趋势、收益和预测图表的财务报告和其他文件一起工作,以及表格形式的资产负债表和损益表,除了通常的文本评论外,投资研究助手可以为分析师提供做出投资决策所需的关键信息。
-
购买助手——通过分析产品图像、文本描述、产品规格(以表格形式)和客户评论,购物助手可以帮助电子商务网站上的购物者提供个性化推荐。
-
编码助手——编码助手根据查询上下文从存储库检索相关的文档、函数使用示例和代码片段。例如,当开发者询问如何实现某个 API 函数时,RAG 系统从文档中检索精确的代码片段和解释,帮助开发者避免耗时搜索。
-
设备维护——通过分析历史文本报告、视觉检查图像或视频流、传感器数据和性能表,维护助手可以提供维护建议和趋势。
这些只是几个例子。虽然仅包含文本的标准 RAG 在用例的初始阶段是可接受的,但大量生产级的 RAG 系统至少包含一种其他数据模态。
8.2.3 多模态 RAG 管道
现在我们来探讨开发多模态 RAG 管道与您迄今为止所学的标准文本 RAG 管道有何不同。一个明显的改变将是在加载和索引非文本模态的数据。
多模态索引管道
开发多模态 RAG 的知识库需要对索引管道的四个组件进行增强。除了加载和分块不同模态的文件外,为多模态数据创建嵌入也需要特别注意。让我们逐一查看每个组件。
数据加载步骤与仅文本的 RAG 标准流程非常相似,但现在包括了连接器和用于非文本模态的数据加载器。有几种选项可供选择。Pillow,也称为PIL,是一个流行的 Python 库,用于加载图像。Unstructured是一个开源库,包括用于摄入各种数据格式的组件。Pydub是另一个 Python 库,允许加载 WAV 和 MP3 等音频文件。LangChain 提供了与未结构化库的集成。UnstructuredImageLoader是 LangChain 文档加载器中可用于加载图像的一个类。对于音频和视频转录,可以使用OpenAIWhisperParser、AssemblyAIAudioTranscriptLoader和YoutubeLoader等库。同样,对于表格数据,CSVLoader和DataFrameLoader也很有用。为了简单起见,有时不同模态的数据会被转录成文本。
分块对于多模态数据在很大程度上遵循与文本分块类似的过程,在音频/视频数据被转录并存储为文本的情况下。然而,对于原始音频和视频数据,可以采用特定的分块方法。语音活动检测(VAD)根据音频中的静默或背景噪声来分块数据。基于场景检测的分块识别场景中的主要变化以分割视频。对于表格数据,有时可以结合行/列级别的分块,而对于代码,分块可以在函数、类或逻辑单元级别进行。所有用于分块文本数据的策略,如上下文丰富、语义分块等,也在这里适用。对于图像,通常不进行分块。semantic_chunkers是一个用于智能分块文本、视频和音频的多模态分块库。它使 AI 和数据处理更加高效和准确。
在多模态 RAG 中,嵌入是细微差别开始的地方。在标准的仅文本 RAG 中,有几种嵌入模型可用于将分块向量化。但如何将不同模态的数据,如图像,向量化呢?处理这种复杂性的方法有三种:共享或联合嵌入模型、特定模态的嵌入以及将所有非文本数据转换为文本。
共享或联合嵌入模型将不同的数据类型映射到一个统一的嵌入空间中。通过这样做,实现了跨模态检索,例如根据文本描述查找图像或从图像生成文本。Google Vertex AI 提供共享嵌入模型,该模型在统一的嵌入空间中为所有数据模态生成向量。共享嵌入模型也称为多模态嵌入模型。虽然多模态嵌入在理解一般图像数据方面效率很高,但在需要细粒度理解时(如图表和表格以图像和信息图表的形式表示),有时会不足。在图 8.2 中,图像、文本、音频和视频数据被绘制在同一个 3D 向量空间中。
模态特定嵌入方法类似于多模态嵌入,但不同之处在于,它不是为所有模态提供一个单一的嵌入空间,而是仅映射两种模态。在这种情况下,我们需要一个图像-文本嵌入模型来处理文本、图像和音频数据(例如,对比语言-图像预训练,或 CLIP)以及一个音频-文本嵌入模型(例如,对比语言-音频预训练,或 CLAP)。知识库在不同的嵌入空间中存储文本、图像和音频嵌入,并分别存储。图 8.3 是 CLIP 图像-文本嵌入的一个例子,其中图像和文本嵌入被投影到一个共享的嵌入空间中。

图 8.2 图像、文本、视频和音频被绘制在同一个嵌入空间中。狗、吠叫和狗的图像彼此靠近。

图 8.3 CLIP 通过多模态预训练将分类转换为检索任务,这使得预训练模型能够处理零样本识别。
将所有非文本数据转换为文本,首先使用多模态 LLM 将所有非文本(图像)数据转换为文本,然后遵循仅文本的 RAG 方法。 (多模态 LLM 是一种处理所有数据模态的大型语言模型。你将在本节后面了解更多关于多模态 LLM 的信息。) 在这种策略中,你可能注意到我们可能并没有完全使用多模态数据,因为将非文本转换为文本数据时必然会发生信息损失。在这种策略的一种变体中,我们不是将所有多模态数据转换为文本并使用它,而是采用双管齐下的方法。在这里,所有多模态数据都使用多模态 LLM 进行总结。在检索过程中,使用这些文本的嵌入进行搜索。然而,对于生成,不仅需要检索总结,还需要检索实际的多模态文件(例如,一个.jpeg 文件)并将其传递给多模态 LLM 进行生成。这减少了转换为文本时的信息损失。
嵌入,无论是多模态还是文本,都存储在向量数据库中,例如标准的仅文本 RAG。除了向量存储外,还需要文档存储来存储可以检索并传递给 LLM 进行生成的原始文件。可以使用如 Redis 这样的文档存储来存储原始文件。当使用文本摘要时,必须创建摘要嵌入到原始文档的关键映射。图 8.4 显示了包含所有三种嵌入选项的索引管道。

图 8.4 多模态索引管道展示三种选项
虽然加载、分块和存储组件相似,但在多模态 RAG 中,嵌入组件提供了几个选项。表 8.1 比较了仅文本 RAG 和多模态 RAG 的索引管道。
表 8.1 仅文本 RAG 与多模态 RAG 的索引管道
| 索引组件 | 仅文本 RAG | 多模态 RAG |
|---|---|---|
| 加载 | 使用标准的文本数据加载器来加载文档,例如纯文本文件、PDF 和其他基于文本的格式。 | 需要连接器来处理额外的数据类型。对于图像,使用如Pillow(PIL)和 LangChain 中的UnstructuredImageLoader库;对于音频,我们使用如Pydub或OpenAIWhisperParser的库,而对于表格数据,则使用CSVLoader和DataFrameLoader。还纳入了如 AssemblyAI 和 YoutubeLoader 这样的音频/视频转录工具来预处理音频/视频内容。 |
| 分块 | 根据上下文或结构(例如,句子、段落)将文本数据划分为段(分块),并可选地进行语义丰富。 | 当数据被转录为文本(音频/视频)时,遵循文本分块。对于原始音频,可以使用语音活动检测(VAD)通过停顿进行分块。对于视频,场景检测识别视觉转换,而表格数据可以按行/列进行分块。通常跳过图像分块。 |
| 嵌入 | 使用单模态文本嵌入模型(例如,OpenAI 嵌入或 BERT)创建文本嵌入,该模型将每个分块向量化以进行存储和检索。 | 嵌入可以通过多模态嵌入模型生成,这些模型将所有数据类型统一到一个共享的向量空间中,以实现跨模态检索,或者使用特定于模态的嵌入(如 CLIP 和 CLAP)或将多模态数据首先转换为文本并使用文本嵌入,尽管这可能会导致信息丢失。 |
| 存储 | 嵌入被存储在向量数据库中。 | 嵌入被存储在向量数据库中,但可能还会使用额外的文档存储来存储原始的多模态文件。 |
一旦创建了知识库,例如在仅文本 RAG 中,生成管道负责与知识库进行实时交互。根据所使用的嵌入策略,生成管道组件会适应以包含多模态数据。
多模态生成管道
一旦索引管道创建了知识库,生成管道需要搜索、检索、处理和生成多模态数据。这需要检索方法的变体和多模态 LLM:
-
检索—根据嵌入策略,检索技术会有所不同:
-
如果使用共享的多模态嵌入模型,检索过程遵循相似度搜索方法,其中用户查询使用相同的模态嵌入转换为向量形式,并根据它们的余弦相似度值检索文档,无论它们的模态如何。
-
在模态特定嵌入方法中,由于存在多个嵌入,采用了多向量检索方法。对于单个查询,根据相似度从每个模态特定嵌入空间检索文档。这些文档在增强和生成之前可能会被重新排序。
-
当非文本数据转换为文本时,检索过程与标准仅文本 RAG 相同。在同时使用文本摘要和原始文件的变化中,检索器首先从文本嵌入空间检索相关摘要,然后检索映射到这些摘要的文档存储中的文件。
-
-
增强—增强步骤与仅文本 RAG 相同,只是增强提示现在包括与文本提示一起的原始多模态文件。
-
生成—类似于多模态嵌入,为了处理和生成多模态数据,使用多模态 LLMs。LLMs 受限于只能处理文本数据的能力。多模态 LLMs 也是基于 transformers 的模型,但除了文本数据外,还训练了所有模态的数据。多模态 LLMs 的训练过程存在细微的差异,鼓励读者探索它们。然而,对于构建 RAG 系统,我们可以使用可用的基础多模态 LLMs。OpenAI 的 GPT 4o 和 GPT 4o mini 以及 Google 的 Gemini 是流行的专有多模态 LLMs,而 Meta 的 Llama 3.2 和 Mistral AI 的 Pixtral 是开源的多模态 LLMs。
虽然增强步骤与仅文本 RAG 相似,但检索步骤根据所使用的嵌入策略进行适应,生成步骤则将 LLMs 替换为多模态 LLMs。生成管道中的差异在
表 8.2.
表 8.2 仅文本 RAG 与多模态 RAG 的索引管道
| 生成组件 | 仅文本 RAG | 多模态 RAG |
|---|---|---|
| 检索 | 使用相似度搜索检索与查询相似的文本嵌入 | 根据嵌入策略而变化——在共享嵌入模型中,无论模态如何,都采用相似度搜索,将查询转换为多模态向量。在模态特定嵌入中,使用多向量检索用于特定模态的结果,在文本转换的非文本数据中,使用标准的文本检索以及映射到文本摘要的原始文件。 |
| 增强 | 将检索到的文本添加到提示中 | 与纯文本类似,但在提示中包括文本旁边的原始多模态文件。 |
| 生成 | 使用 LLM 生成响应 | 使用多模态 LLM 而不是纯文本 LLM。 |
通过调整索引和生成管道,可以将标准的纯文本 RAG 系统升级为多模态 RAG 系统,如图 8.5 所示。
![多级系统图]
AI 生成的内容可能是错误的。](../Images/CH08_F05_Kimothi.png)
图 8.5 对于这三种方法,生成管道也进行了调整。
8.2.4 挑战和最佳实践
多模态 RAG 系统因企业数据中的多样性而日益受到重视。然而,必须注意,随着多模态的出现,系统的复杂性也随之增加,同时延迟更高,在多模态嵌入和生成上的支出也更多。与多模态 RAG 相关的一些常见挑战包括
-
确保不同数据模态(例如文本和图像)之间的一致性对齐可能很困难。利用将不同模态投影到公共嵌入空间的多模态嵌入确实可以创造更好的整合,但这些嵌入模型仍然可能导致不准确,必须进行评估。
-
处理多种数据类型可能会增加计算需求和处理时间。构建健壮的预处理管道,以标准化和调整来自各种模态的数据,是必不可少的。有时,将多模态数据转换为文本并采用仅文本的 RAG 方法可能就足以生成所需的结果。
-
并非所有模型都能有效地处理和整合所有模态的多模态数据。仅包含那些对任务有显著价值的模型,以优化性能和资源利用。
我们已经研究了一种 RAG 变体,它扩展了 RAG 对不同数据模态的能力。然而,当信息分散在不同文档中时,标准 RAG 仍然存在不足。现在让我们看看一种使用知识图来建立更高层次关系的模式。
8.3 知识图 RAG
想象一下总结一份大型报告或回答需要从不同来源获取信息的复杂问题。例如,像“这份报告的主要主题是什么?”或“目录中哪些产品由相同的名人支持?”这样的问题对于标准的 RAG 系统来说很难回答。
在像报告中的“主要主题”这样的摘要任务中,没有文档片段可以完全回答问题。同样,“由相同名人支持”的数据对于检索器搜索来说也不太可能存在。
为了回答这些需要多跳推理、识别上下文关系和解决更高层次查询的复杂问题,一种结合知识图的强大 RAG 模式已经取得了广泛的成功。
这种模式被称为知识图谱 RAG 或简称为图 RAG(不要与微软的 GraphRAG 混淆,它是一个特定的知识图谱 RAG 框架)。在此需要指出的是,图 RAG 不一定取代基于向量的标准 RAG,而是一种混合方法,其中同时使用向量和图来检索上下文。在继续前进之前,以下几节将解释知识图谱是什么以及它们固有的好处。
8.3.1 知识图谱
“知识图谱”这一术语是由谷歌在 2012 年左右普及的,它通过将其搜索引擎中的实体-关系结构整合,以提供更准确和上下文感知的结果。理解知识图谱的最简单方式是通过节点和边结构。节点可以代表实体,如人、组织、产品和事件,边代表节点之间的关系,如“是部分”,“在...工作”,“相关”等。节点和边也可以具有属性,如 id、时间戳等。因此,知识图谱依赖于语义或意义来创建一个共享的、类似人类的对数据的理解。图 8.6 展示了具有节点、边和属性的客户数据的简单知识图谱。
知识图谱通过优先考虑关系和上下文,在标准结构化数据库(如 SQL)之上提供了几个优势,这导致了更深入的数据探索。标准的行-列或文档存储不允许上下文,而知识图谱则允许。
知识图谱中的存储和数据处理是独特的。专门的数据库,如 Neo4j、Amazon Neptune 和 TigerGraph,用于存储知识图谱

图 8.6 客户活动知识图谱表示,其中节点(圆圈)代表实体,边(箭头)代表关系,属性(矩形)是属性。
数据和查询语言,如 Cypher、Gremlin 和 SparkQL,用于图遍历。鼓励读者了解更多关于图数据库的知识,但需要记住的一些关键概念是
-
节点和边—*节点代表实体,边代表关系,以形成图结构并使知识具有可视化结构。
-
属性—属性是实体(节点)和关系(边)的性质。
-
三元组—知识以三元组的形式表示,例如“客户 A 购买了产品 X”(节点-边-节点)。在这里,两个实体“客户 A”和“产品 X”以及一个关系“购买”形成一个三元组。这些三元组是知识图谱的构建块,以结构化的方式捕捉事实和关系。
-
本体—本体定义了知识图谱的架构或结构,指定了实体、关系及其属性的类型。
-
图嵌入——图嵌入是节点和边的向量表示,它捕捉了图结构。
-
图查询语言——SPARQL、Cypher 和类似语言允许用户从图中检索信息,形成复杂的查询以找到模式、连接和洞察。
-
图遍历——这是通过导航节点和边来发现路径、模式和洞察的方法,对于最短路径或推荐系统等算法至关重要。
由于它们内在关注关系和上下文,知识图谱增强了标准的 RAG(关系型数据库查询语言),以实现更高级的上下文感知检索。
8.3.2 知识图谱 RAG 用例
知识图谱在需要处理多跳关系、实体消歧和复杂网络的各种用例中非常有用。标准的 RAG 系统仅限于检索孤立的信息块,而知识图谱 RAG 可以动态连接和分析网络中的数据点,使其非常适合需要深入理解相互关联数据的应用。以下是一些示例:
-
个性化治疗方案——知识图谱 RAG 可以以网络格式链接药物、治疗和条件,这使得它可以识别潜在的相互作用,并根据多个因素定制治疗方案。标准的 RAG 可以检索有关特定药物或治疗的信息,但难以在症状、条件和治疗网络中进行交叉引用。
-
个性化产品推荐——标准的 RAG 可以检索个人接触点或客户评价,但无法捕捉客户在其旅程中遵循的相互关联的路径。知识图谱 RAG 允许跨交易、浏览历史和客户反馈进行多跳推理,从而实现对旅程的更全面分析,并基于客户行为和偏好之间的关系提供高度相关的推荐。
-
合同分析——标准的 RAG 可以从单个合同或条款中检索文本,但不能映射合同、当事人或合规要求之间的关系。知识图谱 RAG 可以在关系网络中链接合同、条款和当事人,使其能够识别冲突、依赖性和合规风险。
虽然标准的 RAG 可以解决简单的查询,但对于需要从多个来源的数据进行分析和推理的过程,知识图谱可以证明是有优势的。
8.3.3 图 RAG 方法
知识图谱是一种强大的数据模式。使用知识图谱的方法可以根据用例的复杂性和数据的多样性来确定。本节讨论了可以遵循的三个常见方法。
通过图实现结构感知
这是将知识图纳入的最简单方法。回想一下,在标准的基于向量的 RAG 方法中,文档被分块,然后创建嵌入并存储以供检索。可能出现的问题是相邻块中的信息可能无法检索,并且可能会发生一定程度的信息丢失。在第 6.2.1 节中,我们讨论了类似于父-子结构的层次索引结构。父文档包含总体主题或摘要,而子文档深入到具体细节。在检索过程中,系统可以首先定位最相关的子文档,如果需要,再参考父文档以获取额外的上下文。这种方法提高了检索的精确度,同时保持了更广泛的上下文。
在图形结构中存储文档是一种高效的方式。父文档和子文档可以存储在节点中,并使用“是子节点”的关系进行关联。可以创建更多层级的层次结构。在图 8.7 中,存在三个层级的索引层次,尽管搜索发生在最低层,但更高层次中的父文档也会被检索以获取更深的上下文。

图 8.7 在层次索引结构中搜索发生在最低层,但检索到的文档从更高层次的上下文中来看更加完整。
增强型向量搜索
在实现层次索引时,图形不是强制性的。知识图的真实价值在于能够在块之间建立连接。通过遍历知识图来检索相关块,可以增强对一组块的标准向量搜索。为此,使用 LLM 从块中提取一系列实体和关系。
在检索阶段,第一步是执行基于用户查询的常规向量搜索。确定了一组与用户查询高度相似的块。在下一步中,遍历知识图以检索与第一步中确定的块中的实体相关的实体。通过这样做,检索器不仅检索到与用户查询相似的块,还检索到相关的块,这有助于更深入地理解上下文,并且在解决多跳查询时可能非常有效。这通常与层次结构和检索文档的重新排序相结合。图 8.8 显示了一个增强的知识图,其中块也包含提取的实体和关系。在检索过程中,除了相似的块之外,还检索相关实体的父块。

图 8.8 从块中提取的实体和关系起着至关重要的作用。当检索到与用户查询相似的块时,也检索与相似块中的实体相关的实体。
图社区和社区摘要
如前所述,知识图谱是关于实体及其关系的。根据处理过程,可能存在某些实体之间互动更频繁的模式。图社区是连接更紧密的实体子集。例如,可以识别具有相似人口统计和购买模式的客户社区,或者可以发现一起出现的功能特性集群。Leiden 和 Louvain 算法等社区检测算法被用于在知识图谱中检测社区。在检测到这些社区后,使用 LLM 生成社区中实体及其关系信息的摘要。检索过程可以类似于向量搜索,其中使用相似度分数识别初始节点,并检索与节点相关的社区摘要,或者可以直接在社区摘要上应用向量搜索,因为它们已经包含了几种实体的更深层次上下文。这种方法在查询与知识库中的更广泛主题相关时特别有用。图 8.9 展示了在社区级别进行检索足以回答更广泛主题层面的问题。
在这些方法中的任何一种,索引和检索管道都需要修改以整合图谱并创建一个混合检索系统,其中既存在向量数据库也存在图数据库。
8.3.4 图 RAG 管道
正如我们一直在讨论的,知识图谱是一种独特的数据模式,需要特定的处理和存储。RAG 管道需要定制以整合知识图谱。根据所采用的方法,索引和生成管道都需要调整。
知识图谱 RAG 索引管道
图 RAG 中的知识库需要不同类型的解析和存储。在索引管道中引入了新的组件来创建知识图谱、提取摘要以及存储生成所需的数据。虽然加载和分块组件保持相似,但其余组件发生了显著变化:
-
数据加载—从标准基于向量的 RAG 加载文档时没有区别。
-
数据分块—为了从文档中创建知识图谱,大文档以与向量 RAG 方法相同的方式进行分块。然后,这些块被传递给一个大型语言模型(LLM)以提取实体及其关系。
-
实体关系属性提取(用于增强图 RAG**)—这是图增强中的关键步骤,因为响应的质量将取决于实体和关系识别得有多好。这一步可以进行定制

AI 生成的内容可能是不正确的。](../Images/CH08_F10_Kimothi.png)
图 8.10 图 RAG 的索引管道。可以直接存储块以进行简单的结构感知索引,并且可以创建并存储与图相关的社区摘要。
生成管道
由于图 RAG 中的知识库性质与标准 RAG 大不相同,因此在生成管道中需要进行重大调整。由于图遍历的额外步骤,检索过程比向量检索稍微复杂一些。图数据库如 Neo4j 通过 Neo4j 向量搜索插件引入了向量索引,这些索引将节点和属性表示为嵌入,并启用相似度搜索。为了有效检索,用户查询(自然语言)被转换为可以用于遍历知识图的图查询。Neo4j 使用一种名为 Cypher 的图查询语言。为了使用 Cypher 查询语言,有几种方法:
-
基于模板**的—创建了几个预定义的 Cypher 模板,并根据用户查询,LLM 选择使用哪个模板。这是一个极其僵化和限制性的方法。
-
*LLM 生成的查询**—LLM 直接根据自然语言用户查询生成 Cypher 查询。采用如少样本提示等提示工程技术。这种方法比基于模板的方法更灵活,但不是 100%可靠的。
在 LangChain 中,GraphCypherQAChain类来自langchain.chains库。为了更好地查询,知识图的架构也提供给 LLM:
-
*增强**—根据图查询,从图数据库接收到的响应被处理以提取可以增强到原始用户查询的文本。除此之外,增强步骤与向量 RAG 相同。
-
*生成**—将增强的提示发送到 LLM,就像在标准向量 RAG 方法中一样。
虽然最终生成步骤以及初始数据加载和分块不需要任何特殊调整,但其余过程变化很大。表 8.3 总结了向量和图 RAG 之间的差异。
表 8.3 向量 RAG 和图 RAG 之间的差异
| 步骤 | 向量 RAG | 图 RAG |
|---|---|---|
| 数据加载 | 加载文档时无需对关系进行特殊预处理 | 与向量 RAG 相似;文档加载时无需特殊图处理。 |
| 数据分块 | 将大文档分成小块进行嵌入和向量存储 | 文档以类似方式分块;然后对每个块进行处理以提取实体和关系,构建关系结构。 |
| 实体和关系提取 | 不适用;专注于从块中创建嵌入 | 使用 LLM 从每个块中提取实体、关系和属性,可能需要多次遍历来精炼和去重实体和关系。 |
| 存储 | 在向量数据库中存储嵌入 | 实体和关系存储在图数据库中(例如,Neo4j),可以选择迭代更新图。LangChain 的 Neo4jGraph 等工具可以自动化此过程。 |
| 社区摘要 | 不适用;主要依赖于对单个嵌入的相似度搜索 | 在知识图谱中检测社区,并使用 LLM 为每个社区创建摘要。这些摘要可以作为混合图-向量 RAG 方法中的向量存储。 |
| 检索 | 在嵌入上执行直接的相似度搜索 | 涉及使用 Cypher 查询进行图遍历,这些查询可以是预先定义的模板生成的,也可以由 LLM 动态生成。Neo4j 的向量索引可以增强基于相似度的节点搜索。 |
| 增强功能 | 使用检索到的嵌入来增强用户的查询 | 检索到的节点、关系或摘要增强用户的查询。可能还会使用额外的 LLM 处理来根据检索到的图内容优化响应。 |
| 生成 | 将增强的提示发送给 LLM 以生成响应 | 类似于向量 RAG,但依赖于包含来自知识图谱的图洞察、关系和上下文的增强数据来丰富响应。 |
8.3.5 挑战和最佳实践
尽管图 RAG 有诸多好处,但仍有一些挑战需要仔细考虑:
-
将多样化的数据源合并成一个统一的知识图谱可能既复杂又耗时。从专注于特定领域开始,逐步扩展知识图谱以管理复杂性。
-
由于在各个阶段进行迭代的 LLM 处理,从文档中生成大规模知识图谱和社区摘要计算成本高昂。因此,必须仔细选择图 RAG 的数据。
-
当前的相似度测量技术可能无法完全捕捉图中细微的关系或结构依赖,导致检索信息可能存在不匹配。为了达到可接受的准确性,需要谨慎使用针对特定案例的评估。
-
每次部署可能需要定制图数据构建、索引和检索的调整,这使得泛化变得困难。保持知识图谱的准确性和时效性信息更新需要持续的努力。因此,图 RAG 可能不是默认的 RAG 策略。
到目前为止,我们已经探讨了两种扩展标准 RAG 功能的 RAG 变体,它们通过包括多模态数据和图结构来实现。接下来,我们将讨论生成 AI 领域中最具影响力的概念之一:代理。
8.4 代理 RAG
到现在为止,你已经了解到标准 RAG 系统存在挑战。它们可能在推理、回答复杂问题和多步骤过程中遇到困难。全面 RAG 系统的关键方面之一是能够搜索多个数据源。这可以包括内部公司文档、公开互联网、第三方应用程序,甚至像 SQL 数据库这样的结构化数据源。到目前为止,在这本书中,我们已经构建了能够搜索单个知识库的系统,并且对于任何查询,都会搜索整个知识库。
这种方法带来了两个挑战。首先,所有信息都必须被索引并存储在单个向量存储中,这在大规模存储时会导致问题。其次,对于任何查询,整个知识库都需要被搜索,这对于大型知识库来说效率非常低。为了克服这个挑战,需要一个能够理解用户查询并将查询路由到相关来源的模块。这是使用一个或多个 LLM 代理进行决策的 agentic RAG 解决的一个局限性。让我们首先了解“代理”这个术语的含义。
8.4.1 LLM 代理
在 LLM 流行之前,AI 中就已经使用了代理。AI 代理的总体含义是一个可以自主感知其所处环境、做出决策并执行行动以实现目标的软件系统。传统上,AI 代理被开发来执行特定任务并依赖于预定义的规则或学习行为,如在自动驾驶汽车或机器人技术领域。由于能够处理和理解语言(现在甚至可以处理多模态数据),LLMs 现在被视为一种通用技术,可以帮助构建无需明确定义规则或环境数据的自主决策。尽管没有关于基于 LLM 的 AI 代理的通用定义,但系统中有四个关键组件可以支持自主决策和任务执行。
核心 LLM 大脑是一个被分配了特定角色和任务的 LLM。这个组件负责理解用户请求并与其他组件交互以响应用户。例如,为旅行助手构建的 AI 代理可能需要处理不同类型的任务,如搜索信息、创建行程、预订票务或管理之前的预订。
记忆组件管理代理的过去经验。它可以像当前对话的聊天历史这样的短期记忆,或者长期记忆,其中存储了之前交互中的重要信息。对于旅行助手 AI 代理,短期记忆将保存用户查询的当前上下文,而票务预订历史或之前的旅行搜索可以从长期记忆中检索。
规划组件创建了一系列逐步的任务,这些任务将被遵循以响应用户的请求。任务分解或把复杂任务分解成更小、更易管理的子任务。ReAct,代表推理和行动或反思,其中代理对自己行动的结果进行自我评估,可以是规划组件的一部分。
工具帮助代理在其外部资源上执行操作。这可以是进行网络搜索,查询外部数据库,如 SQL 数据库,调用第三方 API,如天气 API 等。核心 LLM 大脑负责以接受格式向工具发送有效载荷请求。这四个组件及其交互如图 8.11 所示。

图 8.11 LLM 代理的四个组件分解用户的查询,回忆与用户的交互历史,并使用外部工具完成任务以响应用户。
由于 AI 代理的定义持续演变,这些组件并非一成不变,但通常是被认可的。为了帮助理解这些组件如何相互作用,让我们以一个为旅行辅助构建的 AI 代理为例,比如在线旅行社的客户服务代理。
假设客户提出一个问题,例如,“我的航班是否按计划进行?”核心 LLM 大脑接收这个输入并理解用户的意图是检查特定的航班状态。在这个阶段,核心 LLM 大脑可以调用规划模块来决定回答此类查询所需的行动方案。规划模块可能会响应,例如从之前的交互(记忆)中检索预订信息,从数据库中查询最新的航班信息,将其与记忆中的先前细节进行比较,并将结果传达给用户。在这里,从数据库中检索信息将需要像 API 这样的工具,这是一个核心 LLM 大脑可以访问的预构建模块。规划模块还可以引入条件步骤——例如,如果无法从记忆中检索到之前的预订信息,核心 LLM 大脑必须提示用户提供这些信息。当核心 LLM 大脑从规划模块获得计划时,它会检索之前的预订信息,调用工具检索航班信息,将新信息与记忆中的旧信息进行比较,并基于此分析制定回应。这个代理的简单工作流程如图 8.12 所示。

图 8.12 使用规划、记忆和工具模块对用户查询航班安排的简单任务进行响应的 LLM 代理
这是一个简单的任务的例子。多个代理可以一起解决更复杂层次的任务,例如“为我计划和预订一次假期。”基于 LLM 的 AI 代理领域非常有前景,鼓励读者了解更多关于这个不断发展的领域。在本节的讨论中,我们关注几个方面,特别是工具使用和一点规划。代理 RAG 的应用案例横跨多个行业,因此查看代理 RAG 的能力更有意义。
8.4.2 代理 RAG 能力
在我们介绍代理 RAG 时,我们强调了使用单个知识库的标准 RAG 的挑战。代理 RAG 在 RAG 系统中注入了能力,使系统更加高效和准确。
查询理解和路由
根据用户查询,LLM 代理可以负责决定搜索哪个知识库。例如,假设一个编程助手不仅可以搜索代码库,还可以搜索产品文档,以及搜索网络。根据开发者提出的问题,代理可以决定查询哪个数据库。对于像问候这样的通用消息,代理也可以决定不调用检索器,直接将消息发送到 LLM 以获取响应。
工具使用
在上一个例子中,系统还需要搜索网络。互联网不能存储在知识库中,通常通过返回搜索结果的 API 来访问。这个搜索 API 是代理可以使用的一个工具的例子。同样,其他 API,如 Notion 或 Google Drive,也可以用来访问信息源。这些工具如 API 的一个特点是它们有固定的查询和响应格式。代理的职责是将自然语言信息处理成格式结构,并解析响应以用于生成。
自适应检索
在第六章中讨论的召回自适应检索。一个 LLM 被启用以确定检索的最合适时机和内容。这是查询路由的扩展,在决定查询最合适的来源之后,代理还可以确定检索到的信息是否足够好以生成响应,或者是否需要另一轮检索。对于下一轮检索,代理还可以根据检索到的上下文形成新的查询。这使得 RAG 系统能够解决复杂查询。
这些能力使得代理 RAG 系统能够全面工作并具有可扩展性。虽然索引和生成管道的结构没有变化,但代理可以在两个管道中调用。
8.4.3 代理 RAG 管道
基于 LLM 的代理理解上下文和调用工具的能力可以用来提升 RAG 管道的每个阶段。
索引管道
在代理 RAG 中,知识库的概念与标准 RAG 没有不同。代理可以跨组件使用,以增强索引管道:
-
Data loading—加载数据和提取信息是 RAG 系统开发的第一步,也是极其关键的一步。在构建准确的 RAG 系统时,准确解析信息至关重要。解析复杂的文档,如 PDF 报告可能很困难。虽然存在用于这些任务的库和工具,但 LLM 代理可用于高精度解析。在 RAG 中,元数据的重要性不容忽视。它用于过滤、更具体的映射和来源引用。在大多数情况下,很难获取丰富的元数据。LLM 代理可用于构建元数据架构和提取上下文元数据。
-
Chunking—在代理式分块中,文本块是基于目标或任务创建的。考虑一个希望分析客户评论的电子商务平台。将关于特定主题的评论放入同一块是分块的最佳方式。同样,批评性和积极的评论可以放入不同的块中。为了实现这种分块,我们需要进行情感分析、实体提取和某种形式的聚类。这可以通过多代理系统实现。代理式分块仍然是研究和改进的活跃领域。
-
Embeddings—代理在嵌入中的作用可能是根据块上下文选择正确的嵌入模型。例如,如果加载的数据中包含来自多个领域的信息,那么可能需要对不同的块使用特定领域的嵌入。除此之外,质量控制代理可以通过测量与预定义标准或用例要求的相似性或一致性来验证嵌入。你也许还记得在图 RAG 的讨论中,代理也可以决定对某些块使用图结构。
-
Storage—由于信息性质的原因,也有可能在不同的集合中存储来自同一文档的块嵌入。例如,与产品安装和故障排除相关的信息可以存储在一个向量数据库的集合中,而产品特性和优势可以存储在另一个集合中。这有助于提高检索的精度。你可能注意到,在分块、嵌入和存储中使用代理是紧密相关的。
图 8.13 总结了使用代理如何美化索引管道。知识库本身的性质并没有改变,但创建过程被代理美化了。
生成管道
代理系统的真正优势在于它如何在整个生成管道的三个阶段中转换整个流程:
- Retrieval—代理在检索阶段的应用可能是最显著的。将查询路由到最合适的数据源以及集成工具查询外部信息源是代理 RAG 的一个关键特性。

图 8.13 代理增强索引管道提高了知识库的质量。
-
适应性检索策略也在检索阶段带来了显著的改进。
-
增强—代理可以根据查询的性质和检索到的上下文选择正确的提示技术。提示也可以由代理动态生成。
-
生成—代理 RAG 的用途之一是多步生成,如 IterRetGen 或迭代检索生成。在这种方法中,代理用于审查 LLM 在第一次迭代中生成的响应,并决定是否需要进一步的检索和生成迭代以完全响应用户查询。这在多跳推理和事实核查中特别有用。
另一种思考代理 RAG 的方式是,在动态决策可以改善 RAG 系统的地方,可以使用代理来自主地做出这些决策。从之前的讨论中,你可能会得出结论,代理 RAG 是标准 RAG 的更优版本。表 8.4 总结了代理相对于标准 RAG 的优势。
表 8.4 代理 RAG 的优势
| 方面 | 标准 RAG | 代理 RAG |
|---|---|---|
| 检索过程 | 基于初始查询的被动检索 | 根据需要由智能代理路由和重构查询的适应性检索 |
| 处理复杂查询 | 在多步推理和复杂查询方面存在困难 | 可以用来分解和解决复杂、多方面的查询 |
| 工具集成 | 与外部工具和 API 的集成有限 | 与各种外部工具和 API 无缝集成,以增强信息收集 |
| 可扩展性 | 由于静态过程而存在扩展挑战 | 通过基于模块的代理架构实现可扩展性,便于扩展 |
| 准确性和相关性 | 依赖于初始查询质量;可能检索到不太相关的信息 | 由于代理能够细化查询和验证信息,因此准确性和相关性更高 |
8.4.4 挑战和不良实践
基于 LLM 的代理仍在不断发展,并非万无一失。关于 LLM 的规划和推理能力也存在一些担忧。为了将代理能力集成到 RAG 管道中,应仔细评估以下方面:
-
当单个代理负责调用大量工具时,工具选择的准确性会降低。因此,需要控制代理的决策选择数量。
-
任何代理都不可能始终准确无误。多代理系统中的错误率也可能增加。在每一个阶段建立安全措施至关重要。使用案例的选择也应由预期的准确度水平来指导。
-
在决策中增加自主性,如果未能得到适当控制,可能会导致意外行为。换句话说,代理可能会误操作,因此为代理行为建立明确的边界和指南至关重要。
多模态、图和代理 RAG 模式在标准 RAG 流程中表现出显著的改进。多模态 RAG 使 RAG 系统开放给不同的模态,图 RAG 引入了关系理解,代理 RAG 将智能和自主决策注入 RAG 系统。除了这三个之外,RAG 的持续研究还导致了几个其他框架和标准 RAG 系统的变体。下一节将讨论显示出显著前景的变体。
8.5 其他 RAG 变体
我们在本章中讨论了三种主要的 RAG 变体。该领域的研究非常活跃,研究人员每周都会发布几篇关于他们的实验和关键发现的论文。在这些论文中,相当多的论文展示了在实用应用中找到相关性的 RAG 变体。我们通过简要讨论四种这样的 RAG 变体来结束本章。
8.5.1 纠正 RAG
RAG 系统的有效性取决于检索质量。检索中的不准确会抵消所有 RAG 的好处。为了解决这个问题,纠正 RAG(CRAG)方法评估检索文档的质量。如果发现检索到的信息不准确,它将使用轻量级评估器并触发纠正操作。CRAG 的关键组件包括
-
检索评估者—一个评估检索文档的相关性并为每个检索文档分配相关度分数的模型。在原始 CRAG 论文(
arxiv.org/abs/2401.15884)中,评估者是一个经过微调的 T5 模型,它将评分分为正确、错误或模糊。 -
网页搜索补充—如果一个检索到的文档被分类为不正确,系统将进行网页搜索以补充知识库,确保更准确、更及时的信息。
-
知识精炼—被评估者标记为正确的检索文档以及从网页搜索中检索到的内容被进一步分解成更小的知识片段,每个片段都经过评估。
图 8.14 说明了 CRAG 工作流程,其中添加了评估者、知识精炼和网页搜索到标准的 RAG 流程中。
关于其优势和局限性,CRAG 确保了生成时准确、与上下文相关的知识,尤其是在初始检索可能存在缺陷的情况下。纠正措施增强了生成内容的真实性。CRAG 是一种可以与所有 RAG 流程和其他 RAG 变体集成而不会造成任何干扰的解决方案。还有一些因素需要考虑:
-
额外的纠正措施和网页搜索集成可能会增加响应时间。
-
系统的性能与评估模型准确性紧密相关。
CRAG 在标准 RAG 的基础上进行了改进,后者直接使用检索到的文档。纠正方法使其对需要数据验证的准确性敏感的应用变得有效。

图 8.14 CRAG 在最细粒度级别上纠正知识,因此得名纠正 RAG。来源:arxiv.org/abs/2401.15884。
8.5.2 推测性 RAG
延迟和冗余是 RAG 系统中的普遍关注点。推测性 RAG 采用两步方法来解决这些问题。首先,小型语言模型并行生成多个基于不同文档子集的答案草稿。然后,一个较大的 LLM 验证并选择最准确的草稿。推测性 RAG 的关键组件包括
-
文档聚类——检索到的文档被聚类到与主题相关的组中,每个组提供独特的视角。
-
RAG 草稿生成器——一个较小的 LLM 基于每个簇子集生成初始答案草稿,并行生成响应和理由以提高效率。
-
RAG 验证器——一个较大的 LLM 评估每个草稿的准确性和连贯性,根据自我一致性和理由支持分配置信度分数。
推测性 RAG 的关键优势是通过减少生成 LLM 的工作量并执行并行草稿生成来加快响应生成。然而,以下的一些局限性需要仔细考虑:
-
涉及管理双模型设置和文档聚类,这可能会增加初始设置复杂性。
-
文档聚类直接影响草稿多样性,聚类不良可能导致通过将高度相似或重复的文档分组到多个簇中而产生冗余草稿。
-
较小的 LLM 可能需要训练以有效地生成草稿和理由。
与标准 RAG 不同,它将所有检索到的数据整合到一个单独的提示中,推测性 RAG 为了效率使用并行草稿生成,并采用专门的验证步骤以确保准确性,这导致延迟减少,同时提高了响应的事实效率。
8.5.3 自我反思(自我 RAG)
在 LLM 中的自我反思是指 LLM 分析其行为、识别其推理过程中的潜在错误或缺陷,然后利用这些反馈来改进其响应和决策的能力。自我 RAG 通过反思动态决定是否检索相关信息、评估检索内容以及对其输出进行批判。自我 RAG 的关键组件包括
-
反思令牌——自我 RAG 训练 LLM 使用“反思令牌”,这些令牌帮助其评估检索段落的关联性、支持性和有用性。这些令牌旨在引导模型判断检索内容和其生成响应的质量,增加控制层和适应性。检索令牌指示是否需要检索。同样,相关性令牌确定一个段落是否相关,支持令牌验证生成的响应是否完全由检索内容支持,而效用令牌对响应的有用性进行评分。
-
*动态检索决策**—模型使用反思标记来确定是否需要检索,基于每个响应段,并在任何步骤中如果不需要检索则跳过检索。
-
*自我批评**—模型在每个生成步骤中对其输出进行批评,应用反思标记来引导检索并在实时中细化响应。
在自我 RAG 中,自适应检索减少了不必要的检索,自我反思提高了准确性、事实一致性和相关性。然而,需要考虑以下限制:
-
并行处理多个段落和自我反思可能会增加计算需求。
-
额外的训练和使用反思标记需要调整阈值。
自我 RAG 是 RAG 研究中最常引用的技术之一。它根据任务需求动态调整检索,评估输出质量,实现了更高的准确性。
8.5.4 RAPTOR
树状组织检索的递归抽象处理,或称 RAPTOR,是一种 RAG 变体,旨在处理数据中的层次关系。它创建了一个多层次的、基于树的递归摘要结构,捕捉长文档中的细粒度细节和整体主题。与图 RAG 类似,RAPTOR 使用树结构来实现类似的目标。以下是 RAPTOR 的关键组件:
-
*块聚类和摘要**—基于相似性对块嵌入进行聚类,并使用 LLM 来总结这些聚类。使用高斯混合模型进行软聚类允许文本段属于多个聚类。
-
*递归树构建**—RAPTOR 通过自下而上的过程使用块、聚类和摘要构建多层树。
-
*双重查询机制**—自上而下的方法从顶层开始遍历,根据与查询的余弦相似度选择每个级别的最相关节点。另一个单层搜索检索所有树节点上的上下文,不考虑层级。
与图 RAG 类似,RAPTOR 通过结合细粒度和高级摘要,实现了更好的多跳推理和主题问答。然而,树结构难以管理,RAPTOR 也带来了一系列挑战:
-
递归聚类和摘要步骤可能计算量很大,尤其是对于非常大的文档。
-
有效检索取决于聚类的质量;初始聚类中的错误可能会向上传播到树中。
与可能难以处理多层内容的标准 RAG 不同,RAPTOR 的分层模型允许有针对性的检索,优化了特异性和上下文相关性。
本章探讨了使用高级技术改进特定用例的 RAG 变体。多模态管道使 RAG 系统能够访问以前无法使用的数据,图 RAG 提供了关系分析的能力,而代理 RAG 为复杂任务引入了自主决策。每个 RAG 变体都针对标准 RAG 系统改进的某个方面。纠正 RAG 关注事实相关性,RAPTOR 为层次数据构建关系智能,推测 RAG 旨在提高效率,而自我 RAG 使系统具有适应性。
通过本章,我们几乎结束了对 RAG 的讨论。最后一章讨论了 RAG 系统生命周期不同阶段的独立考虑和最佳实践。
摘要
介绍 RAG 变体
-
RAG 变体是对朴素 RAG 框架的适应性,扩展了其功能以适应特定用例。
-
这些变体解决了处理非文本数据、提高关系理解、提高准确性和实现自主决策等挑战。
-
深入讨论了三种主要的 RAG 变体:多模态、图和代理 RAG。
-
其他有希望的 RAG 变体包括纠正 RAG、推测 RAG、自我 RAG 和 RAPTOR。
多模态 RAG
-
它扩展了 RAG 的能力以处理多种数据模态,如文本、图像、音频和视频。它可以用于
-
医学诊断——分析文本、图像(X 光片)和表格数据(实验室结果)
-
投资分析——处理财务文件、图表和资产负债表
-
设备维护——结合文本报告、视觉检查和传感器数据
-
-
关于管道增强,多模态 RAG 在索引管道中引入了多模态嵌入(共享或模态特定)、转录工具和专门的分块方法。在生成管道中,它使用了多模态 LLM(例如 GPT-4o、Google Gemini)。
-
多模态 RAG 具有高计算需求和增加的延迟。在非文本模态的文本转换过程中可能发生信息丢失。
知识图谱 RAG
-
它通过图结构中表示的关系增强了检索和推理。它可以用于
-
个性化治疗方案——将药物、条件和症状联系起来以提供定制建议
-
合同分析——识别相互关联的法律文件中的依赖关系和合规风险
-
-
关于管道增强,知识图谱 RAG 从索引管道中的块中提取实体、关系和属性以创建图。至于生成管道,它结合了使用 Cypher 等图查询语言的图遍历。
-
构建和维护知识图谱复杂且计算成本高。它还需要为每次部署进行定制化调整。
代理 RAG
-
它介绍了基于 LLM 的代理用于自主决策和动态查询路由。代理 RAG 可用于
-
查询理解并将路由到相关数据源
-
自适应检索和多步生成
-
与诸如网络搜索 API 和外部数据库等工具的集成
-
-
关于管道增强,代理 RAG 在索引管道中通过代理决策增强了分块、元数据提取和嵌入选择。在生成管道中,它动态增强提示并采用迭代检索-生成工作流程。
-
代理 RAG 需要强大的控制来防止代理的不当行为。在多代理系统中,高计算开销和乘以错误率。
其他 RAG 变体
-
纠正 RAG(CRAG)通过评估检索内容来关注事实准确性。它还添加了纠正步骤,如网络搜索补充和知识细化。
-
优势—增强准确性并能与其他 RAG 管道无缝集成
-
挑战—响应时间增加且依赖于评估器模型
-
-
推测性 RAG 通过并行生成多个草稿并使用较小的 LLM 来减少延迟。较大的 LLM 验证并选择最准确的草稿。
-
优势—更快地生成响应
-
挑战—需要仔细的文档聚类和草稿多样性
-
-
自我 RAG 包含反思令牌以实现自适应检索和生成内容的自我评估。
-
优势—卓越的准确性和事实一致性
-
挑战—计算密集且需要微调的阈值
-
-
RAPTOR 通过树状结构摘要构建层级关系。
-
优势—优化多跳推理和主题查询
-
挑战—计算密集且依赖于有效的聚类
-
第九章:RAG 开发框架及进一步探索
本章涵盖
-
使用六阶段 RAG 开发框架回顾本书中涵盖的概念
-
进一步探索的领域
前八章涵盖了广泛的检索增强生成(RAG)内容,包括概念基础、关键组件、评估方法、高级技术、操作堆栈和 RAG 的基本变体。到现在,你应该已经具备了开发 RAG 系统所需的所有必要信息。
这最后一章总结了讨论内容,并回顾了之前讨论的所有概念。为了完成这一目标,我们将开发 RAG 系统的所有不同方面结合起来,并提出一个 RAG 开发框架。在这个 RAG 开发框架的六个阶段中,我们回顾了本书中涵盖的概念以及一些最佳实践。这个框架不仅涵盖了技术方面,而且从整体上审视了开发过程。
RAG 是一种快速发展的技术。在本章结束时,我们还将讨论一些你可以进一步探索的想法。其中一些将上下文纳入的方法可能与 RAG 技术竞争,而另一些则可能是互补的。
到本章结束时,你应该
-
已审查并巩固你对关键 RAG 概念的理解。
-
理解 RAG 开发框架的坚实基础。
-
准备构建和部署 RAG 系统。
通常,RAG 系统开发者面临的问题陈述往往是开放式的。例如,一个电商平台希望开发一个购买助手,或者营销部门需要一个研究代理来跟踪和总结竞争信息。那么,如何从开放式的问题陈述过渡到一个完全开发的 RAG 系统?这个过程由一个思维过程引导变得非常重要。为此,让我们定义并讨论一个开发 RAG 系统的框架。
9.1 RAG 开发框架
开发 RAG 系统的过程与开发使用机器学习模型的程序并没有很大区别。我们已经看到,RAG 系统可能很复杂,包括多个组件。它超越了模型、数据和检索器等元素。它需要一个服务基础设施来使系统可供用户使用。评估、监控和维护系统与开发和部署同样重要。这一切都始于对需求的理解和概念设计。为了解决所有这些方面,我们提出了一个将帮助我们构建 RAG 系统的 RAG 开发框架。这个框架包括以下六个阶段:
-
启动—这一阶段涉及理解问题陈述,协调利益相关者,收集系统需求,并分析这些需求以制定高级系统架构。
-
设计—在这个阶段,为 RAG 管道做出设计选择,并开发用于构建系统的工具集。此外,还概念化了 RAG 操作堆栈的不同层次。
-
开发—这个阶段涉及开发所需 RAG 系统的可工作原型。所有必需的模型都经过训练,并开发了所需的 API。这个阶段导致知识库的创建和应用程序编排层的开发。
-
评估—在这个阶段,评估检索和生成组件,以及测试端到端系统的性能。在这个阶段结束时,系统准备就绪,可以部署。
-
部署—在这个阶段,系统对最终用户可用。部署策略也在此阶段决定。
-
维护—这个最终阶段是一个持续的过程,涉及系统监控、整合用户反馈和跟踪技术改进。
请记住,RAG 开发框架不是一个线性过程,而是灵活的、迭代的和循环的。图 9.1 说明了 RAG 开发框架六个阶段的循环性质,展示了每个阶段的关键工件。

图 9.1 RAG 开发框架的六个阶段是迭代和循环的。在每一个阶段,都可以创建特定的工件。
每个阶段都涉及某些活动。我们逐一查看这些活动,并讨论与之相关的最佳实践。我们首先从启动阶段开始。
9.1.1 启动阶段:定义和范围 RAG 系统
成功 RAG 系统的旅程始于与利益相关者的初始互动。这是一个深入了解问题陈述和用户需求的机会。这是一个探索阶段,并为项目设定了方向。
用例识别
开发者在 RAG 系统开发过程中所做的许多选择都高度依赖于所解决的使用案例。即使对行业领域/功能有基本了解,以及对使用案例的简单定义也足以回答关于系统的关键起始问题。需要评估 RAG 系统的需求。回想一下第一章中 RAG 解决的问题:RAG 克服了训练数据限制、知识截止日期和 LLM 的幻觉,为系统带来了事实准确性、可靠性和信任。评估这些 RAG 收益是否对使用案例至关重要是很重要的。可能存在不需要 RAG 的 LLM 应用。在这个阶段,你可能需要问以下问题:
-
系统是否需要可能不在可用 LLM 训练集中的数据?
-
系统是否需要当前数据或频繁更新的数据?
-
系统需要引用或生成事实吗?生成事实的准确性有多重要?
-
如果引用了来源,用户会受益吗?
如图 9.2 所示的用例评估卡可以帮助评估是否需要 RAG 系统来解决用例。如创意写作、语言翻译、情感分析、语法纠正等用例通常不需要 RAG 系统,除非用例的某些细微之处需要它。
除了这个之外,行业领域和功能也可以给出对系统需求的早期指示。例如,来自医疗和金融领域的用例可能需要更多的安全和合规措施,而来自体育领域的用例可能需要处理快速更新的信息。
对用例的初步评估可能提供早期见解,但在进一步进行之前,对需求进行详细理解和分析是必要的。
收集需求
开发正确的 RAG 系统意味着满足利益相关者的需求和期望。理解这些需求和期望是一个关键步骤。获得这种理解是一个互动和调查的过程。大多数利益相关者和最终用户可能对技术以及如何构建 RAG 系统了解有限。因此,了解成功应用对他们意味着什么非常重要。这些需求可能包括系统中需要的特性,到预期的规模和系统的期望性能。

图 9.2 带有评估问题的用例评估卡可以帮助评估是否需要 RAG 系统来应对用例。
期望的性能。收集需求的一个好方法是通过不同的视角来看待它们,例如
-
业务目标—这些需求与构建这些系统的核心商业原因相关,例如提高点击率、节省流程成本、提高客户满意度等。技术开发者可能不直接负责业务指标,但这些业务指标可以在系统开发过程中起到指引作用。
-
用户需求—这些是系统开发目标用户的核心理求。表达这些需求有助于确定系统的输入和输出,以及其他功能,如多语言支持和来源引用。这些需求也是确定 RAG 系统可以预期的用户查询类型的关键。
-
功能需求—这些是系统的核心功能,例如支持的数据类型、要检索的文档数量以及生成内容的长度/语气/风格等。功能需求受用户需求和业务目标的影响。它们也是开发过程的主要影响因素。
-
非功能性需求——这些是关于系统性能、可扩展性、可靠性、安全性和隐私的要求。可能还有其他要求,如法律和合规性,尤其是在受监管的行业。
-
限制——还应关注系统应意识到的任何限制,例如互联网访问、数据可用性、成本和与现有系统的集成。
例如,一个客户服务系统可能被设想为减少客户查询解决时间,需要快速响应时间,并限制与现有客户支持平台的集成。上述要求的示例文档可能看起来像图 9.3 中所示,详细说明了不同类型的要求。

图 9.3 需要 RAG 的客户支持系统的示例要求文档
需求分析
在启动阶段,从利益相关者中提取需求是一项主要活动。然后需要分析这些原始需求。需求应该是清晰、精确和可量化的,以便它们可以导致特定的开发步骤。例如,对快速响应的非功能性需求可能过于模糊。相反,一个更好的需求是 90%的查询应在 2 秒内得到响应。同样,有限的互联网连接限制可能导致开发者认为需要一个完全离线的系统。这种需求中的模糊性需要在与利益相关者的进一步互动中解决。
在这个阶段,定义系统评估的成功标准也非常重要。需要定义和同意几个成功指标。对于开发者来说,这些成功指标应该与业务目标不同,因为业务成果可能取决于他们无法控制的因素。延迟、吞吐量、查询解决百分比等是成功指标的良好标准。图 9.4 展示了在分析成功指标后的示例要求文档。这是对图 9.3 中显示的先前要求文档的改进。

图 9.4 定义了成功指标并分析了清晰性和精确性的示例要求文档
高级架构
一旦对需求有深入了解,启动阶段可以被视为完成。在启动阶段结束时,使用一个高级架构图作为设计阶段的起点是一个好的做法。这个架构可用于在利益相关者之间达成一致并进一步讨论需求。这个高级架构的重点是说明系统的输入和输出。由于数据在 RAG 系统中扮演着如此关键的角色,这个高级架构还应包括数据组件。如图 9.5 所示,对于一个多渠道客户支持系统,系统必须允许从不同渠道进行输入和输出。

AI 生成的内容可能是不正确的。](../Images/CH09_F05_Kimothi.png)
图 9.5 突出输入输出、数据、人工参与和缓存层的拟议客户支持机器人高级架构
在完成启动阶段后,可以做出初步的通过/不通过决策或前进的战略性决策。一旦利益相关者达成一致,系统所有 RAG 操作层可以在下一阶段进行设计。
9.2 设计阶段:分层 RAGOps 堆栈
在对用例和需求有清晰理解的基础上,开发者可以开始规划开发。在设计阶段,高级架构被细化以绘制 RAGOps 堆栈,并做出关于工具和技术的选择。在这一阶段,我们设计索引和生成管道,以及其他组件,如缓存、安全线等。
9.2.1 索引管道设计
在需求收集步骤中,我们识别数据源。在设计阶段,我们双击这些数据源以确定源系统的性质、文件类型和数据本身的性质,以确定知识库的开发步骤。回想第三章,知识库是通过索引管道为 RAG 系统创建的。数据加载、分块、嵌入和存储等组件构成了索引管道。在第七章,我们还讨论了 RAGOps 堆栈的数据层通过提取、转换和加载数据来实现这一点。图 9.6 总结了索引管道组件和数据层。

AI 生成的内容可能是不正确的。](../Images/CH09_F06_Kimothi.png)
图 9.6 RAG 系统的索引管道使用 RAGOps 堆栈中的数据层执行。
现在我们来看一些重要的考虑要点,这些要点将帮助我们做出索引管道设计的决策。
数据摄取
当你处理较少的数据,如几个 PDF 文件或几个网站时,数据摄取是一个相对简单的步骤。然而,在生产级系统中,随着数据规模的增加,复杂性也会增加。需要特别注意源系统和文件格式。以下是一些关于连接到源系统的问题,这些问题将有助于设计数据摄取组件:
-
数据层需要连接到哪些源系统?
-
连接器是否容易获取?如果是,需要哪些工具或服务来建立这些连接?
-
需要开发哪些连接器?这些连接器将基于哪种技术进行开发?
-
是否需要访问开放互联网?系统将如何连接到互联网?
以下问题组是关于文件解析的:
-
将摄取哪些文件格式?
-
如果需要,网页将如何被抓取?
-
我们是否有不同文件类型的必要解析器?
-
是否需要开发特殊的解析技术?
-
单个文件中可以有多于一种的数据模态吗?
这些问题的答案将决定你需要使用的工具来摄取数据以及需要开发的部件。
数据转换
一旦数据被摄取,转换步骤将数据转换为知识库的合适格式。在数据转换步骤中,数据首先将被清理和预处理。提取元数据信息也是一个好的实践。有时,还需要其他预处理步骤,如 PII 数据删除或解决冲突信息。
在预处理之后,数据将使用合适的分块技术进行分块。在此阶段应决定分块大小、重叠大小和分块策略。分块可以是固定大小、结构驱动、语义分块或代理分块。
一旦创建了分块,它们需要被转换以供检索。我们已经讨论了诸如嵌入和知识图谱的方法。对于需要分块之间关系理解的用例,应探索知识图谱。在所有 RAG 系统中,创建向量嵌入几乎是强制性的。为了创建向量嵌入,可以使用预训练的嵌入模型。然而,有时,由于领域的特殊性,嵌入模型可能需要微调。
让我们现在看看在这个阶段应该考虑的一些问题。第一组问题是关于预处理的:
-
数据有多嘈杂?可以使用哪些算法和技术来清理数据?
-
是否存在结构化数据,如表格或 JSON?
-
元数据是否容易获取,或者是否需要提取?
-
应该使用哪些算法或模型进行元数据提取?(注意:所有模型都位于 RAGOps 堆栈模型层的模型库中。)
-
数据是否包含需要屏蔽或删除的敏感信息?将使用哪些技术来执行此操作?
-
是否有其他需要遵循的数据协议或指南?
当涉及到分块时,考虑以下问题:
-
分块大小是否预先确定?如果不是,应该实验哪些分块大小?
-
数据格式是否需要结构化分块?
-
如果需要,将采用哪些技术和模型进行语义分块?
-
分块代理是否 readily 可用,或者需要构建?分块代理将使用哪些模型、算法和工具?
以下问题组涵盖了 graphRAG:
-
是否需要分层索引结构?
-
我们是否需要提取关系上下文中的实体和关系?我们是否有必要的预算?
-
我们将采取哪些方法进行实体-关系提取?
-
我们是否使用任何用于图提取的框架?
-
将使用哪些模型?
关于嵌入,请考虑以下问题:
-
我们将使用哪种嵌入模型?是否有可用的特定领域嵌入模型,这将更有用?
-
是否需要多模态嵌入?
-
我们是否需要针对我们的用例微调嵌入?我们是否有用于微调的训练数据?训练数据将从哪里获取?
数据转换步骤需要大量的思考和努力。这也是可能产生重大成本的地方,尤其是在使用代理和采用 graphRAG 时。
数据存储
数据层的最后一个组件是存储。根据数据转换期间所做的选择,存储将包括向量存储、图数据库和文档存储(如果需要)。在这一阶段,我们还应该记住,应用程序可能需要一个缓存存储,这可以是数据层的一部分。我们将单独讨论缓存。与数据存储相关的一些问题是
-
所有数据是否可以存储在单个集合中,或者需要多个集合?
-
我们能否管理向量数据库,或者我们需要托管服务?
-
当前数据规模如何,以及它可能如何增长?
-
我们将使用哪种向量数据库?
-
我们是否需要一个图数据库?我们将使用哪个图数据库?
-
我们是否需要存储原始文档或图像?我们将使用哪种文档存储来执行此目的?
在存储就绪后,可以执行知识库的创建。重要的是要注意,这一阶段的决策应该是灵活的。你还应该为开发期间可以实验的工具、服务和库保留选项。你还需要估计这一阶段不同步骤的相关成本,并确保利益相关者对这些成本达成一致。
在 RAGOps 栈的数据层中,索引管道的设计已经完成。你也许还会注意到索引管道也与模型层交互,其中包含嵌入模型和 LLM 以及其他特定任务的算法。
9.2.2 生成管道设计
我们已经讨论过,用户与知识库的实时交互是通过生成管道来实现的。在第四章中,我们开发了生成管道的三个主要组件——检索器、通过提示进行增强以及使用 LLMs 进行生成。除了这三个组件之外,检索前阶段的查询优化和检索后阶段的内容优化是生成管道的高级组件。有时,甚至在生成后,还会进行响应优化以更好地对齐响应。生成管道由 RAGOps 阶段的模型层提供动力,该层包含 LLMs、检索器、嵌入模型以及其他特定任务的模型。生成管道通过 RAGOps 堆栈的应用编排层变得生动起来。接下来,我们将分以下六个步骤讨论生成管道的设计:查询优化(检索前)、检索、内容优化(检索后)、增强、生成和响应优化(生成后)。
查询优化
查询优化技术被采用以帮助检索更好地与查询对齐。采用了几种技术来转换和重写查询。对于代理 RAG,查询路由是这一步骤的一个重要方面。以下是一些有助于确定查询优化性质的问题
-
用户可以提出多少种类型的查询?每种查询类型是否需要不同的下游处理过程?
-
在搜索之前需要选择知识库中的多个集合吗?
-
用户查询预计会是简短的还是通用的?
-
用户是否在寻找精确的响应?
-
我们可以承受多少查询优化的处理时间?
-
我们将使用哪些模型和技术进行查询优化?
查询优化是可选的,但在知识库中的数据量很大时可能不可避免。还必须注意,查询优化可能会增加系统的延迟。
检索
检索是 RAG 系统的一个关键组件。本书中讨论了许多检索技术和策略。RAG 系统的质量取决于检索组件的准确性。对于简单的 RAG 系统,您可以使用密集嵌入相似度匹配。在更复杂的系统中,您将需要使用混合、迭代或自适应检索策略。在这个阶段需要提出的问题是
-
我们的检索组件需要高精度、高召回率,还是两者都需要?
-
查询可以通过简单的相似度匹配来解决吗?
-
我们需要图检索吗?
-
搜索整个数据集是否会过长?我们需要过滤吗?
-
单次遍历可以检索到所有必要的文档吗?
-
从检索到的文档中获取的信息会导致更多问题吗?
-
我们将使用哪些模型和技术进行自适应、递归或迭代检索?
-
我们应该尝试哪些检索算法?
-
我们将利用哪些提供者或库?
-
我们将如何估计检索的成本?
-
应该检索多少文档才能达到可接受的覆盖率水平?
-
检索结果中的排名是否重要?
在大型知识库中,检索可能导致显著的延迟,应该针对速度和准确性进行优化。
上下文优化
一旦从知识库检索到结果,它们需要与原始用户查询一起发送给 LLM 进行生成。然而,一旦检索到结果以锐化上下文,可以应用某些优化技术,如重新排名和压缩。这些技术过滤、压缩和优化检索到的信息,以减少噪声并提高上下文的精确度。为了验证上下文优化的必要性,可以提出以下问题:
-
检索到的信息量是否会压倒 LLM?
-
检索到的信息是否适合 LLM 的上下文窗口?
-
检索到的信息可能存在噪声吗?
-
是否检索了大量文档?我们需要丢弃一些吗?
-
哪些技术可以用来锐化检索上下文以匹配查询?
-
有没有我们可以使用的服务或库?
-
我们能否承担优化所需的时间?
这样的优化对于使上下文精确并提高 RAG 系统的整体质量非常有帮助,但它们确实会增加处理时间和成本。
增强层
增强是将检索到的上下文添加到可以发送给 LLM 进行生成的提示中的过程。虽然这可能看起来是一个简单的步骤,但它可能有很多细微之处。所有用例上下文以及检索到的上下文也需要传递。有时,你可能需要传递期望的响应示例或思维过程。在需要使用 LLM 内部参数化知识的情况下,这也可以在提示中指定。在这个阶段需要询问的关键问题是
-
我们需要 LLM 采取的系统提示或整体角色是什么?
-
响应是否需要细微的分析?这能否作为一个思维链传递?
-
我们是否希望将响应限制在上下文中?
-
应该给出什么样的示例?
-
不同的查询类型是否需要不同的提示技术?
增强是通过提示完成的,提示可以通过 RAGOps 堆栈的提示层进行管理。提示会影响成本和延迟,因为 LLM 的处理取决于提示中传递的令牌数量。
生成
生成是所有生成式 AI 应用的核心组件,它包含一个 LLM,该 LLM 以提示作为输入并生成响应。LLM 的性质在很大程度上决定了 RAG 系统的有效性和效率。你需要做出几个选择:
-
应该使用开源模型吗?我们是否有使用它们的技能和资源?
-
是否应该使用专有管理的 LLM?
-
我们是否需要针对我们的用例微调一个 LLM?
-
我们需要多大型的模型?我们需要哪些能力来应对?
-
我们如何估算生成组件的成本?
-
需要考虑任何部署限制吗?
-
模型在部署前需要优化吗?
-
需要考虑任何安全影响吗?
-
需要考虑任何伦理或法律上的影响吗?
选定的 LLM 将位于模型库中。所有训练微调活动和优化都在 RAGOps 堆栈的模型层进行。LLM 的训练和使用可能成本高昂。选择正确的 LLM 是 RAG 系统成功的关键。
响应优化
有时,生成组件的响应在向用户展示结果之前可能需要进一步处理。这可以从评估响应的相关性到检查格式,以及将检索到的来源附加到响应。在这一阶段可以帮助评估的一些问题是
-
LLM 的响应是否直接以原样呈现给用户?
-
需要对响应进行任何类型的验证吗?
-
不理想结果的影响是什么?
-
是否有基于响应需要触发的任何工作流程?
响应优化非常主观,并且与用例紧密相关,但这是一个不应被忽视的考虑因素。
通过这七个步骤,生成管道设计完成。RAGOps 堆栈的模型库和训练/微调组件可以用必要的工具、平台和算法进行覆盖。生成管道的编排也可以根据这一阶段的选择最终确定。在最终确定增强技术后,也可以解决提示层。图 9.7 显示了生成管道设计,其中每个步骤都有一个总体问题。

图 9.7 需要回答关键问题以对生成管道进行选择。
这完成了核心 RAG 管道的设计选择。到这一阶段,模型、提示和编排层基本上已经完成。但还有更多关于安全、限制、缓存和其他用例要求的设计考虑。
9.2.3 其他设计考虑
虽然设计良好的核心 RAG 管道完成了 RAG 系统的关键层,但还需要解决其他系统考虑因素和业务需求:
-
系统中需要哪些类型的限制?用户查询是否应该受到限制?是否有不应输出的信息?
-
缓存某些类型的响应是否可能且有用?
-
在系统的任何阶段是否需要人工监督或采取行动?
-
模型将如何免受恶意攻击的保护?
-
系统中需要任何审批工作流程吗?
-
用户是否在寻找可解释性?
这些问题将有助于解决 RAGOps 栈的基本和增强层。您应该能够全面了解开发 RAG 系统所需的必要组件、工具、平台和库。最后要作出的选择是部署选项。
您可以选择在云上托管部署、在私有云上自托管部署、裸金属服务器或本地/边缘机器。选择将主要受业务约束驱动,但可能会影响管道的设计选择。完全托管部署倾向于使用托管服务进行存储和计算以降低开发复杂性并确保可扩展性,自托管解决方案需要特别关注具有模块化和优化技术的设计以处理有限的基础设施,而在边缘部署中,由于资源限制,应强调轻量级组件和高效的检索策略。
在所有这些设计元素确定之后,可以开始进行 RAG 系统的开发实验。
9.2.4 开发阶段:构建模块化 RAG 管道
RAG 开发框架的开发阶段侧重于将设计选择实现为一个功能性的 RAG 系统。理想的方式是模块化地构建 RAG 管道,这涉及到将系统分解为不同的、可互换的组件,每个组件负责特定的功能。这种方法增强了灵活性、可扩展性和可维护性,允许根据不同的应用需求进行定制配置。开发阶段的一些活动包括训练和微调模型;为不同组件创建 API 或微服务;以及使用不同的工具、服务和库创建编排层。
模型训练和微调 LLM
对于大多数系统,预训练的基础 LLM 和嵌入模型将满足需求。可能存在需要针对领域适应性微调模型的情况。在罕见的情况下,您可能选择从头开始训练语言模型。在这种情况下,RAG 系统的开发可能会退居次要位置,而模型的训练将成为开发工作的核心。在决定是否微调嵌入模型和 LLM 时,您可以遵循渐进式方法。
当使用预训练模型创建嵌入时,您需要评估相似性搜索是否产生相关结果。为此,您还可以创建真实数据。真实数据可以是一组手动整理的搜索查询及其匹配的文档。如果嵌入模型可以准确检索文档,则可以使用预训练模型。如果不可以,您可以寻找更适合用例领域域的另一个嵌入模型,或者针对用例领域微调预训练的嵌入模型。
类似地,如果预训练的 LLM 仅通过提示就能生成所需的结果,你可以直接使用该模型。在需要特定风格、词汇或语调的情况下,你可以选择微调模型。
如果系统需要其他模型,如查询分类、有害内容检测、有用性检测等,它们也需要进行训练。
模块开发
应将不同的 RAG 管道组件以独立模块的形式开发,形式为包、API 或其他模块化框架。其中一些模块可以是
-
数据加载和解析—负责连接到源系统并解析文件格式
-
元数据提取—负责提取和标记元数据
-
分块—负责从文档中创建文档块
-
嵌入—负责将文档块转换为向量嵌入
-
存储—负责将嵌入存储到向量数据库中
-
查询优化—负责将用户查询与检索器对齐
-
检索—负责高效检索文档
-
增强—负责维护和调用提示库
-
生成—负责使用 LLM 生成响应
-
记忆—负责存储对话、用户偏好等
这些只是几个例子。模块化将取决于组件的复杂性。例如,如果你确信固定大小的分块对你用例足够,你可能不需要开发独立的分块模块。相反,如果你假设随着技术的进步,系统可能需要更改 LLM,你可以创建允许快速轻松替换模型的生成模块。图 9.8 回顾了第六章中讨论的模块化 RAG 设计。
编排
最后,你将开发编排层,该层将管理你开发的各个模块之间的交互。这使你的 RAG 系统的工作流程得以实现。这个工作流程应该足够灵活,能够适应不同查询类型的反馈。

图 9.8 模块化结构允许单个组件的灵活性和可扩展性。
你还将能够访问各种托管服务、框架、库和工具,你可以将它们与任何模块集成。例如,LangChain 是一个提供 RAG 框架大多数组件库的框架。你可以使用这些库进行快速轻松的开发。然而,对于你希望有更多控制的组件,你可能需要从头开始构建功能。
开发是一个以实验驱动的迭代过程。为了最终确定 RAG 系统的不同组件,你需要评估它们,并将它们与你在启动阶段设定的目标进行基准测试。
9.2.5 评估阶段:验证和优化 RAG 系统
RAG 系统的评估是其开发过程中的关键组成部分。所有不同的策略、工具和框架都必须与一些基准进行比较。实际的业务效果只能在部署后衡量,但在开发阶段可以评估一些指标。我们可以从两个广泛的类别来查看这些指标。
RAG 组件
评估 RAG 系统的目的是评估不同 RAG 组件的性能。为此,可以有针对检索器的特定指标、针对生成器的特定指标和整体 RAG 评估指标。以下是第五章中讨论的这些指标的总结。我们首先从检索器特定指标开始:
-
准确率通常定义为在检查的总案例中正确预测的比例(包括真阳性和真阴性)。
-
精度关注检索结果的品质。它衡量检索到的文档中有多少与用户查询相关。它回答了这样的问题:“在所有检索到的文档中,有多少是相关的?”
-
Precision@k是精度的一种变体,它衡量在顶部“k”个检索结果中相关文档的比例。它特别重要,因为它关注的是顶部结果,而不是所有检索到的文档。对于 RAG 来说,它很重要,因为只有顶部结果最有可能被用于增强。
-
召回率关注检索器提供的覆盖范围。它衡量从语料库中检索到的相关文档占所有相关文档的比例。它回答了这样的问题:“在所有相关文档中,有多少被检索到了?”
-
F1 分数是精度和召回率的调和平均值。它提供了一个平衡了检索器质量和覆盖范围的单一指标。
-
平均倒数排名,或 MRR,在评估相关文档的排名方面特别有用。它衡量列表中第一个相关文档的排名的倒数。MRR 是在一组查询上计算的。
-
平均平均精度,或 MAP,是一个结合了不同“k”(即顶部结果的截止数)截止水平的精度和召回率的指标。它首先计算平均精度,然后对所有查询进行平均。
-
nDCG通过考虑相关文档在结果列表中的位置并给较早出现的相关文档分配更高的分数来评估排名质量。
下面是生成器特定指标的总结:
-
连贯性评估响应的逻辑流程和清晰度,确保信息以可理解和组织的方式呈现。
-
简洁性评估响应是否简洁明了,避免不必要的冗长,同时仍然传达完整的信息。
我们以对整体 RAG 指标的总结来结束:
-
上下文相关性评估检索到的信息中有多少与用户查询相关。
-
忠实度或扎根性评估响应中声明的比例,这些声明得到了检索到的上下文的支持。
-
幻觉率计算响应中生成的声明比例,这些声明在检索到的上下文中不存在。
-
覆盖率衡量上下文中相关声明的数量,并计算生成响应中存在的相关声明的比例。
-
答案相关性 通过计算最终响应与原始问题的相关性来评估系统的整体有效性。
回想第五章中 RAG 评估的三要素。图 9.9 展示了用户查询、检索到的上下文和生成的响应之间的相互作用,这些相互作用计算了 RAG 特定的指标。

AI 生成的内容可能是不正确的。](../Images/CH09_F09_Kimothi.png)
图 9.9 TruEra 提出的 RAG 评估三要素
要计算这些指标中的一些,需要一个真实数据集。真实数据是已知为真实或正确的信息。在 RAG 和生成式 AI 领域,真实数据是一组准备好的提示-上下文-响应或问题-上下文-响应示例,类似于监督机器学习中的标记数据。为您的知识库创建的真实数据可用于评估您的 RAG 系统。
您可以测量这些指标的不同组件。例如,您可以通过用自适应检索策略替换混合检索策略来检查上下文相关性是否增加。您还可以检查查询和上下文优化的有效性。您还可以比较特定组件的两个服务提供商。
系统性能
系统性能指标与系统的非功能性需求相关,这些需求比系统的准确性更多地影响系统的可用性。其中一些指标包括
-
延迟——衡量从接收查询到提供响应所需的时间。低延迟对于用户满意度至关重要,尤其是在实时应用中。
-
吞吐量——表示系统在特定时间框架内可以处理的查询数量。更高的吞吐量反映了系统高效管理大量请求的能力。
-
资源利用率——评估操作期间 CPU 和 GPU 使用的效率。最优利用确保成本效益并防止资源瓶颈。
-
每查询成本计算处理每个查询的平均费用,包括基础设施、能源和维护成本。
在基于 LLM 的系统中对延迟和成本给予了特别关注。这是因为 LLM 架构的固有性质。RAG 增加了延迟和成本。因此,应该从这个角度评估检索过程中的过滤、优化和检索策略等附加组件的影响。有时利益相关者也可能要求你评估一些特定用例的指标,这也应该是评估阶段的一部分。
当你的系统经过彻底评估和改进,以满足所有基准时,它就准备就绪了。你现在可以部署它,使其可供目标用户使用。
9.2.6 部署阶段:启动和扩展 RAG 系统
一旦系统准备就绪,就需要将其部署到可由目标用户访问的生产服务器上。对于软件系统,有一些流行的部署技术,这些技术也可以用于 RAG 系统。
蓝绿部署
蓝绿部署维护两个独立的 环境,分别命名为蓝色和绿色。现有系统位于蓝色环境,而新的 RAG 系统置于绿色环境。一旦绿色环境经过测试和验证,所有流量就会导向绿色环境,蓝色环境被停用。这种蓝绿部署的优势在于可以在不影响实时流量的情况下测试生产环境。因此,几乎没有停机时间,并且在遇到任何问题时,可以轻松回滚。然而,这是一个成本较高的选项,因为整个生产环境都被复制了。可以在绿色环境中更新索引管道,而不会影响实时系统。检索策略或嵌入模型的更改可以在生产使用之前安全地验证。
金丝雀部署
金丝雀部署逐渐将新的 RAG 系统发布给一小部分用户。如果它与这些用户的表现良好,就会扩展到所有用户。金丝雀部署允许实时用户反馈,从而能够早期发现问题。然而,它增加了反馈和监控的复杂性,以及需要管理的多个版本。它可以在有限的查询或特定区域上测试检索算法、嵌入或生成模型的变化。
滚动部署
滚动部署用于存在多个生产服务器的情况。在移动到下一个服务器之前,新的 RAG 系统会逐个部署到一台服务器上。因此,没有完全的停机时间,一次只有系统的一部分离线。如果在部署过程中出现问题,可能会变得复杂。当一些服务器更新时,而其他服务器没有更新,回滚可能会变得繁琐。
影子部署
影子部署将实时流量镜像到与旧版本系统并行运行的新版本系统,而不将新 RAG 系统的响应暴露给用户。通过这样做,可以在不影响用户的情况下测试系统。然而,它需要像蓝绿部署一样复制基础设施。
A/B 测试
A/B 测试涉及将 RAG 系统的两个版本(A 和 B)部署到不同的用户子集,并比较它们的性能以确定更好的选项。这也可以用于新系统。它允许直接比较,并为性能提供清晰的见解。然而,它需要强大的机制来分割流量并收集性能指标。它允许尝试不同的 LLM 或检索策略,以及提示和增强技术的变化。
交错实验
交错实验通过将两个 RAG 系统的输出混合成单个结果集展示给用户来比较两个 RAG 系统。两个系统的结果交错,用户交互归因于原始系统以确定哪个表现更好。这种方法提供了快速的反馈,并通过在相同条件下比较系统来减少偏差。然而,将用户参与度归因于正确的系统可能很复杂。
部署策略的选择可能取决于诸如容错性等因素,并且使用如影子、金丝雀和蓝绿等策略可以减轻关键任务系统中的风险。这还取决于规模,对于大规模系统,滚动部署是有意义的。小型新的 RAG 系统也可以一次性部署。
现在系统对用户可用后,你将开始获得实时反馈,系统的成功与失败也将取决于你对反馈的反应。为了衡量和改进系统,需要持续监控。
9.2.7 维护阶段:确保可靠性和适应性
将 RAG 系统部署到生产中只是向进化语境 AI 系统迈进的第一里程碑。显式的用户反馈、技术演变和用户行为的变化带来了系统可能遇到的前所未有的挑战。因此,持续保持警惕并监控系统性能至关重要。RAG 系统在生产中可能失败的原因有几个。有操作性的原因,如计算资源限制、负载的突然激增和恶意攻击。原因也可能是知识库中数据类型的转变或用户查询的变化。因此,测量一些指标是至关重要的:
-
在部署前评估的 RAG 组件指标需要持续监控以检测退化。
-
通过分析用户查询的性质可以跟踪用户行为的变化。
-
系统性能指标,如延迟、吞吐量和类似指标也应持续监控。
-
应跟踪的附加指标还包括错误率、系统停机时间、恶意攻击等。
-
用户参与度指标,如客户满意度评分或重复参与度可以表明系统的可用性。
-
应跟踪如收入影响和成本节省等业务指标。
此开发框架通过维护完成了其周期。然而,它不是一个线性过程。新的需求和业务目标将出现。这将重新启动改进 RAG 系统的开发周期。在构建 RAG 系统时,此开发框架将证明是一个良好的参考资源。
我们在本节结束本书的讨论,并在下一节中讨论 RAG 时,提出一些额外的考虑事项,以保持对生成 AI 领域演变的关注。
9.3 进一步探索的想法
就像任何技术一样,即使是 RAG,也有一些互补和竞争的想法共存。您可能会听到这些技术,有时会面临挑战,需要捍卫 RAG 的使用。RAG 系统也有常见的故障点需要关注。
9.3.1 RAG 中的微调
监督微调(SFT)LLM 已成为定制和适应基础模型以实现特定目标的流行方法。在应用 AI 社区中,关于微调或 RAG 的应用以完成任务的讨论日益增多。虽然 RAG 在不改变参数的情况下增强了基础模型的无参数记忆,但 SFT 改变了基础模型的参数,因此影响了参数化记忆。RAG 和 SFT 应被视为互补技术,而不是竞争技术,因为它们都针对生成 AI 系统的不同部分。如果您需要改变 LLM 响应的写作风格、语气和词汇,您可能会更喜欢微调而不是 RAG。在他们的论文“大型语言模型的检索增强生成:综述”(arxiv.org/abs/2312.10997)中,高及其同事绘制了提示工程到 RAG 和微调的演变图。这如图 9.10 所示,展示了随着模型适应需求增加,微调的必要性。

图 9.10 提示工程需要对模型和外部知识进行低修改,专注于利用 LLM 自身的功能。然而,微调却涉及进一步训练模型。来源:arxiv.org/abs/2312.10997。
对于检索器和生成器,微调方法具有显著提高 RAG 性能的巨大潜力。检索器微调通过使用对比学习、监督嵌入微调等方法,增强了检索模型准确捕捉特定领域相关语义细微差别的能力。
监督检索或基于奖励的微调。生成器微调通过通过融合解码器(FiD)、提示调整、潜在融合技术以及参数高效微调(PEFT)等方法调整语言模型来补充这一点。将这些方法结合在一个混合微调框架中可以更有效地对齐检索和生成组件,从而提高准确性、减少幻觉并提高对特定领域任务的适应性。
9.3.2 LLMs 中的长上下文窗口
在 LLMs 中,上下文窗口随着迭代显著增长。截至本文撰写时,Claude 3.5 sonnet 支持高达 200,000 个 token 的窗口,而 GPT-4o、O1 及其变体可以处理 128,000 个 token。Google Gemini 1.5 以 1 百万 token 的上下文窗口领先。在你阅读这本书的时候,可能会有具有更长上下文窗口的模型。因此,在许多情况下,我们只需将整个上下文,例如长文档,作为提示的一部分传递给模型。这将消除在知识库不是特别大的情况下进行分块、索引和检索的需要。在他们的论文“检索增强生成或长上下文 LLMs?全面研究和混合方法”(arxiv.org/abs/2407.16833)中,Li 及其同事系统地比较了 RAG 和具有长上下文窗口的 LLMs。他们证明,在少数例外的情况下,长上下文 LLMs 优于 RAG。然而,直接使用 LLMs 处理长上下文可能会非常耗费计算资源。RAG 由于处理较短的输入而显著更节省成本。同一篇论文中提出的混合方法 SELF-ROUTE 使用模型自我反思来决定一个查询是否可以用检索到的块来回答,或者是否需要完整的上下文。图 9.11 说明了 SELF-ROUTE 方法,其中模型接收带有检索块的查询,并基于此信息确定是否可以回答查询。如果可以,它生成答案。如果不可以,则向模型提供完整上下文,模型生成最终答案。

图 9.11 利用 RAG 和 LLMs 中的长上下文的混合方法可以在不增加成本的情况下提高性能。
9.3.3 管理解决方案
随着 RAG 的日益流行及其在生成 AI 应用中的重要性,许多服务提供商提供托管 RAG 管道,其中可以配置多个 RAG 组件,而无需定制开发。例如,知识库是 Amazon Bedrock 的一项功能,有助于实现整个 RAG 工作流程。Azure AI Search 提供索引和查询功能,基于 Azure 云的基础设施,而 Vertex AI RAG Engine 是 Google Vertex AI 平台的一个组件,有助于 RAG。还有像 CustomGPT、Needle AI、Ragie 等独立服务提供商,提供托管 RAG 管道。与跨技术托管解决方案一样,需要考虑的因素包括成本、适用性、灵活性和对组件的控制。
9.3.4 难以处理的查询
RAG 系统中失败的一些关键原因与查询类型有关。作为 RAG 开发者,持续关注这些查询类型对于改进技术至关重要。其中一些包括
-
多步推理——RAG 在需要多跳检索的查询上遇到困难(例如,“XXX 歌手的国籍是什么?”)。
-
通用查询——模糊或宽泛的问题难以检索相关片段(例如,“这个团体对 XXX 的看法是什么?”)
-
复杂或长查询——复杂查询挑战检索器的理解。
-
隐含查询——需要全面上下文理解的查询不能仅由 RAG 解决。
我们在 RAG 的讨论中已经走得很远了。本章全面总结了本书的内容,从 RAG 的好处到构建 RAG 系统的最佳实践。尽管有重复的风险,但 RAG 是生成 AI 领域的一个重要且不断发展的技术。希望您阅读这本书时有所收获。以下是我的一些结束语:
-
记住要熟悉由 RAG 驱动的上下文 AI 的原则。
-
信任您构建复杂 RAG 系统的能力。
-
总是牢记开发挑战和克服它们的策略。
-
了解围绕生成 AI 的伦理和法律问题。
-
保持对快速变化的趋势的关注。
摘要
RAG 开发框架
-
RAG 开发框架提供了一个构建、部署和维护检索增强生成系统的结构化方法。
-
通过包含六个迭代和循环阶段:启动、设计、开发、评估、部署和维护,该框架解决了 RAG 系统的复杂性。
-
该框架强调 RAG 系统开发的技术和操作方面。
RAG 开发框架阶段
-
启动阶段
-
专注于理解问题陈述、协调利益相关者并收集需求。
-
强调使用用例识别和评估 RAG 需求,使用如用例评估卡片等工具。
-
涉及业务、功能和非功能性需求的需求收集。
-
以绘制高级架构图来结束,以进行对齐和战略决策。
-
-
设计阶段
-
将高级架构转换为详细的管道设计,用于索引和生成。
-
包含关于分块、嵌入和检索策略的选择。
-
解决额外的考虑因素,如安全网、缓存、安全和部署策略。
-
-
开发阶段
-
实施模块化 RAG 管道,实现灵活性、可扩展性和可维护性。
-
活动包括训练/微调模型、创建独立模块(例如,分块、检索、生成)和构建编排层。
-
-
评估阶段
-
使用上下文相关性、忠实度、精确度、召回率、延迟和每查询成本等指标验证 RAG 系统组件和整体性能。
-
使用真实数据集进行基准测试和优化。
-
-
部署阶段
-
包括部署策略,如蓝绿部署、金丝雀部署、滚动部署和 A/B 测试,以确保平稳过渡和最小化干扰。
-
强调实时用户反馈和系统可扩展性。
-
-
维护阶段
-
通过持续监控组件指标、用户行为和性能指标来确保系统可靠性。
-
适应不断发展的用例、技术进步和用户反馈。
-
RAG 开发的最佳实践
-
模块化设计提高了适应性和更新便利性。
-
真实数据集对于准确评估和微调至关重要。
-
部署策略应与系统关键性、规模和风险承受能力相一致。
-
定期监控用户行为、数据和性能的变化,以保持可靠性。
进一步探索的想法
-
RAG 与微调的比较
-
RAG 通过增强非参数记忆来补充微调,而微调则适应参数记忆以调整风格、语气和词汇。
-
根据具体需求,用例可能从混合方法中受益。
-
-
LLM 中的长上下文窗口
-
LLMs(例如,200k+令牌上下文)的进步可以减少对较小知识库的分块和检索的依赖。
-
混合模型,如 SELF-ROUTE,将 RAG 与长上下文处理相结合,以优化成本和准确性。
-
-
管理解决方案
- 如 Amazon Bedrock、Azure AI Search 和 Google Vertex AI RAG Engine 等服务提供预构建的 RAG 管道,简化部署并减少开发工作量。
-
处理困难查询
- 多步骤推理、通用查询和隐含问题仍然是 RAG 系统的挑战。
第一部分 基础
本书的第一部分介绍了检索增强生成(RAG)背后的核心思想以及 RAG 系统的整体设计。
第一章处理基于大型语言模型(LLMs)的 AI 系统所面临的挑战。此外,它说明了 RAG 如何解决这些挑战以提高这类系统的可靠性。本章还简要概述了 LLMs 的工作原理以及一些流行的 RAG 应用案例。
第二章讨论了构建 RAG 系统所涉及的步骤。本章详细介绍了两个核心 RAG 管道的基本知识以及 RAG 系统的其他重要组成部分。
在阅读完本书的第一部分后,你应该对 RAG 系统有一个基础的理解,并准备好深入探索 RAG 的复杂性。
第二部分 创建 RAG 系统
现在你已经熟悉了 RAG 的基本概念和 RAG 系统的组成部分,本书的第二部分将指导你通过核心管道及其评估来构建一个基本的 RAG 系统。本书的这一部分不仅提供了理论细节,还提供了简单的代码片段,这些代码片段将为你提供构建 RAG 管道的实践经验。
在第三章中,你将了解索引管道的细节及其四个组成部分:加载、分块、嵌入和向量存储。这些组成部分各有多种技术可供选择。本章还讨论了这些选项对不同用例的适用性。逐步地,你将构建一个索引管道并为你的 RAG 系统创建知识库。
第四章讨论了检索器、提示技术以及使用 LLMs 进行输出生成。这些元素构成了生成管道的三个组成部分:检索、增强和生成。在本章中,你将构建一个与第三章中使用的索引管道创建的知识库交互的生成管道。
第五章讨论了评估 RAG 系统的不同方面,这是 AI 系统中的一个关键步骤。你将了解在 RAG 评估中用于衡量准确性、相关性和忠实度的不同指标。你还将被介绍到 RAGAs 框架,用于评估第三章和第四章中构建的管道,并了解在比较不同 RAG 技术中流行的行业基准。本章以对 RAG 评估的限制和最佳实践的讨论结束。
本书的这一部分将为你提供开发基本 RAG 管道所需的所有必要技能和工具。到这一部分结束时,你将能够进一步探索优化任何 RAG 管道所使用的技巧以及构建其周围生产级系统的关键组件。
第三部分 生产中的 RAG
到现在为止,你应该在构建和评估核心 RAG 管道方面充满信心。例如,“与你的 PDF 聊天”或基于网页的问答系统等应用不应再是谜团。本书的这一部分将指导你改进你的 RAG 管道,并概述构建生产就绪 RAG 系统所需的层蓝图。
在第六章中,你将能够尝试不同的技术,将基本的 RAG 管道改进为一个更高级的版本。你将了解在检索前、中、后三个阶段提高 RAG 的技术。你还将了解模块化以及现代 RAG 系统由可替换组件组成。
第七章讨论了 RAG 的操作栈。你将了解任何 RAG 系统都会失败的临界层,提高系统性能的基本层,以及专注于系统可用性、可扩展性和效率的增强层。
到本部分结束时,你应该具备构建简单 RAG 系统和将其投入生产的知识和技能。这也是你准备探索 RAG 系统更深层次细微差别和变化的时候。
第四部分 额外考虑事项
RAG 是一种不断发展的技术,该领域的研究活动一直非常活跃。本书的最后一部分,你将了解 RAG 的流行先进变体以及一个 RAG 开发框架,这个框架将帮助你规划和构建 RAG 系统。
第八章将教你关于 RAG 最重要的变体——多模态 RAG、知识图谱增强 RAG 和代理 RAG,以及一些其他流行的变体。了解这些变体将让你能够根据你正在构建的使用案例定制你的 RAG 系统。
第九章回顾了本书中讨论的所有概念,这些概念在 RAG 开发框架内组织。这个框架将帮助你战略性地规划你的 RAG 系统开发。你还将了解到一些在本书写作时仍处于开放研究状态的领域。
本书最后一部分总结了你对 RAG 的入门学习。到本书结束时,你不仅应该具备构建生产级 RAG 系统的基础,还应该具备跟踪和参与该领域持续研究的知识。


浙公网安备 33010602011771号