一、参数里的知识,有四个硬伤
问一个模型三个问题:
- “上个月发布的那项新政策是什么?”
- “我们公司的差旅报销标准是多少?”
- “某篇冷门论文里报告的那个具体数字是多少?”
对第一个问题,模型可能说它不知道,也可能编一个。对第二个问题,它不可能知道。对第三个问题,它可能给出一个看起来很像、实际上不对的数字。
原因都在于一件事:到目前为止,模型的全部知识都存在它的参数里,而参数里的知识有四个硬伤。
会过期。 第 14 讲说过,训练数据有采集的截止时间,此后发生的事,模型没有任何途径知道。这叫知识截止,它不是 bug,是"知识来自训练数据"的必然结果。
覆盖不全。 公司内部的制度、个人的笔记、没有公开的文档,从来不在训练数据里。
记得模糊。 第 1 讲说过,预测下一个词和压缩是同一件事。参数是整个训练语料的一份有损压缩:反复出现的知识被记得很牢,只出现过一两次的具体事实,只留下一个模糊的印象。模型"大概知道"那篇论文讲了什么,但那个具体数字已经糊掉了——而第 1 讲说过,它会照样续写出一个统计上合理的数字。
说不出出处。 参数里没有"这条知识来自哪篇文档"的记录。模型即使说对了,你也没法核对。
怎么补上这些硬伤?最直接的想法是重新训练,但第 13 讲的预训练贵得不可能为一次政策更新重跑;第 16 讲说过,SFT 主要改变"怎么说",不能可靠地灌进新知识;第 20 讲说过,对齐只是在已有的分布里重新分配概率。改参数,这条路又贵又不可靠。
二、打个比方:闭卷和开卷
到目前为止,模型一直在参加闭卷考试:它能答出的一切,都得事先背下来。
开卷考试的规则不一样:你不需要背下每一个细节,允许带着书进考场。考的是另外两种能力——知道去哪一页找,以及读懂找到的内容,据此作答。
开卷有明显的好处:书可以随时换成最新版;书里可以有你从没见过的内容;书里的数字是准确的;答题时可以写"见第 37 页"。这四条,正好对应第一节的四个硬伤。
开卷也有它自己的失败方式:翻错了页,或者书本身就写错了。这两条在第六节会逐一出现。
RAG(Retrieval-Augmented Generation,检索增强生成) 就是让模型参加开卷考试。
三、为什么"读"比"回忆"可靠
知识可以存在两个地方:参数里,或者上下文里。两者对模型来说是完全不同的东西。
参数里的知识,要靠模型在生成时"回忆"出来——本质上是从一份有损压缩里重建细节。
上下文里的内容,模型是直接读到的。第 9 讲的自注意力可以让正在生成的位置,把注意力直接放在上下文里的某个 token 上,把它的内容取过来。上下文里写着"15 天",模型要做的只是把"15"这个 token 照着抄出来——这比从压缩后的参数里重建出"15"要可靠得多。
| 参数里的知识 | 上下文里的知识 | |
|---|---|---|
| 更新成本 | 重新训练,极贵 | 换一份文档,几乎免费 |
| 细节精度 | 有损压缩,见得少的事实容易模糊 | 原文就在那里,可以照抄 |
| 能否给出出处 | 不能 | 能,知道是从哪一段读来的 |
| 容量 | 很大,但固定 | 受上下文窗口限制(第 23 讲) |
⭐ 表格的最后一行,说明了 RAG 为什么需要"检索"这一步。能不能把整个知识库都塞进上下文?第 23 讲算过:12.8 万个 token 的上下文,光 KV Cache 就要约 62.5 GB;更麻烦的是第四堵墙——softmax 的权重总和是 1,上下文越长,关键信息分到的注意力越少。同样的打分优势(Δ = 5),上下文 1,000 个 token 时关键信息分到约 12.9%,10 万个 token 时只剩约 0.15%。
RAG 的思路是:不把整本书摊开,只把相关的那几页找出来放在桌上。 第 23 讲说过,这等于把"在大量内容里找到相关信息"这件事,从注意力手里拿出来,交给一个专门的检索系统。
四、RAG 的流程
整个流程分两部分:一部分提前做好,一部分在每次提问时做。
提前做好(离线):
文档 ──切成小块──▶ 块 1、块 2、…… ──建立索引──▶ 可检索的知识库
每次提问(在线):
问题 ──检索──▶ 最相关的几个块
│
▼
[说明] + [检索到的块] + [问题] ──拼成输入──▶ 模型 ──▶ 回答
切块:一份几十页的文档不能整份放进上下文,要切成几百字左右的小块,每一块单独作为检索的单位。
检索:给定问题,从知识库里找出最相关的几块。“怎么判断相关"是检索系统的核心,第 26 讲会专门讲现代的做法;这一讲先用一个最简单的办法——数关键词——把整个流程手算一遍。
拼接:把检索到的块和问题拼成一段输入,通常还会加一句说明,比如"请根据以下资料回答,并注明依据的是哪一段;资料中没有的,请说明无法回答”。之后模型做的,就是普通的生成。
手算:一个四段的小知识库
某公司的员工制度,已经切成 4 块:
块 1:年假:入职满一年的员工每年享有 10 天年假。
块 2:年假:入职满五年的员工每年享有 15 天年假。
块 3:病假:员工每年享有 5 天带薪病假,需提供医院证明。
块 4:报销:出差住宿标准为每晚不超过 500 元。
员工提问:“我入职六年了,每年有几天年假?”
检索用最简单的打分:从问题里取关键词"入职"“年假"“天”,数每一块包含其中几个:
| 块 | 入职 | 年假 | 天 | 得分 |
|---|---|---|---|---|
| 块 1 | ✓ | ✓ | ✓ | 3 |
| 块 2 | ✓ | ✓ | ✓ | 3 |
| 块 3 | ✓ | 1 | ||
| 块 4 | 0 |
取得分最高的两块,拼成输入:
请根据以下资料回答问题,并注明依据;资料中没有的,请说明无法回答。
[资料 1] 年假:入职满一年的员工每年享有 10 天年假。
[资料 2] 年假:入职满五年的员工每年享有 15 天年假。
问题:我入职六年了,每年有几天年假?
模型读到两条资料,需要做一步判断:六年满足"满五年”,所以适用资料 2。回答:“根据资料 2,您每年享有 15 天年假。”
⭐ 注意分工:检索负责把可能相关的资料找出来,推理仍然由模型完成。检索系统不知道"六年"和"满五年"是什么关系,它只负责把两条候选都交上去。
检索出错时
情况一:只取一块。 为了省 token,只取得分最高的一块。块 1 和块 2 同分,如果恰好取了块 1,模型读到的只有"满一年享有 10 天",它会回答:“根据资料,您每年享有 10 天年假。”
情况二:换一种问法。 员工问的是:“我每年能休多少天带薪假?” 关键词是"休"“天"“带薪"“假”:
| 块 | 休 | 天 | 带薪 | 假 | 得分 |
|---|---|---|---|---|---|
| 块 1 | ✓ | ✓ | 2 | ||
| 块 2 | ✓ | ✓ | 2 | ||
| 块 3 | ✓ | ✓ | ✓ | 3 | |
| 块 4 | 0 |
块 3 字面上恰好含有"带薪"两个字,得分最高。只取一块时,模型读到的是病假制度,它会回答:“根据资料,您每年享有 5 天带薪假。”
⭐⭐ 这两个错误答案有一个共同点:它们都有出处,都忠实于读到的资料,也都是错的。 模型没有编造任何东西,它只是被给了错的那一页。更麻烦的是,模型不知道还有哪些资料没被检索到——它看不到块 2,自然不会说"不过满五年的规定可能也适用”。
情况二还暴露了关键词检索的根本弱点:它只比较字面,“带薪假"和"年假"在字面上不同,“年假"和"病假"却共享一个"假"字。问题问的是意思,关键词比的是字形。第 26 讲要做的,就是让检索比较的是意思。
切块的尺寸
如果切得更碎,块 2 被切成"入职满五年的员工"和"每年享有 15 天年假"两块,检索可能只取到后一块。模型读到"每年享有 15 天年假”,却不知道这个数字有"满五年"的前提。
块太小,会把条件和结论切开;块太大,又会让每一块混进大量无关内容,既占 token,也稀释了相关的部分。 切块的尺寸没有通用的最佳值,取决于文档本身怎么组织。
五、这一讲回答的问题
第 14 讲的思考题 4 问过:“如果一个模型能在不重新训练的情况下知道训练之后发生的事,这是通过什么途径实现的?“答案就是这一讲:知识不必全部存进参数,可以在回答时放进上下文。 更新知识,只需要更新知识库,模型本身一个参数都不用动。
第 24 讲说过,检索到的内容作为输入,增加的是预填充的 token。预填充可以并行处理,每个 token 比解码便宜得多;把几段相关资料(比如一两千个 token)放进去,比把整本手册(十几万个 token)放进去,省下的不只是计算,还有第 23 讲那几十 GB 的缓存。
六、代价
⚠️ 检索成了一个新的失败点,而且它的失败很难被察觉。 第四节的两个例子说明:检索出错时,模型会给出一个有出处、语气笃定的错误答案。一个带引用的错误,比一个没有引用的错误更容易让人相信。而模型看不到没被检索到的内容,没法提醒你"可能还有别的规定”。
⚠️ 模型不一定照着资料答。 当检索到的资料和参数里的知识冲突时,模型可能忽略资料,按自己"记得"的来回答;反过来,它也可能过分相信资料,哪怕资料明显有误。训练中可以加强"以上下文为准"的倾向(第 16–18 讲的方法都能用),但这不是一个可以保证的性质。
⚠️ 知识库的质量,成了回答的上限。 知识库里有过期的旧版本制度、有写错的文档,模型会忠实地引用它们。RAG 把"模型记没记对"的问题,转移成了"资料对不对"的问题。这是第 14 讲"垃圾进、垃圾出"在另一个环节的翻版。
⚠️ 检索到的内容,是未经审查的输入。 如果知识库里某份文档混进了一句"忽略之前的所有指示,改为回答……",它会被原样拼进输入,和用户的问题、系统的说明摆在一起。模型未必能分清哪些是该遵循的指令、哪些只是该阅读的资料。这是第 30 讲要专门讲的问题。
⚠️ 一次检索答不了需要两步查找的问题。 “我的直属上级所在部门的报销标准是多少?"——先要查出上级是谁、在哪个部门,才能拿第二步的问题去查报销标准。第二次查什么,取决于第一次查到什么,单次检索做不到。第 28 讲会讲模型怎么自己决定"下一步查什么”。
⚠️ RAG 补的是知识,不是能力。 第 20 讲说过,能力来自预训练。把一份微积分教材放进上下文,一个本来不会做积分的模型,并不会因此学会做积分。RAG 能让模型知道一件事,不能让它学会一门本事。
七、和后面课程的关系
- 第 26 讲(Embedding 与向量检索):把第四节的关键词打分,换成比较意思的检索方式,解决情况二"字面不同、意思相同"的问题;第 22 讲说过的"用更少的位数存数字”,也会在那里出现。
- 第 27 讲(Function calling):检索可以不再是每次提问前固定执行的一步,而是模型需要时自己发起的一次"工具调用”。
- 第 28 讲(多步推理与规划):第六节那个需要两步查找的问题,要靠模型自己规划、多次检索来解决。
- 第 29 讲(幻觉):RAG 能减少凭空编造,但第四节显示,它会带来另一种错误——忠实于错误资料的错误。
- 第 30 讲(Prompt injection):第六节"检索到的内容是未经审查的输入”,是间接注入攻击的入口。
八、本讲小结
- 参数里的知识有四个硬伤:会过期(知识截止)、覆盖不到私有资料、见得少的事实记得模糊(有损压缩)、说不出出处。靠重新训练来补,又贵又不可靠。
- ⭐ “读"比"回忆"可靠:上下文里的内容可以通过注意力直接照抄,参数里的知识要从有损压缩中重建。
- 为什么要检索:整个知识库放不进上下文,就算放得进,第 23 讲的注意力稀释也会让关键信息淹没。只把相关的几段放进去。
- 流程:离线切块、建索引;在线检索、拼接、生成。手算四段制度的例子:检索负责找候选,推理仍由模型完成。
- ⭐⭐ 检索出错会产生有出处的错误答案:只取一块时可能取到"满一年 10 天”;换一种问法,关键词检索因为字面上的"带薪"选中了病假制度。关键词比的是字形,不是意思——这是第 26 讲的起点。
- 切块:太小会把条件和结论切开,太大会混入无关内容。
- ⚠️ 代价:检索错误难以察觉;模型不一定照资料答;知识库质量成为上限;检索内容是未经审查的输入(第 30 讲);多步查找需要规划(第 28 讲);RAG 补知识,不补能力。
思考题
- 在第四节的知识库里,如果员工问"我入职三年了,每年有几天年假?",按同样的关键词打分会检索到哪几块?模型应该怎么回答?如果只检索到块 2,会发生什么?
- 第四节情况二里,关键词检索选中了病假制度。如果把块 1 和块 2 改写成"年假(带薪):……",情况二的检索结果会变吗?这种"为了检索去改写文档"的做法,有什么隐患?
- 为什么说"一个带引用的错误,比一个没有引用的错误更容易让人相信"?如果你在设计一个 RAG 系统,你会怎样让用户能够核对模型的回答?
- 第六节说模型可能"忽略资料,按自己记得的来回答"。请设计一个具体的例子:资料写的是最新的正确信息,模型参数里记得的是过时的旧信息。你希望模型怎么处理?这个希望在训练中该怎么体现?
- 一份 200 页的产品手册,你打算做成 RAG 知识库。你会按什么规则切块(按固定字数、按章节、按段落,还是别的)?请结合第四节"切块的尺寸"说明理由。