ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

RAG 系统怎么测:检索和生成要分开测

RAG 系统怎么测:检索和生成要分开测

RAG 的 demo 一天就能搭出来,但“它到底靠不靠谱”这个问题,很多人答不上来。原因很简单:大多数人只测了端到端——问一个问题,看答案对不对。对了就过,错了也不知道错在哪。

这篇讲怎么把评测拆开做。

一、为什么必须拆成两段测

RAG = 检索(Retrieval)+ 生成(Generation)。最终答案错了,至少有四种可能:

  • 检索没找到正确文档
  • 找到了,但模型没用上
  • 用了,但掺了自己的编造
  • 文档里明明有答案,模型却说“不知道”

只看端到端答案对错,你无法定位,也就无法修。所以评测必须分层:检索测召回质量,生成测忠实度与相关性。

二、检索侧:能量化“找得准不准”

前提是标注:每条 query 标注哪些 chunk 是相关的。小样本起步(50~100 条),后续迭代补。

指标含义
Hit@Ktop-K 里是否命中至少一个相关文档
Recall@Ktop-K 覆盖了多少比例的相关文档
MRR第一个相关文档排名的倒数,衡量相关结果排得靠不靠前
NDCG@K考虑排序位置的加权指标,多相关文档时更细

计算这三个最常用的:

fromtypingimportListdefhit_at_k(retrieved:List[str],relevant:set,k:int)->float:return1.0ifset(retrieved[:k])&relevantelse0.0defrecall_at_k(retrieved:List[str],relevant:set,k:int)->float:ifnotrelevant:return0.0returnlen(set(retrieved[:k])&relevant)/len(relevant)defmrr(retrieved:List[str],relevant:set)->float:forrank,doc_idinenumerate(retrieved,start=1):ifdoc_idinrelevant:return1.0/rankreturn0.0

聚合到整个评测集:

importstatisticsdefevaluate_retrieval(dataset,k=5):# dataset: [{"retrieved": [doc_id, ...], "relevant": [doc_id, ...]}, ...]hits,recalls,mrrs=[],[],[]foritemindataset:r,rel=item["retrieved"],set(item["relevant"])hits.append(hit_at_k(r,rel,k))recalls.append(recall_at_k(r,rel,k))mrrs.append(mrr(r,rel))return{"hit@k":statistics.mean(hits),"recall@k":statistics.mean(recalls),"mrr":statistics.mean(mrrs),}# 输出形如:{'hit@k': 0.xx, 'recall@k': 0.xx, 'mrr': 0.xx} 【填真实数值】

三、生成侧:把“答案好不好”拆成三个问题

  • 忠实度 Faithfulness:答案里的每个断言,是否能被检索到的 context 支持?——测幻觉
  • 答案相关性 Answer Relevance:答案是否切题,还是答非所问?
  • 上下文精度/召回 Context Precision / Recall:检索内容里有多少是有用的;该有的有没有

这几个就是 RAGAS 的指标体系,不用自己造轮子:

# pip install ragas datasetsfromdatasetsimportDatasetfromragasimportevaluatefromragas.metricsimportanswer_relevancy,context_precision,context_recall,faithfulness data=Dataset.from_dict(拆成句子,逐句问评审模型——“这句话能否被给定的 context 支持?”)

你是严格的评审员。给定【上下文】和【答案】,
请逐句判断答案中的每个事实性断言是否被上下文支持。
只输出 JSON:{“unsupported”: [“断言1”, …], “score”: 0~1}
不要使用上下文以外的任何知识。

聚合:幻觉率 = 不被支持的句子数 / 总句子数 【填真实】

关键提醒:judge 本身也会错。所以要抽样人工复核,并且给 judge 也算一个准确率——否则你只是把一个不确定的东西换成了另一个。这一步是很多评测文章会漏掉的,也是面试里最能体现深度的点。

五、端到端 + 一张能直接用的 badcase 分类表

端到端通过率 = 判定回答正确的样本占比(人工或 judge)。但比分数更重要的是把错误归类:

类型现象定位侧典型原因修复方向
检索未召回相关 chunk 不在 top-K检索切分、embedding、query措辞调 chunk 大小、加混合检索、query改写
召回了没用检索到了,答案却没引用生成prompt 未强调依据改 prompt、加引用约束
用了但编造答案含 context之外的内容生成模型幻觉引用校验、降温度、加固拒答
该答却拒答context有答案,却说不知道生成/检索拒答阈值过严调阈值、补充 context

有了这张表,每个错误都能落到“检索还是生成”上,修复方向也就出来了。

六、五个常见的坑

  1. chunk 切分直接决定检索上限:切太碎丢上下文,切太大噪声多,这是最该先调的东西
  2. 用户问法和文档措辞不一致:一定要测口语化、同义改写、错别字
  3. 多跳问题:答案分散在多个 chunk,单次检索拿不全,需要单独建一类
  4. 只看平均值:会被简单样本拉高,要按 tag 分组看(政策类、多轮类、多跳类)
  5. 成本:全量评测很贵,日常抽样跑,回归再全量

写在最后

RAG 评测的核心不是算出一个分数,而是让每一个错误都能被定位。分数只用来做基线对比和回归卡点,定位才是日常。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进