跳到主要内容

测试检索-生成接缝:RAG 系统中的集成测试盲区

· 阅读需 12 分钟
Tian Pan
Software Engineer

你的检索器在 94% 的情况下都能返回正确文档。你的 LLM 在给定良好上下文时能正确回答 96% 的问题。可以上线了。能出什么问题?

把这两个数字相乘:0.94 × 0.96 = 0.90。在不考虑任何边缘情况、提示词格式问题、token 截断,以及检索器与正确文档一起返回的干扰文档之前,你就已经损失了 10% 的查询。但更深层的问题不是这个算术——而是你的单元测试永远不会发现这一点。检索器在隔离测试中通过了。生成器在隔离测试中通过了。失败的是两者的组合,而大多数团队对此没有任何测试。

这就是检索-生成接缝:检索器交付内容与生成器实际能够使用的内容之间的接口。它是生产 RAG 系统中测试最不充分的边界,也是大多数故障的根源。

为什么单元测试无法捕获接缝故障

标准的 RAG 测试方案看起来是这样的:编写一组查询,检查检索器是否返回相关文档,然后在一组精心策划的(查询,上下文)对上评估生成质量。两者都通过了。你部署上线。用户开始提 bug。

问题在于,单元测试是针对你控制的输入来评估每个组件的。在生产环境中,生成器接收的是你的检索器实际构建的上下文——包括其失败案例。"检索器测试上下文"与"生产检索器上下文"之间的差距,正是复合故障的藏身之处。

考虑以下这些接缝特有的故障模式:

  • 截断使答案消失。 你的检索器返回了一个 2,000 token 的文档,答案位于最后 400 个 token 中。你将上下文窗口配置为 1,500 个 token。该文档通过了检索器的相关性检查。答案永远无法到达生成器。
  • 干扰文档污染。 你检索了 top-5 文档。四个正确;一个语义相似但事实相互矛盾。你的生成器在努力全面作答时,将它们混合在一起。检索器测试计算了 precision@5 并认定通过。
  • 结构不匹配。 你的生成器在干净、格式良好的文档上经过微调。你的检索器返回原始 HTML 片段、脱离上下文的表格单元格,或中间断句的分块边界。两个组件测试都没有发现这一点,因为检索器针对干净文档测试,生成器也针对干净上下文测试。
  • 归因消除。 生成器产生了一个听起来正确的答案,但实际上并非基于检索到的上下文——它在使用参数化记忆。你对生成器的单元测试检查了答案质量,而非基础性。

"RAG 七大故障点"框架系统性地识别了这些问题:内容缺失、未排在前列的相关文档、在整合时被排除的文档、未能提取相关信息、格式错误、特异性不当以及答案不完整。注意这些问题是多么清晰地分布在检索故障、接缝故障和生成故障之间——然而大多数团队只对端点进行监控。

设计接缝级测试

测试接缝需要模拟真实检索输出的测试夹具,而非理想化的测试上下文。目标是让你的生成器接触检索器实际会产生的上下文分布。

合成上下文注入是基础技术。与其在手工精心制作的黄金标准上下文上测试生成,不如将检索器的实际输出直接输入生成评估器。这意味着对一组有代表性的查询运行检索器,捕获完整的检索上下文(包括排名、分数和任何检索后压缩),然后将这个精确的上下文输入生成评估器。

三类夹具涵盖了大多数接缝故障:

  1. 正确上下文。 检索器找到了答案。验证生成器是否忠实地提取了它。这是你的基线——如果在这里失败,你有生成问题,而非接缝问题。
  2. 相关但不充分的上下文。 检索器找到了主题相关的文档,但没有一个包含具体答案。验证生成器是否回答"不知道",而非凭空捏造。大多数团队完全跳过这类夹具。
  3. 矛盾上下文。 检索器找到了包含相互冲突声明的文档。验证生成器是否明确承认不确定性或解决冲突,而非悄悄选择其中一个。

每类夹具都能告诉你不同的事情。第一类故障指向你的提示词或模型。第二类故障指向你的置信度校准和拒答行为。第三类故障指向你的上下文结构和生成提示词。

接缝测试只有在与组件测试分开失败时才有用。如果检索器单独测试通过而接缝测试失败,你已将问题定位到交接处。这是可操作的。如果一切都同时失败,你什么都没学到。

指标分割:检索召回 vs. 有据可查的准确性

最常见的评估错误是使用单一端到端准确性指标来评估整个管道。当它下降时,你不知道应该调整嵌入模型还是提示词。

能可靠定位责任的指标分割:

检索端指标:

  • 上下文召回率: 检索集是否包含回答问题所需的所有信息?低上下文召回率意味着你的嵌入模型或分块策略是问题所在——而非你的生成器。
  • 上下文精确率: 相关块的排名是否高于不相关块?低精确率意味着你向生成器传递了太多噪声。
  • Recall@K / Precision@K: 传统信息检索指标,在 A/B 测试中用于比较嵌入模型和重排器时很有用。

接缝特定指标:

  • 上下文相关性: 在实际传递给生成器的块中(经过截断、重排后),有多少比例是相关的?这与上下文召回率不同——它衡量的是组装好的上下文窗口质量,而非只是检索候选的质量。
  • 答案归因率: 在生成答案中的声明里,有多少比例可以追溯到上下文中的特定段落?在答案质量高时归因率低,意味着你的模型在使用参数化知识而非检索到的上下文——这在某些用例中没问题,但在其他情况下很危险。

生成端指标:

  • 忠实度: 答案中有多少声明得到了所提供上下文的支持(且未被反驳)?这是 RAG 的主要幻觉检测器。
  • 答案相关性: 生成的输出是否真正回答了被问的问题?出人意料地与忠实度分离——模型可以忠实于糟糕的上下文,但答案仍然不相关。

在同一测试集上同时运行这些指标。故障模式会告诉你去哪里查找:

模式诊断
低上下文召回率,高忠实度检索问题——修复分块或嵌入
高上下文召回率,低上下文相关性重排或上下文组装问题
高上下文相关性,低忠实度生成问题——修复提示词或模型
高忠实度,低答案相关性提示词指令遵循问题
低归因率,可接受的忠实度模型在使用参数化知识——评估这是否可接受

构建测试基础设施

工具生态已经足够成熟,你不需要从头构建这些。实际问题是如何分层使用这些工具。

RAGAS 专为 RAG 评估而构建。它在大多数指标上无需标注的真实标签即可计算上下文召回率、上下文精确率、忠实度和答案相关性。它的测试数据生成器(SDG Hub)通过多阶段流程创建(问题,上下文,答案)三元组:主题提取、问题生成、问题演化和答案生成。这让你可以从自己的文档中获得一个真实的评估数据集,无需手动标注。

DeepEval 与 pytest 集成,使其很自然地将 RAG 评估关卡添加到 CI 流水线中。你定义指标阈值(例如,忠实度 ≥ 0.7,上下文召回率 ≥ 0.8),如果任何指标低于阈值,测试套件就会失败。这是团队最常跳过的最重要投资——一个在质量回归到达生产环境之前捕获它的 CI 关卡。

TruLens 在应用运行中进行监控,在生产中每次 LLM 调用后应用评估函数。这为你提供了上下文质量和生成忠实度的生产分布,它与你的离线测试分布在重要方面有所不同。

推荐的分层方式:

  • 开发阶段:DeepEval 对每个组件进行单元测试,以及接缝级集成测试
  • 预发布阶段:RAGAS 在每次发布前对代表性查询集进行批量评估
  • 生产阶段:TruLens(或 LangSmith)用于持续监控,当指标退化时发出警报

关键架构决策:在同一个 CI 作业中运行组件测试和接缝测试,使用单独的通过/失败阈值。当接缝测试失败但组件测试通过时,你就捕获到了一个真正的集成回归。

大规模定位责任

在实践中,你会遇到端到端失败的查询,需要确定在哪里投入工程时间。一个系统性的责任定位协议:

  1. 单独通过检索器运行失败的查询。 答案是否存在于检索到的文档中?如果不存在 → 检索故障。如果存在 → 继续。
  2. 将精确检索到的上下文注入一个干净的生成调用中。 生成器是否产生了正确答案?如果是 → 接缝是问题所在(上下文组装、截断、排序)。如果否 → 生成故障。
  3. 注入你手动编写的黄金标准上下文。 生成器是否产生了正确答案?如果是 → 生成模型没问题,问题在于检索器传递给它的内容。如果否 → 你有一个生成模型问题,需要通过提示词更改或模型升级来修复。

这个三步协议能在十分钟内将"RAG 系统给出了错误答案"转化为具体的、可操作的诊断。不遵循这个协议的团队会花几周时间调整嵌入模型,而实际问题是一个告诉模型要有创意的系统提示词。

另一个关键实践:保留追踪记录。每个生产 RAG 查询都应记录检索到的文档、其分数、组装好的上下文(实际传递给模型的内容)以及生成的响应。没有这个追踪,你是在对一个已经被清理过的犯罪现场做取证。有了它,你可以在离线测试环境中重现任何生产故障,并准确理解发生了什么。

让团队陷入麻烦的事情

在生产 RAG 事后分析中,有几种反模式反复出现:

在开发文档上进行评估。 当针对你为其构建的文档进行测量时,你的分块策略看起来非常出色。不同的文档类型——带表格的 PDF、代码文件、多语言内容——通常有截然不同的接缝故障模式。在你的生产文档类型的代表性样本上进行测试,而不只是你开始时用的那些干净文档。

同时调整检索和生成。 当你在同一个迭代周期中更改嵌入模型和系统提示词,而你的指标改善时,你不知道哪个变化起了作用。进行独立的更改,并在每次更改后测量。这会减慢开发速度,但能给你一个关于什么在你的管道中真正有效的可靠模型。

将忠实度视为二元问题。 忠实度分数 0.8 意味着你生成答案中 20% 的声明没有检索上下文的支持。对于回答有关你产品问题的客服机器人来说,那可能是 20% 的声明是捏造的或来自参数化记忆。在构建系统之前,就决定什么样的忠实度阈值对你的用例是可接受的,而不是等用户开始抱怨之后。

忽视"不知道"的情况。 大多数 RAG 评估套件是从可回答的问题中构建的。生产查询包括许多你的语料库无法回答的问题。如果你的系统没有在这些问题上进行评估,你就不知道它在应该拒答时的表现——而且几乎总是比你预期的要糟糕。

持续评估的必要性

RAG 系统的退化方式是传统监控无法捕捉到的。你的嵌入模型被悄悄更新。你的文档语料库在增长和变化。一种新的文档类型被添加到知识库中。这些都不会触发错误警报。它们都可能让你的忠实度分数下降 15 个百分点。

这意味着:RAG 评估不是你运行一次的预部署关卡。它是一个持续的过程,并行监控组件指标、接缝指标和端到端指标——当其中任何一个退化时发出警报。

没有这个基础设施就上线 RAG 的团队是在盲目飞行。他们在某次部署后看到支持工单增加,或听到用户说系统"开始给出错误答案",却没有任何关于什么发生了变化的追踪。而对接缝进行监控的团队有一个具体的信号:文档摄取管道更新后上下文相关性下降,定位到某种新文档类型,可以通过一条分块规则修复。

接缝是你的系统可靠性真正被决定的地方。两端的单元测试通过并不能告诉你它能正常工作。只有接缝处的测试才能。

References:Let's stay in touch and Follow me for more thoughts and updates