设计机器学习应用系统设计机器学习应用系统
首页
讨论区
首页
讨论区
  • 目录
  • 前言

    • 关于作者
    • 关于本文档
  • 机器学习数学基础

    • 线性代数

      • 向量基础
      • 矩阵基础
    • 微积分

      • 极限、导数与微分
      • 多元函数与复合函数求导
    • 统计与概率

      • 概率基础
      • 统计推断
  • 经典统计学习方法

    • 线性模型

      • 线性回归
      • 逻辑回归
      • 正则化与广义线性模型
    • 贝叶斯方法

      • 朴素贝叶斯
      • 贝叶斯网络
      • EM 算法
    • 支持向量机

      • 支持向量机
      • 核技巧
    • 决策树与集成

      • 决策树
      • 随机森林
      • 提升方法
    • 无监督学习

      • 聚类
      • 降维
  • 神经网络与深度学习

    • 神经网络结构

      • 神经网络基础原理
      • 线性感知机
      • 多层感知机
      • 前向传播
      • 反向传播
      • 激活函数与损失函数
    • 优化神经网络

      • 梯度下降
      • 自适应优化器
    • 深层网络稳定性

      • 权重初始化
      • Dropout 正则化
      • 批归一化
    • 卷积神经网络

      • CNN 基础原理
      • AlexNet 与 CNN 复兴
      • VGG 与 GoogLeNet
      • ResNet 残差网络
      • 工程实训:AlexNet 图像分类实验
    • 生成式模型

      • 变分自编码器
      • 生成式对抗网络
      • 工程实训:DCGAN 图像生成实验
    • 序列模型

      • 词嵌入与表示学习
      • RNN 基础原理
      • LSTM 与 GRU 门控机制
      • Seq2Seq 序列映射
      • 工程实训:LSTM 古诗词生成实验
  • 语言模型的奇点

    • Transformer 架构

      • Transformer 基础原理
      • Transformer 演进与变体
      • 语言模型与分词
      • 工程实训:Transformer 模型训练实验
    • 预训练与微调

      • 预训练数据工程
      • 缩放定律
      • 分布式训练基础设施
      • 监督微调
      • 工程实训:SFT 模型对话实验
    • 对齐训练

      • 人类反馈强化学习
      • 对齐方法的演进
      • 工程实训:DPO 对齐训练实验
    • 推理能力

      • 思维链与推理模型
      • 推理缩放定律
      • 推理效率优化
      • 工程实训:LLM 推理效率优化实验
    • 模态融合与安全

      • 多模态大模型
      • 模型评估与安全
      • 工程实训:视觉语言模型训练实验
  • AI 基础设施与工程化

    • 模型服务化

      • 推理服务架构
      • 请求调度与批处理
      • GPU 资源管理
      • 工程实训:部署 LLM 推理服务
    • 工程化实践

      • 数据版本管理
      • 实验追踪与模型管理
      • 自动化调参
      • 模型性能监控
      • 漂移检测
  • Agentic 应用系统

    • 向量检索与增强生成

      • 嵌入与向量检索
      • 检索质量评估与优化
      • 检索增强生成
      • 工程实训:构建知识库问答系统
    • 构建 Agent 应用

      • 从 LLM 到 Agent
      • 工具调用

      • 规划与推理

      • 记忆系统

      • 协作与通讯

      • 编排与容错

      • 工程实训:构建自主 Agent

      • 工程实训:构建多智能体协作系统

  • 附录

    • 构建沙箱环境
    • Numpy 数学实践

      • 数据处理实践
      • 微积分计算实践
      • 概率统计实践

检索增强生成

2020 年,Facebook AI 研究院的帕特里克·刘易斯(Patrick Lewis)和伊桑·佩雷斯(Ethan Perez)在 NeurIPS 上发表了题为《Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks》的论文,将检索增强生成(Retrieval-Augmented Generation,RAG)作为一个完整的端到端框架提出。该框架让语言模型在回答问题之前先去外部知识库中查找相关资料,然后像人类查阅文献后撰写综述那样,基于检索到的素材生成答案。

前两章的内容覆盖了嵌入模型从 Word2Vec 到 BGE 的演进、IVF、HNSW、PQ 几种向量索引的工作机制、BM25 与混合检索的设计原理,以及召回率、精确率、NDCG 等评估指标和初次检索加重排序的两阶段架构。这些都是构成 RAG 系统的组件。本章的任务是将这些组件串联起来,搭建出从查询进入系统到最终生成回答的完整工作流,并介绍查询改写、迭代检索、Self-RAG 等让 RAG 系统从能用走向好用的高级模式。

基础 RAG 流程

一个完整的 RAG 系统由检索、注入、生成三个基本阶段组成。用户查询到达后,系统先用嵌入模型将查询文本编码为向量,在预先建好的向量索引中检索 Top-K 篇最相关的文档片段。这一步在嵌入与向量检索中有详细的展开,涵盖了从文本嵌入生成到近似索引搜索的完整链路。检索完成后,系统将这些文档片段按照一定格式拼接到提示词中,形成增强后的上下文。最后,语言模型基于这个增强提示词生成最终回答。这套基础 RAG 流程下,一个典型的提示词模板如下所示:

基于以下参考资料回答问题。如果无法从资料中找到答案,请说明"根据现有资料无法回答"。

参考资料:
{context}

问题:{query}
回答:

这个模板明确要求模型优先使用检索到的内容,基于检索结果生成是 RAG 与纯模型生成的根本区别。模板也设置了检索失败后的兜底策略,当检索结果中确实没有相关信息时要求模型诚实反馈,而非自行推断,更不能强行编造。模版将资料放在问题之前,是利用了 LLM 对上下文开头部分更敏感的特性来提升生成质量。

RAG 的三阶段基础流程在简单问答场景中效果不错,但面对复杂问题时经常力不从心。瓶颈可能出在查询端。用户的原始查询往往过于简短或措辞不够精确,譬如输入"RAG 怎么做",实际想问的却是"如何在现有的 Python Web 应用中集成 RAG 功能"。查询表达不充分,单次检索就很容易遗漏关键信息。即便查询本身足够清晰,检索端的 Top-K 数量取值也是一个两难选择。K 太小可能遗漏关键文档(检索不足),K 太大则引入噪声干扰模型的判断(检索噪声)。到了生成阶段,当多篇检索结果包含矛盾信息时,模型还需要面对以哪个来源为准的判断难题。从查询表达到检索粒度再到信息来源冲突,这些现实困难催生了 RAG 系统的一系列改进模式,本章将逐一展开介绍。

查询改写与扩展

RAG 的基础流程假设用户的查询本身就足以表达检索意图,现实中这个假设经常不成立。用户可能口语化描述一个专业问题("那个做图片很厉害的 AI 是什么"),而知识库中的文档用的是正式术语("扩散模型"、"Stable Diffusion")。查询中的词汇与文档中的词汇不匹配,检索系统就很难找到正确的内容。查询改写的目的是在检索之前先对用户的查询做预处理,弥合这个语义差异。

多查询策略(Multi-Query)是最早出现的查询改写策略。它先驱使 LLM 从一个原始查询生成多个不同角度的子查询,再用每个子查询进行独立检索,最后合并去重得到综合结果。假设用户查询 "Transformer 的位置编码",LLM 可能生成 "Transformer 中正弦位置编码的原理"、"可学习位置编码与正弦编码的区别"、"相对位置编码在 Transformer 中的应用"等变体。从不同角度检索到的文档相互补充,召回率通常显著高于单查询检索。

假设性文档嵌入(Hypothetical Document Embedding,HyDE)走了一条更有创意的查询改写路线。2022 年,滑铁卢大学的论文《Precise Zero-Shot Dense Retrieval without Relevance Labels》发现让 LLM 先根据查询虚构一篇假想的答案文档,然后将这篇虚构文档的向量拿去检索真实文档,效果反而比直接用查询向量检索更好。HyDE 背后的直觉是答案文档与真实相关文档在向量空间中的距离,比简短的查询与文档之间的距离通常更加接近。查询往往是几个关键词,而文档是完整的段落,两者的语义密度不对等。LLM 生成的假想答案补全了查询中隐含的上下文,使其在语义空间中更接近目标文档。这个策略的风险在于,如果 LLM 的假想答案偏离了正确方向,譬如对专业领域的概念给出了不准确的解释,生成的向量也会把检索引导到错误的区域,结果会比直接使用原始简短查询时更差。

反过来,当查询不是过于简单,而是太过复杂,譬如一个复杂查询中包含多类混合条件时,也会显著影响结果的准确性。自查询检索(Self-Query Retrieval)处理的是同时包含语义条件和结构化条件的混合查询。以"2026 年发表的关于 Transformer 注意力机制改进的论文"为例,这个查询中 "Transformer 注意力机制改进"需要语义匹配,"2026 年"需要精确的年份过滤。纯向量检索难以处理年份条件,纯标量过滤难以处理语义匹配。自查询检索用 LLM 将查询拆解为两部分,语义部分("Transformer 注意力机制改进")交给向量索引,结构化条件("year = 2026")交给元数据过滤器,然后对两路结果取交集。LangChain 等框架中就内置了这种查询的解析和执行逻辑。

上下文注入策略

检索完成后,将文档注入提示词也不是简单的字符拼接。模型上下文窗口长度是有限的宝贵资源(虽然最新模型已支持 1M tokens 甚至更长,但更长的上下文意味着更高的延迟和成本),检索到的文档总量必须控制在模型能处理的范围内。更微妙的是,LLM 对上下文中不同位置的关注度并不均匀。"Lost in the Middle" 现象揭示了模型倾向于关注提示词开头和结尾的信息,中间部分容易被忽略。这意味着仅靠相关性排序还不够,还需要在拼接时做位置上的安排,将最相关的文档放在上下文的首尾位置,次相关的放在中间,让模型的注意力集中在最重要的信息上。

简单按检索得分降序拼接是最容易的做法,但文档之间的信息可能是重复的,也可能相互矛盾。更精细的做法是在拼接前对文档先做结构化分组。按主题将文档归类,每组添加一个概括性标题,让模型先获得全局视图再深入细节。如果检索到的文档过长,可以先对每个文档做压缩摘要再注入,用信息密度换取上下文窗口的有效利用率。当多篇文档包含矛盾信息时(譬如两篇文档分别声称同一个事件发生在 2023 年和 2024 年),在注入时标注信息来源让模型自行判断通常比提前消歧更安全,模型在理解上下文中细微信息差异方面往往优于规则系统。

上下文压缩(Context Compression)是另一个实用的优化方向,每个用过 Vibe Coding 工具的开发人员对此都不会陌生。在 RAG 场景中,如果将 20 篇检索文档原封不动地塞进提示词,总长度可能达到数万 token,其中大量内容是过渡句、重复信息或与查询无关的细节。压缩的目标是保留每篇文档中与当前查询最相关的部分,删去无关内容。实现方式从简单的关键句提取(基于查询词与文档句子的相似度排序截取)到让 LLM 对文档做逐段摘要,精度和延迟各有取舍。上下文压缩的难点在于如何判断相关性。压缩器看到的只是单个文档,不知道其他文档是否已经包含了相同的信息,因此交叉文档的去重通常需要在压缩之后的拼接阶段单独进行处理。

迭代检索

如果一次检索就能覆盖回答所需的所有信息,这对用户和 RAG 系统设计者来说都是最简单的。像"法国的首都是什么"这样的简单事实型查询,这个假设成立。但当用户问的是"比较 Transformer 和 Mamba 在长序列建模上的设计理念和性能差异"时,单次检索很难同时覆盖 Transformer 的位置编码机制、Mamba 的状态空间模型原理以及两者的长序列建模评测数据。这种场景下就需要引入迭代检索(Iterative Retrieval)。迭代检索的思想是通过多轮检索逐步收集回答所需的信息,每轮检索可以基于前一轮的结果进行调整和聚焦。根据迭代路径的组织方式不同,迭代检索可以进一步分为链式检索、子问题分解和迭代精化三种模式。

  • 链式检索逐轮逐步推进,第一轮检索 "Transformer 长序列建模",基于检索到的文档生成初步回答。从回答中发现 Transformer 在长序列上的瓶颈主要来自自注意力机制的 O(n2)O(n^2)O(n2) 复杂度,于是第二轮检索"降低自注意力复杂度的方法",引入了稀疏注意力、线性注意力等变体。第三轮再针对比较对象检索 "Mamba 状态空间模型长序列性能"。链式检索每一轮都以前一轮的输出为锚点,检索方向逐步聚焦,适合步骤清晰、依赖关系明确的问题。

  • 子问题分解则是先将复杂问题拆解为多个独立的子问题,然后对每个子问题并行检索,最后合并所有检索结果统一生成。仍以"比较 Transformer 和 Mamba"为例,拆解结果为三个子问题:"Transformer 长序列建模机制"、"Mamba 状态空间模型机制"、"两者长序列性能基准对比"。每个子问题独立检索不受其他子问题结果的干扰,合并后模型一次性获得完整的信息全景图,避免了链式检索中前一轮错误被传递到下一轮的风险。

  • 迭代精化结合了前两种模式的优势,像链式检索一样根据已有答案定向补充信息,同时又像子问题分解一样,通过自检机制确保回答覆盖问题的各个方面。先生成初步回答,然后让 LLM 自我检查这份回答是否完整。如果发现某个方面信息不足(譬如回答中只讨论了 Transformer 而缺少 Mamba 的具体数据),LLM 生成一个补充查询去检索缺失的信息,用新结果更新回答,重复这个过程直到回答覆盖了问题的所有方面或达到迭代上限。

迭代何时终止是重要的设计决策。最简单的做法是设置固定的最大迭代轮数(通常 3 到 5 轮),可靠但不够灵活。更精细的做法是让 LLM 在每一轮判断新检索结果是否提供了增量信息。如果新一轮检索返回的文档与前几轮高度重复,说明信息已经收敛,无需继续。在延迟敏感的场景中,还可以设置总时间预算,一旦超时就用当前信息生成最终回答,确保用户体验不受影响。

Self-RAG

前面讨论的 RAG 变体都有一个共同的隐含前提:既然是检索增强生成,那 RAG 系统执行检索应该是理所当然的。但并非所有查询都需要检索。"1 加 1 等于几"这类问题模型自身就能准确回答,额外的检索不仅浪费计算资源,还可能引入无关文档干扰判断。2023 年,华盛顿大学的论文《Self-RAG: Learning to Retrieve, Generate, and Critique through Self-Reflection》中提出了 Self-RAG,让模型在生成过程中自主决定是否需要检索、检索结果是否相关、以及生成的内容是否忠实于检索文档。

Self-RAG 实现这一自主决策的机制是在模型的词表中引入四个特殊的反思标记(Reflection Token)。[Retrieve] 标记让模型判断当前查询是否需要检索,取值为 Yes、No 或 Continue,相当于模型在脑海中先自问"这个问题我靠自己的知识能回答吗"。当检索执行完毕后,[ISREL] 标记判断检索到的每一篇文档是否真正与查询相关,取值为 Relevant 或 Irrelevant,不相关的文档在后续生成中会被忽略。在生成阶段,[ISSUP] 标记检查生成的每一句话是否都能在检索文档中找到支撑依据,取值为 Fully Supported、Partially Supported 或 No Support,相当于实时监控幻觉的产生。[ISUSE] 标记评估生成的回答对用户是否有实际帮助,取值为 1 到 5 的五级评分,5 表示最有用,覆盖了回答问题但没回答到点上的情况。

这四个标记构成了一套完整的自省循环。查询到达后,模型先输出 [Retrieve] 决策。如果答案是 No,直接生成回答并输出。如果答案是 Yes,执行检索后模型对每篇文档输出 [ISREL] 判断,过滤掉不相关的内容。基于相关文档生成回答后,模型输出 [ISSUP] 逐句验证忠实度,如果某一句没有文档支撑,模型可以触发重新检索或调整表述。最后输出 [ISUSE] 评估整体回答质量,不满意则重新生成。整个过程由模型自身驱动,无需外部规则干预。

Self-RAG 的训练方式是将这些反思标记视为普通 token 加入词表,在训练数据中插入正确位置的标记让模型学会何时输出它们。训练数据的构造通过 GPT-4 自动生成反思标记,然后用这些标注数据训练一个 Critic 模型,再由 Critic 模型批量标注全部训练数据,避免了人工标注的高昂成本。训练完成后模型获得了反思的元认知能力,它不仅会回答问题,还知道自己知道什么、不知道什么,以及什么时候应该去查资料。

多路召回

多路召回(Multi-Channel Retrieval)是组合多种检索策略、扩展 RAG 系统查询能力的重要手段。向量检索擅长语义泛化,但面对"产品编号 AB-12345 的技术规格"这类精确匹配需求时,仅靠嵌入向量的余弦相似度可能返回编号相近但完全不同的产品文档。BM25 等稀疏检索在精确匹配上表现优异,但又无法理解"汽车"和"轿车"之间的语义关联。不同类型的信息天然分布在不同的检索路径上,多路召回同时从多条路径检索,然后对结果进行整合。嵌入与向量检索中讨论的混合检索(稠密向量 + BM25)是多路召回最基础也是使用最广泛的形式,除此之外,RAG 系统中与多路检索密切相关的策略还有查询路由和知识图谱增强检索等。

查询路由(Query Routing)往往作为多路召回的前置决策环节来使用。不是所有查询都需要走完所有的检索路径,路由的作用是根据查询的特征将其导向最合适的路径。事实型查询("2024 年诺贝尔物理学奖得主是谁")路由到知识图谱或精确匹配索引,语义型查询("如何处理深度学习中的梯度消失")路由到向量索引,统计型查询("第三季度各产品线的营收对比")路由到 SQL 结构化查询。路由决策本身可以由 LLM 完成,将查询连同各检索路径的描述一起交给 LLM,让它判断应该走哪条路,或者同时走多条路并分配不同的权重。

图 RAG(Graph RAG)是与多路召回互补的另一种重要检索架构,它将知识图谱的结构化关系推理能力与向量检索的语义泛化能力结合起来。知识图谱中实体之间的关系(如"药物 A 治疗疾病 B"、"论文 C 引用论文 D")无法通过向量相似度直接获取,但这些关系在医学诊断、法律案例分析等场景中至关重要。图 RAG 的流程是从查询中提取实体,在知识图谱中检索这些实体的邻居节点和多跳关系路径,同时通过向量检索获取相关的非结构化文本,最后将结构化关系和非结构化文本融合后交给 LLM 生成回答。微软的 GraphRAG 项目在这个方向上做了系统性的探索,通过从原始文档中自动构建实体关系图来增强 RAG 的回答质量。

引用溯源与可信度

RAG 相比纯模型生成的一个重要优势是答案可被验证。当模型回答 "Transformer 架构发表于 2017 年"时,如果附带了引用标注指向原始文档,用户可以点击链接确认信息是否准确、是否存在断章取义。在法律文书辅助、医学文献综述等场景中,引用不仅是锦上添花的功能,还是合规性的基本要求。

引用的实现粒度有三种常见选择。全文级引用在回答段落中插入 [1]、[2] 等数字标记,文末附上编号对应的来源列表,实现简单,适合快速验证。段落级引用为每个自然段标注来源,一个段落内的所有陈述都指向同一篇文档。句子级引用粒度最细,每句话都有独立的来源标注。句子级引用实现难度最高,因为 LLM 在生成长段落时容易混淆哪句话对应哪个来源,需要额外的归因机制来追踪。

RAG 生成结果的可信度评估一般从来源的权威性和信息的一致性两个维度来展开。来源权威性取决于文档来源的可靠程度。同行评审的学术论文的权威性显然高于个人博客,官方文档显然高于社区 Wiki。实际系统中通常会维护一个来源信任等级列表,在检索时优先召回高权威来源的文档。一致性检查是多源验证的实现方式,如果三篇独立来源的文档都确认了同一个事实,这个事实的可信度就远高于只有单一来源支撑的陈述。当检索结果不足以支撑确定性回答时,模型应该主动表达不确定性的边界,譬如"根据现有资料,这个问题目前没有明确的答案,但以下是相关的讨论",这比模型为一个不确定的问题给出看似确定但可能错误的回答更有价值。

本章小结

RAG 通过检索外部知识来增强语言模型的生成能力,让模型的知识不再受训练数据截止日期的束缚,同时为回答提供了可验证的来源依据。从基础的检索 - 注入 - 生成三阶段流程出发,查询改写弥合了用户输入与文档表达之间的语义鸿沟,上下文注入策略管理着有限窗口内的信息布局,迭代检索让复杂问题可以通过多轮检索逐步收集完整信息,Self-RAG 让模型具备了是否检索、是否采信的自省能力。多路召回与融合将不同检索路径的优势叠加,引用溯源让答案从黑箱输出变为可验证的结论。结合上一章所讲的检索评估相关内容,将检索引擎、生成模型和评估流程作为一个整体来迭代,RAG 系统才能在实际应用中持续改进。

练习题

  1. 对比单查询检索与 Multi-Query 检索在复杂问题上的表现:选取 5 个需要多方面信息的查询,比较两种策略在 Top-5 检索结果的召回率差异,并分析 Multi-Query 在什么类型的查询上提升最大。

    参考答案

    对于需要从多个角度收集信息的查询(如"比较 A 和 B 的优缺点"),Multi-Query 能通过不同角度的子查询覆盖更多相关文档,召回率通常有明显提升。但对于简单事实型查询(如"某年某事件的日期"),原始查询已经足够精确,Multi-Query 可能引入噪音,反而会降低精确率。

  2. 实现迭代检索模式:对"比较 CNN 和 Vision Transformer 在图像分类任务上的设计理念和性能表现"这类复杂问题,先进行子问题分解,对每个子问题独立检索,再合并结果生成回答。对比单次检索与迭代检索在回答完整性和忠实度上的差异。

    参考答案

    子问题分解建议拆为"CNN 架构设计理念"、"Vision Transformer 架构设计理念"、"两者在 ImageNet 上的性能对比"。迭代检索的回答完整性通常显著优于单次检索,因为每个子问题都有针对性的检索结果支撑。但子问题分解的质量直接影响最终效果,分解过于细碎可能导致各子问题的检索结果之间缺少关联,回答时难以形成连贯的论述。

文章字数:6,528
更新于 2026-07-09
Star
Last Updated:
Contributors: icyfenix, Claude, Claude Opus 4.7
Prev
检索质量评估与优化
Next
工程实训:构建知识库问答系统