# 先修好检索，再去怪模型

关于 RAG 与 grounding（接地）的速成课。22 个概念 —— knowledge cutoff、RAG、grounding、分块、元数据、embeddings、向量检索、混合检索、重排序、精确率与召回率、引用、诚实拒答、忠实度、golden set、索引新鲜度等等 —— 每个都有英文名、一幅图、一个例子和一张卡片。核心观点：在 RAG 里，模型几乎从不是问题 —— 是你的检索出了问题。结尾附一页纸的全部概念速查表。

- **Author:** Fedor Chishchin
- **Level:** intermediate
- **Reading time:** 约 35 分钟阅读
- **Published:** 2026-06-13
- **Source:** https://fedorthinks.com/zh/learn/rag-and-grounding-express

---

## 1. RAG 为何存在

模型不了解你的数据，也不知道训练截止日期之后的任何事。RAG 就是把事实交给它、让它据此作答的办法 —— 所以先弄懂它要解决的问题，再看机制。

### 地图：七组共 22 个概念

> 一张地铁图：先看整张线路网，再一站一站地坐过去。

先是三个**基础概念** —— 为什么模型的记忆不够用、RAG 是什么、为什么 grounding 很重要。然后是六组，每章一组：**分块**、**embeddings 与检索**、**检索质量**、**grounding**、**评测**，以及**把它做好**。

之后的每个概念都是同一个结构：**英文名**（记住它 —— 这就是术语）、一个生活中的画面、一幅**图**，以及一张带字段的**卡片**：*是什么*或*问题*、*原理*或*思路*、_例子_、*注意*或*代价*，还有*关联*。

_Diagram: 上面是基础概念，下面是六个分组 —— 第 2–7 章依次讲它们。_

### Knowledge Cutoff —— 模型的记忆是冻结的

> 一位聪明的毕业生，多年前读完了整座图书馆 —— 但没读过你公司的文件，也没读过他毕业之后印刷的任何东西。

LLM 只知道训练数据里有的东西，冻结在某个截止日期 —— 也就是它的 **knowledge cutoff**。它不了解你的文档、你的产品、你客户的档案，也不知道昨天的新闻。你照样去问它，它就会**凭模糊的记忆作答，或者编出一个听上去合理的答案。**RAG 的存在正是为了解决这件事：不再依赖模型背下来的东西，而是在提问的那一刻把相关事实交给它。

_Diagram: 截止日期之后的内容，以及你公司内部的内容，模型从来没见过。_

#### Knowledge Cutoff (训练截止日期)

- **是什么:** 模型只知道它的训练数据，冻结在某一天。
- **例子:** 它不了解你的文档、某位客户的档案，或者昨天的新闻。
- **注意:** 模型不知道时并不会沉默 —— 它会凭模糊的记忆作答，或者直接编造。
- **关联:** **RAG** 补上这个缺口：事实在提问的时刻送到。

### RAG —— 先检索，再回答

> 开卷考试 —— 不靠记忆，先查出相关的几页，再根据眼前的内容写答案。

这就是 **Retrieval-Augmented Generation（RAG，检索增强生成）** 模式。三步：**检索** —— 拿到用户的问题，**取回你文档中最相关的片段**；**增强** —— 把它们放进上下文；**生成** —— 让模型据此作答。这样答案来自你真实的数据，而不是模型的回忆。助手就是这样回答关于你的文档、你的政策、你的知识库的问题的 —— 准确而且是最新的。

_Diagram: RAG 的三步：检索片段、加入上下文、生成答案。_

#### Retrieval-Augmented Generation (RAG)

- **问题:** 模型不了解你的数据，也不知道截止日期之后的事。
- **思路:** 找出文档中相关的部分，让模型据此作答。
- **例子:** 客服助手根据知识库里现行的那篇文章，回答退款政策问题。
- **代价:** 一整套检索系统：分块、索引、新鲜度、评测。
- **何时使用:** 知识量大、经常变化，或者因用户而异。
- **关联:** 为 **grounding** 而存在；建立在**分块**、**embeddings** 和**向量检索**之上。

### Grounding —— 真正的收获

> 每句话都必须注明来源的记者，写出的捏造内容要比凭记忆写作的记者少得多。

RAG 重要的深层原因是 **grounding**（接地）：因为答案取自检索到的文本，你可以要求引用，并检查每个论断是否真的有来源支撑。它不能完全消除幻觉，但能大幅减少，并让漏网的部分更容易被发现。能追溯到某份文档的答案，才是你可以信任 —— 也可以为之辩护的答案。

_Diagram: 每个论断都有来源。没有来源的论断一眼就能看出来。_

#### Grounding

- **是什么:** 答案建立在检索到的文本上，而不是模型的记忆上。
- **原理:** 每个论断都能追溯到具体的某个片段，并可核对。
- **例子:** “退款需 14 天 [1]”，其中 [1] 是退款政策的某一段。
- **注意:** 它大幅减少幻觉，但不能降到零。
- **关联:** 通过**仅依据上下文作答**、**引用**和**拒答**来实现；用**忠实度**来衡量。

### Retrieval-first —— 末端挂着一个模型的搜索系统

> 研究助理的水平取决于他查的那套归档系统 —— 给他一座好图书馆却配一个糟糕的索引，他照样会递给你错误的文件夹。

能帮你省下几个月的思维模型：RAG 主要是一个**搜索问题**，末端接一个语言模型来组织答案。模型是简单、基本已解决的那一部分。困难、决定质量的部分，是一切决定*哪些文本能到达模型*的环节 —— 这正是本课其余部分的内容。

_Diagram: 分块、embedding、检索和排序才是难点。模型只负责把答案说出来。_

> **定调的问题:** “这个答案来自我检索到、并且能引用的事实 —— 还是来自模型冻结的、模糊的记忆？”

> 别去问模型它知道什么。检索出相关事实，让它据此作答 —— 有依据、够新、可引用。

## 2. 分块

在检索之前，你要先把文档切成片段。怎么切，悄悄决定了检索的质量 —— 这是最不起眼的一步，却也是最重要的步骤之一。

### Chunk —— 质量的基本单位

> 一本参考书只有切成可查找的条目才有用 —— 一卷巨大的、没有索引的长卷，或者一千张零碎的纸片，查起东西来都一样没用。

你检索的不是整篇文档，而是 **chunk（片段）** —— 几百个词长的段落。切出它们的过程叫**分块（chunking）**。这个 chunk 是搜索所看到的、也是模型所读到的单位，所以它的边界极其重要。好的 chunk 自成一体，只讲一个主题。分块做错了，再巧妙的检索、再聪明的模型都救不回来。

_Diagram: 文档被切成 chunk。搜索看到的是 chunk，模型读到的是 chunk —— 而不是整篇文档。_

#### Chunk (段落)

- **是什么:** 几百个词长的段落 —— 搜索与阅读的基本单位。
- **原理:** 文档预先切好；搜索返回 chunk，模型据此作答。
- **大小:** 太大会把答案埋掉，太小会丢掉上下文。这个数字要靠测量来找。
- **注意:** 糟糕的分块，搜索和模型都救不回来。
- **关联:** 用 **structure-aware chunking** 来切，用**元数据**来标记，再变成 **embedding**。

### Chunk Size —— 太大会埋掉答案，太小会丢掉上下文

> 为了回答一行字的问题，递给别人整整一章，他得在噪音里趟水；只递给他一句没有前后文的话，他又看不出这是什么意思。

chunk 切得太**大**，每一块都把相关事实和好几段无关文字混在一起 —— 搜索变得模糊，模型的注意力也被稀释。切得太**小**，又会切断让这个事实有意义的上下文。最合适的大小，是装下一个完整的想法，并带着足够的周边内容、能独立成立。不存在通用的 **chunk size**；它取决于你的文档，要靠测量来调。

_Diagram: 彩色条是你需要的事实。左边它淹没在噪音里；右边它丢掉了上下文。_

### Structure-Aware Chunking —— 按含义切，而不是按字符数切

> 按字数数着切一本书，可能把一句话 —— 或者一道菜谱 —— 从中间劈开。按章节切，每一块都保持完整。

朴素的做法 —— **fixed-size chunking（定长分块）** —— 每 N 个字符切一刀，会切穿句子、表格和想法。更好的做法是按文档的**天然结构**来切 —— 标题、小节、段落 —— 让每个 chunk 都是一个完整的意思。相邻 chunk 之间留一点**重叠（overlap）**，避免某个事实掉进两块之间的缝隙。尊重文档的形状，检索就会不费力地变容易。

_Diagram: 上：每 N 个字符切一刀。下：按小节切，接缝处留一点重叠。_

#### Structure-Aware Chunking (semantic chunking，重叠（overlap）)

- **问题:** 按字符数切分，会把句子和表格从中间劈开。
- **思路:** 按标题、小节和段落切分，并留一点重叠。
- **例子:** 整个“退款时限”小节成为一个 chunk。
- **代价:** 你得解析文档格式：Markdown、HTML、PDF。
- **关联:** 改善每一个 **chunk** 以及之后的一切。

### Metadata —— 给每个 chunk 贴上标签

> 图书卡片记录的不只是文字 —— 还有作者、日期和章节，所以你在搜索之前就能先筛到恰当的那个书架。

存储每个 chunk 时带上**元数据（metadata）**：来源文档、标题、日期、小节、权限。这让你可以在语义检索之前或同时做**过滤** —— 只看这个产品的文档、只看现行政策、只看这个用户有权看的内容 —— 它还为引用提供了来源。元数据保存起来很便宜，却能把一堆扁平的文字变成可以精准定位的东西。

_Diagram: 元数据给你两样东西：搜索前的过滤条件，以及引用的来源。_

#### Metadata (chunk 元数据)

- **问题:** 一堆扁平的文字：没法缩小搜索范围，也没有可引用的来源。
- **思路:** 每个 chunk 都存上来源、标题、日期、小节和权限。
- **例子:** 只在这个用户有权看的现行政策里搜索。
- **代价:** 几乎为零 —— 每个 chunk 多几个字段。
- **关联:** 给**向量检索**提供过滤条件，给**引用**提供来源。

> **分块的问题:** “每个 chunk 是否都能独立成为一个完整的想法 —— 既有足够的上下文让人看懂，又有足够的元数据可以过滤和引用？”

> 你检索的是 chunk，不是文档。按含义切，让每一块自成一体，并给它贴上标签 —— 分块质量决定了下游一切的上限。

## 3. Embeddings 与向量检索

要找到与问题匹配的 chunk，你得按含义搜索，而不是匹配字词。Embeddings 正是让“帮我找类似这样的东西”成为可能的那个窍门。

### Embedding —— 含义变成坐标

> 一张地图，每个想法都有一个位置，含义相近的东西彼此靠得很近 —— “狗”挨着“小狗”，两者都离“纳税申报表”很远。

**Embedding** 是一串数字 —— 一个**向量（vector）** —— 它表示一段文本的含义，放在高维空间里，让含义相近的文本落在彼此附近。你把每个 chunk 只做一次 embedding，并存下这些向量。这样“含义”有了坐标，“找相关的文本”就变成了“找附近的点” —— 这是计算机能很快解决的问题。

_Diagram: Chunk → embedding 模型 → 向量。每个 chunk 做一次，然后存进库里。_

#### Embedding (向量)

- **是什么:** 一串数字，表示一段文本的含义。
- **原理:** embedding 模型输出坐标；含义相近就意味着点靠得近。
- **例子:** “狗”和“小狗”靠得近；两者都离“纳税申报表”很远。
- **关联:** 让**向量检索**成为可能；向量存放在**向量数据库**里。

### Vector Search —— 按相似度找，而不是按关键词

> 一位按书的内容来找书的图书管理员 —— “类似这样的东西” —— 而不是只匹配你说的那个确切书名。

提问的时候，你用同样的方式给**问题**做 embedding，然后在库里找向量离它最近的 chunk。这就是**向量检索（vector search）**，也叫**语义检索（semantic search）**：即使用户问的是“把钱要回来”，它也能找到讲“退款政策”的 chunk，因为两者含义很近。关键词检索会漏掉这个；向量检索就是为此而生的。

_Diagram: 问题和退款 chunk 没有一个共同的词 —— 但在含义空间里，它们紧挨着。_

#### Vector Search (语义检索)

- **是什么:** 找出向量离问题向量最近的那些 chunk。
- **原理:** 用同一个模型给问题做 embedding，然后找最近的点。
- **例子:** “把钱要回来”能找到“退款政策”小节。
- **注意:** 对确切的代码和名称表现不佳；“近”并不总是“有用”。
- **关联:** 运行在**向量数据库**上；由**混合检索**和**重排序**补全。

### Vector Database —— 检索引擎

> 一座仓库，经过精心设计：给它任何一件物品，它都能立刻递给你最相似的一百件 —— 不是靠把每个货架看一遍，而是靠它的组织方式。

**向量数据库（vector database）**存放你的 embeddings，并在毫秒内回答“离这个最近的是什么”这类查询，即使面对几百万个 chunk 也一样，靠的是近似索引（**ANN**，近似最近邻），而不是全量扫描。它是 RAG 背后的检索引擎。你不需要自己造它 —— 但你得知道你的 chunk 就住在这里，以及它的检索有多快、多准。

_Diagram: 向量数据库不会全部扫描一遍：近似索引直奔最近的那些。_

#### Vector Database (vector store，ANN index)

- **是什么:** 存放向量、并能快速做最近邻搜索的库。
- **原理:** 用近似索引（ANN），而不是全量扫描。
- **例子:** 几百万个 chunk —— 毫秒内找到离问题最近的那些。
- **注意:** 你不用自己造它，但必须知道它的检索有多快、多准。
- **关联:** 存放 **embeddings**；**向量检索**运行在它上面。

### Similar ≠ Relevant —— 相似不等于相关

> 两段文字可能主题相同，却回答不同的问题 —— “如何取消”和“人们为什么取消”挨得很近，但只有一个是被问到的。

向量检索返回的是**语义上接近（相似）**的内容，这通常是**相关**的，但并不总是。一个 chunk 可能讲的是正确的主题，却不包含答案。这个差距 —— 含义上接近与真正有用之间的差距 —— 就是为什么原始的向量检索是不错的第一轮，却不是最终结论，也是下一节存在的原因。

_Diagram: 两个 chunk 都离问题很近。只有一个包含答案。_

#### Similar ≠ Relevant (相似度 vs 相关性)

- **是什么:** 含义上接近的 chunk，不一定包含答案。
- **例子:** “如何取消”和“人们为什么取消”挨得很近；只有前者能回答问题。
- **注意:** 原始向量检索把“接近”误当成了“有用”。
- **关联:** 用**重排序**来修正；用**检索评测**来衡量。

> **检索的问题:** “我匹配的是问题的含义 —— 还是只是指望用户敲出的关键词恰好和我的文档用词一样？”

> Embeddings 给含义以坐标；向量检索按相似度找 chunk。它很强大 —— 但“含义上接近”并不完全等于“回答了问题”。

## 4. 检索才是全部

这一课能修好大多数出问题的 RAG 系统：答案不好时，原因通常在检索。把对的 chunk 送进去，一个像样的模型就能完成剩下的事。

### Garbage In, Confident Garbage Out —— 垃圾进，自信的垃圾出

> 把错误的文件递给别人，让他做总结 —— 他会给你一份无可挑剔的总结，总结的却是完全错误的东西，而且听上去十分肯定。

RAG 的答案，只和交给它的 chunk 一样好。检索到了错误的段落，模型就会**忠实地依据错误的上下文作答**，带着它一贯的自信。这个 bug 看起来像是“模型错了”，但真正的失败发生在上游的检索。所以答案不好时，**先检查检索到了什么，再去动提示词或模型。**

_Diagram: 错误出现在答案里，但诞生在检索中。先看 chunk。_

### Hybrid Search —— 把关键词和含义结合起来

> 一位搜索者清楚字词的含义，另一位能匹配确切的名称和代码 —— 两人合起来，能抓住任何一人单独会漏掉的东西。

向量检索懂含义，但可能在确切术语上出错 —— 产品代码、名称、罕见的行话。**关键词检索（keyword search）**能精确命中这些，却抓不到换种说法的表述。**混合检索（hybrid search）**把两者都跑一遍并合并结果，互相弥补盲区。对大多数真实语料来说，混合检索都优于任何单一方式，因为真实的问题把概念和具体名称混在一起。

_Diagram: 并行两次搜索：一次抓住确切的代码，另一次抓住换种说法的表述。结果合并。_

#### Hybrid Search (keyword + vector)

- **问题:** 向量检索对确切的代码和名称出错；关键词检索抓不到换种说法的表述。
- **思路:** 两种搜索都跑，并合并结果。
- **例子:** “退货时报错 SKU-4471” —— 关键词检索找到代码，向量检索找到含义。
- **代价:** 两套索引，外加合并逻辑。
- **何时使用:** 面对真实语料，几乎总是该用。
- **关联:** 是**重排序**之前那一轮宽泛的初筛。

### Reranking —— 给候选短名单重新排序

> 一场招聘：廉价的初筛先挑出五十份看似合适的简历，然后一位认真的审阅者仔细读过，排出真正的前五名。

第一轮检索又快又粗。**重排序器（reranker）**取前五十个候选，更仔细地逐个对照问题打分，把真正相关的 chunk 推到最前面。先广泛检索，再重排序，留下精准的少数几个。这种两阶段的形态 —— 宽泛廉价的召回，加上锐利的排序 —— 是对一个平庸的 RAG 系统来说杠杆最高的升级之一。

_Diagram: 第一阶段 —— 快速收集 50 个候选。第二阶段 —— 仔细挑出最好的 5 个。_

#### Reranking (two-stage retrieval)

- **问题:** 第一轮又快又粗：对的 chunk 可能排在第 30 位。
- **思路:** 取前 50 个，仔细地逐个对照问题打分。
- **例子:** 从检索到的 50 个 chunk 里，重排序器留下最有用的 5 个。
- **代价:** 多一步 —— 每个问题都要多花一点延迟和费用。
- **何时使用:** RAG 表现平庸时 —— 最强的升级之一。
- **关联:** 修正 **similar ≠ relevant**；排在**混合检索**之后。

### Precision & Recall —— 两者此消彼长

> 网眼大的网只能捞到大鱼，会漏掉很多；网眼细的网什么都能捞到，连水草也不放过。你根据需要的渔获来调整网眼。

检索的 chunk 太少，你可能**漏掉带有答案的那个**（低**召回率 recall**）；检索得太多，答案又被淹没在无关文本里，稀释模型的注意力并浪费 token（低**精确率 precision**）。合适的 chunk 数量（常叫 **k**）能平衡两者，而且它取决于你的数据和问题类型。你不是猜出来的 —— 而是测出来的，这正是下一节的内容。

_Diagram: chunk 太少 —— 漏掉答案。太多 —— 答案被淹没。中间值要靠测量来找。_

#### Precision & Recall (top-k)

- **是什么:** 召回率 —— 对的 chunk 回来了没有；精确率 —— 同时带回了多少垃圾。
- **原理:** k 越大，召回率越高、精确率越低，反之亦然。
- **例子:** k = 2 会漏掉答案；k = 40 把它埋掉，还白烧 token。
- **注意:** 你猜不出合适的 k —— 要在自己的数据上测量。
- **关联:** 用**检索评测**来衡量；决定**成本与延迟**。

> **检索的问题:** “答案出错时，我真的看过检索到了哪些 chunk 吗 —— 还是我认定是模型的问题，就开始调提示词？”

> 大多数糟糕的 RAG 答案，都是糟糕的检索。把关键词和语义结合起来，给短名单重排序，在怪模型之前先检查 chunk。

## 5. Grounding 与引用

一旦对的 chunk 进入上下文，接下来的任务是让模型严格依据它们作答 —— 并证明它确实这样做了。这才把检索变成值得信赖的答案。

### Context-Only Answering —— 只依据检索到的文本作答

> 一位被要求只陈述自己亲眼所见的证人 —— 不是他推测的、模糊记得的，或者听别人转述的。

指示模型**只依据提供的 chunk** 作答，答案不在其中时就说不知道。这是 grounding 的核心：检索到的文本是被允许的**事实来源**，模型自己的记忆则不在考虑之列。这不会完美 —— 模型仍可能跑偏 —— 但这条指令加上对的上下文，已经完成了大部分工作。

_Diagram: chunk 是被允许的来源。模型的记忆不是。_

#### Context-Only Answering (依据上下文作答)

- **问题:** 模型把检索到的事实和自己的记忆混在一起。
- **思路:** 一条指令：只依据提供的 chunk 作答，否则就说“我不知道”。
- **例子:** “只依据下面的摘录作答。如果答案不在其中，就直说。”
- **代价:** 并不完美：模型仍可能跑偏。
- **关联:** **grounding** 的核心；由**引用**和**忠实度**来检查。

### Citations —— 让论断可以被核对

> 带脚注的论文，让任何读者都能把一个论断追溯到它的来源并加以验证 —— 或者发现它站不住脚的地方。

让模型**注明**答案的每一部分来自**哪个 chunk**。**引用（citations）**有两个作用：让用户（和你）能对照来源验证论断；而且光是把每句话都建立在某段检索到的文字上，这个行为本身就会让模型不容易偏离事实。有可追溯来源的答案是你能审计的；没有来源的答案，只是一个自信的猜测。

_Diagram: 答案的每一句都指向它的来源 —— 你可以打开来核对。_

#### Citations (来源标注)

- **问题:** 没有来源的答案无法核对 —— 它只是一个自信的猜测。
- **思路:** 模型说明每个论断来自哪个 chunk。
- **例子:** “退款需 14 天 [1]”，其中 [1] 是 refund-policy.md 的“时限”小节。
- **代价:** 每个 chunk 都需要带有来源的元数据。
- **关联:** 建立在**元数据**之上；让 **grounding** 可被核对。

### Refusal —— 教它说“我不知道”

> 你最信任的专家，是那个会说“这个不在我手头的资料里”的人，而不是自信地用猜测去填补空白的人。

RAG 最危险的失败，是检索结果为空或偏题时仍然照答不误。所以要让**拒答成为一种合法、被预期的输出**：如果 chunk 里没有答案，模型就应该这样说，而不是凭记忆即兴发挥。一个承认空白的系统，远比一个把它遮掩过去的系统可信 —— 而且它还会暴露出你的检索哪里需要下功夫。

_Diagram: 两个分支都是正确的输出。只有一件事是错的：凭记忆编造答案。_

#### Refusal (诚实的“我不知道”)

- **问题:** 检索结果偏题，模型却照样作答。
- **思路:** “这不在我的资料里”是一个正常的、被预期的回答。
- **例子:** 知识库之外的问题 → “文档里没有涉及这一点。”
- **代价:** 有时用户得不到答案 —— 但绝不会得到编造的答案。
- **关联:** 属于 **grounding**；拒答会暴露检索中的缺口。

### Grounding 能减少幻觉 —— 但不能终结它

> 安全带能大幅降低死亡率，但你依然要小心驾驶。一道强力的保障，并不是不再看路的理由。

即使 chunk 完美，模型也可能读错、过度概括，或者把检索到的事实和自己的记忆混在一起。Grounding **大幅减少**了**幻觉**，并让它可被发现；但它不会消除幻觉。所以你仍要验证 —— 用用户能核对的引用，以及衡量忠实度的评测。把 grounding 当作一种强有力的控制手段，而不是保证。

> **Grounding 的问题:** “这个答案里的每个论断，都能追溯到某个检索到的 chunk 吗 —— 当事实不在时，系统会说‘我不知道’吗？”

> Grounding 意味着答案只来自检索到的文本，并用引用来证明 —— 而且当事实不在时，诚实地说一句“我不知道”。

## 6. 评测 RAG

RAG 有两个阶段，它们的失败方式不同，所以要分开衡量。把它们混在一起，你就会连着几周调错了那一半。（Evals 课程讲得更深；这里是 RAG 专属的形态。）

### Two stages —— 把检索和生成分开衡量

> 一家餐厅出了一道坏菜，有两个可能的元凶 —— 送来的食材，或者厨师。你要先尝食材，否则会去培训错误的人。

RAG 的答案失败，可能是因为**检索**带回了错误的 chunk，也可能是因为**生成**阶段在对的 chunk 上答得不好。两者需要不同的修法，所以要分开衡量：对的 chunk 回来了吗？以及，给定这些 chunk，答案是否忠实且完整？大多数“没法改进自己 RAG”的团队，只给最终答案打分，然后猜该怪哪一半。

_Diagram: 每个阶段都有自己的度量表 —— 也有自己的修法。_

### Retrieval Eval —— 对的 chunk 回来了吗？

> 在评判作文之前，先看看学生拿到的参考页对不对 —— 如果不对，他写的任何东西都不可能是对的。

单独评测检索 —— 这就是**检索评测（retrieval eval）**：对一组已知相关文档的问题，搜索是否在靠前的结果里把它们返回了？这种命中所占的比例常被称为 **recall@k**。它能直接发现糟糕的分块、薄弱的检索和缺失的重排序 —— 也就是大多数糟糕答案的上游原因。**先修检索**，因为对提示词或模型做任何改进，都救不了建立在错误 chunk 之上的答案。

_Diagram: 问题对应的正确文档是已知的。如果它落在前 k 名，测试通过。_

#### Retrieval Eval (recall@k)

- **问题:** 从最终答案看不出是不是检索的错。
- **思路:** 拿已知正确文档的问题来测：它们回到前 k 名了吗？
- **例子:** 50 个真实问题里，有 41 个的正确文档在前 5 名。
- **能发现什么:** 糟糕的分块、薄弱的检索、缺失的重排序。
- **关联:** 衡量 **precision & recall**；要在**忠实度**之前先修好它。

### Faithfulness —— 答案忠于 chunk 吗？

> 一位事实核查员对照引用的来源阅读答案，把来源其实并不支持的每一句都标出来。

检索一旦做好，就要评测答案的**忠实度（faithfulness）**：每个论断是否都有检索到的 chunk 支撑，没有编造，也没有与之矛盾？还要检查它是否真的用上了检索到的内容，并回答了问题。这正是你抓住模型偏离坚实上下文的地方 —— 而且它是可以衡量的，常常由另一个模型当评分员（**LLM-as-judge**）。

_Diagram: 评分员逐句对照 chunk，把 chunk 不支持的部分标出来。_

#### Faithfulness (groundedness)

- **是什么:** 答案中的每个论断都有检索到的 chunk 支撑。
- **原理:** 由评分员 —— 常常是另一个模型 —— 把句子与 chunk 逐一核对。
- **例子:** 两句有支撑，第三句没有：它被标记出来。
- **注意:** 忠于 chunk 的答案，仍然得回答问题。
- **关联:** 衡量 **grounding**；在做好**检索评测**之后才有意义。

### Golden Set —— 用真实问题搭建评测

> 你用将要真正驶过大桥的卡车来测试它，而不是用你觉得方便的重量。

你的评测集 —— 常被称为 **golden set** —— 应该是用户真实会问的**真实问题**，包括杂乱的和超出范围的，每个问题都配上应当被检索到的 chunk，以及一个已知正确的答案。每次改动都跑一遍，这样你就能看出新的分块策略或重排序器是否真的有帮助。没有这个，你就是在凭轶事调 RAG —— 而轶事会骗人。

_Diagram: 一张表：真实问题、期望的 chunk 和答案 —— 每次改动都跑一遍。_

#### Golden Set (评测集（eval set）)

- **问题:** 凭轶事调优：“现在好像好些了。”
- **思路:** 真实问题 + 应该回来的 chunk + 已知正确的答案。
- **例子:** 一个杂乱的问题、一个换了说法的问题，以及一个超出范围、期望得到“我不知道”的问题。
- **代价:** 搭建和维护这套评测集要花时间。
- **关联:** 同时为**检索评测**和**忠实度**提供数据。

> **评测的问题:** “答案出错时，我能分清是检索漏掉了 chunk，还是模型答砸了 —— 还是我在瞎猜？”

> RAG 会在两个地方失败。把检索和生成分开衡量，先修检索，并用真实问题来搭建评测。

## 7. 把它做好

RAG 很强大，也常被滥用。真正的功夫在于：在它物有所值的时候才用，保持数据新鲜，并且不为一个更简单的办法本可以省掉的机制付费。

### Paste First —— 能直接粘贴的，就别上 RAG

> 你不会为桌上的三本书建一套图书馆目录 —— 你只是把它们翻开。

如果相关的事实又少又固定 —— 几份文档、一段简短的政策 —— 就直接**放进提示词里。**RAG 只有在知识量大到上下文装不下、经常变化，或者必须按用户过滤时，才配得上它的复杂度。为三页纸搭一条检索管线，就像为一次调用写一个智能体循环那样，属于过度设计。数据逼你用的时候，再去用它。

_Diagram: 小而稳定 —— 粘进提示词。大、多变或因用户而异 —— 用 RAG。_

#### Paste First (context stuffing)

- **问题:** 在根本不需要的地方搭了一条检索管线。
- **思路:** 小而稳定的事实直接放进提示词。
- **例子:** 一份两页的政策放进提示词，不用建索引。
- **何时用 RAG:** 知识放不进上下文、经常变化，或者要按用户过滤。
- **关联:** 阶梯的最底层一级；**RAG** 是下一级。

### Index Freshness —— 过时的数据就是错误的数据

> 电话簿只有重新印刷才有用 —— 十年前的号码，是自信而又毫无用处的错误。

RAG 的承诺是最新的事实，这意味着你的索引必须**保持最新。**源文档变化时，chunk 和 embeddings 也必须更新 —— 即**重建索引（reindexing）** —— 否则模型会把答案建立在自信的过时文本之上。把重建索引当作系统的一部分来规划，而不是事后补救 —— 新鲜度是一项需要持续维护的功能，不是一次性得到的属性。

_Diagram: 上：文档变了，索引随之重建。下：没有计划，答案就此过时。_

#### Index Freshness (重建索引（reindexing）)

- **问题:** 文档变了，索引没变 —— 答案自信地过时了。
- **思路:** 按计划对变更的文档重新分块、重新做 embedding。
- **例子:** 政策更新了 —— 它的 chunk 当天就重建。
- **代价:** 一条需要你维护的重建索引管线。
- **关联:** 让 **grounding** 保持最新；涉及 **chunk** 和 **embeddings**。

### Cost & Latency —— 盯着它们

> 管线里每多一步 —— 做 embedding、搜索、重排序、塞进上下文、生成 —— 都会给每一个问题增加一点时间、一点费用。

RAG 增加了若干阶段，每个阶段都要花**延迟**和 token。检索更多 chunk、重排序、更大的上下文 —— 都会在一定程度内提升质量，同时一路抬高账单。所以要调到**能答好的最少 chunk 数**，能缓存的地方就缓存，并记住：一个太慢或太贵的好答案，在生产环境里并不是好答案。

_Diagram: 每个阶段都增加时间和费用 —— 每个问题都要为此买单。_

#### Cost & Latency

- **是什么:** RAG 的每个阶段，都会给每个问题增加时间和 token。
- **原理:** 更多 chunk、重排序、更大的上下文 —— 质量在一定程度内变好，成本则始终更高。
- **例子:** 重排序之后把 k 从 20 降到 5 —— 答案一样，账单更小。
- **注意:** 一个太慢或太贵的好答案，在生产环境里算不上好。
- **关联:** 与 **precision & recall** 和**重排序**相互拉扯。

### RAG 只是一级台阶；模型仍然只是一个组件

> 好的厨房有储藏室，但储藏室不是厨师 —— 它只是给仍要亲手做出这道菜的人准备的、一份整理得当的输入。

RAG 在阶梯上位于普通提示词之上、工具和智能体之下：模型需要你的事实时就用它，并像对待任何依赖一样，把它放在干净的接口之后。检索是给模型喂料；它并不取代围绕模型的判断。纪律与到处一样 —— 用能行得通的最简单的那一级，并让模型可以替换。

_Diagram: 普通提示词 → RAG → 工具与智能体。只有任务逼你时才往上爬。_

### 这些概念如何连在一起

> 同一间厨房里的两个班次：夜里是备料 —— 把一切切好上架；白天是烹饪 —— 找出来、挑好、端上桌。

本课的一切都是分两个阶段的同一条链。**离线（建索引）**：文档被切成带**元数据**的 **chunk**，变成 **embeddings**，存进**向量数据库** —— 文档变化时再重建（**index freshness**）。**查询时**：**混合检索**找出候选，**重排序**留下最好的，**精确率与召回率**决定取多少个。然后是 **grounding**：模型**只依据上下文**作答，附上**引用**或诚实的**拒答**。另外，**paste first**：如果事实不多，你根本不需要这条链。而**评测** —— **检索评测**、**忠实度**、**golden set** —— 衡量每一个环节。

_Diagram: 上：建索引。中：一个问题的路径。下：衡量整条链的评测。_

#### 上线 RAG 功能之前

- **到底需不需要 RAG** —— 还是事实又少又稳定，直接粘进提示词就行？
- **文档是怎么分块的** —— 按含义、自成一体、带元数据和一点重叠？
- **检索是混合并重排序的**，还是一个你从没测量过的原始向量检索？
- **模型是否只依据检索到的文本作答**、注明来源，并会说“我不知道”？
- **检索的评测是什么**，与生成分开了吗？
- **索引如何保持新鲜**，一次查询要花多少时间和 token？

#### 检索出问题的嗅探信号

- 答案**自信地出错**，而你从没看过检索到的那些 chunk。
- **只有原始向量检索** —— 没有关键词兜底，没有重排序。
- chunk **按字符数**切分，切穿了句子和表格。
- 你在**调提示词和模型**，去修其实是检索遗漏的问题。
- 自源文档变化以来，索引一直没有**重建**过。

#### 你做得好的迹象

- chunk **语义完整、自成一体**，带有用于过滤和引用的元数据标签。
- 检索是**混合 + 重排序**，调到能答好的最少 chunk 数。
- 答案**有依据且有引用**，事实没检索到时会诚实地拒答。
- 你把**检索和生成分开衡量**，并且先修了检索。
- 索引有**新鲜度计划**，RAG 位于一个你随时能替换的接口之后。

## 速查表：全部 22 个概念

### 基础

- **Knowledge Cutoff** (训练截止日期): 模型只知道截止某一天的训练数据 —— 不包括你的文档。
- **RAG** (Retrieval-Augmented Generation): 检索相关 chunk，放进上下文，据此作答。
- **Grounding** (依据来源作答): 答案建立在检索到的文本上，而且可以核对。

### 分块

- **Chunk** (段落): 几百个词长的段落 —— 搜索的单位；大小靠测量来调。
- **Structure-Aware Chunking** (按结构切分): 按标题和段落切分，并留一点重叠。
- **Metadata** (chunk 标签): 来源、日期、小节、权限 —— 用于过滤和引用。

### Embeddings 与检索

- **Embedding** (向量): 一个向量 —— 文本含义的坐标。
- **Vector Search** (语义检索): 找出含义上离问题最近的 chunk。
- **Vector Database** (ANN index): 存放向量，并在毫秒内找到最近的那些。
- **Similar ≠ Relevant** (相似度 vs 相关性): 含义上接近的 chunk，不一定包含答案。

### 检索质量

- **Hybrid Search** (keyword + vector): 同时按字词和含义搜索，再合并结果。
- **Reranking** (two-stage retrieval): 先广泛收集候选，再仔细挑出最好的几个。
- **Precision & Recall** (top-k): chunk 太少 —— 漏掉答案；太多 —— 答案被淹没。要测量 k。

### Grounding

- **Context-Only Answering** (依据上下文作答): 只依据检索到的 chunk 作答，绝不依据模型的记忆。
- **Citations** (来源标注): 每个论断都指向它的 chunk，并且可以核对。
- **Refusal** (“我不知道”): chunk 里没有答案 —— 诚实地说出来，而不是编造。

### 评测

- **Retrieval Eval** (recall@k): 对的 chunk 回到前 k 名了吗？先修这个。
- **Faithfulness** (groundedness): 答案中的每个论断都有 chunk 支撑。
- **Golden Set** (eval set): 带期望 chunk 和答案的真实问题 —— 每次改动都跑一遍。

### 把它做好

- **Paste First** (context stuffing): 几条稳定的事实 —— 用提示词，不用 RAG。
- **Index Freshness** (重建索引): 文档变了 —— 重建索引，否则答案就过时了。
- **Cost & Latency** (时间与 token): 每个阶段都花时间和 token；取能答好的最小 k。

> RAG 是末端挂着一个模型的搜索系统。把 chunk 做对，答案自然随之而来 —— 模型很少是问题所在。

速成课结束 · 7 章 · 22 个概念

接下来是实践：在手头的一小批自己的文档上，搭出最小的真实 RAG —— 按结构分块、做 embedding、检索，并让模型带着引用和诚实的“我不知道”来作答。然后，在调任何东西之前，先写十个真实问题，看看检索到了什么。但要把一个想法放在所有想法之上：答案出错时，先看 chunk。在 RAG 里，模型很少是问题所在 —— 是你的检索，而这正是你能掌控的那一半。
