12 段资料、5 个问题:top1 命中 4/5,top3 也是 4/5。 没进前三的那个是改写了问法——问「上个月好用这个月不准」,而资料里写的是「数据漂移」, 字面上一个字都不重合。
上一节定了参数。这一节给它喂资料。 检索类应用的效果上限,八成由这一步决定,剩下两成才是提示词和模型。
一、知识库不是「把文件传上去」
平台的界面上,这一步就是选文件夹、点上传、等进度条。看起来最简单。 但实际上它背后有三道工序,每一道都会影响效果:解析(把 PDF、Word、网页转成纯文本)、 切分(长文切成小段)、向量化(每段算一个向量)。 三道工序里最容易被忽略的是切分。 切得不好,一段里前半句讲 A、后半句讲 B,向量就是两者的平均,检索时两边都不匹配。 所以「上传完了」不等于「能用了」。判断标准只有一个:问几个真问题,看它能不能答对。
二、检索这一步到底在匹配什么
用户的问题被转成一个向量,知识库里每段也各有一个向量,然后算「问题向量和哪几段最像」。 「像」的度量通常是余弦相似度:两个向量的夹角越小越像。 它只看方向,不看长度——所以长段落不会因为字多就占优势。 取最像的前 k 段,拼进提示词,一起交给模型。这就是 RAG(检索增强生成)的骨架。 关键认知:模型的回答质量上限,等于检索到的资料质量。 检索没取到那一段,模型再强也只能编或者拒答。
三、实测:4/5 命中,漏的那个是改写
Demo 用 12 段关于训练流程的资料,配 5 个问题。 向量用字二元组加余弦(不装分词库,也不用真 Embedding 模型)。 结果是 top1 命中 4/5,top3 也是 4/5——也就是命中的四个都是第一名就对了, 没命中的那个连前三都没进。 漏掉的那个问题问的是「上个月还好用的模型,这个月明显不准了,先查什么」,正确段落叫「数据漂移」。 两句话字面上没有一个词重合——这种情况字面匹配注定抓不到。 这一条正是字面匹配的边界:同义改写的问法只能靠语义向量。 真 Embedding 模型能把「模型变不准了」和「数据漂移」映射到相近的位置,字二元组不行。 所以这个 Demo 的命中率偏保守,不代表真系统的水平。 还有个细节:这里的相似度绝对值都很小(0.098 到 0.365)。因为字二元组向量很长、交集很少。 所以只能比大小,不能定绝对阈值——设一个「大于 0.5 才算命中」的门槛,会把所有结果都筛掉。
四、提升召回的四种手段
加同义词表:把业务黑话映射到标准词(「模型变不准」→「数据漂移」)。 便宜、可解释,但要人工维护。 换成语义向量:用 Embedding 模型算向量。这是最有效的一招,代价是要跑推理、要存向量库。 混合检索:语义向量和关键词各取一批,合并去重。 工程上最常见,因为关键词能兜住专有名词,语义能兜住改写。 加大 top-k 并加元数据过滤:多取几条几乎不花钱,漏掉代价很大。 如果资料有分类或时间字段,先用它缩小范围,再在里面做相似度排序。 四种可以叠加。顺序上建议先加 k(零成本)、再上混合检索、最后才换语义向量。
五、动手 Demo:检索实测:五个问题里四个第一名就命中
准备 12 段关于训练流程的短资料,配 5 个问题; 每段和每个问题都用「去掉标点后的字二元组」做向量,算余弦相似度取前 3 名, 逐条核对正确答案在第几名、有没有进前三。
def toks(s):
s = re.sub(u"[^\\u4e00-\\u9fa5a-zA-Z0-9]", u"", s)
return set(s[i:i + 2] for i in range(len(s) - 1))
scored = sorted(((cos(qv, vec(d[1])), d) for d in DOCS), key=lambda x: -x[0])
top = scored[:3]
实跑输出:
--------------------------------------------------------------------
知识库检索:12 段资料里,5 个问题命中了 4 个
--------------------------------------------------------------------
问题 top1 段落 相似度 top1 top3 内
---------------------------------------------------------------------------------------
一次喂给模型的批大小太多,显存吃得住吗? 批大小 0.345 命中 是
训练集分数高、测试集低,这是过拟合吗? 过拟合 0.365 命中 是
学习率设太大了会怎样? 学习率 0.152 命中 是
上个月还好用的模型,这个月明显不准了,先查什么? 模型部署 0.098 未命中 否
类别不平衡的时候准确率还够用吗? 评估指标 0.270 命中 是
top1 命中率 4 / 5 = 0.80
top3 命中率 4 / 5 = 0.80
top1 和 top3 一样高(都是 0.80):命中的那几个都是第一名就对了,剩下 1 个连前三都没进。
没进前三的那个是**改写了问法**——问「上个月好用这个月不准」,而资料里的词是「数据漂移」,字面上没有一个字重合。这种情况只能靠语义向量,字面匹配注定抓不到。
所以检索的门槛不该定在 top1:多取几条几乎不花钱,漏掉一条代价很大。
**检索这一步的目标是「召回」,不是「精确排序」。** 排序交给模型去读。
还有一个细节要注意:这里的相似度绝对值都很小(0.03 到 0.36),因为字二元组向量很长、交集很少。所以**只能比大小,不能定绝对值阈值**——设一个「相似度大于 0.5 才算命中」的门槛,会把所有结果都筛掉。
这里的向量是字二元组加余弦,不是真的 Embedding 模型。真 Embedding 能抓同义改写(「样本不平衡」对「类别不均衡」),字面匹配抓不到。所以这个 Demo 的命中率偏保守,不代表真 Embedding 的水平。
top1 和 top3 都是 4/5。 命中的四个都是第一名就对了,剩下那一个连前三都没进——不是排错位置,是彻底没被匹配上。 看相似度那一列:命中的最高 0.365、最低 0.152,没命中的那个是 0.098。 数小但排序正确,说明「相对大小」才是有效信息。 这也解释了为什么不能定绝对阈值。 换一批资料、换一种切分,相似度的整体水平就会变,昨天 0.2 算高、今天 0.2 算低。 我把 5 个问题故意设计成「三个带原词、两个改写」,就是为了让字面匹配的边界显出来。 如果五个都带原词,命中率会是 5/5,但那个数字没有信息量。
30 秒实验
- 把 top-k 从 3 改成 5,看那个改写的问法能不能进前五。
- 把资料从 12 段加到 24 段(每段再拆细),看命中率怎么变。
- 想一想:为什么检索阶段的目标是「召回」而不是「精确排序」?
常见误区
- 「文件传上去就等于建好知识库」——解析和切分的质量才是效果上限。
- 「相似度低于某个值就丢弃」——绝对值不可比,只能比相对排序。
- 「只取 top1 就够」——多取几条几乎不花钱,漏掉一条代价很大。
自测三问(点开对答案)
1. 知识库建设的三道工序是什么? —— 解析(转纯文本)、切分(切成小段)、向量化(每段算一个向量)。 2. 为什么字面匹配抓不到改写的问法? —— 它只比较字词重合,同义改写没有共同字符,交集为空。 3. 提升召回可以怎么做? —— 加同义词表、换语义向量、混合检索、加大 top-k 并加元数据过滤。资料切得好不好,直接决定检索的上限。下一节专讲切分和清洗。
- ☐ (本节完,下一节 10.3.5 第五步:文本分段与清洗)