RAG 在长上下文大语言模型 (LLM) 中的应用探讨 [译]

这是@rlancemartin 最近在几个聚会上关于在长上下文 LLM 时代使用 RAG 的讲座。随着上下文窗口增至超过 100 万 Token,很多人质疑 RAG 是否已经过时。我们结合几个最新的项目成果来分析这个问题。我们讨论了长上下文 LLM 在事实推理和信息检索方

面现有的限制(采用多针索引分析法),同时也探讨了上下文窗口扩展可能带来的 RAG 应用场景的变化,如文档中心的索引技术和 RAG 的流程优化。 幻灯片展示:查看详情

重点参考文献:

  1. 多针索引分析,合作研究者@GregKamradt

  2. RAPTOR 研究项目,主要研究者包括@parthsarthi03

  3. Dense-X / 多维数据索引技术,主要研究者@tomchen0

  4. 长期上下文数据嵌入技术,研究者包括@JonSaadFalcon, @realDanFu, @simran_s_arora

  5. 自适应 RAG (@AkariAsai 等),及 C-RAG (Shi-Qi Yan 等)

  • 0:20 - 上下文窗口正逐渐增大
  • 2:10 - 多针索引挑战
  • 9:30 - RAG 的未来变革
  • 12:00 - 查询机制分析
  • 13:07 - 以文档为中心的索引技术
  • 16:23 - 自我反思的 RAG 模式
  • 19:40 - 会议总结

好的,这里是来自 Langchain 的 Lance。这是我最近在旧金山举办的两场聚会中的一次演讲,题为“Rag 真的终结了吗?”考虑到很多人未能参加,我决定将演讲录制下来,上传至 YouTube,希望这能引起大家的兴趣。

上下文窗口正逐渐增大

我们都知道,大语言模型 (LLM) 的上下文窗口正逐渐扩大。在 x 轴上,展示的是预训练时使用的 Token 数量,这一数字也在持续增长。专有模型的规模已达到约 2 亿亿个 Token。 而小型模型,如 5.2,使用的 Token 数远少于此。 更引人注目的是,在 y 轴上,可以看到一年前的顶尖模型处理能力大约在 4000 到 8000 Token,相当于几十页纸的内容。 Claude 2 推出了一个可处理 20 万 Token 的模型,而 GPT-4 则有 12.8 万 Token,相当于几百页纸的内容。 而现在,Claude 3 和 Gemini 推出的模型可以处理高达 100 万 Token,这相当于几百到几千页的内容。 因此,随着这种技术的发展,人们开始质疑 RAG 的必要性——如果一个 LLM 能够处理数千页的内容,为何还需要一个检索系统? 这个问题在 Twitter 上激发了热烈的讨论。 RAG,即基于检索的推理,涉及使用索引过的文档进行推理和检索。 这些文档通过语义相似度搜索或关键词搜索等机制被检索出来,然后由 LLM 进行分析,以便在回答问题时能够引用这些文档。 整个过程不仅涉及多个文档,还包括了复杂的推理活动。

最近我探讨了一个问题:如果长语境的大语言模型 (LLM) 能够取代 RAG,那么它应当能够非常有效地进行多事实的检索和推理。 为此,我与 Greg Cameron 共同进行了一系列压力测试。 Greg 已经针对 Paul Graham 的文章进行了一些精彩的单一事实分析。 我进一步扩展了这一分析,模拟 RAG 的使用场景,使用了多个事实,我称之为“多针”模式。 基于 Anthropic 发布的一个趣味挑战,我进行了改进:他们将比萨配料设置为任务目标,我将比萨配料分为三部分,分散在不同的文本位置,让 LLM 从文本中找出这三种配料。 这个实验的设定是:要制作完美的比萨,你需要哪些特别的配料?这些配料包括无花果、火腿和山羊奶酪,我按特定频率将它们加入文本中。 此测试的具体方法是:你可以设置首个“针”所占文本的比例,其余两个“针”则大致均等地分布在后续文本中。 这个测试现在是开源的,详见以下链接。 放置好“针”后,你提出问题,用相关文本和问题启动 LLM,它会生成答案。 现在,系统会对答案进行评估:一是检查所有特定配料是否都被提及,二是标出缺失的配料。 通过在 GPT-4 上进行了一系列的测试,我们获得了一些有意思的发现。 在左侧图表中,你可以看到在为 GPT-4 设置的 120,000 令牌的文本窗口中,分别测试了不同数量的“针”——一个、三个或十个。 我还让 GPT-4 对这些“针”进行推理,这在图表的红色条形中有所体现。 绿色代表仅为检索配料,红色表示进行了推理。

这里面的推理挑战很简单,只需要返回每个成分的首字母。 基本上涉及到两个问题: 随着“针”数量的增加,检索出的“针”的比例会下降。这是直观可理解的。 事实越多,性能越差;如果进行推理,情况则更糟。 比如,如果指令是仅返回“针”,效果会比同时要求返回“针”的首字母要好。 这就是所谓的推理叠加。 这是我们的初步观察结果。 更多的事实和推理任务,都比简单的检索要困难。 接下来的问题是,那些我们没能检索到的“针”具体遗漏在哪里? 例如,我们知道检索 10 个“针”的成功率约为 60%。 那些遗漏的“针”具体在哪里? 从右侧的结果可以看到,这些“针”分布在文档的哪些部分。 当上下文长度为 1000 个词符时,你可以找到所有的“针”。 然而,实际上我要关注的是 120000 个词符的情况。 较小的上下文有助于更好的检索。 随着上下文窗口的扩大,文档开始部分的“针”检索失败的情况有所增加,这一点从图中的红色区域可见。 这是一个引人注目的发现,并且与 Greg 在单一“针”实验中的观察相符。 这表明,如果你阅读了一本书后被问到关于第一章的问题,可能会记得不太清楚。 相似的情况也出现在这里,文档前端的“针”似乎容易被忘记,或者检索不够精确。 这是我们在使用 GPT-4 时观察到的一个现象,已经多次被验证。 我这里进行了九次实验,Greg 在他的实验中也有相似的发现。 这看起来是一个非常稳定的结果。

这里有一个有趣的观点。 我在 Twitter 上发布了这个内容。 引来了众多回复。 其中一位网友向我推荐了这篇论文,内容颇为引人深思。 论文提出,最近偏差可能是一个原因。 换句话说,预测下一个词符时,与生成活动最近的词符通常包含最多信息。 这就导致了一种倾向于关注近期词符的偏见,这对解决检索问题显然是不利的。 再次,我们的实验结果表明,推理问题比检索问题更为复杂。 找到更多的针(信息点)相对更难。 并且,上下文开始处的信息点比结束处的更难以被找到。 这些是我们的三个主要发现。 这些问题很可能与最近偏差有关。 总的来说,这些发现提醒我们,在使用长上下文的大语言模型 (LLM) 时,不能仅仅依赖于填充上下文。 这种方法并没有检索保证。 同时,最新的研究结果也表明,单一信息点的检索可能出奇的简单,但这可能会误导人。 如你所见,没有涉及到复杂的推理,仅仅是简单的信息检索。 此外,正如这条推特所展示的,在包括我自己的在内的许多针与干草堆挑战中,我们所寻找的具体信息与背景信息(如保罗·格雷厄姆的文章)大相径庭。 这种差异可能是一个值得注意的现象。 研究指出,如果所寻找的信息更为隐蔽,那么检索的难度也会增加。 因此,当你看到一些模型提供商发布的、表现出色的针与干草堆分析时,你应该保持警觉。 你不能简单假设这些长上下文大语言模型能够提供高质量的检索,因为这里面涉及到多种复杂的因素。 你需要考虑多重信息的检索,推理的深度,以及信息与背景的匹配度。 总之,这些因素可能会使这些挑战比现实世界的情况简单许多。 我希望这些警示能给你带来启示。 但公平地说,我们有理由相信情况会有所改善。 同时,可以预见,未来的技术变革将带来新的转变。

这不只是个不怎么样的笑话,音乐家 Frank Zappa 曾说:爵士乐没死,只是有点儿异味。 我认为 rag 也是这样。 Rag 没有消失,只是在转变。 这是一个关键的观点。 接下来说说现在的 rag,它主要专注于精确地检索相关的文档片段。 这通常涉及以特定方式将文档分成块,使用的分块方法很有个性。 比如,块的大小常常似乎是随机决定的。 这些块被编码后存入一个索引中,把一个问题也编码后,通过 K 近邻 (KNN) 相似度搜索来找出相关的块。 通常需要设置一个 K 值,即检索的块的数量。 在找到的块上可能还会做些过滤或后处理,然后在这些块的基础上构建答案。 这个过程非常注重精确地找到最合适的块。 在长上下文模型越来越普遍的今天,我们不禁要问,这真的是最合理的方法吗? 在这里你可以看到,有人可能会太过追求精确,这不仅会增加复杂性,还会因为块大小、K 值等奇特的参数而变得过于敏感,而且可能因为只选择极其精确的块而导致召回率低。 这种方法很依赖特定的编码模型。 因此,随着长上下文模型的进一步发展,我们确实需要重新思考这种极端精确的块检索方式是否还适合现在。 另一方面,简单地将所有文档堆积到上下文中似乎也不是最好的选择,这会导致更高的延迟和更多的令牌消耗。 值得一提的是,现在每生成一次 100,000 令牌的 GPT-4 要花费 1 美元。 我在 LangChain 的账户上为这种多角度分析花了一大笔钱,我不太想告诉 Harrison 花了多少。 显然,这种方式有其不便之处——你无法对检索进行审计,如果不同用户需要对检索到的不同文档或块有不同的访问权限,还可能涉及安全性和认证问题。

在这种情境下,管理安全性变得不那么容易。 因此,可能存在一种较为理想的帕累托最优状态在中间位置。 我还在 Twitter 上分享了这个想法。 我认为,有些提出的观点是挺有道理的。 我觉得,在文档级别进行包含处理是相当明智的选择。 文档本身就是独立完整的内容块。 那么,以文档为中心的处理方式怎么样呢? 不进行分块,直接操作完整文档的内容。 想象一下,如果我们采用这种以文档为中心的处理方式,我们还是需要解决如何将具体问题定位到正确的文档这一问题,这一点并没有改变。 因此,我们通常会考虑各种查询分析方法,比如重新编写问题以优化信息检索,或者如何将问题正确地定向到适当的数据库,无论是关系型数据库、图数据库还是向量数据库,以及如何构建查询语句。 例如,将文本转换为 SQL 语句,转换为用于图的 Cypher 语句,或者转换为向量存储的元数据过滤条件,这些方法在使用长文本大语言模型的情境下依然适用。 你可能不会完全放弃你的 SQL 数据库去使用大语言模型。 你还会继续使用 SQL 查询和图查询。 虽然你可能对提取的数据更加宽容,但大部分结构化数据还是会被以传统形式存储。 同理,对于非结构化数据,如文档,我们之前也提过,最好还是将文档独立存储,优先考虑直接检索整个文档,而不是过分关注如块大小这样的细节。 我们已经尝试了一些优化文档检索的方法。 其中一个我要特别提到的是所谓的“多维表征索引”技术。 还有一篇很棒的论文《Dense X Retriever 或 Proposition Indexing》详细讨论了这一点。 简而言之,这个方法包括取出原始文档,制作一个摘要,并对这个摘要进行索引。

然后在检索过程中,你提出问题并将问题转换为查询关键词,只需使用一个高层次的摘要即可准确地找到所需的文档。接着,将完整文档提交给大语言模型(LLM,Large Language Model)以生成最终的内容。这是一个巧妙的方法,在这种情况下你无需处理整篇文档的嵌入问题。你可以利用精确的描述性摘要提示来创建文档摘要。这里你面临的任务简单明了:就是找到正确的文档。这比寻找正确的文档片段要简单得多。这种方法很有效。还有一些其他的变体,例如我接下来要介绍的“父文档检索器”,它允许你按需检索较小的文档片段,但仍会返回完整的文档。核心思想是,在生成过程中保持文档的完整性,而在检索时则使用文档摘要或片段等表述形式。这可以视为一个非常有趣的方法。第二种方法称为“Raptor”,这是一篇源自斯坦福的新论文,解决了如何在需要时跨多个文档整合信息的问题。通过这种方式,文档被编码并按主题聚类,每个类别的文档都会被简要总结,并且这一过程会递归进行,直到只生成一个针对所有文档的高级摘要。这种层次化的文档总结框架被全部编入索引,并在检索时使用。这样,如果你的问题涉及多个文档的信息,你就很可能找到一个包含答案的摘要。这是一个有效的方法来整合多文档中的信息。论文中还提到,尽管案例中的文档被分为不同的小片段,但我的视频和笔记本演示显示,这种方法同样适用于完整文档。要实现这一点,你需要考虑使用长文本嵌入模型,因为这涉及到整个文档的嵌入工作,这是追踪研究中一个非常有趣的方向。Hazy Research 在其博客上发布了一篇关于使用 Monarch Mixer 进行此类工作的精彩文章。

所以这实际上是一种新的架构,它能处理更长的上下文。在 Together AI 上,他们提供了一个包含 32,000 个 Token 的嵌入模型,非常值得一试。我认为这是一个极具趣味的新趋势。长上下文嵌入与这种理念非常契合。例如,你可以将整个文档通过长上下文嵌入模型进行嵌入,然后高效地创建文档摘要树。这也是在长上下文大语言模型体系下处理全文档的一个有效策略。另外值得一提的是,我认为未来可能会从单次执行型 rag 向其他模式转变。在现有的 rag 系统中,我们通常将文档分块并嵌入后存入索引库,通过检索和生成内容,但实际上我们完全可以在生成或检索过程中添加推理步骤来纠错。有一篇称为 "Self-rag" 的论文详细介绍了这一点,我们已经用 Langraph 成功实现了这一机制,效果非常好。这个方法的核心是先评估文档与问题的相关性,如果不相关,则重写问题并重试。我们还会评估幻觉和答案的相关性。这种方式将 rag 从单次模式转变为一个循环流程,在这个流程中,我们会在多个阶段进行评估。这在长上下文大语言模型体系中也同样适用。事实上,你应该充分利用例如性能越来越好的大语言模型来进行这些评估。像 Langraph 这样的框架可以帮助你建立这样的流程,使得 rag 系统更加高效和自省。对于延迟的问题,我完全理解大家的担忧,确实,性能、准确性与延迟之间需要做出一定的权衡。在选择模型时,你可以考虑使用如 Grok 或 GPT-35 Turbo 这样的快速模型,这些模型在处理这些评估任务时表现出色。

你可以使用非常快的大语言模型 (LLM) 来进行评分。你还可以将这种循环的迭代次数限制为一次,这样也可以相应地控制响应时间。 这个方法非常酷,即使在我们转向处理更长文本的今天,也依然适用。 这就像在文本生成和搜索阶段添加上推理过程。 另外,一个常见问题是,你的搜索可能会遇到数据库之外的查询,这总是个难题。 几个月前有篇非常有启发性的论文发布,名为 C rag 或修正性 rag,提出了一种类似之前讨论过的评分方法。 如果搜索到的文档不相关,系统会自动转到网上搜索,并把结果送回大语言模型 (LLM) 来完成生成,这为超出常规搜索范围的问题提供了一种备选方案。 这种在 rag 上增加推理层的方法很有用,也让系统对非典型问题的处理更加健壮。 这个策略被证明与开源模型特别兼容,我甚至在我的笔记本上用 Llama 运行了 Mistral 7B 模型,效果很好。 这种方法值得推广,不受模型处理的文本长度影响,增强了搜索阶段的推理能力,可以显著提升性能。 总的来说,正确导向合适的数据库或文档仍是关键,无论是查询分析、路径规划还是构建查询,这些因素都十分重要。 在处理较长的文本时,可能不再需要那么频繁地分割文档,整体处理可能更有效。 此外,我们还探讨了一些高效的文档索引技巧,如多重表示索引法。

我们之前讨论过使用 Raptor 实现的层级索引,以及两个关于文档中心索引的有趣思路。 此外,还有检索后的推理与内容生成,包括对检索结果和生成内容的质量控制,例如检测是否有内容出现错误的幻觉现象。 这些都是 RAG 系统的重要组成部分,我认为随着我们从简单的直接回答模式(Prompt Response Paradigm)向更加动态的流程模式(Flow Paradigm)转变,这类系统的使用将会更加广泛。 事实上,在代码生成领域,这种趋势已经显现。 预计这种趋势也将影响到 RAG 系统的发展,我们可能会看到更多采用周期性流程的 RAG 系统,它们会处理文档数据,运用复杂的大语言模型,并进行精确的路由与查询分析。 即涉及检索前的逻辑推理,也包括检索后的逻辑推理。 以上就是我此次的分享。 如果你有任何问题或评论,请在视频下方留言,我会尽力解答。 感谢你的观看和听讲。