找得准 — 两条路、一次融合、一次重排
这一章讲三件事: 为什么按意思找不够、要再加一条按词面找的路; 两路结果怎么合成一份;以及为什么最后还要用一个更贵的模型再排一遍。 它在全书链条里的位置: 这是六站里的第五站(检索)的精修版。 第 05 章交代了「怎么取回来」,这一章交代「怎么取得对」 —— 而这是全书数字最扎实的一段。
1. 顶层全景
一个问题
│
├──── 路 A:按意思找(把问题变成一串数,比远近)
│
└──── 路 B:按词面找(数两边共同的词,罕见词加权)
│
▼
两份名单 ──► 融合成一份 ──► 取前几条
│
▼
用一个更贵的模型逐条重打分(重排)
│
▼
最终交给模型的那几条
图说:前面三步都在「快速地缩小范围」,最后一步在「慢工出细活」。
这个「粗一遍、再细一遍」的形状,是检索系统里最通用的一条骨架。
一句话链条: 按意思找有死角 → 补一条按词面找的路 → 两路分数 没法直接加,要先缩到同一个尺度 → 合出来的名单前几条仍然不够准 → 那就对这几条花大价钱重算一遍 → 而这一步的效果大到不像话。
2. 两条路各有死角
先看现象
| 你问什么 | 按意思找 | 按词面找 |
|---|---|---|
| 「辞职要提前多久打报告」(文档里写的是「离职需提前一个月提交书面申请」) | 找得到 —— 说法不同但意思一样 | 找不到 —— 一个共同的字都没有 |
| 「XR-4471B 这个型号的保修期」 | 常常找偏 —— 型号在它眼里就是一串没意义的字符 | 一抓一个准 —— 这个字串在全库只出现一次 |
两条路的死角正好互补,所以真实系统一般两条都走。
这两条路的正式名字
这两条路在这一行有固定的叫法,你出门一定会撞见。
按意思找的那条路,每篇文档变成一串 384 个数,而这串数几乎每一位都是非零的小数, 密密麻麻 —— 所以这一行管这种表示叫稠密。
按词 面找的那条路,心里另有一张表。这一行管「你的资料里一共出现过哪些词」的那张清单叫词表, 通常有几万个词条。
它的做法概念上就是给词表里每个词分配一个位置,文档里没出现的词全记 0。 一份几万个位置的表里绝大多数是 0 —— 空空荡荡,所以这种表示叫稀疏。
于是两条路各自的正式名字就叫稠密检索和稀疏检索1。 这两个名字来自各自表示的形状,不是来自效果好坏。
3. BM25 比「数词频」多做的三件事
按词面找那条路最常用的算法叫 BM25,是几十年前就有的老办法。 书在这里给了全书唯一一次真正的算法解释,值得完整留住2。
最朴素的做法及其毛病
最朴素的做法是数:查询里的词在这篇文档里出现了几次,次数多就排前面。三个毛病立刻冒出来。
BM25 逐个修掉它们
毛病一:重复刷词。 一篇文档把「保险」写了 50 遍,按次数算它就赢了。
BM25 的修法:词频饱和 —— 同一个词重复出现,分数会涨,但涨得越来越慢,最后基本不再涨。 出现 1 次到 2 次,加分很多;出现 20 次到 21 次,几乎不加。
毛病二:所有词一样重。 查询「RAG 的保修期」里,「的」和「RAG」被同等对待。
BM25 的修法:罕见词加权 —— 一个词在整个文库里出现得越少,它一旦命中就越值钱。 「的」在每篇文档里都有,所以几乎不加分;「RAG」只在几篇里有,命中一次就是强信号。 这一项的正式名字叫逆文档频率。
毛病三:长文档天然占便宜。 一篇一万字的文档,什么词都可能出现几次。
BM25 的修法:按长度扣分 —— 同样出现 3 次,短文档得分高于长文档。
边界:它只看表面
书自己也说清楚了:BM25 简单、高效、可解释,常被当作基线(一个简单、公认、拿来做对照的起点做法)或补充检索器; 但它只看表面的关键词重合,抓不住深层语义2