16 道题,闭卷只蒙对 2 道;接上检索之后 top-1 就到 14 道。 但错的 2 道全出在「改了说法」那 4 道里——召回率 14,top-3 提到 15,答对还是 14。 瓶颈不在排序,在「问题怎么变成向量」。
上一节讲强化学习把「推理」推上去。这一节讲另一个毛病:模型不知道的时候会编。 RAG 是治这个最直接的办法——但它治的不是「不会」,是「没有」。
一、幻觉不是「故意骗人」,是「被逼着答」
语言模型的训练目标是「给定上文,下一个字最可能是什么」。 这个目标里没有「我不知道」这个选项——即使什么都不知道,它也会照着一个流畅的句子往下写。 所以幻觉的机制很朴素:它不是在撒谎,是在补全。 你问一个训练数据里没有的事实, 它按语言的惯性补出一个听起来对的答案。 Demo 里的闭卷基线就是这个样子:12 个主题的知识库它一个都没看, 但它照样答——一律答成出现最多的那个主题「退换货」,16 道题蒙对 2 道。 这个基线很蠢,但它精确地模拟了「不知道还硬答」的样子:输出看起来很确定,内容跟事实没关系。
二、RAG 的三步:切、查、塞
第一步切:把资料切成一段一段。切太大,一段里混着好几个主题,检索出来什么都有; 切太小,上下文不全,答案对不上。 第二步查:把问题也变成向量,跟每段资料的向量算相似度,取最像的几条。这一步叫「召回」。 第三步塞:把查到的几段原文拼进提示词,让模型「照着这些材料回答」。 这一步才是 RAG 真正起作用的地方——它把「凭记忆答」变成了「看着资料答」。 所以 RAG 的准确说法不是「让模型学会知识」,是「在提问时把相关资料摆到它眼前」。 资料更新了,回答就更新了,不用重训模型。这是它比微调省事的地方。
三、召回归召回,排序归排序
Demo 的表里有三列:答对题数、正确段落进了候选、准确率。 后两个的差,就是「捞到了但没排第一」的数量。 接上检索后 top-1 答对 14 道、召回 14 道——这两个数相等,说明这一轮没有出现「捞到但排错」。 top-3 的召回是 15,答对还是 14——多捞的那 1 道,进了候选却没排第一。这就是排序问题。 但主要矛盾不在排序:top-3 也只把召回从 14 提到 15,剩下 1 道根本就没进候选。 那是向量化问题——改排序、加去重都没用,只能换嵌入模型。 这两个数必须分开量,因为修法完全相反:召回不行改切分和向量化,排序不行改相似度算法或加 rerank。 只看最后答案对不对,永远分不清是哪种病。
四、RAG 治不了什么
治不了「不会推理」。 资料里写着「A 比 B 贵,B 比 C 贵」,问「A 和 C 谁贵」, 检索能把两段都捞上来,但推不出来还是推不出来。 治不了「资料本身是错的」。 检索系统只负责找,不负责判真假。 知识库里有过时的内容,它就会照着过时的答。 也治不了「问题本身有歧义」。 「退款多久到账」——是问审核时间还是到账时间? 检索会按字面找,找不到你想要的那一层。 Demo 里那 2 道答错的,全是「改了说法」的:问「买完多久能收到货」, 资料里写的是「付款后 48 小时内发出」。人和文档用的不是一套词,字面比对再准也接不上这种沟。 所以做 RAG 的第一件事不是选模型,是把「召回率」和「答对率」分开建指标。 只盯答对率,你会一直在调提示词,而病根在向量化。
五、动手 Demo:闭卷蒙对 2 道,接上检索 14 道,剩下 2 道卡在「换了说法」
建一个 12 段的小知识库(退换货、发票、发货、会员、支付、售后各两段),配 16 道题——12 道照原文问, 4 道改成用户的口语说法。 用字二元组向量做检索,统计闭卷、top-1、top-3、top-5 四种情况的答对数和召回数。
def grams(s):
s = u''.join(c for c in s if c not in u',。?、!: ')
return set(s[i:i+2] for i in range(len(s) - 1))
def retrieve(q, k):
qv = grams(q)
sc = sorted([(len(qv & grams(t)) / (len(qv) * len(grams(t))) ** 0.5, i)
for i, (_tag, t) in enumerate(KB)], reverse=True)
return sc[:k]
for k in (1, 3, 5):
src = ans = 0
for q, tag, a, _kind in QS:
got = retrieve(q, k)
if any(KB[i][0] == tag and a in KB[i][1] for _s, i in got):
src += 1
if KB[got[0][1]][0] == tag and a in KB[got[0][1]][1]:
ans += 1
print(k, ans, src)
实跑输出:
--------------------------------------------------------------------
RAG 治的是「不知道硬答」,不是「不会答」
--------------------------------------------------------------------
方式 答对题数 正确段落进了候选 准确率
------------------------------------------------------
闭卷(只有参数) 2 0 0.125
检索 top-1 14 14 0.875
检索 top-3 14 15 0.875
检索 top-5 14 15 0.875
题目总数 16 道(12 道照原文问,4 道改了说法)
闭卷那行就是「幻觉」的样子:它不知道,但它答了——一律答成「退换货」,蒙对 2 道。
检索接上之后,top-1 就跳到 0.875。**注意这不是模型变聪明了**,是它面前多了几段原文,照着念就行。
错的题是哪几道?按问法分开看:
原文用词:12 道里 top-1 答对 12 道
改写问法:4 道里 top-1 答对 2 道
**错的 2 道全出在改写问法这 4 道里。** 举一个:
问「买完多久能收到货?」,正确段落是「48 小时」;实际抽到的是「退款到账时间取决于支付渠道,一般为 」。
人和文档用的根本不是一套词。**字面比对再准,也接不上这种沟。**
所以 RAG 好不好,得拆成两个数来量,修法完全不同:
① 召回 正确段落有没有进候选(第 3 列)
② 排序 进了候选,排在第几(第 2 列和第 3 列的差)
top-3 的候选数是 15,答对数还是 14——多捞的那 1 道,捞进来了却没排到第一,这是**排序问题**。
但主要矛盾不在排序:top-3 也只把召回从 14 提到 15,剩下的 1 道**根本就没进候选**——那是**向量化问题**,改排序、加去重都没用,只能换嵌入模型。
这种病加 top-k 也救不回来:把 k 加到 5,召回还是 15。唯一的解法是换成语义向量模型,让「钱退回来」和「退款到账」在向量空间里靠近。
最后一句必须说清:**RAG 治不了「不会推理」。** 它只是把相关资料摆到模型眼前。资料里没有的,它照样编;资料里有但要三步推导的,它也未必推得出来。
闭卷那行 2/16 = 0.125,接上检索后 top-1 就到 14/16 = 0.875。 涨的这 12 道,一道都不是因为模型变聪明了,是它面前多了几段原文。 按问法分开看更清楚: 原文用词那 12 道,top-1 全对;改写问法那 4 道,只对 2 道。 错的 2 道全在后一组。 错的那道长什么样:问「买完多久能收到货」,正确段落是「现货商品在付款后 48 小时内发出」, 实际抽到的是「退款到账时间取决于支付渠道」。 字面上「买完」「多久」「收到」跟「付款后」「48 小时」「发出」几乎不重合。 这张表里 top-1 和 top-3 的召回差 1 道(14 对 15),说明有 1 道是「捞到了没排第一」——排序有问题, 但只占 1 道。主要矛盾是剩下那 1 道根本没进候选。 要说明的是:这里的向量是字二元组的集合,没有任何语义。 真实的 RAG 用嵌入模型(embedding),「钱退回来」和「退款到账」在向量空间里会靠得很近。 这一节能说明的是「RAG 的结构」,不是「RAG 的上限」。
30 秒实验
- 把 top-k 从 3 加到 20,看召回还能不能涨。 如果纹丝不动,说明那几道题的正确段落根本不在候选池的前 20,加 k 没用。
- 给检索加一个「同义词表」(把「退回来」映射到「退款」),重跑那 4 道改写题,看准确率能回到多少。 这就是最简单的语义补偿。
- 把知识库从 12 段加到 100 段(加些不相关的内容),看召回率怎么掉。 候选越多,干扰越大——真实的企业知识库就是这个处境。
常见误区
- 「RAG 能让模型学会新知识」。它只是把资料放进提示词,模型本身没变。 换个对话、换个问法,可能又答不上来。
- 「有了 RAG 就不会幻觉了」。检索错了、资料错了、问题有歧义,照样幻觉。 RAG 降低的是「不知道硬答」,不是「答错」。
- 「top-k 越大越好」。k 大了会塞进大量不相关段落,模型要在噪声里挑,效果反而下降,成本也涨。 k 要调,不能拍。
自测三问(点开对答案)
1. 为什么闭卷的时候模型「一律答成最常见的那一个」? —— 因为它没有任何可用的信息,只能按训练数据的先验分布答。最常见的主题概率最高,所以每次都答它。 这就是「幻觉」最朴素的形态。 2. 召回率和答对率,什么时候会分家? —— 召回是「正确段落在不在候选里」,答对是「排第一的那条对不对」。 候选里有多条相似段落时,正确的那条可能排第二——这时召回高、答对低,病在排序。 3. 如果 top-k 加大到 20 召回也不涨,下一步该改什么? —— 换向量化方式。 说明当前的字面向量根本表达不了这个问题,加候选数量只是往池子里倒更多不相关的东西。RAG 靠的是外部资料。但模型本身的内功还是那套神经网络——下一节把「一层不够加一层」这件事算清楚。
- ☐ (本节完,下一节 1.2.5 神经网络是AI模型训练的核心技术)