RAG 系列(九):效果不好怎么定位——用 RAGAS 做根因诊断

"感觉效果不太好"不是诊断

你部署了一个 RAG 系统,用户反馈说"答案有时候不准"。

然后呢?你改了 Prompt,感觉好一点。再换了个 Embedding 模型,又好了一点。几轮下来,你也不知道是哪一步起了效果,下次出问题依然无从下手。

这是 RAG 工程中最常见的陷阱:靠直觉调系统,没有量化诊断

上一篇我们搭建了 RAGAS 评估体系,知道了 4 个指标的含义。这一篇,我们把这 4 个指标变成一套诊断工具------通过故意制造 3 种典型问题,用数据驱动的方式定位根因。


诊断的核心思路:决策树

RAG 系统的回答质量差,根因只有两大类:检索出了问题生成出了问题

arduino 复制代码
用户反馈"回答不好"
        ↓
检查 context_recall(上下文召回率)
        ├─ 低 ───→ 检索问题
        │           ├─ 重要内容没被检索到
        │           ├─ Chunk 太小或太大
        │           └─ Top-K 不够
        │
        └─ 正常 ──→ 检查 faithfulness(忠实度)
                        ├─ 低 ───→ 生成问题(幻觉)
                        │           └─ Prompt 引导模型超出上下文发挥
                        │
                        └─ 正常 ──→ 检查 answer_relevancy(答案相关性)
                                        └─ 低 ──→ 答案偏题
                                                   └─ Prompt 结构固化,不聚焦问题

逻辑很简单

  1. 先看 context_recall------重要内容有没有被检索到?没有的话,问题在检索阶段,再好的 Prompt 也救不了。
  2. 再看 faithfulness------答案里的内容,有没有超出检索结果的范围?超出了就是幻觉,要修 Prompt。
  3. 最后看 answer_relevancy------答案有没有直接回答问题?没有就是偏题,同样是 Prompt 问题。

三种典型问题的复现

我们用同一套知识库和测试集,通过改变配置刻意制造 3 种问题,让 RAGAS 量化每种问题的指标特征。

基准配置

python 复制代码
baseline = RAGPipeline(
    chunk_size=512,
    chunk_overlap=50,
    top_k=4,
    prompt_type="baseline",  # 正常 Prompt
)

正常的 Prompt 明确要求模型基于上下文回答:

python 复制代码
PROMPT_BASELINE = ChatPromptTemplate.from_messages([
    ("system", "你是一个专业的技术问答助手。请严格根据提供的参考资料回答问题。"
               "如果参考资料中没有相关信息,请明确说明。回答要简洁准确。"),
    ("human", "参考资料:\n{context}\n\n问题:{question}\n\n请回答:"),
])

问题一:检索召回不足(chunk 过碎 + top_k 太小)

python 复制代码
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 引导模型超出上下文)

python 复制代码
p2_pipeline = RAGPipeline(
    chunk_size=512,
    chunk_overlap=50,
    top_k=4,
    prompt_type="hallucination",  # 幻觉诱导 Prompt
)

幻觉 Prompt 明确鼓励模型"扩展":

python 复制代码
PROMPT_HALLUCINATION = ChatPromptTemplate.from_messages([
    ("system", "你是一个知识渊博的百科全书式 AI 助手。请基于你丰富的知识储备全面回答问题。"
               "下面的参考资料仅供参考,你可以在此基础上扩展更多相关知识,不必局限于参考资料内容。"
               "尽量补充背景知识和延伸信息,让回答更加丰富。"),
    ("human", "参考资料:\n{context}\n\n问题:{question}\n\n请给出全面详细的回答:"),
])

为什么这样会产生幻觉?

模型被明确告知"不必局限于参考资料",它会从自身预训练的知识中生成额外内容。这些内容可能是真实的,但 RAGAS 的 faithfulness 指标衡量的是:答案里的每一个声明,能否在检索上下文中找到依据。任何超出上下文的声明都会被标记为幻觉。

预期结果:faithfulness 大幅下降,而 context_recall 不变(检索没问题)。


问题三:答案偏题(Prompt 强制结构化输出)

python 复制代码
p3_pipeline = RAGPipeline(
    chunk_size=512,
    chunk_overlap=50,
    top_k=4,
    prompt_type="offtopic",  # 强制学术综述格式
)

偏题 Prompt 要求固定的学术格式:

python 复制代码
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 后,得到如下对比报告:

diff 复制代码
================================================================================
  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 携带的信息极少,即使检索到了也"精度"不足。


决策树诊断输出

程序还会自动输出决策树分析:

markdown 复制代码
================================================================================
  诊断决策树分析
================================================================================

  【问题一:检索召回不足】(预期问题类型: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 低 → 检修检索配置

python 复制代码
# 修复前:chunk 太碎,top_k 太小
RAGPipeline(chunk_size=64, chunk_overlap=0, top_k=1)

# 修复后:合理的 chunk 大小 + 足够的 top_k
RAGPipeline(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

核心原则:明确告诉模型「只依据参考资料回答」,并且设定「没有信息时如何处理」。

python 复制代码
# 修复:严格约束 Prompt
PROMPT_STRICT = ChatPromptTemplate.from_messages([
    ("system", """你是一个技术问答助手。
规则:
1. 只能基于「参考资料」中的内容作答
2. 如果参考资料不包含答案,直接回答「根据现有资料无法回答」
3. 不允许添加参考资料之外的信息
4. 回答要简洁,不超过 200 字"""),
    ("human", "参考资料:\n{context}\n\n问题:{question}"),
])

问题三:answer_relevancy 低 → 简化 Prompt 格式

python 复制代码
# 修复:去掉固定格式要求,让模型自然回答
PROMPT_FOCUSED = ChatPromptTemplate.from_messages([
    ("system", "你是技术问答助手。请直接回答问题,简洁准确,不要添加不必要的格式或结构。"),
    ("human", "参考资料:\n{context}\n\n问题:{question}"),
])

完整代码

完整代码已开源:

github.com/chendongqi/...

核心文件:

  • rag_pipeline.py --- 支持 3 种 Prompt 类型的 RAG Pipeline
  • diagnose.py --- 3 个问题场景 + 决策树诊断

运行方式:

bash 复制代码
git clone https://github.com/chendongqi/llm-in-action
cd 09-rag-diagnosis

cp .env.example .env  # 填入你的 LLM 和 Embedding API Key
pip install -r requirements.txt
python diagnose.py

小结

这套诊断框架的核心思路是:

  1. 不靠直觉,靠指标------context_recall、faithfulness、answer_relevancy 分别对应检索、生成、相关性三个维度
  2. 按决策树顺序检查------先 context_recall,再 faithfulness,最后 answer_relevancy,避免误诊
  3. 制造对照实验------好配置和坏配置的指标差异才是定位根因的关键证据

在实际项目中,出现问题时先跑一次 RAGAS 评估,看哪个指标最低,再按决策树找方向。这比"调一调感觉好了"要靠谱得多。


参考资料

相关推荐
火山引擎开发者社区1 小时前
ArkClaw 的技能是不是越多越好?很多人一开始就想错了
人工智能
火山引擎开发者社区1 小时前
星穹方舟基于火山引擎 ArkClaw 推出全场景龙虾硬件
人工智能
甲维斯2 小时前
JCode支持Claude和第三方模型tokens统计!
人工智能·ai编程
拓朗工控2 小时前
深度学习工控机部署实战:从硬件选型到稳定运行的避坑指南
人工智能·深度学习·智能电视·工控机
iDao技术魔方2 小时前
DeepSeek TUI:原生 Rust 打造的终端 AI 编码 Agent
开发语言·人工智能·rust
飞Link2 小时前
AI 原生开发已至:从代码补全到自主仓库重构,Coding Agent 如何重塑程序员的终极形态?
人工智能·重构
老纪的技术唠嗑局2 小时前
深度解析 LLM Wiki / Obsidian-Wiki / GBrain:Agent 时代知识的“自组织”与“自进化”
大数据·数据库·人工智能·算法
志栋智能3 小时前
告别报告堆砌:超自动化巡检的智能分析与洞察
运维·服务器·网络·人工智能·自动化
测试_AI_一辰3 小时前
AI 产品输出格式测试实战:为什么模型返回的 JSON 前端解析总报错
人工智能·ai·自动化·状态模式·ai编程