第 5 章 — 搭一条检索流水线
LLM Primer III: Enhancing Enterprise AI with RAG 章节走读的第五篇。一次向量搜索是大多数 demo 停下的地方,也是大多数生产故障开始的地方。本章把一条从半成形的查询走到送进生成器的那组候选的全路径走完 — 以及每一步存在的理由。
这一章为什么存在
第 2 到第 4 章产出了一座向量库:文档解析、谨慎分块、嵌入、入索引。下一步的朴素做法是把用户查询嵌入、跑一次最近邻、把 top-k 送进生成器。在小语料上这能跑。在生产里几乎不行。查询常常说不全、塞满嵌入器没见过的专有名词;语料里满是近重复,把任何单一排序的前几名挤满;标识符和代码携带的语义,被嵌入器抹平了。
第 5 章讲的是成熟系统终归会收敛到的那种架构。它不是研究产物。它是当召回、精度、延迟必须同时立得住的时候,团队真正会跑的形态。
5.1 一次向量搜索为什么不够
稠密检索把搜索的经济学改写了,但同样是「容得下改写」让嵌入有用的那一条性质,也让它变脆。数字 token、法条引证、交易代码、零件号 — 凡是「表面形态本身就是含义」的东西 — 在向量空间里落在随便哪个角落。BM25 这种只数「出没出现过」的方法,没这个毛病。
这两种方法在不重叠的输入上各自翻车。仅凭这一句观察,就足以给「混合检索」立案 — 也是本章靠的第一条原则。剩下的顺理成章:既然没有一种检索器足够,流水线就得合上几种,把它们的排名诚实地融合,在最终精度那一刀上花真算力,并且在这一切之前先把查询准备好。
5.2 混合检索:稠密向量与 BM25 并行
同一批块上两份索引:一份来自嵌入器的稠密 HNSW 或 IVF,一份来自 BM25 或 SPLADE 的稀疏倒排。两份都查,两份都返回排好的列表,入库流水线两份同步写。BM25 不是遗产,它是史上最可靠的关键词排序函数,参数少但不是没参数;在 BEIR 这一整套基准上,混合检索在大多数域外任务上跑赢纯稠密。距离嵌入器训练分布越远的领域,差距越大。
有个值得点名的失败形态:BM25 必须按每种入场语言正确分词。把一份日语语料喂给默认英文分析器,BM25 那条腿就静悄悄变成纯噪声,系统看起来还能跑,只是因为稠密那条腿在扛活。稀疏检索这一脉也在演进 — SPLADE 那一档学到的稀疏模型,继承了 BM25 的运维简洁,带着稠密检索器的召回行为。
5.3 Reciprocal rank fusion 与 cross-encoder 重排
合并两份排序的朴素做法是把分数相加。这一招不行 — BM25 量级不受限,且依赖语料;余弦相似度大致落在 [-1, 1]。两者不可通约,任何固定权重都成了一道永恒调参题。Reciprocal Rank Fusion 干脆把分数扔了,绕开问题。对每个候选,它的融合分是各检索器上 1/(k + rank) 之和,k = 60。曲线在顶上陡、在尾上平,对 k 不敏感;这个算法跟多查询展开自然组合 — 三份转述对两个检索器跑出六份列表,一行代码就融合了。
RRF 救不了任何一种检索器都没召回的文档;那活归查询改写。它干的事 — 便宜、无超参 — 是让独立升级、独立替换的两条腿之间的融合,不用重新调参。一条腿一换就得重调融合的流水线,维护成本会贵得多。
那两个产出排名的 bi-encoder,从来没有同时见过查询和块。Cross-encoder 重排器 见到了 — 它把查询和块拼一起,联合过一遍专门调过的 transformer 输出相关性分数。每一个注意力头同时看见两边,模型能精确地把查询里某一短语对到块里某一短语。它不能预计算,所以做主检索器太慢;但在混合检索捞回来的 50 到 200 个候选上,它正合适。NDCG@10 上的提升通常是 5 到 15 个点 — 比在 bi-encoder 家族里换嵌入模型还大。
5.4 查询理解:改写、扩展、HyDE
上面那一整套都默认查询是好好成形的。它通常不是。客服里用户敲「休假」,政策写的是「年度休假权利」;开发者敲「auth fails 500」,运维手册里写的是「身份验证服务返回 HTTP 500 且 token 校验失败」。这一活,得在查询那一侧做。三种样式可以叠:把查询改写 成自包含的(消解代词、展开缩写、把语言切换到与语料对齐);把它扩展 成几条转述,各自分别去打两条检索腿;HyDE,让小模型先写一份假设性回答,把它嵌入而不是把问题嵌入。语料里全是回答,回答看起来更像别的回答,而不是问题。
防御性的样式是把原查询和改写后的并排发一份,鲜活的改写器输出只是假设,不是替代。所谓 agentic 系统里的「检索回退」,大多其实是「改写回退」,没有逐段遥测看不见。
第 5 章接下去会怎么走
这条画出来的流水线,也是攻击者要破坏的全部表面。每一步都收输入、出输出,把它处理的数据当真。语料能在入库时被投毒;嵌入器能被对抗性块操纵;重排器能被偏置;生成器能被藏在检索内容里的指令骗住。从这里起,第四部分开篇,视角从「怎么检索得好」转到「检索被攻击时会发生什么」。
明天 — 第 6 章:RAG 的威胁模型。让 RAG 有用的那种开放性,正是对手利用的那一面 — 语料投毒、对抗性检索、间接 prompt 注入、嵌入反演,以及那位糊涂代理。