点 Redis 8 已发布——它是开源的

了解更多

使用 Redis 实现实时 RAG:超越向量数据库

为什么 RAG 需要实时数据?

我们看到检索增强生成 (RAG) 正成为需要访问私有数据的生成式 AI 应用事实上的标准架构。然而,有些人可能会想知道为什么实时访问这些数据很重要。答案很简单:您不希望在向堆栈中添加 AI 时,应用会变慢。

那么,什么是快速应用?Paul Buchheit(Gmail 的创建者)提出了100 毫秒规则。它规定每次交互都应该快于 100 毫秒。为什么?100 毫秒是“交互感觉即时”的阈值。

让我们检查一下典型的基于 RAG 的架构是什么样的,以及每个组件当前的延迟边界以及预期的端到端延迟。

  1. 网络往返时间 — 假设您应用的终端用户和数据中心位于美国,往返时间预计在 20-50 毫秒范围内。
  2. LLM — 来自 ChatGPT:“截至我上次更新,LLM 处理生成响应的时间通常在几十到几百毫秒之间,具体取决于上面提到的细节。此处理时间可能会受到模型架构、输入文本长度和复杂性以及与生成响应一起执行的任何额外任务(例如上下文分析或格式化)的影响。”
  3. 生成式 AI 应用 — 对于本地操作,我们预计需要几十毫秒;对于调用第三方服务,则需要几百毫秒。
  4. 向量数据库 — 存储您想要用于向 LLM 添加上下文的数据集或语料库,以生成准确且相关的响应。该数据集捕获文档的语义信息(即向量),并在检索阶段实现高效的基于相似性的检索。向量搜索查询通常是计算复杂度很高的操作查询。在我们进行并将很快发布的全面基准测试中,跨多个数据集和负载的向量搜索查询加上 10 个文档的结果,中位数响应时间为 569 毫秒。
  5. 基于代理的架构 — 可能驱动组件 2-4 的多次执行周期。

基于分析,使用上述架构构建的生成式 AI 应用预计端到端响应时间平均为 1,513 毫秒(或 1.5 秒)。这意味着您很可能会在几次交互后失去终端用户的兴趣。

要构建一个更接近 100 毫秒规则体验的实时生成式 AI 应用,您需要重新思考您的数据架构。

Redis 如何让 RAG 实现实时性?

为了应对上述挑战,Redis 为 AI 提供了三个主要的数据存储功能,这将使实时 RAG 成为可能。

实时向量数据库

即使在“生成式 AI”一词被创造之前,Redis 就已经支持向量数据类型和向量搜索功能。Redis 向量搜索算法使用高效的内存数据结构和专用搜索引擎,从而使搜索速度提高多达 50 倍(我们将很快发布全面的基准测试结果),并且文档检索速度提高两个数量级。本文稍后将展示实时向量搜索如何显著改善端到端用户体验。

语义缓存

Redis(以及通常的)传统缓存技术使用关键字匹配,这难以捕捉 LLM 服务相似查询之间的语义相似性,导致命中率非常低。使用现有缓存,我们无法检测到“给我推荐一部喜剧电影”和“推荐一部有趣的电影”之间的语义相似性,导致缓存未命中。语义缓存超越了精确匹配:它使用智能算法来理解查询的含义。即使措辞不同,缓存也能识别它是否在上下文上与之前的查询相似,并返回相应的响应(如果存在)。根据最近的一项研究,31% 的 LLM 查询可以被缓存(换句话说,31% 的查询是上下文可重复的),这可以在 dramatic地降低 LLM 成本的同时,显著改善基于 RAG 架构运行的生成式 AI 应用的响应时间。

您可以将语义缓存视为 LLM 的新缓存。利用向量搜索,语义缓存可以在性能和部署成本方面带来显著优势,我们将在以下章节中解释。

LLM 记忆(或扩展对话历史)

LLM 记忆是 LLM 与特定用户之间所有先前交互的记录;可以将其视为 LLM 的会话存储,只不过它也可以记录跨不同用户会话的信息。使用现有 Redis 数据结构和向量搜索实现,LLM 记忆由于多种原因而具有令人难以置信的价值。

  • 改进个性化
    • 理解用户偏好:通过分析过去的对话,LLM 可以识别用户的偏好主题、沟通风格和术语。这使得 LLM 可以调整其响应,以更好地满足用户的需求和兴趣。
    • 建立融洽关系:引用过去的讨论并承认用户的历史有助于 ایجاد连续性和融洽关系,从而促进更自然、更具吸引力的用户体验。
  • 增强上下文感知
    • 消除查询歧义:LLM 记忆允许 LLM 理解当前查询的上下文。它可以将用户当前的问题与之前的讨论联系起来,从而产生更准确和相关的响应。语义缓存可以利用 LLM 记忆来回答诸如“接下来是什么?”之类的通用问题。
    • 基于现有知识:LLM 可以利用过去的对话来建立关于用户兴趣或目标的现有知识。这使得它可以提供更全面和信息丰富的响应,超越基本信息检索。

示例:计划旅行

没有 LLM 记忆
用户:“我计划去意大利旅行。有哪些有趣的地方可以参观?”
LLM:“意大利有很多美丽的城市!以下是一些热门旅游目的地:罗马、佛罗伦萨、威尼斯……”

有了 LLM 记忆
用户:“我计划去意大利旅行。我对艺术和历史感兴趣,不太喜欢拥挤的地方。”(假设这是对话的第一回合)
LLM:“既然您对艺术和历史感兴趣,那去佛罗伦萨怎么样?它以文艺复兴时期的艺术和建筑闻名。”(LLM 利用对话历史来识别用户偏好并建议相关地点)
用户:“听起来不错!有没有什么博物馆不容错过?”
LLM(引用对话历史):“对于佛罗伦萨的艺术爱好者来说,乌菲齐美术馆和学院美术馆是必去之地。”(LLM 利用对话历史来理解用户在旅行背景下的特定兴趣)

在此示例中,LLM 记忆(或对话历史)允许 LLM 根据用户的初始陈述个性化其响应。它避免了通用推荐,并根据用户表达的兴趣定制其建议,从而带来更有帮助和更具吸引力的用户体验。

使用 Redis 的实时 RAG 如何工作?

要解释使用 Redis 的 AI 功能实现的实时 RAG,没有什么比图表和简短解释更好的了。

  1. 收到用户的提示后,生成式 AI 应用调用嵌入服务(例如 OpenAI Ada2)将其向量化。
  2. 生成式 AI 应用启动语义缓存操作,查找相似的响应(在这种情况下,相似度 >= 97%,但也可以使用其他参数)。如果应用命中缓存(超过 30% 的时间),它只需将缓存的响应发送回用户。
  3. 缓存未命中时,生成式 AI 应用将根据向量化的提示从 Redis 的 LLM 记忆中检索历史上下文。
  4. 为了获取与向量化提示匹配的前 K 个文档,Redis 中运行着相似性搜索(在这种情况下,Redis 用作实时向量数据库)。
  5. 生成式 AI 应用根据对话历史和向量数据库中的文档生成一个基础提示,并将其发送给 LLM。
  6. 响应被处理,然后发送给用户,同时更新语义缓存。

使用 Redis 的实时 RAG 有多快?

我们应该考虑两种情况:

  1. 语义缓存命中 — 在这种情况下,由于相关响应已在缓存中,因此可以节省所有 LLM 调用(如前所述,这占生成式 AI 查询的约 30%)。
  2. 语义缓存未命中(占 70% 的情况) — 生成式 AI 将触发与非实时 RAG 架构类似的过程,使用 Redis 的 LLM 记忆、实时向量搜索和实时文档检索。

为了了解实时 RAG 应用的端到端性能,让我们分析每种情况。

语义缓存命中分析

如上图所示,在这种情况下实际只涉及两个组件:

  1. 接收到向量化提示后,生成式 AI 应用执行向量搜索和检索调用以检索缓存的响应并将其发送回用户。我们假设此过程比缓存未命中过程短 33%,即 20-60 毫秒。
  2. Redis – 仅执行语义缓存,对应于一次向量搜索加上一次缓存响应检索。此操作的中位数延迟为 40 毫秒,详细计算可在此处找到
  3. 网络访问保持不变,占 20-50 毫秒的延迟。
  4. 缓存命中情况下的平均端到端延迟 – 100 毫秒

语义缓存未命中分析

  1. 网络 – 保持不变,占 20-50 毫秒的延迟。
  2. 生成式 AI 应用 – 执行此处详述的缓存未命中情况下的所有步骤,仍在 20-100 毫秒内。
  3. Redis – 执行 Redis 所有可用的 AI 功能:(1) 语义缓存,(2) LLM 记忆,以及 (3) 向量数据库。我们对各种数据集和负载场景进行了基准测试,发现所有组合操作(包括往返)的中位数时间为 79 毫秒。
  4. LLM – 基于历史上下文,由于更短、更相关、更准确的提示(更少的 token),LLM 处理预计会提高多达 25%,即 40-400 毫秒。
  5. 基于代理的架构 — 保持不变,可能驱动组件 2-4 的多次执行周期。
  6. 平均端到端延迟 – 513 毫秒

实时 RAG 总响应时间分析

基于 Redis 的 RAG 架构的平均端到端响应时间为 389 毫秒,比非实时 RAG 架构快约 3.2 倍,并且更接近 Paul Buchheit 的 100 毫秒规则。这使得现有和新的应用可以在其堆栈中运行 LLM 组件,而性能影响最小,甚至没有影响。

额外优势

除了确保您的快速应用保持快速外,基于 Redis 的实时 RAG 架构还提供其他优势:

  • 成本 — 使用语义缓存,您可以削减多达 30% 的 LLM API 调用。这可以节省大量成本!
  • 更准确的响应 — LLM 记忆提供关于历史对话的上下文,帮助 LLM 理解用户偏好,建立融洽关系,并基于先前知识改进响应。

总结和下一步

这篇博客分析了基于 RAG 架构的响应时间,并解释了 Redis 如何在复杂、快速变化的 LLM 环境中提供实时终端用户体验。如果您想尝试此处讨论的所有内容,我们推荐 Redis Vector Library (RedisVL),一个基于 Python 的 AI 应用客户端,它利用 Redis 的功能实现实时 RAG(语义缓存、LLM 记忆和向量数据库)。RedisVL 可与您的 Redis Cloud 实例或您自行部署的 Redis Stack 一起使用。

附录:详细端到端延迟分析

在本附录中,您将找到我们如何计算 RAG(实时和非实时)端到端响应时间的详细信息。它基于我们进行并将很快发布的全面基准测试,该测试跨越了四种类型的向量数据集:

  1. glove-100-angular(召回率 >= 0.95)
  2. gist-960-euclidean(召回率 >= 0.98)
  3. deep-image-96-angular(召回率 >= 0.99)
  4. dbpedia-openai-1M-angular(召回率 >= 0.99))

一旦基准测试发布,将提供更多关于这些数据集的信息。

非实时 RAG

对于非实时 RAG,我们平均了所有基于磁盘的数据库(专用和通用)的结果。由于数据严重倾斜,我们取了四组不同测试和所有被测试供应商的归一化中位数。

组件延迟
网络往返(20+50)/2 = 35ms
LLM(50+500)/2 = 275ms
生成式 AI 应用
*假设未调用其他服务时为 20ms,否则为 100ms
(20+100)/2=60ms
向量数据库
*假设一次向量/混合搜索 + 10 个文档
一次向量搜索查询(我们取了低负载和高负载下的中位数) – 63ms;10x 文档检索 – 10x50ms = 500ms;总计 – 563ms
基于代理的架构假设 1/3 的 LLM 调用触发代理处理,这将触发 LLM 的应用调用以及数据检索和 LLM 调用的另一次迭代。33% x (LLM + 应用 + 向量数据库)
总计35 + {275+60+563}⅔ + {275+60+563}2*⅓ = 1232

实时 RAG

对于实时 RAG,我们考察了两种情况:缓存命中(使用语义缓存)和缓存未命中。根据这项研究,我们计算了加权平均值,假设 30% 的查询会命中缓存(70% 未命中)。我们取了基准测试中所有被测试数据集的 Redis 中位数延迟。

语义缓存命中

组件延迟
最佳情况
网络往返(20+50)/2 = 35ms
生成式 AI 应用
*假设缓存命中将导致应用处理时间减少 33%
40ms
Redis 语义缓存
一次向量搜索查询(我们取了低负载和高负载下的中位数) – 24.6ms;1x 文档检索 – 1×0.5ms;总计 – 25ms
总计35+40+25 = 100ms

语义缓存未命中

组件延迟
最佳情况
网络往返35ms
LLM

*基于历史上下文,我们假设由于更短、更准确、更相关的提示(少得多 token),LLM 处理将提高 25%
(40+400)/2 =220ms
生成式 AI 应用
*假设未调用其他服务时为 20ms,否则为 100ms
(20+100)/2=60ms
Redis语义缓存未命中 – 24.6ms;LLM 记忆搜索 (24.6ms) + 5 次上下文检索
(5x 0.5ms ) = 27.1ms;向量搜索 (24.6ms) + 5 次上下文检索 (5x 0.5ms ) = 27.1ms;总计 – 24.6+27.1+27.1 = 79ms
基于代理的架构假设 1/3 的 LLM 调用触发代理处理,这将触发 LLM 的应用调用以及数据检索和 LLM 调用的另一次迭代。33% x (LLM + 应用 + Redis)
总计35 + {220+60+79}⅔ + {220+60+79}2*⅓ = 513ms

端到端应用延迟

缓存命中和未命中的加权平均值计算如下:30% * 100ms + 70% * 513ms = 389ms