LLM Wiki / RAG
Naive RAG 为什么容易失败:四类根因拆解
从召回、分块、上下文、生成与权限角度分析朴素 RAG 的真实失败模式。
朴素 RAG 的问题不是“太简单”,而是它把很多生产约束都藏起来了:文档质量、权限、版本、查询理解、排序、引用、评测。系统跑通以后,失败通常集中在四类:找不到、找不准、用不好、管不住。
失败模式总览
一、找不到:召回失败
典型现象:用户问的问题在文档里有答案,但系统回答“不知道”或者召回无关段落。
| 原因 | 示例 | 修复方向 |
|---|---|---|
| 术语不匹配 | 用户问“远程办公 PTO”,文档写“telecommute time off”。 | query rewrite、同义词、hybrid search。 |
| 精确词漏召回 | 错误码、接口名、合同编号、产品 SKU。 | BM25 + vector,不要只用向量。 |
| 元数据缺失 | 用户问“2024 版政策”,chunk 没有更新时间。 | 保存 updated_at、version、source_type。 |
| 数据未入库 | 文档同步失败但无人知道。 | ingestion trace、失败重试、数据质量报表。 |
判断方法
先不要改 Prompt。把用户问题、改写后的 query、Top-20 召回结果全部打印出来。如果正确证据不在 Top-20,问题在检索前半段。
二、找不准:排序和候选质量失败
召回到了正确证据,不代表模型能答好。Top-K 中如果混入大量相似但不可回答的片段,LLM 很容易被噪声带偏。
常见修复方式:
- 用 Reranker 区分“语义相似”和“能回答问题”。
- 对同一文档的重复 chunk 做去重或多样性约束。
- 对标题、权威来源、更新时间设置 boost。
- 给候选结果保留分数和来源,方便 bad case 分析。
三、用不好:上下文断裂和证据失真
很多回答错误不是因为没找到文档,而是因为 chunk 缺少前置条件。比如只召回了“审批通过后可报销”,但没召回上一段“仅适用于正式员工”。
| 场景 | 风险 | 处理方式 |
|---|---|---|
| 政策文档 | 条件和结论分离 | parent-child chunk,召回小块后补父级上下文。 |
| 表格 | 行列关系丢失 | 表格结构化抽取,保留表头和单位。 |
| 代码文档 | 函数说明和示例分离 | 按标题和代码块边界切分。 |
| 长 PDF | 页眉页脚污染 | 解析阶段清理重复页眉页脚。 |
四、管不住:权限、版本和审计失败
企业 RAG 最危险的问题不是答错,而是答出用户无权访问的信息。权限不能交给 LLM 判断,必须在检索阶段生效。
生产要求:
- Chunk 必须继承文档 ACL。
- 权限变更要触发索引更新或查询时过滤。
- Trace 中要记录用户身份范围、过滤条件、命中文档。
- 日志中不要保存未脱敏的敏感上下文。
Bad Case 归因表
| 现象 | 优先检查 | 不要先做什么 |
|---|---|---|
| 答案完全无关 | Top-K 召回结果、query rewrite | 不要先换大模型。 |
| 答案部分正确 | chunk 是否缺上下文、是否有冲突文档 | 不要盲目增大 Top-K。 |
| 引用不支撑答案 | prompt 约束、引用映射、evidence selection | 不要只要求“请给引用”。 |
| 同一问题时好时坏 | rerank 稳定性、索引版本、模型温度 | 不要只看单次结果。 |
| 越权风险 | ACL 元数据、检索过滤、日志脱敏 | 不要让 LLM 自己判断权限。 |
最小修复路线
- 保存完整 trace:query、Top-K、rerank score、上下文、答案。
- 使用混合检索,先解决“找不到”。
- 引入 reranker 和去重,解决“找不准”。
- 改造 chunk schema,解决“用不好”。
- 把 ACL 放进检索过滤,解决“管不住”。
Naive RAG 的失败不是偶然,而是缺少工程闭环。把失败归因拆清楚,优化才有方向。
讨论
继续讨论这篇笔记
有问题、补充案例或不同观点,可以通过 GitHub Discussions 继续交流。