系统学习 AI 学习路径:从 GPU 运行时到推理、微调与 RAG 评估

版本信息最后核对:2026-10-25

rag-retrieval-quality-incident

RAG 召回质量事故:从“答非所问”出发,分层定位切分、向量化、索引、权限过滤与生成问题。

现象

用户反馈集中在“答非所问”“答案缺关键步骤”“引用文档不对”“明明库里有却说没有”。这类投诉往往同时混杂检索问题和生成问题,只看最终回答无法定位。监控上可能看到检索命中率、点赞率、引用点击率下降,转人工率上升;也可能所有服务指标正常,只有离线评测或用户反馈变差。

另一类现象更接近故障:检索结果为空、结果重复、旧文档搜不到、新上传文档长时间不出现,或者低权限用户看到了不该出现的文档。这类问题通常指向索引任务、权限过滤或元数据,而不是模型。

先把链路拆开:query 改写 → 向量化 → 多路召回 → 融合 → 重排 → 权限过滤 → 上下文拼接 → 生成。任何一层都可能让最终答案变差,且不同层的修复方式完全不同。

快速判断

挑 3 到 5 个典型 bad case,逐个打印链路中间结果,而不是先改 prompt。

# RAGFlow 检索接口:观察返回的 chunk、相似度与来源
curl -s -X POST "http://<ragflow-host>:9380/v1/api/retrieval" \
  -H "Authorization: Bearer $RAGFLOW_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"question":"<用户原问题>","dataset_ids":["<DATASET_ID>"],"top_k":10}' \
  | jq '.data.chunks[] | {id, score, document_id, content: .content[0:200]}'

接口路径和字段随版本变化,以当前实例的 API 文档为准。重点看三件事:标准答案所在的 chunk 是否在候选里、排在第几、经过重排和权限过滤后是否还在。

再用下面的判断表做粗分类:

线索 更可能的方向
正确文档完全不在 top-k 切分、向量化、索引或 query 表达
正确文档在候选但排名很靠后 召回融合、embedding、query 改写
候选里有、重排后消失 reranker 阈值、截断或超时降级
上下文里有正确证据但回答仍错 生成、prompt、上下文拼接或模型
只有某类文档或某个租户搜不到 解析失败、元数据、权限过滤
新文档搜不到、旧文档正常 索引任务延迟、失败或别名未切换
全库同时退化 embedding 服务、索引、检索引擎或配置变更
低权限用户看到敏感文档 权限过滤缺失或元数据错误,按安全事故处理

再回答四个问题:

  1. 影响面是全局、单租户、单文档类型,还是单类问题?范围越小,越可能是数据或过滤条件。
  2. 时间上是否与某次变更重合?切分参数、embedding 模型、索引重建、reranker、prompt、模型升级都要查。
  3. 是“找不到”还是“找得到但答错”?前者查检索,后者先用标准上下文做对照实验。
  4. 线上反馈与离线指标是否一致?只改离线分数而线上不变,说明评测集与真实流量分布脱节。

区分生成问题与检索问题,最直接的方法是把标准上下文直接交给模型:

实验 A:原始检索上下文 + 用户问题 → 模型回答(线上链路)
实验 B:人工标注的正确上下文 + 同一问题 → 同一模型(oracle 上下文)

B 答对而 A 答错,问题主要在检索或上下文拼接;两者都错,优先查生成、prompt 和模型。

常见原因

解析与切分

PDF 版面、表格、扫描件 OCR 解析失败,会直接产生空 chunk 或乱序文本;切分过小会丢上下文,过大则稀释语义;标题层级和表格结构没有保留,检索命中后模型也拼不出完整答案。切分参数调整后没有重建索引,是新旧 chunk 混用的常见来源。

向量化与模型不一致

索引侧和查询侧使用了不同的 embedding 模型、不同 revision、不同前缀或不同归一化方式,向量不在同一空间,召回会明显退化。模型服务超时、限流或返回全零向量时,部分文档会“写入成功但不可检索”。

索引与新鲜度

全量重建中断、增量任务失败、别名仍指向旧索引、分片写入失败、向量库与源数据库数量不一致,都会让部分文档缺失。新文档上传后需要解析、切分、向量化和写入,任何一步排队都会造成“刚上传搜不到”。

权限与元数据

租户 ID、部门、密级、ACL 等元数据缺失或类型不一致,会让过滤条件失效:过滤过严导致召回为空,过滤缺失导致越权。权限问题不能只当质量事故处理,必须按安全事件验证。

查询表达与改写

用户使用口语、缩写、错别字、多语言混写时,向量召回可能偏离;query 改写能补全上下文,但也可能引入不存在的约束,把正确文档排到后面。改写前后的检索结果要分别观察,不能只看最终结果。

融合、重排与阈值

向量与关键词的权重、去重策略、reranker 的截断长度和分数阈值、超时降级逻辑,都会改变最终顺序。沿用旧模型的阈值,在分数分布变化后会大量误杀。

生成侧

上下文过长被截断、拼接顺序混乱、引用编号错位、prompt 要求与模型能力不匹配、模型升级后指令遵循变化,都会让“检索对了但答错”。这类问题要和检索问题分开验证。

排查步骤

第一步:固定现场

记录 query、用户与租户、时间、top-k、索引别名、embedding 模型与 revision、reranker 配置、prompt 版本和模型版本。检索结果要保存 chunk ID、分数和文本摘要,便于回放。

第二步:建立最小评测集

从线上反馈、客服工单和人工标注中抽取 30 到 100 条,覆盖短查询、长查询、多语言、表格、代码、时效性问题和权限场景,每条标注标准文档或标准 chunk。规模不必大,但要能重复跑、能比较版本。

第三步:分层观测

按链路逐层打印:改写后的 query、向量召回 top-k、关键词召回 top-k、融合后顺序、重排后顺序、过滤后结果、最终进入 prompt 的上下文。确认正确 chunk 在哪一层丢失,避免在错误的层反复调参。

第四步:跑离线指标

至少看 recall@k、MRR 或 nDCG,以及上下文精确率和召回率。Ragas 等框架可以把回答忠实度、上下文召回拆开,但裁判模型、prompt 和版本必须固定,否则分数不可比。

python - <<'PY'
from ragas import EvaluationDataset, SingleTurnSample, evaluate
from ragas.metrics import LLMContextRecall, Faithfulness

samples = [SingleTurnSample(
    user_input="<问题>",
    response="<线上回答>",
    retrieved_contexts=["<检索到的上下文>"],
    reference="<标准答案>",
)]
result = evaluate(EvaluationDataset(samples=samples),
                  metrics=[LLMContextRecall(), Faithfulness()])
print(result)
PY

先跑小样本确认指标方向,再扩到全量;裁判调用次数会随样本数放大,注意限流和费用。

第五步:核对索引一致性

对比源文档数、解析成功数、chunk 数、向量库文档数和可检索文档数,查失败任务、重试队列和索引别名。抽样用文档标题或唯一 ID 反查,确认“库里确实有”。这一层不做,后面所有调参都可能是在错误前提上打转。

第六步:验证权限过滤

用不同角色、不同租户查询同一问题,确认结果集合差异符合预期;检查过滤字段是否为空、类型是否一致、默认值是否放行。权限用例要纳入回归,不能只靠人工抽查。发现越权时先收紧访问,再排查数据。

第七步:二分变更

把最近的切分、embedding、索引、reranker、prompt、模型变更逐项回滚或灰度对比。一次只动一个变量,用同一评测集和同一批 bad case 复测。没有基线时,先用当前版本建立基线,再谈优化。

修复与验证

验证至少覆盖四层:离线评测集指标不退化、bad case 集修复率达到预期、权限用例全部通过、线上灰度期间点赞率和转人工率不恶化。还要观察检索延迟、token 成本和索引新鲜度,避免用更大 top-k 换来无法承受的成本。

重建索引、修改别名、批量重刷向量都属于高风险操作:先在测试环境演练,保留旧索引和配置,选低峰期执行,并准备好一键切回。不要在生产库上直接删除 collection 或原地修改向量维度。

预防

相关命令

参考链接

读完自测

合上页面,先回答,再展开对照。

  1. 如何用一次对照实验判断问题在检索还是生成?
  2. 正确文档不在 top-k,和正确文档在候选但重排后消失,排查方向有什么不同?
  3. 为什么权限过滤问题要优先于召回质量优化处理?
答案
  1. 把人工标注的标准上下文直接交给同一模型和同一 prompt。若用标准上下文能答对、用线上检索上下文答错,问题在检索或上下文拼接;两者都答错,优先查生成、prompt 和模型;若标准上下文也答不对,还要检查问题本身是否有歧义或标准答案不完整。
  2. 不在 top-k 说明候选生成阶段就丢了,查解析切分、embedding 模型与查询前缀、索引是否完整、query 改写是否偏移;在候选但重排后消失,查 reranker 的截断长度、分数阈值、超时降级和融合权重。前者是“没找到”,后者是“找到了但排序错”。
  3. 越权访问是安全问题,不是质量问题:它可能泄露敏感数据,且修复窗口越短越好。应先收紧权限和访问控制,再排查元数据与过滤条件,最后才做召回优化。把权限问题混在质量调优里,会延长暴露时间。
微信小程序码:扫码打开命令速查小程序

小程序版

微信扫码,随时查命令