Skip to content

5.3 RAG·评估与防幻觉

RAG 上线后最怕两件事:该找到的没找到(检索失败)、找到了但答错/编造(生成幻觉)。这一节教你分层评估,并用工程手段把幻觉压下去。

RAG 会在两个地方出错

用户问题

   ├─【检索层】没召回到相关文档      → 后面再聪明也白搭(巧妇难为无米之炊)

   └─【生成层】召回对了,但模型没好好用
        ├─ 编造了检索内容里没有的事(幻觉)
        └─ 检索到无关内容,被带偏

评估要分这两层来做,因为修法完全不同:检索差→改分块/检索策略(5.1/5.4);生成差→改 Prompt/加约束。


检索层评估

先准备一批"问题 → 它该命中哪些文档"的标注集,然后看检索结果:

  • Recall@k(召回率):该命中的文档,有没有出现在 top-k 里?(最关键——没召回到,一切免谈)
  • Precision@k(精准率):top-k 里有多少是真相关的?
  • MRR:第一个正确结果排在多靠前?(越靠前越好)

💡 实战里先盯 Recall@k:把 k 调大点(如 top-10)看相关文档到底进没进候选池。进了但排名靠后 → 加 Reranking;压根没进 → 是分块或检索策略的问题。

javascript
// 检索层评估骨架
const testset = [
  { q: "退款多久到账", relevantIds: [2] },
  { q: "怎么升级会员", relevantIds: [3] },
]
let hit = 0
for (const t of testset) {
  const got = (await search(t.q, { topK: 5 })).map(r => r.id)
  if (t.relevantIds.some(id => got.includes(id))) hit++   // Recall@5 命中
}
console.log(`Recall@5: ${(hit / testset.length * 100).toFixed(0)}%`)

生成层评估:忠实度(Faithfulness)

生成层最重要的指标是忠实度:回答里的每一句,是不是都能在检索到的内容里找到依据?没依据的就是幻觉。

用 LLM-as-Judge(2.5)来判:

javascript
async function checkFaithfulness(context, answer) {
  const res = await chat.chat.completions.create({
    model: MODEL,
    messages: [{
      role: "user",
      content: `参考资料:\n${context}\n\nAI 回答:\n${answer}\n\n` +
        `请判断"AI 回答"里的每个事实是否都能在"参考资料"里找到依据。` +
        `如果全部有依据输出 PASS;如果有任何编造/无依据的内容输出 FAIL 并指出哪句。`
    }]
  })
  return res.choices[0].message.content
}

另外两个常看的:Answer Relevance(回答有没有答到问题)、Context Relevance(检索到的内容跟问题相不相关)。


防幻觉的四个工程手段

评估是发现问题,下面是把幻觉压下去的手段(按性价比排序):

1. Prompt 里立规矩:只能用资料,没有就说没有

你只能根据"参考资料"回答。资料里没有的,直接说"暂无相关信息",
绝对不要用你自己的知识补充或推测。

2. 强制引用(Citation)——让它标出每句话来自哪条资料,既能溯源,又逼它"言出有据":

javascript
const prompt = `根据带编号的资料回答问题,每个结论后用 [编号] 标注来源。
无法从资料得出的,不要回答。

资料:
[1] 退款需在购买后7天内提交。
[2] 退款3-5个工作日原路退回。

问题:${question}`
// 期望输出:"需在7天内申请[1],到账约3-5个工作日[2]。"

3. 检索为空就别硬答:检索分数都很低(没相关内容)时,直接回"没找到",根本不调生成。

4. 生成后校验:用上面的 checkFaithfulness 对回答做一道 Guardrail,FAIL 就重答或兜底(2.7)。

💡 性价比最高的是 1+2:把"无依据不要答 + 强制引用"写进 Prompt,几乎零成本,效果立竿见影。要求高的关键场景再叠加 4。


把评估变成回归测试

每次改分块、换 Embedding、调 Prompt,跑一遍评估对比数字,而不是凭感觉:

改动前:Recall@5 = 72%,忠实度 PASS 率 = 85%
        ↓ 加了查询改写 + 强制引用
改动后:Recall@5 = 88%,忠实度 PASS 率 = 96%   ✅ 数字说话

🛠️ 实战练习:给你的 RAG 建评估闭环

  1. 准备 10 个问题,标注每个该命中哪些文档(检索集)+ 一句参考答案(生成集)
  2. 跑出当前 Recall@5 和 忠实度 PASS 率两个数字
  3. 给生成 Prompt 加上"无依据不要答 + 强制引用",再跑一遍
  4. 对比两个数字,确认幻觉是否下降

进阶挑战:故意问一个知识库里没有的问题,验证你的 RAG 是老实说"没找到",还是开始编——如果编,回去补手段 1 和 3。


📌 关键结论

  1. RAG 分两层评估:检索层(召回没有)和生成层(答得忠不忠实),修法不同
  2. 检索先盯 Recall@k:相关文档进没进候选池;进了排后→Rerank,没进→改分块/检索
  3. 生成层最重要是忠实度:回答每句是否都有检索依据,用 LLM-as-Judge 判
  4. 防幻觉性价比最高:Prompt 立规矩"无依据不答" + 强制引用,再按需加生成后校验
  5. 把评估做成回归测试,每次改动用数字判断好坏

下一节:5.4 RAG·真实文档处理

写给自己的 AI 学习地图