很多 RAG 排错会停在一句“正确文档已经进 TopK”。这句话听起来像结论,其实只是一位证人的口供:某个片段曾经出现在候选列表里。它没有证明片段覆盖了全部必要事实,没有证明片段越过重排与截断进入模型,也没有证明模型最后写出的每个声明都来自这些证据。
于是,团队一边看着不错的相似度,一边面对答非所问、漏掉限制条件、混淆新旧版本和凭空补充等问题。
本文换一个调查方向:不再从流水线左端逐项巡检,而是从最终错答逆向追踪。先把答案拆成原子声明,再为每条声明寻找支持、反证与缺失条件,最后沿“模型实际看见的上下文—重排结果—候选召回—原始语料”反向寻找最早断点。
这样,一次错答就会从模糊的质量问题,变成一宗可以归因的证据链断裂事件。
这套方法不依赖特定厂商。它的目标不是证明某个评测框架分数最高,而是为每个坏例留下案件编号、现场快照、声明与证据的映射、最早失败点和复验结果,让修复动作能够准确送到责任环节。
一、先封存错答现场:TopK命中只是一份旁证
假设用户问:“某项内部流程在什么条件下需要二次审批?”
检索结果里确实出现了制度文档,因此调试者宣布召回正常。但仔细检查,可能存在四种完全不同的情况:
- 召回的是已经废止的旧版本;
- 命中片段只包含审批动作,没有包含适用条件;
- 正确片段排在很后面,前面的大量相似文本稀释了注意力;
- 证据完整,但生成模型把“满足任一条件”改写成了“同时满足全部条件”。
这四种情况在“有没有命中文档”这个粗指标上都可能得到一分,修复位置却完全不同。
端到端成功至少要连续满足三件事。
第一,检索成功。参考片段进入了候选集合,并出现在合理位置。
第二,证据成功。真正传给模型的上下文包含回答所需的事实,没有因为切分、过滤、权限或长度预算丢掉关键限定。
第三,生成成功。答案中的每个外部事实都能回指证据,同时没有遗漏用户真正询问的内容。
把这三件事压成一个“回答正确率”,相当于只记录“案件发生了”,却丢掉了证据链究竟断在哪里。
发现错答后,不要立刻重跑,也不要先调整 TopK。首先保存用户问题、最终回答、候选片段、重排顺序、实际上下文、语料快照和组件版本。
随后把回答拆成最小可核验声明,并分别标记:
supported:声明能够被上下文直接支持;contradicted:声明被上下文明确反驳;not_in_context:上下文没有提供足够证据;irrelevant:声明与用户问题无关。
答案级的“对或错”适合汇报,声明级状态才适合定责。
RAGAS 的原始论文把相关且聚焦的检索上下文、模型对上下文的忠实利用,以及生成质量列为不同维度。ARES 也分别讨论上下文相关性、答案忠实度和答案相关性。
这些研究真正重要的启发,不是必须采用某个现成分数,而是评测对象必须与系统阶段对齐。检索器不应该为生成模型的幻觉背锅,生成模型也无法从根本上补回从未进入上下文的事实。
因此,第一次改造不是更换模型,而是改变记录结构。每次运行都必须能够回答:
- 用户的问题是什么;
- 参考事实是什么;
- 哪些文档或片段被视为相关;
- 实际取回了哪些片段;
- 片段的排序发生了什么变化;
- 最终传给模型的上下文是什么;
- 模型生成了什么答案;
- 每个阶段分别使用了哪个版本。
如果只保存问题和最终答案,事后便无法判断错误是在索引前、检索中,还是生成后发生的。
二、建立案件档案:让每条声明都能找到证物
一个实用的评测单元,不应该只是“问题—标准答案”二元组。
它至少应包含问题、期望事实列表、参考文档标识、参考片段标识、实际检索片段及排序、最终上下文、生成答案和不可回答标签。
为了能够复现实验,还要保存语料快照、切分配置、过滤条件、检索器版本、重排器版本、提示词版本和生成配置。
敏感正文不一定要进入日志,但稳定的内容哈希、片段 ID 和版本标识必须留下。
期望事实最好写成原子声明,而不是一段文学化的标准答案。
例如,可以把下面这句话:
申请人在金额超过阈值或涉及指定地区时需要二次审批,并由风控负责人确认。
拆成三个声明:
- 金额超过阈值会触发二次审批;
- 涉及指定地区会触发二次审批;
- 二次审批由风控负责人确认。
这样就能区分“答案完全错误”和“答案正确但漏了一项”。
如果只保留一整段参考答案,自动裁判容易受到措辞差异影响,人工复核也很难指出具体缺口。
参考文档与参考片段也要分开。
文档级标签适合回答“正确材料有没有出现”,片段级标签则适合回答“送入模型的文字是否真的包含证据”。
同一份文档里可能同时存在已废止条款、例外说明和当前规则。仅凭文档 ID 命中就算成功,会掩盖切分边界和版本混杂问题。
对于长表格、FAQ 和多级标题,片段还应保留父标题、页码、表头或路径。否则片段离开原文以后,可能失去完整语义。
一条案件档案可以采用下面的结构:
{"case_id":"rag-eval-0042","question":"什么条件下需要二次审批?","expected_claims":["条件A触发","条件B触发","由指定角色确认"],"reference_chunk_ids":["policy-v7-3.2","policy-v7-3.3"],"retrieved":[{"chunk_id":"policy-v7-3.2","rank":1},{"chunk_id":"policy-v6-3.2","rank":2}],"context_chunk_ids":["policy-v7-3.2","policy-v6-3.2"],"answer":"……","corpus_version":"2026-07-06","pipeline_version":"candidate-b"}Ragas 的评测模式同样会区分user_input、retrieved_contexts、reference_contexts和response等字段。
真正关键的是,不要在评测前把这些字段过早拼成一个字符串。只有保留结构,才能分别计算确定性指标、运行声明级核验,并在失败时展示原始证据。
三、反查候选现场:证据何时出现,又在哪里失踪
候选现场首先使用不依赖生成模型的确定性指标。
Recall@K 关心参考相关片段中有多少进入了前 K 个结果,适合发现漏召回。
Precision@K 关心前 K 个结果中有多少真正相关,适合发现噪声。
NDCG@K 同时考虑相关性等级和排序位置,适合在一个问题同时存在核心证据、补充证据和弱相关背景时比较排序。
这三个指标没有谁能单独代表检索质量,因为它们回答的是不同问题。
例如,前十条结果包含全部两条参考证据,Recall@10 可以很高;但另外八条都是噪声,Precision@10 仍然很低。
如果核心证据排在第十位,平均相似度可能看起来不错,模型实际使用它的机会却会下降。
反过来,把 K 调得很小可能提高精度,却会让需要多条证据组合的问题丢失补充条款。
因此,参数扫描不能只追一个平均分,而应同时观察召回、噪声和排序,并按照问题类型分组。
检索失败还要继续定位到候选生成之前还是之后。
如果参考片段从未进入候选集,需要检查:
- 文档解析是否正确;
- 切分是否破坏语义;
- 索引是否成功写入;
- Embedding 空间是否一致;
- 查询改写是否改变原意;
- 元数据过滤是否误删目标文档。
如果候选集包含参考片段,但最终列表将它丢弃,需要检查:
- 重排器;
- 去重规则;
- 多样性策略;
- 权限过滤;
- 最终保留数量。
如果排序正确,但最终上下文仍然缺少目标证据,需要检查:
- 上下文拼装;
- 字符或 Token 预算;
- 去重规则;
- 截断顺序;
- 片段合并策略。
只有同时记录候选集、重排后列表和最终上下文三个快照,才能分清证据究竟在哪个位置失踪。
BEIR 的价值在于提醒我们:检索器在单一同质数据集上的好成绩,并不能代表跨领域表现。
实际评测集应覆盖短问句、长描述、术语缩写、多条件问题、表格问题、跨文档问题和带时间约束的问题。
同时还要覆盖不同文档形态,例如规范、FAQ、代码、日志、表格和扫描件解析文本。
如果所有测试都来自一批结构整齐的 FAQ,评测结果只能说明系统擅长处理这类 FAQ。
最后,不要把检索器返回的相似度当成跨模型通用的概率。
不同索引、距离函数、归一化方式和重排器产生的分数含义不同。案件档案可以保存原始分数,用于同配置诊断;但发布判断应该基于已经标注的相关性和稳定指标,而不是硬编码一个从其他系统抄来的相似度阈值。
四、检查送达证物:相关上下文不等于完整证据
确认候选召回以后,下一站是检查真正传给模型的上下文。
上下文证据至少包含四个维度:
- 相关性:片段是否与问题有关;
- 充分性:片段是否覆盖回答所需的全部声明;
- 一致性:不同片段是否互相冲突;
- 时效性:版本和生效范围是否适用于当前问题。
一个片段可以高度相关,却不足以支持完整答案。
充分性是最容易被忽略的一项。
多条件问题往往需要来自两个章节的证据;比较题需要双方材料;流程题需要触发条件、执行步骤和例外情况。
当系统只召回其中一半时,生成模型可能用自身常识补齐剩余内容,最终得到一段流畅但没有证据的回答。
评测时应该把期望事实映射到参考片段,再检查最终上下文覆盖了哪些事实。
可以计算“被上下文支持的期望声明比例”,但同时必须保留缺失声明列表。这个列表通常比单个分数更适合排错。
一致性检查也不能简单地把重复文本删除。
两个版本的条款可能文字相似,结论却不同;同一制度的正文与例外条款也可能表面矛盾。
上下文拼装应保留版本、生效时间、适用对象和来源优先级。
评测样本则要包含至少一组冲突证据,确认系统会提示冲突、请求澄清或按照明确规则选择,而不是随机吸收排在前面的片段。
还要专门设计“不可回答”样本。
以下情况都不应该被迫生成确定结论:
- 语料中完全没有答案;
- 语料只包含部分条件;
- 问题超出了当前权限;
- 问题引用了不存在的版本;
- 上下文中的证据彼此冲突。
这类样本的成功标准,不是与某段参考答案相似,而是能够识别证据不足,明确说明缺少什么,并避免把模型参数中的记忆伪装成知识库事实。
如果评测集全部都是可回答问题,就无法知道系统是否会在证据空白处编造答案。
实践中,可以为证物状态设置以下结构化标签:
sufficient:证据充分;partial:只有部分证据;conflicting:证据互相冲突;stale:证据已经过期;unanswerable:现有语料无法回答。
除了状态,还应记录已经支持和仍然缺失的声明 ID。
这样生成层可以接收更明确的控制信号:证据充分时正常回答,部分充分时只回答已经证实的部分,证据冲突时呈现差异,不可回答时拒绝猜测。
关键是把“是否应该回答”变成可评测的契约,而不是只在提示词中写一句“请勿编造”。
五、核验最终口供:忠实、正确、相关、完整是四件事
最终回答至少要从忠实度、正确性、相关性和完整性四个方向核验。
忠实度比较回答与模型实际看到的上下文,检查每个外部声明能否从证据中推出。
正确性比较回答与人工确认的参考事实,检查结论是否真实。
相关性比较回答与用户问题,检查模型是否真正回答了问题。
完整性比较回答与期望声明,检查答案是否遗漏关键条件。
这四项可能出现看似矛盾、实际上完全合理的组合。
例如,上下文本身是一份旧版制度,模型逐字复述。此时答案对上下文很忠实,但相对于当前参考事实并不正确。
又如,上下文缺少一个条件,模型只回答现有证据可以支持的部分。它可以既忠实又正确,却并不完整。
再如,答案包含全部正确事实,但在开头写了大量无关背景。它的正确性可能很高,相关性和可用性却仍然较差。
只有把指标分开,团队才知道应该更新语料、改善检索、调整生成约束,还是优化表达。
忠实度最好按照声明进行核验。
先把答案拆成最小可判断的事实声明,再为每条声明寻找支持片段,并记录:
supported;contradicted;not_in_context。
不要只让裁判返回一个从 0 到 1 的数字。至少应该保留声明文本、证据片段 ID、判定结果和理由。
Ragas 当前 Faithfulness 实现的核心思路,也是先生成声明,再判断声明是否能从检索上下文直接推出。
源码同时表明,如果没有可评分声明,结果可能是 NaN。
这种状态不是“完全不忠实”,更不是“默认通过”,而是评测器没有产出有效判定。
正确性需要可靠的参考事实。
对于高风险规则、数字、日期和条件关系,优先使用人工维护的原子声明和精确匹配规则。
对于允许多种表达方式的解释性回答,可以使用 LLM 裁判,但必须明确参考事实、评分标准和冲突判定规则。
相关性也不应该奖励无边界扩写。先检查答案是否直接回应问题,再检查背景是否有助于理解,最后限制与任务无关的内容。
完整性尤其适合使用多声明覆盖方式进行评估。
把期望事实设置成集合,分别统计答案明确覆盖、部分覆盖和遗漏的项目。
如果答案把两个条件之间的“或”写成“且”,不能因为关键词都出现了就算覆盖。关系词、否定词、主体和时间范围都必须进入核验。
声明级记录能够让这类错误变得可见,也方便人工快速复核最重要的失败案例。
六、建立判例库:覆盖失败类型比盲目堆数量更重要
建立评测集时,最常见的误区是先追求数量。
随机生成几百个同质问答,可能让平均分显得很稳定,却覆盖不到真正会引发事故的边界。
更有效的起点是按照真实任务分类:
- 事实查询;
- 多条件归纳;
- 内容比较;
- 操作步骤;
- 时间与版本问题;
- 跨文档组合;
- 表格读取;
- 缩写与别名;
- 不可回答问题;
- 冲突证据。
每一类先选择少量代表案例,确保每个失败阶段都有样本,再逐步扩充。
样本来源可以分为三路。
第一路是业务或产品验收问题,由领域人员给出期望声明和权威来源。
第二路是生产坏例,去除敏感信息后回流,并保留真实措辞和失败上下文。
第三路是有目的的扰动,例如同义改写、拼写错误、旧版本干扰、相近实体、缺少一个条件和互相矛盾的片段。
合成问题可以补充覆盖,但不能替代真实问题。因为合成器很容易生成与语料措辞过度贴合的简单问题。
标注过程应把“相关文档”“相关片段”“期望声明”和“可回答状态”分开。
标注者可能对相关性产生分歧,因此需要明确规则:
- 片段属于直接证据、补充背景还是无关内容;
- 是否必须同时出现多条证据;
- 旧版本是否算相关但不适用;
- 只包含答案关键词、却没有关系信息的片段是否算证据。
对于存在争议的案例,应保留多个标注和最终裁决记录,而不是静默覆盖。
划分数据时,不要让同一文档的高度相似问题同时出现在调参与验收集合中。否则团队很容易针对少数文档过拟合。
还应该保留一个冻结的小型回归集,只在发布前运行。日常调参使用开发集,线上坏例进入候选池,经人工确认后再升级为长期样本。
语料更新时,不要直接重写旧标签,而应该创建新版本。这样才能区分“系统发生退化”和“事实本身发生变化”。
平均分之外必须查看切片。
可以按照问题类型、文档类型、语言、长度、权限范围、是否跨文档、是否不可回答等维度拆分。
总体提升可能掩盖某个关键切片的大幅下降。对高风险切片设置独立门槛,对低风险表达问题允许人工抽样复核。
发布决策的重点不是追求一个完美数字,而是明确哪些退化绝对不能接受。
样本还要覆盖“近似正确”的困难负例。
普通负例与问题毫无关系,检索器很容易将其排除。真正危险的是:
- 同一产品的旧版手册;
- 名称相近但主体不同的制度;
- 只差一个否定词的条款;
- 数字单位不同的表格;
- 包含大部分答案却缺少适用范围的片段。
这类内容最容易获得较高相似度,也最容易诱导生成模型补齐错误结论。
可以为这些片段单独增加hard_negative标签,观察候选生成和重排是否真正理解了关键差异。
标注质量本身也需要检查。
每个样本至少经过一次独立复核。争议通常集中在直接证据与背景材料的边界、条件关系是否完整,以及问题在当前语料版本下是否可回答。
可以定期抽样计算标注一致性,但更重要的是保存分歧原因。
如果两个领域人员对规则本身的理解不同,系统评测无法替组织完成事实裁决。应该先明确权威来源和生效范围,再更新参考声明。
评测集规模扩大后,还要防止重复样本让某类问题获得过高权重。
可以按照问题意图和参考片段进行聚类,检查大量改写是否都指向同一事实。
报告同时提供“按样本平均”和“按意图平均”,避免某个热门问题的几十种说法主导总体结果。
对于少见但高风险的案例,不要依靠重复数量提升权重,而应在发布闸门中设置独立的全量通过条件。
最后,为每个样本建立生命周期:
- 新增;
- 已复核;
- 冻结;
- 待更新;
- 已废止。
当语料版本变化导致参考事实失效时,样本应转为待更新,并从当前发布判定中隔离。不能继续使用旧事实给新系统扣分,同时也要保留历史版本,用于回放旧事故。
评测数据不是一次性的测试脚本,而是一套需要版本、审阅和变更记录的工程资产。
七、自动裁判只是鉴定助手,不能成为唯一事实源
LLM 裁判适合判断语义等价、声明是否得到证据支持,以及回答是否切题。
但裁判本身也会受到模型版本、提示词、顺序、上下文长度和输出格式影响。
ARES 使用少量人工标注样本校准自动评测的思路值得借鉴:先建立人工金标准,再测量裁判与人工的一致性,最后才扩大到更多样本。
没有校准集的自动分数,只是另一个模型的意见。
校准时至少要观察误报和漏报。
忠实度裁判可能把常识推断误判成证据支持,也可能因为同义表达将正确答案判为不支持。
正确性裁判可能偏好更长、更接近参考答案措辞的文本。
成对比较还可能受到答案顺序影响。
对关键指标,可以交换候选顺序后再运行一次,或者使用两个独立提示词进行交叉检查。
如果判定不一致,应将案例送入人工复核,而不是取一个看起来很精确的平均数。
裁判提示词必须版本化,输出采用严格结构,并包含判定、理由以及引用的声明或片段 ID。
每次运行还应记录:
- 裁判模型标识;
- 提示词哈希;
- 温度等生成设置;
- 重试次数;
- 原始输出;
- 解析状态。
裁判升级时,先在冻结校准集上并行运行旧版和新版,比较混淆矩阵和切片差异。
不要把裁判变化造成的分数漂移,误认为 RAG 流水线发生了变化。
自动评测还需要明确的失败状态。
网络错误、超时、内容被截断、结构化输出解析失败、没有生成声明、输入上下文为空,都应该记录为evaluation_error并单独统计。
Ragas 既往错误中出现过No statements were generated和 NaN,当前源码也明确在声明列表为空时返回 NaN。
流水线必须在聚合前检查数值是否有效,不能让 NaN 被数据库默默丢弃,也不能用零填充后误判为模型退化。
对于高风险声明,保留人工抽样是必要的。
可以优先抽查以下案例:
- 自动裁判置信度较低;
- 多个裁判结论不一致;
- 涉及否定或数量关系;
- 引用了互相冲突的文档;
- 版本切换后首次出现。
人工反馈应该回写到校准集和错误分类,而不是只修改本次报告。
这样,裁判本身也会进入持续回归,而不是成为一个不可质疑的黑盒。
八、用请求ID封好证物袋:把错误码和中间产物串起来
离线评分只有在能够回到运行证据时,才具有调试价值。
每条请求都应该生成一个稳定的逻辑请求 ID,并在检索、重排、上下文拼装、模型调用和评测阶段持续传递。
阶段记录至少包含开始与结束时间、输入版本、输出数量、状态码、错误类型和内容哈希。
不要记录真实密钥,也不必默认保存完整用户正文。可以通过脱敏字段、短期受控样本和哈希定位,在排错能力和最小化采集之间取得平衡。
开发工具中最值得查看的,不是一张成功界面的截图,而是最终请求和中间产物。
检索阶段检查:
- 过滤条件是否按预期生效;
- 候选数量是否为零;
- 参考片段是否在重排前出现。
上下文阶段检查:
- 实际传给模型的片段 ID;
- 片段顺序;
- 截断原因;
- 版本和来源信息是否保留。
生成阶段检查:
- 结束原因;
- 解析状态;
- 答案声明。
评测阶段检查:
- 裁判输入是否与生成时的上下文一致;
- 裁判使用的模型和提示词版本;
- 是否出现解析失败或无有效声明。
如果裁判看到的文本与模型当时看到的文本不同,忠实度分数就没有可比性。
错误也应该按照阶段分类。
例如:
retrieval_empty:没有候选结果;context_truncated:候选存在,但上下文预算丢弃了证据;generation_empty:模型调用完成,却没有可用答案;evaluation_nan:评测器没有产生有效数值;judge_parse_error:裁判输出不符合预期结构。
retrieval_empty还应继续区分索引未写入、过滤清空、权限拒绝或查询异常。
分类之后,再附加原始 HTTP 状态、框架异常和请求 ID,避免把所有情况都压成一句“RAG 失败”。
调试比较必须控制变量。
首先固定语料快照、问题集、生成模型和提示词,只修改切分或检索参数。
然后固定检索结果,只比较上下文拼装策略。
最后固定上下文,只比较生成提示词或模型。
一次同时更换 Embedding、TopK、重排器和提示词,即使总体分数有所提升,也无法知道贡献来自哪里,更无法在发生退化时快速回滚。
为了让对照实验可信,还要记录缓存命中和随机性。
如果候选版本复用了旧检索缓存,而基线重新计算,那么比较的就不是两个配置。
如果生成模型存在随机采样,只运行一次也可能把偶然波动误认为改进。
实验记录应该注明缓存策略、随机种子是否可控、每个案例的重复次数和聚合方式。
对于无法完全确定的模型输出,优先检查逐案例方向是否稳定,并把波动最大的案例送入人工复核。
生产追踪和离线评测应该共享同一种案例格式。
线上发现坏例后,通过请求 ID 拉取脱敏的问题、片段 ID、版本和答案,经人工确认后写入候选评测集。
离线重放产生的新结果,再与原始运行进行比较。
这个闭环比只看线上满意度更可操作,因为它把用户反馈连接到了具体的流水线阶段。
九、观察失败标签迁移:让证据链直接决定能否发布
发布前,基线版本与候选版本必须在同一语料快照、同一评测集和同一裁判配置上运行。
首先比较确定性检索指标,然后比较证据状态分布,最后比较生成指标。
如果检索 Recall 提升,但上下文噪声明显增加,就不能只看第一项宣布成功。
如果忠实度提升,但完整性下降,也要判断产品是否能够接受更加保守的回答。
发布闸门应该表达这种权衡,而不是把全部指标加权成一个难以解释的总分。
确定性指标可以设置硬条件,例如:
- 高风险参考片段不得从前 K 个结果中消失;
- 不可回答样本不得生成无证据的确定结论;
- 关键条件关系不得从“或”变成“且”;
- 有效版本不得被旧版本覆盖;
- 权限过滤不得让无权用户看到不应访问的证据。
LLM 裁判分数具有一定波动,更适合采用重复运行、置信区间或允许的小范围变化,并对边界案例进行人工复核。
不要把小数点后很多位当成确定性,也不要因为一次运行高于阈值就忽略方差。
发布闸门还要检查失败率。
评测任务超时、NaN、解析错误和缺失追踪,不是可以从分母中删除的杂项,而是评测基础设施不可靠的信号。
应该先要求有效评测覆盖率达到预期,再比较质量分数。
否则,候选版本可能通过“让困难案例无法评分”获得更高的平均值。
报告应该同时列出:
- 总样本数;
- 有效样本数;
- 各类错误数量;
- 进入人工复核的样本数。
每次变更还应生成差异报告:
- 哪些案例从通过变成失败;
- 哪些案例从失败变成通过;
- 最早断点从哪一站迁移到了哪一站;
- 相关片段顺序发生了什么变化;
- 声明判定发生了什么变化。
团队应该优先阅读差异最大的案例,而不是根据平均分猜测原因。
如果候选版本失败,应能回到对应配置版本和证据快照;如果候选版本通过,也要保存结果,作为下一次比较的基线。
上线以后,可以继续进行小比例在线抽样,但在线分数不能替代离线金标准。
线上数据负责发现新的分布和失败方式,离线集合负责稳定地比较版本。
新增坏例需要先去除敏感信息、确认权威事实并标注失败阶段,然后再进入长期回归集。
这样,评测集会随着真实问题增长,同时保持每个样本的来源和判定结果可追溯。
十、结案清单:回答哪句错、断在哪里、如何防止复发
整套方法可以从一条最小闭环开始。
第一步,为现有 RAG 请求增加稳定的案例 ID,保存问题、片段 ID、顺序、上下文、答案和版本。
第二步,选择覆盖不同问题类型的小型集合,为每条样本标注参考片段、期望声明和可回答状态。
第三步,从错误声明逆向核对 Recall@K、Precision@K 和 NDCG,并保存漏召回和低排序的片段。
第四步,检查实际送达的证据,标记充分、部分、冲突、过期和不可回答。
第五步,把答案拆成声明,分别核验忠实度、正确性、相关性和完整性。
第六步,为自动裁判准备人工校准集,记录裁判模型和提示词版本,把 NaN、超时和解析错误设置为显式失败。
第七步,按照问题、文档、风险和可回答性查看切片,而不是只看总体均值。
第八步,让基线版本与候选版本在固定快照上并行重放,输出逐案例差异。
第九步,把关键确定性条件、裁判有效覆盖率和高风险人工复核写入发布闸门。
第十步,将线上坏例按照相同数据结构回流,持续扩大评测覆盖。
如果需要在 OpenAI 兼容客户端中做最小链路核验,应先区分三个地址层级:
- 服务根地址:
https://api.vectorengine.cn - 兼容接口前缀:
https://api.vectorengine.cn/v1 - Chat Completions 接口:
https://api.vectorengine.cn/v1/chat/completions
这三个字符串代表不同的配置层,不能在客户端字段中想当然地互换。
示例凭据只应使用YOUR_API_KEY或环境变量VECTORENGINE_API_KEY,不要在案件档案、日志或截图中保存真实密钥。
最终验收时,不要只问“总分是多少”,而应该问三组可以执行的问题:
- 候选现场能否指出缺失片段和错误排序?
- 送达证据能否指出缺失、冲突或过期的声明?
- 最终回答能否把每条声明回指到证据,并区分忠实、正确、相关和完整?
如果其中任何一个问题只能得到一个无法追溯的数字,评测体系就仍然不具备排错能力。
真正可用的评测体系,还应该让一个没有参与事故的新成员,只凭一条失败记录就能复现问题:找到相同的语料快照,重放相同的检索配置,查看进入上下文的片段,再核对答案声明与证据。
如果复现仍然依赖当事人的记忆,说明证据链还没有闭合,也不适合承担自动发布判断。
RAG 系统最危险的状态,不是偶尔答错,而是答错以后只能得到一句:“检索已经命中,可能是模型问题。”
这句话把文档、解析、切分、过滤、召回、排序、裁剪和生成全部藏进了一个模糊结论。
把错答视为证据链断裂,改变的是团队观察系统的单位:从整段答案变成原子声明,从“有文档”变成“证据完整送达”,从单一总分变成失败标签迁移,从一次修复变成可以持续回放的判例。
当每条错误声明都能追溯到最早断点,Recall@K、Precision@K、NDCG、忠实度、正确性、相关性和完整性,才不再是一组用于展示的名词,而会真正成为守住不同链路的工程仪表。
参考资料
RAGAs: Automated Evaluation of Retrieval Augmented Generation
https://aclanthology.org/2024.eacl-demo.16/ARES: An Automated Evaluation Framework for Retrieval-Augmented Generation Systems
https://aclanthology.org/2024.naacl-long.20/BEIR: A Heterogenous Benchmark for Zero-shot Evaluation of Information Retrieval Models
https://arxiv.org/abs/2104.08663Microsoft Learn, Retrieval-Augmented Generation Evaluators
https://learn.microsoft.com/en-au/azure/foundry/concepts/evaluation-evaluators/rag-evaluatorsLangChain Documentation, Evaluate a RAG application
https://docs.langchain.com/langsmith/evaluate-rag-tutorialRagas Faithfulness metric source
https://github.com/vibrantlabsai/ragas/blob/main/src/ragas/metrics/_faithfulness.pyRagas evaluation schemas
https://docs.ragas.io/en/latest/references/evaluation_schema/