在前面章节中,我们详细拆解了 RAG 的基础链路:索引构建、检索、增强生成。这套流水线在原型验证和早期部署时通常呈线性串联,但随着系统走向生产环境,单一的“检索-生成”链路很快会暴露出局限性:
- 不同的查询类型需要不同的检索策略(如关键词搜索、语义搜索、混合搜索),硬编码的单一检索器难以全面兼顾。
- 知识来源多样(结构化数据库、非结构化文档、API 实时数据),每种来源的最佳访问方式不同,很难用一套逻辑统一处理。
- 生成环节可能需要额外的前后处理,例如查询改写、结果重排序、答案过滤、事实核查等,这些能力如果与核心流程紧耦合,会导致系统僵化、难以扩展。
Modular RAG(模块化检索增强生成)正是为了解决这类复杂性而提出的架构思想。它的核心主张非常直白:将 RAG 系统拆解为一系列功能独立、接口清晰的模块,每个模块可以独立开发、测试、替换和组合,从而让整个系统具备高度灵活性与持续演进的能力。
设计目标:从单体管线到可插拔组件
传统 RAG 流水线可以理解为一条固定的处理链:
用户问题 → 检索器 → 结果排序 → 上下文拼接 → LLM 生成 → 返回答案
在 Modular RAG 中,这条链被重新定义为由多个可配置的“处理节点”构成的有向图(或流程编排)。你可以根据需要插入、移除、置换节点,而不影响整体架构。例如,可以在检索前加入一个“查询分解”节点,将复杂问题拆成子问题分别检索;也可以在生成后接入一个“合规检查”节点,确保回答不包含禁止内容。
可插拔与可替换的含义:
- 可插拔:可以在现有流程的任意位置添加新功能模块,无需重写其他部分。比如某天业务要求所有回答必须过滤掉未授权的术语,只需新增一个“术语白名单过滤器”模块,将它配置在生成模块之后。
- 可替换:某个模块可以有多种实现,根据场景动态切换。例如向量检索模块可以分别对接不同的向量数据库(Milvus、Pinecone、Weaviate),或根据语言切换不同的嵌入模型。切换时只需修改模块配置,整体逻辑保持不变。
典型的模块划分
一个 Modular RAG 系统通常会包含以下几类可替换组件:
- 查询处理模块(输入层)
负责接收用户原始问题并进行预处理,可能包括:
- 查询改写(将口语化表达转为更适合检索的形式)
- 查询扩展(补充同义词、相关术语以提升召回)
- 意图分类与路由(判断问题类型,分发到不同的下游链路)
示例:用户输入“怎么退那台笔记本?”→改写为“X200 型号笔记本电脑退货流程”
- 检索适配器(检索层)
将标准化后的查询发送到一个或多个检索源,并统一返回结构化的文档片段列表。一个系统可以同时挂载:
- 向量检索器(语义相似度)
- 关键词检索器(BM25,适合精确匹配)
- 结构化查询器(SQL,用于从关系型数据库中提取数据)
- API 检索器(调用内部服务获取实时信息)
所有这些检索器都遵循统一的输入输出接口,可以在同一流程中并行或级联使用。
- 后处理与融合模块(结果处理层)
检索结果通常不能直接喂给 LLM,需要经过一系列精炼步骤:
- 重排序(Reranker):对多路召回的结果按相关度重新打分,确保最相关的片段排在最前。
- 去重与融合:合并来自不同检索源的重叠内容,控制上下文长度。
- 切片压缩:对过长片段进行摘要或截断,避免超出模型窗口。
- 生成适配器(生成层)
负责将处理后的上下文与提示模板结合,调用 LLM 并返回结果。此模块也支持替换:
- 切换不同 LLM 提供商(如从 OpenAI 迁移至本地部署的开源模型)
- 接入多个模型做答案选择或投票
- 流式与非流式输出适配
- 后生成校验与输出层
在答案返回给用户前执行最后的控制:
- 事实一致性检查(将答案与检索到的原文对比,检测编造)
- 风控/合规过滤(屏蔽敏感词、不符合公司政策的表述)
- 来源引用格式化(统一将片段元数据渲染为可读引用)
可插拔架构的实际价值
这种模块化理念并不是为了追求架构上的“完美”,而是直接回应生产环境中几个非常实际的痛点:
- 快速响应需求变化
业务团队要求“将最近三天的政策优先展示”,不需要改动整个 RAG 流程,只需在重排序模块中加入时间衰减逻辑,或在检索模块增加一个文档新鲜度过滤器。新功能可以安全上线,不影响其他部分。
- 降低技术锁定风险
向量数据库、LLM、嵌入模型都是快速演进的领域。通过统一抽象接口,当需要切换底层技术时(比如把 Milvus 换成 Qdrant,把 OpenAI 嵌入换成 BGE 模型),替换工作被局限在单个模块内,大大降低了迁移成本。
- 便于独立优化与测试
每个模块可以单独进行单元测试和性能评估。例如,可以基于同一套标注数据,分别测试不同的重排序模型,选优后即可上线替换,而无需修改上下游逻辑。
- 支持复杂业务流程编排
并非所有问题都适合最简单的“检索-生成”线性流。某些查询可能需要先查知识库,若未命中则转接人工;或先检索出摘要后再针对细节进行二次检索。模块化让这些分支逻辑可以通过简单的流程编配实现,而不用在代码里写死无数 if-else。
一个贴近实际的模块化示例
某软件公司为其运维团队搭建的 RAG 助手采用了 Modular RAG 设计:
- 查询路由模块:识别到问题是“服务器 X 的 HTTP 502 错误处理手册”时,自动路由到技术文档库检索;而“今天值班经理是谁”则直接查询值班系统 API。
- 检索模块:并行调用向量检索(找语义相似的排障文档)和关键词检索(匹配具体错误码),结果经重排序后融合。
- 生成模块:如果置信度足够高,直接生成带引用的排障步骤;置信度低时,加装一个“人工确认”节点,将草稿暂存,待工程师快速确认后发出。
- 合规过滤模块:确保回答不会泄露内部 IP 地址、数据库连接串等敏感信息。
整个系统上线后,运维主管提出新需求:所有排障步骤中如涉及重启服务,必须在最后附加一段免责声明。实现这个需求时,开发人员只是在“后生成校验”模块新增了一个简单的文本匹配规则,无需变动任何其他代码,当天即上线。
实施 Modular RAG 的务实建议
- 从最简单的线性流开始,按需拆分
不要在一开始就设计一个包含十几个模块的复杂架构。先让基础的 RAG 管道跑通并验证价值,当某个环节确实需要变体、替换或扩展时,再将其抽象为独立模块。
- 定义清晰的模块接口
每个模块只做一件事,输入输出数据结构应尽可能标准化。例如,检索模块的输出统一为 List[Document],包含文本内容和元数据;生成模块的输入统一为 (query, contexts, history)。
- 利用现有编排工具,而非从零造轮子
LangChain、LlamaIndex、Haystack 等框架都已经提供了丰富的模块抽象和流程编排能力,可以将其作为起点,根据自身需要定制特定模块。
- 为模块变更制定测试与灰度策略
由于模块可以频繁替换,务必建立对应的回归测试集,每次替换后验证端到端效果。同时,借助配置中心实现模块的灰度切换,避免全量上线意外。
Modular RAG 的实质,是把系统工程中“关注点分离”和“依赖反转”的思想引入生成式 AI 应用。它让 RAG 从一条僵硬的流水线,蜕变为一个可以随需求生长、随时优化的智能体框架。在接下来的 17.2 和 17.3 节,我们将分别介绍几种经典模块化架构模式,以及如何基于主流工具快速实现一个可插拔的 RAG 系统。