跳转至

第 16 章:RAG 从原理到项目

1. 本章要解决的问题

上一章我们已经把 RAG 里最重要的一半讲清楚了:

  • 什么是 embedding
  • 为什么语义检索比纯关键词检索更适合很多知识问答场景
  • chunk、metadata、向量库、reranking 分别在系统里扮演什么角色

但如果你真的开始做一个“能回答私有知识问题”的系统,很快会发现:

光把相关片段检索出来,还不等于问题已经被解决。

因为真正的用户需求通常不是:

请返回三段和问题相似的文本。

而是:

请基于课程资料,回答这个问题,并说明依据。

这中间还差了关键的一步:

怎样把“检索到的外部知识”正确地喂给大模型,让它基于证据生成回答,而不是脱离上下文自由发挥。

这就是 RAG 要解决的核心问题。

RAG 的全称是 Retrieval-Augmented Generation,通常翻译成:

检索增强生成。

这个名字其实已经把思路说得很清楚了:

  • Retrieval:先从外部知识源中找相关信息
  • Augmented:把这些信息补充进当前上下文
  • Generation:再让大模型基于这些信息生成回答

从全书结构上看,这一章承接第 15 章,又为第 17 章做准备:

  • 第 15 章解决“如何找知识”
  • 本章解决“如何把找回来的知识变成回答”
  • 第 17 章再进一步讨论“当模型不只是查知识,而是要主动调用工具、规划步骤时,该怎么做”

如果说上一章回答的是:

我们怎样把知识库做成一个能检索的系统。

那么这一章要回答的就是:

我们怎样把检索系统和大模型拼接起来,做成一个真正可用、可解释、可展示的问答应用。

2. 你学完后应该会什么

  • 能解释 RAG 的基本定义,以及它和直接让模型裸答的区别
  • 能描述一个标准 RAG 流程:索引构建、查询改写、召回、重排、上下文构造、答案生成
  • 能理解 Naive RAG、Advanced RAG、Agentic RAG 之间的大致差异
  • 能说清为什么 RAG 能缓解幻觉,但不能神奇消灭幻觉
  • 能分析 chunking、top-k、prompt、citation、reranking 对最终效果的影响
  • 能设计一个最小可用的文档问答项目
  • 能从面试和工程视角解释一个 RAG 系统该怎么评估、怎么优化、怎么排查问题

3. 为什么有了大模型,还需要 RAG

很多人刚接触大模型时,最自然的疑问就是:

既然模型已经学过这么多知识,为什么还要额外做检索?

这个问题很重要,因为 RAG 不是为了“让系统看起来更复杂”,而是为了应对几个非常现实的限制。

3.1 预训练知识不是你的私有知识

大模型在预训练阶段学到的是大规模公开语料中的统计规律。
它也许知道 Transformer、梯度下降、LoRA,但它并不知道:

  • 你们公司的内部制度文档
  • 你项目里最新的 API 设计
  • 你导师上周刚发的课程资料
  • 你团队复盘会议里的结论

这些知识不在模型参数里,或者至少不可靠地存在于模型参数里。

3.2 参数里的知识很难精确追溯

即使模型碰巧知道某个事实,它通常也很难告诉你:

  • 这句话是从哪篇资料来的
  • 依据具体出自哪个段落
  • 哪个版本才是最新版本

而企业场景、学习场景、研究场景都越来越在意:

答案不仅要像对的,还要有证据。

3.3 模型会补全,但不等于会克制

大模型最大的优点之一,是它非常擅长根据上下文流畅地继续生成。
但这也意味着如果上下文不够,它很可能会:

  • 用常识补全缺失信息
  • 把相近概念混在一起
  • 在“不确定”时仍然给出看似很完整的回答

换句话说,模型的强项是生成,而 RAG 的作用是:

在生成之前,尽量把“该参考的外部证据”放到它面前。

3.4 更新知识比重新训练便宜得多

如果一个系统的知识每天都在变化,你几乎不可能每次知识更新都重新微调模型。
但如果走 RAG 路线,你只需要:

  1. 更新文档
  2. 重新切块和建索引
  3. 让检索在查询时拿到最新内容

这样知识更新和模型训练就被解耦了。

这也是为什么很多落地系统里,RAG 的优先级常常高于“继续调模型”。

4. RAG 的核心思想到底是什么

最简化地说,RAG 的工作流可以概括成一句话:

先找资料,再回答问题。

但如果只记住这句口号,还是太粗。
更准确的理解应该是:

RAG 把“知识访问”从模型参数内部,部分转移到了推理时的外部上下文。

也就是说,系统不再完全依赖“模型脑子里记住了什么”,而是在提问时动态去查:

  • 当前问题相关的知识片段是什么
  • 哪些证据最值得放进上下文
  • 模型应该基于哪些资料作答

这个变化非常重要,因为它改变了系统的能力边界。

4.1 裸模型回答

如果没有 RAG,流程大致是:

  1. 用户提问
  2. 问题直接进入大模型
  3. 模型根据参数记忆和当前 prompt 生成回答

这种方式的优点是简单,但缺点也明显:

  • 无法访问外部私有知识
  • 回答依据不可追踪
  • 对时效性和版本敏感信息不稳

4.2 加上 RAG 之后

加入 RAG 之后,流程变成:

  1. 用户提问
  2. 系统先去知识库里找相关 chunk
  3. 把这些 chunk 组织成上下文
  4. 再把“问题 + 检索上下文”一起交给大模型
  5. 模型基于这些证据生成回答

因此 RAG 的本质不是“换了一个更强的模型”,而是:

给模型加了一条访问外部知识的路径。

5. 一个标准 RAG 系统长什么样

把它展开看,一个相对标准的 RAG 系统通常包含两条链路:

  • 离线索引链路
  • 在线问答链路

5.1 离线索引链路

这条链路主要负责“把知识准备好”,常见步骤是:

  1. 收集原始文档
  2. 清洗文本
  3. 按合适策略切 chunk
  4. 生成每个 chunk 的 embedding
  5. 写入向量库或检索引擎
  6. 存储 metadata,便于过滤和引用

这一部分和上一章关系最紧密,本质上是在回答:

知识库怎样被做成一个可检索对象。

5.2 在线问答链路

这条链路主要负责“当用户发问时怎样回答”,常见步骤是:

  1. 接收用户 query
  2. 必要时对 query 做改写或扩展
  3. 召回 top-k 候选 chunk
  4. 对候选做 reranking
  5. 选择最终上下文
  6. 构造 prompt
  7. 调用大模型生成答案
  8. 返回答案和引用来源

这条链路决定了用户的实际体验。

5.3 用一张流程图先建立全局感

原始文档
文档清洗 / 切块 / metadata
embedding 编码
向量库 / 检索引擎

用户问题
query embedding / query rewrite
召回 top-k
rerank
构造 prompt(问题 + 上下文 + 约束)
LLM 生成答案
返回回答 + citation

当你以后分析任何一个 RAG 系统时,都可以先问:

  • 它的索引链路是怎么做的
  • 它的在线链路是怎么做的
  • 它的问题更可能出在哪一段

6. 最小 RAG 示例:它到底比纯检索多了什么

假设知识库里有三段文本:

Chunk A: LoRA 通过低秩矩阵近似更新权重,从而减少可训练参数量。
Chunk B: QLoRA 在低比特量化基座模型的同时训练 LoRA 适配器,以降低显存占用。
Chunk C: 全参数微调会更新模型中几乎所有参数,因此成本通常更高。

用户问题是:

为什么 QLoRA 比全参数微调更省资源?

6.1 如果只有检索

系统可能返回:

  • Chunk B
  • Chunk C
  • Chunk A

这一步其实只完成了:

找证据。

6.2 如果做 RAG

系统会把这些证据组织进 prompt,例如:

你是一个课程助教,请严格依据给定资料回答。

问题:
为什么 QLoRA 比全参数微调更省资源?

参考资料:
[1] QLoRA 在低比特量化基座模型的同时训练 LoRA 适配器,以降低显存占用。
[2] 全参数微调会更新模型中几乎所有参数,因此成本通常更高。
[3] LoRA 通过低秩矩阵近似更新权重,从而减少可训练参数量。

要求:
1. 只基于参考资料作答
2. 如果资料不足,请明确说明
3. 回答尽量简洁

然后模型输出:

QLoRA 更省资源,主要因为它不会像全参数微调那样更新整个模型,而是在量化后的基座模型上训练较小的 LoRA 适配器,因此显存和训练成本都更低。[1][2][3]

所以纯检索和 RAG 的差异,不只是“有没有向量库”,而是:

  • 检索负责找材料
  • RAG 负责把材料变成回答

7. RAG 不等于“把 top-k 原样塞进 prompt”

这是一个非常常见的误解。

很多入门实现会写成:

  1. 检索 top-k
  2. 拼接文本
  3. 直接调用模型

这当然是一个可以跑起来的 baseline,但距离“好用”还差不少。
因为真正影响效果的,往往不只是有没有检索,而是下面这些细节。

7.1 检索到的内容不一定都该放进去

如果把 top-k 全部无脑拼进去,可能出现:

  • 冗余上下文太多
  • 相互矛盾的片段同时出现
  • 真正关键的证据被淹没
  • prompt 太长,成本太高

所以“召回结果”不等于“最终上下文”。

7.2 模型需要明确的回答边界

如果 prompt 没有约束,模型即使看到了资料,也可能:

  • 只部分参考资料
  • 用自己已有常识补全
  • 混合资料信息和参数记忆

因此 prompt 里通常要明确写出:

  • 只根据参考资料回答
  • 资料不足时要承认不知道
  • 尽量给出处

7.3 证据组织方式会影响生成质量

同样的三段资料,按不同顺序、不同格式、是否标号、是否附标题,都会影响模型使用它们的方式。

所以 RAG 不是单点技术,而是一个系统工程。

8. RAG 的常见分层:Naive、Advanced、Agentic

为了建立学习路径,我们可以先把 RAG 粗略分成三层。

8.1 Naive RAG

最基础的版本通常是:

  1. 文档切块
  2. 向量化
  3. top-k 检索
  4. 拼接上下文
  5. LLM 作答

它的优点是:

  • 容易实现
  • 很适合教学和原型
  • 足够展示你理解了基本流程

它的缺点是:

  • 检索不稳时,答案也会直接变差
  • 缺少 query rewrite、rerank、过滤等增强步骤
  • 对复杂问题、多跳问题支持较弱

8.2 Advanced RAG

进一步做工程优化后,系统会加入:

  • hybrid retrieval
  • metadata filter
  • reranker
  • query rewrite
  • chunk compression
  • citation
  • answer validation

这个阶段的重点是:

让系统从“能跑”走向“更稳、更准、更可解释”。

8.3 Agentic RAG

再往后,当问题本身更复杂时,系统可能不再是“一次检索,一次回答”,而是:

  • 先判断是否需要检索
  • 再决定查哪个知识源
  • 视情况多轮检索
  • 比较不同来源
  • 必要时继续调用其他工具

这就开始接近第 17 章要讲的 Agent 与 Tool Calling 了。

所以一个很自然的理解路径是:

  • 第 15 章:先学会检索
  • 第 16 章:学会把检索接进生成
  • 第 17 章:再学会把“检索”作为工具纳入更复杂的决策流程

9. 索引构建:知识库准备阶段要做什么

RAG 的很多效果问题,其实在用户提问之前就已经埋下了。
因为如果知识准备得不好,后面检索和生成再精细也救不回来。

9.1 文档加载

首先你要处理的往往不是“纯净文本”,而是各种原始文件:

  • PDF
  • Markdown
  • HTML
  • Word
  • PPT
  • FAQ 表格
  • 数据库导出的富文本

这一层的目标不是立即建索引,而是先尽量提取出干净、结构化、可切分的内容。

9.2 文本清洗

常见清洗内容包括:

  • 去掉重复页眉页脚
  • 去除无意义分页符
  • 处理 OCR 噪声
  • 清理导航栏、版权信息、广告块
  • 保留标题层级和段落边界

为什么这一步重要?
因为 embedding 编码的不是“知识本体”,而是你喂进去的文本。
脏数据越多,向量空间里的噪声就越多。

9.3 切块策略

这一部分和上一章高度衔接。
这里再强调一遍:

chunking 决定了检索的最小知识粒度。

常见策略包括:

  • 固定长度切分
  • 滑动窗口切分
  • 按标题与段落切分
  • 按问答单元切分
  • 对代码块、表格、列表做特殊处理

如果文档结构很清晰,通常结构化切块比纯固定长度切块更好。
因为用户的问题往往也天然对齐到某个标题、小节、步骤或定义。

9.4 metadata 设计

metadata 常常决定你后面能不能做这些事情:

  • 限定某课程、某项目、某产品线
  • 只查最新版本
  • 给回答附出处
  • 做权限过滤
  • 做多知识源融合

一个好的 chunk 往往不只是文本,还要包含诸如:

  • doc_id
  • title
  • section
  • source
  • updated_at
  • permission_tag

9.5 建索引不是一次性动作

很多初学者把“建向量库”理解成一次性预处理。
但真实系统里,知识库往往会变化:

  • 文档新增
  • 文档删除
  • 文档改版
  • 权限变更

所以你还要考虑:

  • 增量更新
  • 去重
  • 版本控制
  • 失效数据清理

10. 在线查询:用户提问后系统经历了什么

在线链路是用户真正感受到“聪不聪明”的地方。

10.1 Query 理解

用户的原始问题不一定适合直接拿去检索。
例如:

它为什么后来没继续用?

这种问题在多轮对话里是有指代的。
如果直接拿去 embedding,效果通常很差。

所以系统常常需要先做 query understanding,例如:

  • 结合对话历史补全指代
  • 把口语化问题改写成检索友好的问题
  • 提取关键词、时间、实体、过滤条件

例如把:

它为什么后来没继续用?

改写成:

为什么项目组在最终实验报告中没有继续采用混合检索方案?

这一步往往能显著提升检索质量。

10.2 Recall:先把候选找出来

接着系统会做第一阶段召回。
常见做法包括:

  • dense retrieval
  • BM25
  • hybrid retrieval

此时目标通常是:

先别漏掉可能相关的证据。

所以这一阶段更偏召回导向,而不一定追求最终排序绝对最准。

10.3 Rerank:把最值得看的放前面

召回一批候选之后,系统再做精排。
这一阶段会更关心:

  • 哪几段最直接回答问题
  • 哪几段信息最完整
  • 哪几段最适合作为引用证据

很多“回答看起来差一点点”的问题,其实不在生成,而在于第一条证据没排到最前面。

10.4 Context Assembly:构造最终上下文

到了这里,系统才会真正决定:

  • 选哪些 chunk
  • 按什么顺序放
  • 要不要去重
  • 要不要压缩
  • 要不要带标题和来源

这一步非常像“给模型准备参考资料包”。
准备得好,模型就容易答得准;准备得乱,模型就容易被误导。

10.5 Generation:基于上下文生成答案

最后,大模型才登场。

这一步它要做的,不只是复述检索结果,而是:

  • 整合多段证据
  • 用自然语言回答用户问题
  • 在必要时承认信息不足
  • 尽量把答案和证据绑定起来

所以一个好用的 RAG 系统,本质上不是“让模型更会说”,而是:

让模型在正确资料约束下,做更稳的表达。

11. Prompt Construction:上下文怎么喂,差别很大

RAG 的 prompt 往往至少包含三部分:

  • system instruction
  • user question
  • retrieved context

但光有这三部分还不够,关键在于如何组织。

11.1 一个常见模板

你是一个知识库问答助手。请严格依据给定参考资料回答问题。

如果参考资料不足以回答,请明确说“资料不足,无法确定”。
不要编造资料中没有的信息。

问题:
{question}

参考资料:
{contexts}

请输出:
1. 简洁答案
2. 如可行,附上引用编号

这个模板看起来很简单,但已经包含了几个关键约束:

  • 指定角色
  • 限定依据来源
  • 明确不知道时怎么办
  • 规定输出形式

11.2 为什么“资料不足时请明确说明”很关键

因为如果你不写这句话,模型很容易默认任务目标是:

无论如何都给出一个看起来像答案的答案。

而很多业务场景更需要的是:

宁可保守,也不要瞎编。

11.3 为什么 chunk 最好带编号

给上下文编号有两个好处:

  • 模型更容易在回答里引用
  • 你更容易调试它到底用了哪段证据

例如:

[1] ...
[2] ...
[3] ...

通常比一大段无标识文本更好分析。

11.4 是否要把来源信息也放进去

这通常是值得的。
例如每段上下文都附上:

  • 文档标题
  • 章节名
  • URL 或文件名

这样模型更容易生成可追溯回答,用户也更容易建立信任。

12. Citation:为什么“附出处”会显著提升可用性

很多 RAG 演示只关注“答得像不像对的”,但真正提高可用性的,经常是 citation。

12.1 citation 的直接价值

它能让用户知道:

  • 答案依据来自哪里
  • 是否愿意进一步点开原文
  • 这条信息是不是来自权威来源

12.2 citation 也能帮助你调试

如果模型回答错了,但附了引用,你可以继续判断:

  • 是检索本身错了
  • 还是检索对了,但模型理解错了
  • 或者引用和答案根本不一致

没有 citation 时,很多错误会更难定位。

12.3 citation 不代表一定真实使用了证据

这里要保持清醒:
模型即使给了引用编号,也不意味着它真的“严格忠实地使用了证据”。
它可能:

  • 引错编号
  • 把多个来源拼接错
  • 用来源做了一半依据,另一半靠脑补

所以 citation 会显著提升系统可解释性,但它不是绝对真实性保证。

13. 为什么 RAG 能缓解幻觉,但不能消灭幻觉

这是面试里很常见的一问。

最简短的回答是:

RAG 通过给模型提供外部证据,降低了“无中生有”的概率,但生成模型本身仍可能误读、误引或过度推断。

可以把幻觉来源粗分成三类。

13.1 没检到

如果真正相关的内容根本没被召回,那么模型看到的上下文就不完整。
这时它可能只能靠常识补全。

13.2 检到了,但排得不好

如果真正关键的证据被排在很后面,或者被大量弱相关片段包围,模型也可能抓错重点。

13.3 检对了,但生成时还是错了

即使上下文已经对了,模型仍可能:

  • 错误概括
  • 忽略限定条件
  • 混淆多个 chunk
  • 过度总结出上下文中没有的结论

所以你会看到一个重要工程事实:

RAG 的问题既可能是 retrieval problem,也可能是 generation problem。

14. RAG 里最常见的失败模式

学会做系统,也要学会诊断系统。

14.1 Chunk 太大

表现:

  • 召回看起来相关,但答案抓不住重点
  • 上下文很长,真正关键句被淹没

14.2 Chunk 太小

表现:

  • 单段信息不足以支撑回答
  • 需要多段拼起来才有意义

14.3 Query 没改写

表现:

  • 多轮对话里检索结果突然变差
  • 指代词、简称、口语问法很难命中

14.4 top-k 取得不合理

表现:

  • k 太小:漏掉关键证据
  • k 太大:噪声过多,prompt 被污染

14.5 检索和生成目标不一致

例如检索偏向“主题相关”,但生成任务需要的是:

  • 明确结论
  • 操作步骤
  • 最新版本说明

这时即使检索结果看起来相关,回答也可能不够可用。

14.6 知识源本身脏乱

如果原始文档重复、过时、相互矛盾,系统最终也会把这些问题暴露出来。

所以很多时候别急着怪模型,先看看知识库本身是不是健康。

15. 一个求职级 RAG 项目应该怎么设计

如果你想把这一章真正沉淀成项目,最推荐的是做一个:

课程资料 / 技术文档 / 项目文档问答助手。

原因很简单:

  • 数据容易获取
  • 问题场景真实
  • 你能解释业务价值
  • 结构上足够完整,适合面试展示

15.1 项目目标

例如你可以这样定义:

构建一个基于课程讲义、作业说明和实验报告的问答助手,支持学生通过自然语言提问,并返回带引用的回答。

15.2 最小系统模块

一个最小项目通常包括:

  1. 文档解析模块
  2. chunking 与索引模块
  3. 检索模块
  4. RAG 生成模块
  5. Web 界面或命令行界面
  6. 简单评估脚本

15.3 技术选型可以很朴素

入门项目完全没必要一上来就追求最复杂栈。
例如:

  • 文档处理:Markdown / PDF loader
  • embedding:任一稳定文本 embedding 模型
  • 向量库:FAISS / Chroma
  • 生成模型:可调用的大语言模型 API
  • 前端:StreamlitGradio 或简洁 Web 页面

重点不是“工具多高级”,而是你能否把链路讲明白。

15.4 面试官最想听到什么

通常不是“我用了某某框架一键搭建”,而是:

  • 为什么这样切 chunk
  • 为什么 top-k 取这个值
  • 是否加了 rerank
  • 如何减少幻觉
  • 如何做 citation
  • 如何评估检索和回答质量
  • 你遇到过哪些失败案例,怎么改

也就是说,项目价值不在壳子,而在你是否真正理解系统机制。

16. 一个项目实现的最小伪代码

下面给一个足够表达思路的伪代码:

docs = load_documents(data_dir)
chunks = split_documents(docs, chunk_size=500, overlap=100)

records = []
for chunk in chunks:
    vec = embed_text(chunk.text)
    records.append({
        "text": chunk.text,
        "embedding": vec,
        "metadata": chunk.metadata,
    })

vector_store.add(records)


def answer_question(question, chat_history=None):
    rewritten_query = rewrite_query_if_needed(question, chat_history)

    candidates = vector_store.retrieve(
        query=rewritten_query,
        top_k=10,
        filters=None,
    )

    reranked = rerank(question, candidates)
    selected_contexts = select_top_contexts(reranked, n=4)

    prompt = build_prompt(
        question=question,
        contexts=selected_contexts,
        instruction="只依据参考资料回答,资料不足时明确说明"
    )

    answer = llm_generate(prompt)
    return answer, selected_contexts

这个伪代码虽然简单,但已经把核心链路表达出来了:

  • 离线建索引
  • 在线检索
  • 精排
  • prompt 构造
  • 生成回答

17. RAG 系统该怎么评估

这是很多项目最容易缺失的一部分。
如果你只能展示几个看起来不错的 demo,对方很难判断系统到底稳不稳。

17.1 先分开评估检索和生成

一个很重要的原则是:

不要把所有问题都堆到“最终回答好不好”上。

因为回答差,可能是检索错,也可能是生成错。
所以最好拆成两层。

17.2 检索侧常见问题

你可以问:

  • 正确证据是否出现在 top-k 中
  • 最关键证据排在第几位
  • query rewrite 是否提高了召回
  • rerank 是否改善了最终顺序

简单来说,就是看:

该找回来的,系统有没有找回来。

17.3 生成侧常见问题

你可以继续问:

  • 回答是否忠于证据
  • 回答是否覆盖了问题重点
  • 回答是否过度脑补
  • 是否给出了清晰引用

简单来说,就是看:

在证据已经给到的情况下,模型有没有好好作答。

17.4 入门阶段怎么做最小评估

如果你现在还不想引入复杂评测框架,也可以先做一个小规模人工评估集:

  1. 自己准备 20 到 50 个问题
  2. 为每个问题标注期望证据文档或关键 chunk
  3. 记录系统是否召回正确
  4. 再人工打分答案质量

这已经足够帮助你做第一轮系统优化。

18. 常见优化方向

当一个 Naive RAG 已经能跑后,后续优化通常集中在下面几类。

18.1 优化检索

  • 调整 chunk size 和 overlap
  • 更换 embedding 模型
  • 引入 hybrid retrieval
  • 增加 metadata filter

18.2 优化排序

  • 增加 reranker
  • 针对特定业务规则做重排
  • 根据问题类型动态选择上下文数量

18.3 优化 prompt

  • 强化“只依据资料回答”的约束
  • 优化引用格式
  • 明确回答结构
  • 引导模型在资料不足时拒答

18.4 优化知识源

  • 清理脏数据
  • 合并重复文档
  • 处理过时版本
  • 补齐缺失资料

很多团队做了一圈之后会发现:

最有效的优化不一定来自更贵的模型,反而常常来自更干净的知识库和更合理的检索链路。

19. 面试里怎么讲 RAG

如果面试官问你“介绍一下 RAG”,你可以按下面这个逻辑回答:

19.1 先讲定义

RAG 是 Retrieval-Augmented Generation,也就是在生成前先从外部知识库检索相关内容,再把这些内容作为上下文交给大模型回答。

19.2 再讲它解决什么问题

它主要解决:

  • 模型不了解私有知识
  • 参数知识不可追溯
  • 纯生成容易幻觉
  • 知识更新不方便

19.3 再讲一个标准流程

你可以顺着说:

  1. 文档清洗和切块
  2. embedding 建索引
  3. query 检索
  4. rerank
  5. prompt 拼接
  6. 生成带引用答案

19.4 最后讲工程难点

真正能体现理解深度的,往往是这些点:

  • chunk 怎么切
  • 检索怎么评估
  • top-k 怎么选
  • 为什么需要 rerank
  • 怎样减少 hallucination
  • citation 有什么价值和局限

这几件事能讲清楚,通常就已经不是“只会背概念”的水平了。

20. 本章小结

这一章我们把上一章的检索基础,真正接成了一个完整的问答系统思路。

你应该已经建立起这样的整体认识:

  • RAG 不是单独一个模型,而是一条系统链路
  • 它把“外部知识检索”和“语言生成”结合在一起
  • 它能显著提升私有知识问答、课程资料问答、企业知识库问答的可用性
  • 但它的效果取决于知识准备、检索质量、上下文组织和生成约束的共同作用

如果把第 15 章和本章合起来看,你现在已经具备了构建一个最小知识问答系统的核心认知:

  • 第 15 章教你如何把知识变成可检索对象
  • 本章教你如何把检索结果变成可用回答

下一章我们会继续往前走一步。

因为当系统面对的任务不再只是:

“查资料,然后回答。”

而变成:

“根据任务需要,决定是否查资料、是否调用工具、是否分步骤行动。”

这时你需要的就不只是 RAG,而是更广义的:

Agent 与 Tool Calling。

21. 练习题

  1. 用自己的话解释:RAG 为什么能提升私有知识问答效果,但不能彻底消除幻觉?
  2. 如果一个 RAG 系统总是“检索到相关主题,但答不到问题点上”,你会优先排查哪些环节?
  3. chunk size 太大和太小,各自会带来什么问题?
  4. 为什么 citation 对用户体验和系统调试都很重要?
  5. 请你设计一个课程资料问答助手的最小系统结构,并说明每个模块的职责。

22. 面试题

  1. 什么是 RAG?它和纯 prompt 问答有什么区别?
  2. RAG 的标准流程有哪些?
  3. 为什么说 RAG 的问题既可能出在检索,也可能出在生成?
  4. reranking 在 RAG 中起什么作用?
  5. query rewrite、chunking、top-k、citation 分别会如何影响效果?
  6. 如果用户问的是一个多轮上下文相关问题,你会如何改进检索?
  7. 如果知识库经常更新,为什么 RAG 往往比继续微调更合适?