当 RAG 系统从“跑通 demo”走向“生产可用”时,最明显的变化就是模块拆分越来越细。单一“检索→生成”的简单链路,在真实需求面前很快会暴露出缺陷:用户问题可能模糊、多意图,初次检索的片段可能不够精炼,生成结果可能包含幻觉。因此,一个健壮的 RAG 流水线通常可以抽象为五个核心模块。它们各司其职,又环环相扣,共同构成了从用户提问到可信回答的完整链路。
1. 查询模块
职责:理解、规范并优化用户的原始提问,使其更适合后续检索。
输入:用户原始的自然语言问题(可能包含口语、指代不清、拼写错误)。
输出:一个或多个标准化后的查询语句(可以是多角度改写、关键词提炼或子查询)。
用户在对话框里的输入常常是“不干净”的。例如:“上个月那个改假期的文件在哪来着?”或者“退货流程”。查询模块的任务就是把这些随意、模糊的表述变得对检索系统友好。
常见策略:
- 指代消解与补全:在多轮对话中,把“它”“那个政策”替换为明确的实体名称。
- 意图分类:识别用户是要查文档、问具体数据、还是想找政策原文,后续不同意图可以走不同检索策略。
- 多路改写:用小型 LLM 或规则,把原问题改写成几个不同侧面的查询(如一句口语、一句正式书面语、一句关键词组合),分别去检索,再合并结果。
- 元数据过滤:从问题中抽取时间、产品线、文档类型等限定条件,转化成向量搜索时的元数据过滤条件。
一个非常务实的做法是,直接把“查询改写”和“意图识别”做到提示词里,调用开销很小的轻量模型(甚至同一个大模型的简短调用),几毫秒就能返回一份精炼过的检索指令。这样检索模块拿到的就不再是杂乱的原始输入,而是一组结构清晰、有针对性的查询。
2. 检索模块
职责:根据查询从知识库中快速召回最相关的文本片段或文档。
输入:查询模块输出的标准化查询(可附带元数据过滤条件)。
输出:初始候选片段列表,通常为 top‑k 个相似度最高的 chunk,并附带对应的元数据(源文件、章节等)。
检索模块是 RAG 系统的“感知层”,它的召回质量直接决定了生成答案的信息天花板。工业化实现几乎都采用混合检索,而非单一向量检索:
- 向量检索(语义匹配):把查询和文档片段分别嵌入为向量,计算余弦相似度。擅长捕捉同义改写,但对专有名词、数字不敏感。
- 关键词检索(字面匹配):例如 BM25,可以精准命中“第 12 条第 3 款”这样的精确表述。在法规、合同类场景中不可或缺。
- 混合融合:将两路召回的结果通过 RRF(倒数排名融合)或加权求和重新排序,取前 k 个去重后的片段。
真实设计考量:
- 分块策略:检索模块的效果高度依赖前期的切片质量。除固定长度切分外,越来越多的系统会混合不同粒度的切片(如“父块+子块”),检索返回子块,生成时带上父块上下文作为背景。
- 性能与成本:向量数据库的选择(Milvus、Qdrant、pgvector 等)会影响检索延迟。生产环境通常会设置并发检索、缓存高频查询,以降低延迟。
检索模块的产出仍是一个“毛坯”结果。这些片段虽然表面相关,但可能存在噪音、重复、与问题精准度不高等问题,需要下一步精细加工。
3. 重排模块
职责:对检索出的候选片段进行精细化排序,筛除低相关项,提升最终送入生成模型的材料质量。
输入:检索模块输出的候选片段列表(通常 20~30 条)及原始问题。
输出:经过精排和过滤后,保留的最优片段列表(通常 5~10 条)。
为什么必须要有重排?因为向量相似度和关键词分数只是“粗筛”指标。一个片段和查询向量距离很近,可能是因为共享了高频词,但不一定真正回答了问题。重排通过让模型直接判断问题与片段的相关性,来校准排序。
典型实现:
- 交叉编码器重排:使用一个专门的排序模型(如 bge‑reranker、Cohere rerank),将问题与每个片段拼接后输入,输出一个精确的相关性分数。这一步虽比向量检索慢,但精度高,因此只对少量候选集操作。
- LLM 重排:在候选集数量可控时,也可以调用大语言模型,要求它对片段的相关性打分并排序,甚至给出取舍理由。
- 规则性后处理:例如强制保留包含某些关键词(如条款号)的片段,或剔除带有“广告”“招聘”等非目标内容的片段。
真实场景中,重排模块往往能带来检索质量最明显的提升。很多 RAG 优化经验都表明:与其费力调整嵌入模型,不如加一个重排步骤,性价比极高。经过重排后,送入生成模型的上下文既精炼又高度相关,直接从输入侧抑制了幻觉的产生。
4. 生成模块
职责:基于重排后的上下文片段与用户问题,生成流畅、准确且可溯源的最终回答。
输入:重排后的高质量片段、原始用户问题(或改写后的查询)、提示词模板。
输出:最终回复文本,可选择性地附上引用来源。
生成模块是对用户可见的最终输出端,它的设计核心不再是“能不能生成”,而是“如何约束生成行为”。
关键设计要点:
- 提示词构建:将片段按顺序编号,并附上每条片段的来源信息(如文件名、章节),在提示词中明确要求:“仅使用以上材料回答;若信息不足,请告知用户未找到;回答时请在对应位置引用材料编号。”
- 引用要求固化:在系统 prompt 中设定统一的引用格式(如
【来源1】),使前端可以解析为可点击链接,增强可信度。 - 流式与非流式:需支持流式输出以改善用户体验,但要注意流式场景下引用的延迟标记问题。
- 兜底策略:当所有片段相关性得分低于某个阈值时,生成模块应直接触发预设的“无法回答”回复,而非激活模型自由发挥。
模型选择:生成模块通常调用能力最强的通用大模型(如 GPT‑4、Claude 3.5、通义千问等)。但如果领域术语极强,也可能使用经过特定指令微调的小模型,以降低延迟和成本。无论选择哪条,生成模块都不再是“孤军奋战”,而是在严格的信息边界内完成高质量的文本组织。
5. 校验模块
职责:对生成答案进行事实一致性验证和风险过滤,确保最终输出的可靠性。
输入:生成模块的原始输出、参考上下文片段、用户问题(可选)。
输出:通过校验后的最终答案,或标记为不可用并触发重新生成/兜底的信号。
即便经历了重排和严格的提示约束,大模型依然可能在生成时过度推断、错误合成信息或遗漏关键事实。校验模块是最后一道防线。
常见校验维度:
- 事实一致性检查:使用一个独立的 LLM(或相同的模型但以验证模式调用),输入“参考材料”和“生成回答”,要求判断回答中的每一条主张是否可以被上下文片段支持。如果不支持,则标记为“事实矛盾”或“无根据”。
- 敏感信息过滤:检测回复中是否包含 PII、内部机密或不当内容。可以使用正则表达式加关键短语黑名单(必须精确匹配专有词),再辅以内容安全模型。
- 引用合规性:验证回答中声称引用的编号是否确实对应到输入的片段,以及这些片段是否真实存在。这可以自动化完成。
- 幻觉兜底:如果校验模块判定回答整体可靠性低于某个阈值,系统可以自动隐藏该回答,向用户返回“当前无法提供准确回答,请稍后重试或联系人工”。
务实做法:校验模块不一定要很重。很多生产系统仅用一个小模型做“是否基于给定上下文”的二元判别,再配合一套规则,就显著降低了外发风险。对于强合规场景,甚至可以加入人工审核步骤,将低置信度的回答送入审核队列,由人工确认后再发送。
模块串流:一张图看清运行流
用户原始问题
↓
[查询模块] → 改写、拆分、过滤
↓
[检索模块] → 向量+关键词混合召回 top‑N
↓
[重排模块] → 交叉编码器/LLM 精排 top‑K
↓
[生成模块] → 基于上下文生成回答+引用
↓
[校验模块] → 事实检查、敏感信息过滤
↓
最终回复(或兜底应答)
这套五模块抽象并不是僵化的教条,而是实践中提炼出的弹性框架。不同系统可以根据需求增减:简单场景可能省略重排甚至校验;高要求场景可能将校验扩展为多步验证。但核心思路不变:通过模块解耦,把最容易出错的环节拆开,逐级提升信息密度和可信度,最终交付一个经得起推敲、让用户真正信任的答案。