如何评估 RAG 系统的效果?常用的评估指标有哪些?

#RAG#Agent#面试八股

如何评估 RAG 系统的效果?常用的评估指标有哪些?

结论:RAG 评估必须分层——检索层看"找没找到",生成层看"用得对不对",端到端看"用户满不满意"。 三层混在一起算一个总分,出了问题根本不知道该改哪。没有标注集就先手工造 50~100 条,这比任何调参技巧都值钱。

1. 三层指标体系

层指标回答的问题计算依赖
检索recall@k、hit rate正确片段进了前 k 吗查询 → 相关片段标注
检索MRR、NDCG@k排得够不够靠前带序的相关性标注
生成忠实度(Faithfulness)答案每句都有依据吗答案 + 上下文
生成答案相关性(Answer Relevancy)有没有答到点上答案 + 问题
生成上下文精确率/召回率检索的噪声与遗漏上下文 + 标注答案
端到端答案正确率最终对不对标准答案
端到端拒答准确率该说"不知道"时说了吗库外问题集

2. 几个公式,面试要能写出来

指标公式直觉
recall@k命中数 / 相关总数前 k 条覆盖了多少应有的证据
MRRmean(1 / 第一个相关片段的名次)第一个对的排多靠前
NDCG@kDCG@k / IDCG@k分级相关性下,排序质量如何
忠实度有依据的句子数 / 总句子数答案里有多少句是"编的"

命中率(Hit Rate)只看"有没有",召回率(Recall)看"覆盖多少",两个别混用。

3. 评估集怎么造

来源数量说明
线上真实 query 采样60%最能反映分布
业务方整理的典型问题25%覆盖核心场景
故意构造的库外问题15%测拒答能力

每条样本至少包含:question、relevant_chunk_ids(或 ground_truth)、should_refuse。 标注规范要写清"什么算相关"——是含答案,还是只沾边,否则两个人标出两套标准。

4. 检索层评估脚本

import numpy as np

def evaluate_retrieval(dataset: list[dict], k: int = 5) -> dict:
    """dataset: [{"question": str, "relevant": set[str]}]"""
    recall, mrr = [], []
    for item in dataset:
        hits = store.query(query_embeddings=embed([item["question"]]), n_results=k)
        ids = hits["ids"][0]
        hit = [i for i, doc_id in enumerate(ids) if doc_id in item["relevant"]]
        recall.append(len(hit) / len(item["relevant"]) if item["relevant"] else 0.0)
        mrr.append(1.0 / (hit[0] + 1) if hit else 0.0)
    return {"recall@k": float(np.mean(recall)), "mrr": float(np.mean(mrr)), "n": len(dataset)}

# 输出:{'recall@k': 0.82, 'mrr': 0.64, 'n': 80}

先把这个数拉到 0.85 以上,再动生成侧的提示词,顺序不能反。

5. 生成层:忠实度用 LLM 判定

import json

JUDGE = """逐句判断<答案>是否被<资料>支持,输出 JSON:
{"supported": 支持的句子数, "total": 总句子数, "unsupported": ["原句"]}"""

def faithfulness(answer: str, contexts: list[str]) -> float:
    resp = llm.chat.completions.create(
        model="gpt-4o-mini", temperature=0,
        response_format={"type": "json_object"},
        messages=[{"role": "system", "content": JUDGE},
                  {"role": "user",
                   "content": f"<资料>\n{chr(10).join(contexts)}\n</资料>\n\n<答案>\n{answer}"}],
    )
    r = json.loads(resp.choices[0].message.content)
    return r["supported"] / max(1, r["total"])

成熟方案也可以直接用开源框架,它把忠实度、答案相关性、上下文精确率/召回率打包成一条流水线(各版本 API 有差异,以安装版本的文档为准):

from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision, context_recall

result = evaluate(
    dataset=samples,       # 字段:question / answer / contexts / ground_truth
    metrics=[faithfulness, answer_relevancy, context_precision, context_recall],
)
print(result)              # 各指标 0~1,按样本汇总

LLM 裁判适合做相对比较(A 方案 vs B 方案),绝对值要打折扣:同一份答案换个模型评分能差 0.1。

6. 指标好看但用户不满意的四种情况

现象真实原因该改哪里
recall 高,答案仍空泛块太大,证据被稀释重新分块
忠实度高,但没回答问题模型只复述原文提示词要求"先结论后依据"
正确率高,引用全错引用编号未校验加后置校验
离线全绿,线上投诉分布漂移线上采样回流评估集

7. 常见追问

Q:没有标注集怎么办? 先用 LLM 从文档反向生成"问题-答案"对,人工抽检 20% 修正;50 条就能看出方向,不必等 500 条。

Q:需要每次全量跑吗? 不必。回归集固定 50~100 条,每次改动跑一遍;全量评估放在版本发布前。

Q:线上怎么持续评估? 埋点采集空召回率、引用命中率、差评率,人工抽样每周 30 条灌回评估集,让集合跟着业务长大。

小结

评估是 RAG 的"仪表盘":没有它,所有优化都是玄学。先分层、再定量、最后才谈调优——顺序对了,每次改动都知道自己在改什么。

笔记加载中…