宣布 LlamaCloud 正式发布 (以及我们的 1900 万美元 A 轮融资!)
LlamaIndex

Jerry Liu 2024-03-01

走向长上下文 RAG

Google 最近发布了 拥有 100 万上下文窗口的 Gemini 1.5 Pro,该版本面向有限数量的开发者和企业客户开放。它的性能激发了 AI Twitter 的想象。它在由 Greg Kamradt 推广的“大海捞针”实验中 达到了 99.7% 的召回率。早期用户分享了同时输入数十篇研究论文和财务报告的结果,并表示在跨海量信息进行综合方面的能力令人印象深刻。

自然地,这引出了一个问题——RAG 已死吗?一些人是这样认为的,而另一些人则不同意。前者阵营的观点有其合理之处。大多数小型数据用例都可以容纳在 1-1000 万的上下文窗口中。随着时间的推移,Token 的处理成本会越来越低,速度会越来越快。通过注意力层使 LLM 原生地交织检索/生成,与朴素 RAG 中的一次性检索相比,可以带来更高的响应质量。

我们很幸运能够提前体验 Gemini 1.5 Pro 的能力,通过试用,我们形成了一套关于上下文增强型 LLM 应用将如何演进的理论。这篇博文阐明了我们作为数据框架的使命,以及我们对长上下文 LLM 架构将如何演变的看法。我们的观点是,虽然长上下文 LLM 将简化 RAG 管道中的某些部分(例如分块),但仍需要演进的 RAG 架构来处理长上下文 LLM 带来的新用例。无论出现什么新范式,LlamaIndex 的使命都是为未来构建工具。

我们的使命不止于 RAG

LlamaIndex 的目标非常简单:赋能开发者在其数据上构建 LLM 应用。这一使命不仅限于 RAG。迄今为止,我们投入了大量精力来改进现有 LLM 的 RAG 技术,这样做是因为它帮助开发者解锁了数十种新用例,例如对半结构化数据和复杂文档进行问答,以及在多文档环境中的 Agent 推理。

但我们也对 Gemini Pro 感到兴奋,并且在长上下文 LLM 的未来,我们将继续推进 LlamaIndex 成为生产级数据框架。

LLM 框架本身就具有内在价值。作为开源数据框架,LlamaIndex 为从原型到生产构建任何 LLM 用例铺平了道路。框架使得构建这些用例比从头开始更容易。无论是通过使用我们的核心抽象设置适当的架构,还是利用我们生态系统中的数百个集成,我们都赋能所有开发者构建这些用例。无论底层的 LLM 有何进展,也无论 RAG 是否会继续以当前形式存在,我们都会持续努力使框架达到生产就绪状态,包括严密的抽象层、一流的文档和一致性。

我们上周还发布了 LlamaCloud。LlamaCloud 的使命仍然是构建数据基础设施,使任何企业都能将其庞大的非结构化、半结构化和结构化数据源转化为可用于 LLM 的生产就绪状态。

Gemini 1.5 Pro 初步观察

在我们的初步测试中,我们试用了一些 PDF 文档:SEC 10K 文件、ArXiv 论文,以及这份庞大的原理设计手册等等。一旦 API 可用,我们将进行更深入的分析,但在此期间,我们分享一些观察结果。

Gemini 的测试结果令人印象深刻,并且与我们在技术报告和社交媒体上看到的一致。

  • Gemini 对特定细节的召回能力令人印象深刻: 我们输入了 10 万到 100 万 token 的上下文,并询问了这些文档中非常具体的细节(包括非结构化文本和表格数据),在所有情况下,Gemini 都能够召回这些细节。关于 Gemini 比较 2019 年 Uber 10K 文件中表格结果的示例,请参见上文。
  • Gemini 具有令人印象深刻的摘要能力。该模型可以分析跨多个文档的大量信息并合成答案。
此图展示了 Gemini 对 2019 年 Uber 10K 文件的问答示例。问题和答案显示在顶部,来源表格显示在底部。Gemini 能够返回正确答案。

在某些方面,我们注意到 Gemini 表现得有些吃力。

  • Gemini 无法正确读取所有表格和图表。Gemini Pro 在读取图表和复杂表格方面仍然存在困难。
  • Gemini 可能需要很长时间。 对 Uber 10K 文件 (~160k token) 返回答案大约需要 20 秒。对 LHS 原理设计手册 (~890k token) 返回答案大约需要 60 秒以上。
  • Gemini 可能会出现幻觉页码。当被要求提供摘要并引用页码时,Gemini 出现了幻觉来源。
Gemini 1.5 Pro 仍会产生幻觉的一个例子。当被问及所有部门的总预订量时,模型会产生一个错误的数字——该数字在图表中可见,也可以从表格中拼凑出来。

尽管如此,从方向上看,这是对未来令人兴奋的一瞥,值得就哪些 RAG 范式将消退以及将出现哪些新架构进行更深入的讨论。详情请看下文!

长上下文解决了一些痛点,但仍存在一些挑战

Gemini 1.5 Pro 只是众多长上下文 LLM 中涌现的第一个,这将不可避免地改变用户构建 RAG 的方式。

以下是我们认为长上下文 LLM 将解决的一些现有 RAG 痛点:

  1. 开发者将减少对如何精确调整分块算法的担忧。我们真心认为这对 LLM 开发者来说将是一个巨大的福音。长上下文 LLM 可以使原生块大小更大。假设每个 token 的成本和延迟也随之降低,开发者将不再需要纠结如何通过调整分块分隔符、块大小和仔细的元数据注入将块分割成细粒度的条带。长上下文 LLM 使得块可以达到整个文档的级别,或者至少是页面的分组。
  2. 开发者将减少对单文档检索和思维链的调优时间。小块 top-k RAG 的一个问题是,虽然某些问题可以通过文档中的特定片段得到回答,但其他问题需要在章节之间或两个文档之间进行深入分析(例如比较性查询)。对于这些用例,开发者将不再需要依赖思维链 Agent 对弱检索器进行两次检索;相反,他们可以直接一次性提示 LLM 来获取答案。
  3. 摘要将变得更容易。这与上述说法相关。许多大型文档的摘要策略涉及“技巧”,例如顺序细化或分层摘要(请参阅我们的 响应合成模块 作为参考指南)。现在只需一次 LLM 调用即可缓解此问题。
  4. 个性化记忆将更好、更容易构建: 构建对话式助手的一个关键问题是如何将足够的对话上下文加载到提示窗口中。对于非常基本的网络搜索 Agent,4k token 很容易溢出这个窗口——例如,如果它决定加载一个维基百科页面,该文本将很容易超出上下文限制。100 万至 1000 万的上下文窗口将使开发者更容易实现对话式记忆,而无需采用较少的压缩技巧(例如向量搜索或自动知识图谱构建)。

然而,仍然存在一些挥之不去的挑战:

  1. 对于大型文档库来说,1000 万 token 仍然不够——万文档检索仍然是一个挑战。100 万 token 大约相当于 7 份 Uber SEC 10K 文件。1000 万 token 大约相当于 70 份文件。1000 万 token 大致相当于 40MB 的数据。虽然这对于许多“小型”文档库来说足够了,但企业中的许多知识库规模达到 GB 或 TB 级别。要在这些知识库上构建 LLM 驱动的系统,开发者仍然需要构建某种方式来检索这些数据,以增强语言模型的上下文。
  2. Embedding 模型在上下文长度方面落后。迄今为止,我们看到的 Embedding 模型最大上下文窗口是 来自 together.ai 的 32k。这意味着,即使用于长上下文 LLM 合成的块可以很大,用于检索的任何文本块仍然需要小得多。
  3. 成本和延迟。 是的,所有成本和延迟问题都会随着时间得到缓解。然而,用 100 万 token 填充上下文窗口大约需要 60 秒,按照目前的定价,成本可能在 0.50 美元到 20 美元之间。Yao Fu 提出的一个解决方案是,KV 缓存可以缓存文档激活项,以便后续的生成可以重用相同的缓存。这引出了我们下文要讨论的下一个问题。
  4. KV 缓存会占用大量 GPU 内存,并且存在序列依赖性。我们与 Yao 交流过,他提到目前缓存 100 万 token 的激活项大约需要 100GB GPU 内存,或者 2 块 H100 显卡。如何最好地管理缓存也存在有趣的挑战,特别是在底层语料库很大时——由于每个激活项都是其之前所有 token 的函数,替换 KV 缓存中的任何文档都会影响该文档之后的所有激活项。

走向新的 RAG 架构

正确使用长上下文 LLM 将需要新的架构,以充分利用其能力,同时克服其剩余的限制。我们在下文概述了一些建议。

1. 基于文档的从小到大检索

鉴于长上下文 LLM 需要对大型知识库(例如 GB 级别)进行检索增强,我们将需要从小到大检索:索引和检索小块,但让每个小块链接到最终将在合成过程中馈送给 LLM 的大块。

这种架构已经以不同形式存在于 LlamaIndex 中(句子窗口检索器跨块大小的递归检索),但对于长上下文 LLM 可以进一步扩展——嵌入文档摘要,但链接到整个文档。

我们希望嵌入和索引较小块的一个原因是,当前 Embedding 模型在上下文长度方面未能跟上 LLM 的发展。另一个原因是,与文档的单个文档级 Embedding 相比,拥有多个细粒度的 Embedding 表示实际上可以带来检索优势。如果一个文档只有一个 Embedding,那么该 Embedding 就承担着编码整个文档所有信息的负担。另一方面,我们发现嵌入许多较小的块,并让每个小块链接到更大的块,将有助于更好地检索相关信息。

请查看上图,了解从小到大检索的两种变体。一种是索引文档摘要并将其链接到文档,另一种是索引文档内的较小块并将其链接到文档。当然,你也可以同时进行这两种方法——提高检索效果的一个通用最佳实践是同时尝试多种技术,稍后融合结果。

2. 用于权衡延迟/成本的智能路由

长上下文 LLM 的到来将不可避免地引发关于每个用例适合多少上下文的问题。为 LLM 注入长上下文会带来实际的成本和延迟权衡,并且不适合每个用例甚至每个问题。尽管未来成本和延迟会降低,但我们预计用户在未来一两年内仍需要仔细考虑这种权衡。

询问特定细节的问题非常适合现有的 RAG 技术,即 top-k 检索和合成。

更复杂的问题需要来自不同文档中分散片段的更多上下文,在这些情况下,如何在优化延迟和成本的同时正确回答这些问题尚不明确。

  • 摘要类问题需要查阅整个文档。
  • 多部分问题可以通过思维链以及交织检索和推理来解决;也可以通过将所有上下文塞入提示来解决。

我们设想一个智能路由层,它在知识库上的多个 RAG 和 LLM 合成管道之上运行。对于一个问题,路由器理想情况下可以选择一种在检索上下文回答问题方面成本和延迟最优的策略。这确保了单一接口可以处理不同类型的问题,同时又不会变得过于昂贵。

3. 检索增强型 KV 缓存

Google 和其他公司肯定正在致力于通过KV 缓存来解决延迟和成本问题。从宏观上看,KV 缓存存储注意力层中预先存在的键向量和值向量的激活项,从而避免了在 LLM 生成过程中重新计算整个文本序列的激活项(我们发现这篇文章对 KV 缓存的工作原理进行了很好的介绍)。

使用 KV 缓存缓存上下文窗口内的所有文档 token,避免了在后续对话中重新计算这些 token 的激活项,从而显著降低延迟和成本。

但这引发了如何最好地使用缓存的有趣检索策略,特别是对于超出上下文长度的知识库。我们设想一种“检索增强型缓存”范式正在出现,在这种范式下,我们希望检索用户最有可能希望回答的最相关文档,并期望用户将继续使用缓存中的文档。

这可能涉及将检索策略与传统缓存算法(例如 LRU 缓存)交织使用。但与现有 KV 缓存架构的不同之处在于位置很重要,因为缓存的向量是该位置之前所有 token 的函数,而不仅仅是文档本身的 token。这意味着你不能简单地从 KV 缓存中换出一个块,而不影响其后方所有按位置排序的缓存 token。

总的来说,使用 KV 缓存的 API 接口尚不确定。缓存本身的性质是否会演变,或者算法是否会演变以最好地利用缓存,也尚不确定。

未来展望

我们相信 LLM 应用的未来是光明的,我们很高兴能站在这个快速发展领域的前沿。我们邀请开发者和研究人员与我们一起探索长上下文 LLM 的可能性,并构建下一代智能应用。