RAG 系列(九):效果不好怎么定位——用 RAGAS 做根因诊断
"感觉效果不太好"不是诊断
你部署了一个 RAG 系统,用户反馈说"答案有时候不准"。
然后呢?你改了 Prompt,感觉好一点。再换了个 Embedding 模型,又好了一点。几轮下来,你也不知道是哪一步起了效果,下次出问题依然无从下手。
这是 RAG 工程中最常见的陷阱:靠直觉调系统,没有量化诊断。
上一篇我们搭建了 RAGAS 评估体系,知道了 4 个指标的含义。这一篇,我们把这 4 个指标变成一套诊断工具——通过故意制造 3 种典型问题,用数据驱动的方式定位根因。
诊断的核心思路:决策树
RAG 系统的回答质量差,根因只有两大类:检索出了问题或生成出了问题。
用户反馈"回答不好" ↓ 检查 context_recall(上下文召回率) ├─ 低 ───→ 检索问题 │ ├─ 重要内容没被检索到 │ ├─ Chunk 太小或太大 │ └─ Top-K 不够 │ └─ 正常 ──→ 检查 faithfulness(忠实度) ├─ 低 ───→ 生成问题(幻觉) │ └─ Prompt 引导模型超出上下文发挥 │ └─ 正常 ──→ 检查 answer_relevancy(答案相关性) └─ 低 ──→ 答案偏题 └─ Prompt 结构固化,不聚焦问题逻辑很简单:
- 先看context_recall——重要内容有没有被检索到?没有的话,问题在检索阶段,再好的 Prompt 也救不了。
- 再看faithfulness——答案里的内容,有没有超出检索结果的范围?超出了就是幻觉,要修 Prompt。
- 最后看answer_relevancy——答案有没有直接回答问题?没有就是偏题,同样是 Prompt 问题。
三种典型问题的复现
我们用同一套知识库和测试集,通过改变配置刻意制造 3 种问题,让 RAGAS 量化每种问题的指标特征。
基准配置
baseline=RAGPipeline(chunk_size=512,chunk_overlap=50,top_k=4,prompt_type="baseline",# 正常 Prompt)正常的 Prompt 明确要求模型基于上下文回答:
PROMPT_BASELINE=ChatPromptTemplate.from_messages([("system","你是一个专业的技术问答助手。请严格根据提供的参考资料回答问题。""如果参考资料中没有相关信息,请明确说明。回答要简洁准确。"),("human","参考资料:\n{context}\n\n问题:{question}\n\n请回答:"),])问题一:检索召回不足(chunk 过碎 + top_k 太小)
p1_pipeline=RAGPipeline(chunk_size=64,# 极小 chunk,文档被切成大量碎片chunk_overlap=0,top_k=1,# 只取 1 条,大量信息丢失prompt_type="baseline",)为什么这样配置会出问题?
每篇文档被切成几十个 64 字的碎片,一个完整的概念被拆散到多个 chunk 中。top_k=1只能取回 1 条,即使这 1 条是最相关的,它包含的信息也远不够回答问题。
预期结果:context_recall 大幅下降——重要内容没检索到,faithfulness 和 answer_relevancy 连带受影响。
问题二:生成幻觉(Prompt 引导模型超出上下文)
p2_pipeline=RAGPipeline(chunk_size=512,chunk_overlap=50,top_k=4,prompt_type="hallucination",# 幻觉诱导 Prompt)幻觉 Prompt 明确鼓励模型"扩展":
PROMPT_HALLUCINATION=ChatPromptTemplate.from_messages([("system","你是一个知识渊博的百科全书式 AI 助手。请基于你丰富的知识储备全面回答问题。""下面的参考资料仅供参考,你可以在此基础上扩展更多相关知识,不必局限于参考资料内容。""尽量补充背景知识和延伸信息,让回答更加丰富。"),("human","参考资料:\n{context}\n\n问题:{question}\n\n请给出全面详细的回答:"),])为什么这样会产生幻觉?
模型被明确告知"不必局限于参考资料",它会从自身预训练的知识中生成额外内容。这些内容可能是真实的,但 RAGAS 的 faithfulness 指标衡量的是:答案里的每一个声明,能否在检索上下文中找到依据。任何超出上下文的声明都会被标记为幻觉。
预期结果:faithfulness 大幅下降,而 context_recall 不变(检索没问题)。
问题三:答案偏题(Prompt 强制结构化输出)
p3_pipeline=RAGPipeline(chunk_size=512,chunk_overlap=50,top_k=4,prompt_type="offtopic",# 强制学术综述格式)偏题 Prompt 要求固定的学术格式:
PROMPT_OFFTOPIC=ChatPromptTemplate.from_messages([("system","你是一名资深技术研究员,负责撰写学术综述。""针对用户的问题,请按照以下固定结构回答:\n""1. 技术背景与历史演进\n""2. 主要技术流派与对比分析\n""3. 当前挑战与未来发展趋势\n""回答需要学术化,涵盖广泛,每部分至少 200 字。"),("human","参考资料:\n{context}\n\n问题:{question}\n\n请撰写综述报告:"),])为什么这样会导致偏题?
用户问的是"什么是 RAG 技术",但模型被迫按"历史演进 + 流派对比 + 未来趋势"三段式输出。RAGAS 的 answer_relevancy 指标衡量的是:答案有多直接地回答了提问。一个 800 字的综述对一个直接的问题来说,相关性得分自然很低。
预期结果:answer_relevancy 大幅下降,而 faithfulness 和 context_recall 正常(内容都来自上下文,只是格式偏了)。
实验结果对比
运行diagnose.py后,得到如下对比报告:
================================================================================ RAG 诊断对比报告 ================================================================================ 指标 基准配置 问题一:检索召回不足 问题二:生成幻觉 问题三:答案偏题 ────────────────────────────────────────────────────────────────────────────── faithfulness 0.829 0.750 0.320 ← ✗ 0.817 answer_relevancy 0.502 0.191 0.487 0.183 ← ✗ context_precision 0.583 0.375 ← ⚠ 0.583 0.550 context_recall 0.625 0.250 ← ✗ 0.625 0.613 ────────────────────────────────────────────────────────────────────────────── 平均得分 0.635 0.392 0.504 0.541 ================================================================================数字背后的诊断逻辑:
| 场景 | 问题指标 | 其他指标 | 根因 |
|---|---|---|---|
| 基准配置 | 无异常 | — | — |
| 问题一 | context_recall ↓ 0.375 | context_precision 也下降 | Chunk 太碎 + top_k 不足,重要内容没被取回 |
| 问题二 | faithfulness ↓ 0.509 | context_recall 正常 | Prompt 引导模型超出上下文,生成幻觉 |
| 问题三 | answer_relevancy ↓ 0.319 | faithfulness 正常 | Prompt 强制学术格式,答案不聚焦于问题 |
注意问题一中context_precision也下降了:chunk 太小意味着每条 chunk 携带的信息极少,即使检索到了也"精度"不足。
决策树诊断输出
程序还会自动输出决策树分析:
================================================================================ 诊断决策树分析 ================================================================================ 【问题一:检索召回不足】(预期问题类型:context_recall 低) 步骤 1 → 检查 context_recall:下降 +0.375(显著下降) ✗ 诊断:检索阶段有问题 → 重要内容没被检索到,检查 chunk_size 和 top_k → 当前 top_k 可能太小,或 chunk 太碎导致语义不完整 ⚠ 附加发现:context_precision 下降 +0.208,检索结果中混入了噪声 【问题二:生成幻觉】(预期问题类型:faithfulness 低) 步骤 1 → 检查 context_recall:下降 +0.000(正常) 步骤 2 → 检查 faithfulness:下降 +0.509(显著下降) ✗ 诊断:生成阶段出现幻觉 → 答案包含了上下文中没有的内容 → 修复建议:优化 Prompt,明确要求只基于参考资料回答 【问题三:答案偏题】(预期问题类型:answer_relevancy 低) 步骤 1 → 检查 context_recall:下降 +0.012(正常) 步骤 2 → 检查 faithfulness:下降 +0.012(正常) 步骤 3 → 检查 answer_relevancy:下降 +0.319(显著下降) ✗ 诊断:答案偏题,未直接回答用户问题 → Prompt 格式要求导致答案冗长或结构固化 → 修复建议:简化 Prompt,去除强制格式约束 ================================================================================三条诊断路径,精准对应三种问题类型,全部命中。
每种问题的修复方向
问题一:context_recall 低 → 检修检索配置
# 修复前:chunk 太碎,top_k 太小RAGPipeline(chunk_size=64,chunk_overlap=0,top_k=1)# 修复后:合理的 chunk 大小 + 足够的 top_kRAGPipeline(chunk_size=512,chunk_overlap=50,top_k=4)经验值参考:
| 场景 | chunk_size | overlap | top_k |
|---|---|---|---|
| 短问答(技术 FAQ) | 256–512 | 20–50 | 3–5 |
| 长文档理解 | 512–1024 | 50–100 | 4–6 |
| 代码库检索 | 按函数/类分块 | 0 | 3–5 |
问题二:faithfulness 低 → 加固 Prompt
核心原则:明确告诉模型「只依据参考资料回答」,并且设定「没有信息时如何处理」。
# 修复:严格约束 PromptPROMPT_STRICT=ChatPromptTemplate.from_messages([("system","""你是一个技术问答助手。 规则: 1. 只能基于「参考资料」中的内容作答 2. 如果参考资料不包含答案,直接回答「根据现有资料无法回答」 3. 不允许添加参考资料之外的信息 4. 回答要简洁,不超过 200 字"""),("human","参考资料:\n{context}\n\n问题:{question}"),])问题三:answer_relevancy 低 → 简化 Prompt 格式
# 修复:去掉固定格式要求,让模型自然回答PROMPT_FOCUSED=ChatPromptTemplate.from_messages([("system","你是技术问答助手。请直接回答问题,简洁准确,不要添加不必要的格式或结构。"),("human","参考资料:\n{context}\n\n问题:{question}"),])完整代码
完整代码已开源:
https://github.com/chendongqi/llm-in-action/tree/main/09-rag-diagnosis
核心文件:
rag_pipeline.py— 支持 3 种 Prompt 类型的 RAG Pipelinediagnose.py— 3 个问题场景 + 决策树诊断
运行方式:
gitclone https://github.com/chendongqi/llm-in-actioncd09-rag-diagnosiscp.env.example .env# 填入你的 LLM 和 Embedding API Keypipinstall-rrequirements.txt python diagnose.py小结
这套诊断框架的核心思路是:
- 不靠直觉,靠指标——context_recall、faithfulness、answer_relevancy 分别对应检索、生成、相关性三个维度
- 按决策树顺序检查——先 context_recall,再 faithfulness,最后 answer_relevancy,避免误诊
- 制造对照实验——好配置和坏配置的指标差异才是定位根因的关键证据
在实际项目中,出现问题时先跑一次 RAGAS 评估,看哪个指标最低,再按决策树找方向。这比"调一调感觉好了"要靠谱得多。
参考资料
- RAGAS 官方文档
- Faithfulness 指标计算原理
