大可的 AI Builder 手记
跟随系统
颜色主题
长沙小桌实战
大可 Dako
大可 Dako大可 DakoAI Builder · Agent 实践者用 AI 做真正能用的产品。专注探索 Agent 工程化落地、Vibe Coding 实践与商业化交付。
内容平台即将上线,敬请期待
强弱互补,所以生产系统一律混着用关键词看字面重合:编号、型号、专名、新词都能精确命中换个说法就漏,同义词抓不到向量看意思接近:同义改写、口语提问都能找到精确串、否定词、新词全不灵混合再重排两路各召回一批,合并去重,再一起读一遍重排几乎总比单一路更好,这一步收益最高召回追求不漏,重排负责挑准
一种的盲区正好是另一种的强项,所以只上一种等于主动放弃一半召回。

两种检索方式

关键词擅长精确串、向量擅长换说法,两者的盲区正好互补。真正拉开差距的是召回之后那一次重排。

关键词擅长精确串,向量擅长换说法,两者的盲区正好互补。所以真实系统几乎都是混着用,再补一次重排。「做知识库就是上向量库」这句话漏掉了后面两步,而漏掉的那两步恰恰决定答得准不准。把「先检索、再作答」这套做法命名为 RAG 的那篇论文,检索那一环用的就是稠密向量召回。rag-paper

读完你能回答:

  • 用户输货件追踪号找不到,问题出在哪一路?
  • 为什么两路都要跑,只跑一路会丢什么?
  • 重排比向量多做了什么,为什么它最值得先上?
  • 召回了十几段都塞进去,为什么反而更差?

输编号找不到,是字面这一路缺了

同一个「找不到」,成因完全不同,先分清是哪一种。

关键词检索走的是字面重合:用户输入什么词,就去找包含这些词的文档,再按词频和稀有度打分。搜索引擎沿用了很多年的成熟做法,快,而且结果容易解释。它的强项是精确串——货件追踪号、图纸版本号、设备序列号、员工工号。这类内容不存在同义词,字面本身就是全部信息;但用户只要换个说法,它就抓瞎:用户写「机子开不起来」,工单里记的是「设备无法启动」,字面零重合,直接漏掉。

向量检索看意思接近程度,强弱刚好对调:换种说法来问、用大白话问、概念上相关的内容,它都能捞回来,但精确串不灵。为什么?一串追踪号在训练语料里承载不了什么语义,变成坐标之后就和别的数字串挤在一处,互相之间分不开。它拿手的是「差不多」,而追踪号偏偏要求一个字都不能差。

向量还有两个软肋:对否定不敏感(「支持」与「不支持」的坐标挨得很近),以及对新词无能为力——上周刚上线的新功能名,向量模型训练时从没见过,不知道把它摆在图中哪个位置。而关键词遇到新词毫无压力,照着字面匹配就够了。

反过来说,用户输入一个编号却什么都没搜到,那多半不是向量的错——是字面这一路没接上。

配之前,先把真实提问读一遍

这一节给的是判断顺序,不是具体数字——阈值要靠你自己的数据定。

最后一条动作之所以放在最前面,是因为它会改变前面所有取值:把用户真实打过的提问拉出来通读一遍。 你很快就能看出自己的场景偏口语还是偏编号,两路的配额和权重该往哪边倾斜。这一步比调任何参数都有效,而且多数团队从来没做过。

读完日志,接下来要定的就是三件事——具体做法在后面两节展开,这里先把判断摆清楚:

两路并行召回,两路都要留够量。只调一路的数量,另一路的盲区还在。

合并时给双路命中加权。同一段如果两路都召到了,它相关的可能性就更大,可以额外加点分。

重排之后设一条分数下限。如果重排给出的最高分也低得可怜,说明库里根本没有相关内容,此时应该走「不知道」那条分支,而不是硬凑几段让模型去编。想减少答错,这条比调排序更管用。

合并时按名次算,不按分数加

把两路的强弱摆在一起看,结论很直接:它们的盲区几乎不重叠,所以只跑一路等于主动放弃一半召回能力。

混合的做法很朴素,四步一条线:

  1. 两路各自召回一批候选——关键词一路、向量一路,两边都留足量。
  2. 合并去重,同一段在两路都出现的标记出来。
  3. 统一排序,进入下一步重排。
  4. 重排取前几名,送进模型。

其中第 3 步有个细节:两路的分数量纲不同,不能直接相加。常见做法是依据名次而非分数来融合——各路的每一段按它在本路排第几换算权重,然后再合并。具体算法不必深究,但要知道这里的取值需要自己调。

工作量不大,多数向量库和搜索引擎都已经内置了这个能力。针对 RAG 失败模式的研究也得出同样的经验——查询语义相近但字面不同时,只用单一检索是最常见的翻车点之一。rag-failure-points 实践中的结论也很一致:混合几乎总比单一好,在既有大量口语化的提问、又充斥着各种编号的企业知识库场景里,这一点格外突出。

只有重排是真的把问题读了一遍

召回阶段追求不漏,所以宁可多召——两路合起来拿几十段。但这些段不能一次全塞给模型:既贵,又会把重点稀释掉。

于是加一个重排模型:它把问题和每一段合在一起读,判断「这一段能不能回答这个问题」,据此重新打分,只留下最好的几段。

它和向量的关键差异就在这里:向量让问题和文档各自算坐标再比距离,信息在压成坐标那一刻就丢了;重排把两者一起读,细节都看得到,判断的准确度高出不少。慢一些、贵一些是它的代价,但每次只处理几十段,总成本依然很低。相似不等于相关 讲的那个问题,主要就靠这一步纠正。

很多团队会跳过这一步,而它通常是整条链路里收益最高的一次改进。原因在成本结构上:召回阶段无论怎么调,都只是在改变候选集合;重排是唯一一个真正读了问题的环节。如果你现在只有一路向量检索,加上关键词再加重排,通常比继续调相似度阈值有效得多。

答错的时候,先分成两步查

这一层的输出是几段候选材料,它最终决定模型能看见什么。所以配完之后要能回答一个问题:当它答错时,你怎么知道是没找到还是没答对?这就是按四步往前查要处理的事。想先看这几段在整条链路里的位置,先检索再回答:四步从建库讲到拼上下文。

还有一条边界要留在心里:把召回做得更准,仍然只保证「找出可能相关的内容」。复杂场景里真正决定判断对不对的那些约束,措辞往往和问题不相似,也不会自然地出现在召回结果里——知识库要先对齐领域讲的是为什么这件事要靠结构来兜,而不是靠调检索。

参考资料

  1. Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks — arXiv
  2. Seven Failure Points When Engineering a Retrieval Augmented Generation System — arXiv