Skip to content

필사 모드: 生产级 RAG 模式 — 朴素 RAG 为何失败,以及真正管用的技法

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

引言 — 朴素 RAG 为何失败

RAG(检索增强生成)的基本想法很简单 — 找到与问题相关的文档、贴进提示词,让模型据此作答。2020 年 Lewis 等人的原始论文,把它形式化为参数化记忆(模型权重)与非参数化记忆(外部索引)的结合。演示版半天就能做出来 — 把文档切开、做嵌入、放进向量数据库,再把与问题最接近的前 k 个贴上去,就完事了。

问题在于,这条朴素的流水线会在生产环境中悄然崩塌。而失败大多不来自生成,而来自 检索

  • 向量检索很擅长抓住语义,却 会漏掉精确的 token 匹配 — 错误码、产品 SKU、人名、API 名之类。
  • 从文档里切出来的片段 会丢失自身的上下文。 只看"营收增长了 3%"这一个分块,根本说不清是哪家公司、哪个季度。
  • 检索器即便出错,也会 不声不响地返回貌似合理的片段, 模型却会信心十足地引用它。看着像幻觉,实则是检索失败。

核心的直觉只有一条 — 检索质量为下游的一切设定了上限。 相关文档如果压根没进入上下文,再怎么做提示词工程也救不回来。所以下面这些技法,大多不是瞄准"把生成变得更聪明",而是瞄准"让正确的片段进入上下文"。

也有人想靠扩大上下文窗口、用"全都塞进去"来绕过它,但那并不是解法 — 在长上下文里,模型容易漏掉埋在中间的信息(即所谓 lost-in-the-middle),token 成本和延迟也会一起上升,而最关键的是,正确的文档一开始就得在那里面,这个问题依然原封不动。

分块 — 悄然决定质量的选择

是什么。 把文档切成检索与嵌入的单元。常见的错误是按固定长度(比如字符数)机械地切 — 结果把句子中间、表格正中、代码块中央都劈开了。

何时有用。 让边界落在语义单元上,检索准确率就会提升。实务上的基本功有两条。(1) 尊重结构来切 — 以段落、标题、表格、代码为单位。(2) 滑动窗口/重叠 — 让相邻分块稍微交叠,使跨越边界的句子不会整句消失。"Searching for Best Practices in RAG"(2024) 报告说,大体上 256–512 token 这一档的较小分块,在忠实度(faithfulness)方面更占优。

代价。 分块越小越精确,但上下文也越单薄;越大上下文越丰富,但一个分块里混进杂音,检索信号也随之变糊。正确答案因语料库而异 — 所以分块大小是个该靠评估、而非靠猜测来定的值。

嵌入与混合检索(BM25 + 向量)

是什么。 嵌入检索(稠密·dense)把文本转成向量,靠 语义相似度 来查找。BM25(稀疏·sparse)用 TF-IDF 一系的词法匹配,靠 精确的词语一致 来查找。两者失败的方式不同 — 向量对同义词、改述很强,却会漏掉稀有 token;BM25 对精确 token 很强,可一旦表述变了就找不到。

何时有用。 几乎总是有用。大多数生产语料库里都混着两类查询 — "帮我总结退款政策"(语义)和 "ERR_2043 是什么"(词法)。所以 混合检索(两者一起跑、再合并结果)是个强力的默认选项。合并常用 RRF(Reciprocal Rank Fusion,倒数排名融合),把两个排名的名次取倒数再相加,从而不被某一边的分数尺度带偏。

代价。 得同时运营两套索引(向量 + 倒排索引),还多出一个叫融合权重的调参旋钮。但它通常是 ROI 最高的第一步 — 因为它能把纯稠密检索在结构上必然漏掉的精确匹配查询重新救回来。

元数据过滤 — 先缩小检索空间

是什么。 在给向量、BM25 打分之前(或与之同时),用文档的属性把候选先筛一遍 — 租户 ID、创建日期、文档类型,以及最重要的 访问权限(ACL)

何时有用。 在多租户 SaaS、或权限有别的企业内部知识库里,这不是可选项,而是必需项。把用户无权查看的文档泄进检索结果,那就不是质量问题,而是 安全事故。附带的好处是,检索空间缩小了,精度和延迟也跟着变好。

代价。 得在建索引时就挂上干净的元数据,而且过滤得太窄,可能连正确答案的文档也一并砍掉。记住:过滤器不是排名,而是硬约束。

重排序 — 头部结果的精度

是什么。 一次检索先宽松地捞出候选(比如前 20–100 个),再由 交叉编码器(cross-encoder) 重排器把(查询, 文档)这一对一起读进去,重新给相关度打分。嵌入是把查询和文档分别向量化(双编码器·bi-encoder),而重排器把两者一次性一起看,所以精确得多。

何时有用。 当一次检索的召回率(recall)还不错、但头部精度不尽如人意时。经验法则是"宽进严出" — 检索 20 个、重排到 5 个,再把其中 3–5 个交给模型。前面那篇最佳实践论文强调了它的必要性:一旦拿掉重排序模块,性能就明显下滑。

代价。 交叉编码器要为每个候选各跑一次前向传播,因此会带来延迟和成本。所以它只用在 一份很短的候选清单 上,而非全部。把候选无限制地扩到 100 个、200 个再去重排,通常都收不回本。

上下文检索 — 修复孤立分块问题

是什么。 分块会带来一个根本缺陷 — 切下来的片段丢失了原文的上下文。Anthropic 的 上下文检索(Contextual Retrieval) 会在做嵌入、BM25 索引 之前,在每个分块前面,用 LLM 生成一小段说明该分块在整篇文档中处于什么位置的上下文(通常 50–100 token)并拼接上去。就像"本分块摘自 ACME 2023 年第三季度的财报"这样。

何时有用。 尤其在代词、相对指代很多、且文档偏长的语料库里。Anthropic 报告的数字令人印象深刻 — 以 recall@20 下的失败率(1 − recall@20)衡量,仅靠上下文嵌入就把失败 降低了 35%(5.7% → 3.7%),再加上上下文 BM25 则 降低 49%(→ 2.9%),在此之上再叠加重排序,更是 降低 67%(→ 1.9%)。

代价。 会产生建索引时的开销 — 每个分块都要调用一次 LLM。Anthropic 说明,借助提示词缓存,每处理一百万 token 文档大约 $1.02;但文档每次更新都得重跑,流水线复杂度也会上升。知识库越是静态、引用越是盘根错节,它就越值这个价。

查询改写 — 与检索器在中途会合

是什么。 在检索之前,对用户的原始问题做一番打磨。形式有好几种 — 在对话场景里把后续问题的代词解开、变成独立查询(去上下文化·decontextualize),扩展缩写与术语,把复合问题拆成子查询(多查询·multi-query),或者像 HyDE 那样先生成一个假设的答案、再把它嵌入去检索。

何时有用。 多轮对话、又短又含糊的查询,以及用户用词与文档用词对不上的情形。问题若本就整理得很清楚,反而不太需要它。

代价。 会多出一次 LLM 调用,延迟和成本随之增加,还会带来 新的失败模式 — 改写一旦跑偏,就会招来比原始查询更差的结果。所以改写同样是个该用评估去比较开与不开的对象,而不是一个无脑常开的开关。

评估 — 把检索指标与端到端(end-to-end)分开,用自己的数据

把两个层次分开。 RAG 的评估,一定要分成两条线来看。

  • 检索指标 — recall@k、precision@k、MRR、nDCG。衡量的是"正确的分块有没有进入上下文";需要一份 查询→相关文档 的标注集。
  • 端到端(生成)指标 — 忠实度/据实性(答案是否真的有检索到的上下文作支撑 = 是否幻觉)、答案相关性、答案正确性。通常用 LLM-as-judge 来打分。

为什么要分开 — 因为一个聪明的生成器会 把糟糕的检索给遮住(反过来也一样)。只看端到端分数,检索明明在漏,却可能显得一切正常。检索的 recall 一旦低,用提示词是救不回来的 — 只有把层次分开,才看得见瓶颈在哪。

在生产中,把失败分装进两个桶里的习惯很有用 — (a) 正确的文档一开始就没被检索到,(b) 检索到了,可生成却忽视了它、或用错了。(a) 去修检索这一段(分块、混合、重排序),(b) 去调提示词、强制引用、以及模型。少了这道分类,只盯着端到端分数,就会一直在错的地方修修补补。

公开基准无法预测你的语料库。 从真实查询里抽出一份小小的标注集(几十条就足够起步),对每种技法用 A/B 来比较开与不开。这就是"评估集先于模型"这一 eval-first 原则 的 RAG 版。有了先行的评估,分块大小、融合权重、重排器的选择就不再是口味问题,而成了实验。

务实的落地顺序

别想着一次全上。通常下面这个顺序 ROI 最高。

  1. 先从尊重结构的 分块 + 重叠做起。这里一漏,后面全跟着漏。
  2. 混合检索(BM25 + 向量,RRF 融合) — 把精确匹配查询救回来、最便宜的大改进。
  3. 重排序 — 宽进严出,把头部精度拉上去。
  4. 引用盘根错节的长文档,就上 上下文检索
  5. 对话式、含糊查询多,就上 查询改写

如果语料库是多租户、或权限有别,那么 元数据过滤(尤其是访问权限)就该独立于这个顺序、从一开始就是默认项 — 它不是事后再加的优化,而是第一天就要满足的要求。

还有,在这一切步骤 之前,先做一份小小的评估集。唯有如此,你才能用数字回答每一步到底有没有真的帮上忙。

结语

RAG 不是魔法 — 给 LLM 接上检索,并不会让知识问题消失。它只是 变成了检索问题 而已。而检索是个几十年的老领域,至今依然很难。好在有个好消息:这里最大的改进,往往来自最枯燥的地方 — 不是更大的模型,而是更好的分块、混合检索,以及"多捞一些再重排"的习惯。

若只带走一句,就是这句 — 用自己的数据来评估。 上面这些技法是一个工具箱,而不是一份菜谱。在某些语料库里,上下文检索能扭转全局;在另一些地方,把 BM25 打开就是全部。这种差别,不会在基准里显现,只会在你自己的查询里显现。

参考资料

현재 단락 (1/45)

RAG(检索增强生成)的基本想法很简单 — 找到与问题相关的文档、贴进提示词,让模型据此作答。2020 年 Lewis 等人的原始论文,把它形式化为参数化记忆(模型权重)与非参数化记忆(外部索引)的结...

작성 글자: 0원문 글자: 4,498작성 단락: 0/45