RAG 噪声敏感度评测:注入无关与矛盾上下文,量化忠实度退化与回归门禁
检索指标全绿不代表回答可靠。RAG 上线后最常见的劣化不在检索不到而在检索结果里混进了噪声知识库膨胀后召回阈值放宽、embedding 模型升级、旧版本文档没下线都会让 top-k 里混进跟问题相关但内容错误、或完全不相关的 chunk。LLM 对上下文里的具体数字和结论有很强的采信倾向上下文混噪后它很少拒答而是自信地把错的讲成对的——这是 RAG 最贵的故障模式点赞类业务指标短期根本看不出来。噪声敏感度noise sensitivity就是量化这个风险的指标控制变量地往上下文里注入噪声看回答质量退化多少。Ragas 的噪声敏感度指标把噪声按性质分成两类——relevant相关但错误/误导和 irrelevant完全无关两类破坏机制不同注入评测也要分开设计。这篇讲注入实验怎么设计、判定口径怎么定、怎么接成回归门禁附一份可直接改的注入评测代码。两类噪声两种破坏机制先把噪声分清楚后面的实验设计都从这里长出来噪声类型典型来源破坏机制检索指标能否发现irrelevant完全无关跨产品线文档混入、top-k 放宽稀释注意力、占用上下文窗口多数模型能忽略但长上下文推理任务会被带偏不能命中率照常全绿relevant相关但错误旧版本本文档未下线、相似产品条款、同名实体不同客体模型采信上下文中的数字和结论产出忠实于错误上下文的回答不能相关度分甚至更高relevant 噪声最危险原因在检索原理本身embedding 检索做的是语义相似旧版本文档和新版本文档的相似度往往高过不相关内容。所以大部分噪声不是混进来的是被检索器请进来的。评测时注入的噪声必须模拟这个分布——纯随机拼一段话塞进去太假模型识别后直接忽略测不出真实退化。注入实验设计变体矩阵评测集沿用上一篇的三层流水线产物合成打底 日志校准 人工收口取 200-300 条高价值 case。对每条 case 生成 5 个变体变体上下文构成回答的问题v0 基线真实检索 top-k干净检索下的忠实度基线v1 irrelevanttop-k 3 条完全无关 chunk无关噪声耐受度v2 relevant-softtop-k 3 条同主题但无信息量/泛化表述 chunk低质量相关噪声v3 relevant-hardtop-k 3 条与正确答案直接冲突的 chunk旧版本、错误数字矛盾噪声耐受度最狠v4 全噪声上下文全部替换为无关 chunk检索全挂时模型知不知道拒答能力控制变量的三条铁律只动 context不动 question 和 prompt 模板同一条 case 的全部变体在同一轮内跑完同一个 judge 模型、同一温度避免 judge 漂移把噪声影响和评分波动混在一起注入数量和位置做成显式参数别散落在代码里。代码注入评测 harness核心难点在噪声采样irrelevant 噪声从语料库随机采样即可relevant 噪声必须按语义相似度区间采样模拟被检索器请进来的噪声。import numpy as np from dataclasses import dataclass, field dataclass class NoisyVariant: name: str contexts: list[str] def sample_noise_chunks(question: str, doc_store, embedder, pool: list[str], sim_band(0.70, 0.85), n: int 3) - list[str]: 从噪声候选池里按语义相似度区间采样 hard negative。 sim 0.85 的基本就是正确答案sim 0.70 的模型一眼识破都不合格。 q_vec embedder.embed(question) scored [] for doc_id in pool: s cosine(q_vec, embedder.embed(doc_store.get(doc_id))) if sim_band[0] s sim_band[1]: scored.append((s, doc_id)) scored.sort(reverseTrue) return [doc_store.get(doc_id) for _, doc_id in np.random.default_rng(42).choice(scored[: max(n * 3, 10)], n, replaceFalse)] def build_variants(case, retriever, doc_store, embedder, noise_pool, version_map, k_noise3) - list[NoisyVariant]: base [c.text for c in retriever.retrieve(case.question, top_k4)] return [ NoisyVariant(v0_base, base), NoisyVariant(v1_irrelevant, base sample_noise_chunks(case.question, doc_store, embedder, noise_pool, sim_band(0.0, 0.4))), NoisyVariant(v2_relevant_soft, base sample_noise_chunks(case.question, doc_store, embedder, noise_pool, sim_band(0.70, 0.85))), NoisyVariant(v3_relevant_hard, base [doc_store.get(version_map[chunk.doc_id]) # 同主题旧版本 for chunk in retriever.retrieve(case.question, top_kk_noise)]), NoisyVariant(v4_all_noise, sample_noise_chunks(case.question, doc_store, embedder, noise_pool, sim_band(0.0, 0.4), n4)), ]打分不要用整体对不对这种粗粒度 judge噪声场景下它必然失真。用 keypoint 级核对参考答案拆成可判据要点逐条问 judge 两个独立问题——该要点是否被上下文支持忠实度代理和回答是否覆盖该要点正确性代理。两个问题分开问模型混在一起答时倾向给自己找补FAITH_PROMPT 判断【回答】中的每个要点是否被【上下文】支持。 只依据上下文回答支持/不支持/上下文未提及。{context}\n{answer} def score_variant(variant: NoisyVariant, case, judge_llm) - dict: answer run_rag_pipeline(case.question, variant.contexts) keypoint_verdicts [judge_llm(FAITH_PROMPT.format( context\n.join(variant.contexts), answera)) for a in case.keypoints] faithful mean(v 支持 for v in keypoint_verdicts) # 忠实度代理 correct mean(v in (支持, 上下文未提及但不矛盾) for v in keypoint_verdicts) # 宽松正确率 return {faithful: faithful, correct: correct} def degradation(base: dict, noisy: dict) - float: return round((base[faithful] - noisy[faithful]) / max(base[faithful], 1e-9), 3)跑完对每个变体聚合 Δfaithful输出退化矩阵按类目和难度分桶。判定口径与一组实测示意退化分级建议按业务容忍度定我们内部用的口径Δfaithful相对基线评级动作≤ 5%稳健观察5% - 15%需关注查检索阈值与 rerank下个迭代处理 15%敏感阻断发版优先修一组内部项目的实测形态数据脱敏量级可参考单跳事实问答对 v1 几乎不退化Δ≈2%对 v3 矛盾噪声退化 8-15%多跳整合和长尾实体类对 v3 退化 20-35%且 v4 全噪声下正确率直接腰斩——说明多跳类的问题在检索失败时缺少我不知道的兜底。只报平均分会把多跳类的退化稀释掉分桶报告才有决策价值。踩坑记录judge 自评在噪声场景下系统性偏高。模型答完再自评倾向于我觉得我答对了尤其矛盾噪声注入后它会认为自己的错误输出同样被上下文支持。解法是上面 keypoint 拆解 两问分离必要时对支持类判定加证据回查要求 judge 引用原文片段。纯随机噪声测不出东西。随机拼接的噪声语义距离远模型识别后直接忽略v1 永远全绿。要让噪声像真的必须按相似度区间采样真实线上噪声的主体就是 0.7-0.85 这个区间的近误内容。v3 矛盾噪声测的是内容治理不只是模型。没有版本管理、旧文档不下线的知识库v3 必然飘红——这时候该修的不是 prompt 而是文档管线。这个指标当内容治理体检用也很好使。位置效应真实存在但别照抄结论。我们实测部分模型对 context 开头混入的噪声更敏感另一部分模型是近因偏好——噪声放结尾破坏更大。在自己系统上跑一遍位置对比同一噪声放前/中/后把结论写进测试文档比引用别人的结论靠谱。变体数量要控成本。5 个变体 × 300 条 case × keypoint 级 judge 调用跑满全矩阵的成本不低。日常回归只跑 v0 v3性价比最高全矩阵降频到每周一次judge 用 DeepSeek 这类便宜模型别用旗舰模型烧钱。进阶用法用噪声敏感度反推检索参数把 v3 从发版门禁升级成参数调优工具是这套评测最划算的用法。检索链路有三个旋钮——top_k、相关性阈值、rerank 强度它们的 trade-off 本质是同一件事召回越多噪声越多。拿同一份评测集在不同参数下跑 v0 v3能画出两条曲线recallk 随 top_k 上升而上升v3 的 Δfaithful 也随 top_k 上升——两条曲线的交叉区域就是甜点区。调过的一个典型 casetop_k 从 4 放到 8recallk 涨了 11%但 v3 Δfaithful 从 9% 跳到 19%——相关噪声 chunk 进入 top-8 的概率接近翻倍把相关性阈值从 0.5 提到 0.6 后recall 只掉 3%Δfaithful 回到 11%净收益为正。没有噪声敏感度这个维度你只会看到top_k8 召回更好就上线把噪声风险全部留给用户。rerank 评测同理rerank 模型换版后检索指标可能完全持平但 v3 退化曲线能告诉你新 rerank 是更会去噪还是更会把相似但错误的 chunk 排到前面。到这个阶段评测集就从测试资产变成了调参方向盘。回归门禁与线上监控接门禁时给关键类目单独设阈值用户问得最多、答错代价最高的 3-5 个类目Δfaithful 10% 直接阻断发版其他类目放宽到 20%。线上侧加一个 canary 指标——对每次检索的结果算噪声率相关性分低于阈值的 chunk 占比噪声率趋势上涨通常先于业务指标恶化几周是检索退化最早的信号。检索阈值、rerank、embedding 升级这类变更发布前强制跑一遍 v3 集比上线后看用户投诉便宜一个数量级。RAG 的质量评测做到这层才算闭环检索指标回答能不能找到噪声敏感度回答找错了会不会一本正经地错下去。进阶方向把注入实验从文本推广到多模态文档、给 v4 全噪声场景加显式拒答判定、以及用噪声敏感度反推检索阈值和 rerank 参数——噪声敏感度不只是个测试指标它能直接指导检索链路调优。如果你也在做 AI 应用RAG / Agent / LLM不知道质量怎么测——我最近在给 AI 应用做免费质量体检出一份可执行的测评报告检索命中率、回答忠实度、噪声敏感度等维度感兴趣可以直接私信我。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →