具体的架构模式对于设计大规模分布式检索增强生成(RAG)系统非常重要。设计一个大规模的分布式RAG系统需要慎重选择如何分解系统、分配数据和计算,以及管理各组件之间的协作。没有一个放之四海而皆准的方案;最佳架构很大程度上取决于具体要求,如数据量、查询吞吐量、延迟目标、更新频率和成本限制。
本节阐述了几种既定的架构模式,可用于构建可扩展、有弹性和高性能的分布式RAG系统。这些模式通常解决了整体式或简单扩展的RAG实现中发现的特定瓶颈,并且可以经常组合起来形成全面的方案。
1. 横向扩展的无状态服务(微服务)
构建可扩展应用的一个基本模式是将系统分解为一组小型、独立、无状态的服务。在RAG的背景下,这意味着将管道(查询理解、检索、重新排序、提示构建、生成、后处理)分解为单独的微服务。然后,每个服务都可以通过在负载均衡器后部署多个实例来进行横向扩展。
-
应用于RAG:
- 一个
EmbeddingService可以处理摄取和查询的文本嵌入。
- 一个
RetrievalService可以管理与向量数据库的交互并执行初始文档获取。
- 一个
ReRankingService可以应用更复杂的模型来优化搜索结果。
- 一个
GenerationService将与LLM接口以生成最终答案。
- 一个
IngestionService可以管理数据处理管道。
-
优势:
- 独立扩展性:每个组件(例如,检索、生成)都可以根据其特定负载进行扩展。如果生成是瓶颈,则可以仅扩展
GenerationService。
- 故障隔离:一个服务中的问题不太可能导致整个系统崩溃。
- 技术多样性:不同的服务可以使用最适合的技术或编程语言实现。
- 独立部署:服务可以独立更新和部署,从而加快迭代周期。
-
考量:
- 复杂性增加:管理多个服务会增加部署、监控、服务发现和跨服务通信方面的开销。
- 网络延迟:服务之间的调用会增加网络延迟。仔细的API设计和共置策略很重要。
- 分布式追踪:对于跨服务边界的调试和性能分析很重要。
RAG的典型微服务架构,其中用户请求通过负载均衡器和API网关路由到可独立扩展的检索和生成服务。
2. 用于检索的分片数据和计算
检索组件,特别是向量索引,随着文档库的增长经常成为瓶颈。分片涉及将索引(以及可能还有文档存储)划分到多个节点。每个分片都包含一部分数据,并拥有自己的计算资源来搜索其本地分区。
-
应用于RAG:
- 向量索引根据文档ID或其他标准进行分片。
- 查询路由器服务(或检索服务中的逻辑)决定查询哪些分片。这可以是分散-聚合方法(查询所有分片并合并结果)或有针对性的方法(如果元数据允许路由到特定分片)。
-
优势:
- 海量索引的可扩展性:允许索引增长远超单台机器的容量。
- 改进查询延迟:跨分片并行搜索可以减少延迟。对特定分片的定向查询可以非常快。
- 更高的吞吐量:将查询负载分配到多个节点。
-
考量:
- 分片管理:添加、移除或重新平衡分片可能很复杂。
- 分散-聚合开销:查询所有分片会引入网络开销和扇出/扇入延迟。聚合来自多个分片的结果需要严谨的逻辑。
- 数据分配策略:糟糕的分片策略可能导致热点分片(某些分片接收不成比例的更多负载)。
- 一致性:在更新期间确保跨分片一致性可能具有挑战性。
分片检索架构。一个传入的查询被路由到多个分片,每个分片搜索索引的一个分区。结果随后被聚合。
3. 摄取和嵌入的数据并行
文档的初始处理(加载、清洗、分块和嵌入生成)通常是批处理密集型工作。Apache Spark、Dask或Ray等分布式数据处理框架可用于在机器集群中并行化这些任务。
-
应用于RAG:
- 大量文档被分割成多个分区。
- 多个工作节点并行处理这些分区:每个工作节点对文档进行分块并生成嵌入。
- 生成的嵌入和处理后的文本随后被加载到分布式向量数据库和文档存储中。
-
优势:
- 摄取高吞吐量:显著加速大型数据集的处理。
- 数据量可扩展性:可以处理TB或PB级的原始文档。
- 容错性:Spark等框架为长时间运行的批处理作业提供容错性。
-
考量:
- 批处理延迟:尽管吞吐量很高,但对于非常大的批次,处理新文档的端到端延迟可能需要数分钟或数小时,具体取决于设置。此模式非常适合初始批量加载或定期大型更新。
- 资源需求:分布式处理集群可能资源密集。
- 与实时更新的集成:如果新鲜数据很重要,需要辅以接近实时的更新机制(例如,流式摄取)。
并行数据摄取和嵌入生成。大型数据集在加载到向量数据库之前,会被分配到多个工作器进行处理。
4. 分层缓存策略
缓存是提高性能和减轻后端系统负载的基本技术。在分布式RAG中,缓存可以应用于多个层面:
-
应用于RAG:
- 边缘缓存/CDN:缓存相同或非常热门查询的完整RAG响应,特别是当响应在一段时间内是静态或半静态时。
- 查询-响应缓存:缓存给定查询的最终生成响应,以查询本身(或规范表示)为键。
- 检索文档缓存:缓存经常检索的文档内容,以避免从主文档存储中重复获取。
- 嵌入缓存:如果嵌入生成计算量大或涉及外部调用,则缓存常见查询词或文档块的嵌入。
- LLM提示/响应缓存:缓存相同提示的LLM完成结果(如果上下文和LLM参数相同)。
-
优势:
- 延迟降低:从缓存提供响应或中间数据比重新计算或重新获取快得多。
- 后端系统负载降低:减少对LLM等昂贵组件或密集型数据库查询的调用。
- 成本节省:LLM API调用减少或检索计算量降低可以带来显著的成本降低。
-
考量:
- 缓存失效:这是一个难题。决定何时以及如何使过期缓存条目失效至关重要,特别是在底层数据频繁更新的情况下。
- 缓存一致性:在分布式缓存中,确保所有节点看到一致的视图可能很复杂。
- 缓存大小和淘汰策略:确定合适的缓存大小和淘汰策略(LRU、LFU等)需要仔细调整。
- 缓存命中率:缓存的有效性很大程度上取决于工作负载模式和实现良好的命中率。
RAG系统中的分层缓存。缓存在边缘、检索数据存储之前和LLM之前设置,以快速服务频繁请求并减少后端负载。
5. 使用队列的异步处理
对于不需要立即同步响应的任务,或者为了解耦服务并平滑突发工作负载,消息队列(例如,Apache Kafka、RabbitMQ、AWS SQS)非常有用。
-
应用于RAG:
- 异步摄取:新文档被提交到一个队列,工作进程按照自己的节奏拾取它们进行嵌入和索引。
- 批量RAG查询:用户提交可以离线处理的查询,结果稍后交付(例如,通过通知或回调)。
- 解耦耗时步骤:如果RAG管道的某个部分特别慢(例如,复杂的重新排序步骤或非常大的LLM生成),可以将其异步化。用户可能会获得一个初始的快速响应(可能来自更简单的模型或仅是检索),并在完整、详细的响应准备好时收到通知。
-
优势:
- 系统弹性提高:如果下游服务暂时不可用,任务会保留在队列中,稍后可以处理。
- 负载均衡:队列吸收请求高峰,防止处理服务过载。
- 服务解耦:任务的生产者和消费者不需要直接了解彼此,简化了系统演进。
- 消费者可扩展性:从队列消费的工作池可以独立扩展。
-
考量:
- 最终用户延迟增加(对于异步化的同步路径):如果一个面向用户的同步请求通过队列,它本质上会增加延迟。此模式通常更适合后台任务。
- 队列管理:监控队列深度、消息处理速率和处理死信队列会增加操作开销。
- 精确一次处理:确保消息只被精确处理一次可能很复杂,需要幂等消费者或分布式事务机制。
异步RAG处理。任务被提交到消息队列并由一个工作池处理,将请求提交与实际处理解耦。
6. LLM推理端点复制
大型语言模型(LLM)生成步骤通常是RAG系统中计算量最大且对延迟最敏感的部分。为了处理并发请求并提供高可用性,LLM推理通常通过部署在负载均衡器后的多个复制模型实例来提供服务。
-
应用于RAG:
- LLM的多个实例(例如,使用vLLM、TensorRT-LLM或Hugging Face Text Generation Inference等服务框架)被部署,通常在GPU加速硬件上。
- 负载均衡器将来自RAG系统核心逻辑的传入生成请求分配到这些LLM实例。
-
优势:
- 高可用性:如果一个LLM实例出现故障,其他实例可以继续处理请求。
- 可扩展吞吐量:更多实例可以处理更多并发生成请求。
- 优化服务:专门的LLM服务框架提供诸如连续批处理和量化等优化,以获得更好的性能。
-
考量:
- 成本:GPU价格昂贵,因此扩展LLM推理可能是主要的成本因素。高效利用(例如,通过批处理、模型量化)很重要。
- 模型一致性:如果使用多个不同的LLM模型或版本,可能需要路由逻辑来适当地引导请求。
- 冷启动:将大型模型加载到GPU内存可能需要时间。管理热实例或最小化冷启动的策略是必要的。
复制的LLM推理。RAG系统将生成请求发送到负载均衡器,负载均衡器将其分配到多个LLM服务实例,以实现可扩展性和高可用性。
模式组合
认识到这些架构模式并非相互排斥很重要。有效的大规模分布式RAG系统通常会组合使用其中几种模式。例如:
- 分片检索系统(模式2)的每个分片可能实现为横向扩展的微服务(模式1)。
- 数据摄取几乎肯定会使用数据并行(模式3),并且可能会将数据馈送到异步处理队列(模式5)进行索引。
- 所有服务都将受益于分层缓存(模式4)。
- 生成组件将始终使用复制的LLM推理端点(模式6),并且是更广泛的微服务架构(模式1)的一部分。
模式的选择和组合取决于对系统特定瓶颈、性能要求和操作限制的全面分析。接下来,我们将讨论评估这些系统的指标,这有助于指导这些架构决策并确定优化方向。