测试数据不够用又不敢碰生产:一份带脱敏的数据合成脚本

简介: RAG系统答非所问,问题八成出在检索层而非生成层!本文揭示反直觉排查法:先分层评测(检索命中→上下文相关→答案忠实→答案相关),定位“塌陷”环节;强调金标准构建与recall@k/MRR等核心指标,避免盲目换模型。精准诊断,事半功倍。

一个反直觉的排查经验:RAG 系统答非所问,八成问题不在生成层,而在检索层。 用户看到的答案是错的,团队第一反应往往是「换个更强的大模型」,但真正该先问的是——那份正确的文档,到底有没有被召回进上下文里。

如果检索根本没捞到对的文档,再强的模型也只能在错误的材料上编一个通顺的答案。这时候调 prompt、换模型全是无用功。

所以 RAG 质量不能当成一个整体去打分,必须分层测、先定位是哪一层塌了。

一、业务场景:企业知识库客服机器人,问 A 答 B

先把场景钉死。

我们接的是一个企业内部知识库客服机器人:底下挂着一堆制度文档、报销流程、IT 工单手册,员工问一句,系统先从知识库里检索若干段落塞进上下文,再让大模型基于这些段落作答。

问题很典型:员工问「年假怎么折算」,机器人答的是「病假需要哪些证明材料」。 答非所问,但答案本身读起来通顺、格式漂亮,甚至带了引用编号。

这时候最容易犯的错,是直接怀疑生成模型「幻觉了」,然后开始折腾 prompt、加约束、换模型。但在动手之前,必须先回答两个完全不同的问题:

  • 是检索层没召回对文档?——「年假折算」那段制度压根没进上下文,模型手里根本没有正确材料。
  • 还是检索对了、生成层瞎编?——正确段落明明在上下文里,模型却没用,自己脑补了一套。

这两种病因,药方完全相反。前者要改切分、改 embedding、改召回策略;后者才轮到调生成、加忠实度约束。不分层,就分不清该治哪一头。

二、四层评测:先分层,再定位

RAG 的质量评测,从检索到生成,可以拆成四层。每一层测的东西不同、塌了说明的病因也不同:

层级 测什么 怎么算 塌了说明什么 常用工具口径
① 检索命中 正确文档有没有被召回进 top-k recall@k、MRR、命中率 检索层塌了:对的文档根本没进上下文,改切分/embedding/召回 信息检索通用指标;RAGAS 的 context recall
② 上下文相关性 召回的段落跟问题相不相关 相关段落数 / 召回段落数 召回一堆噪声:命中了但也塞进大量无关段落,挤占上下文 RAGAS context relevance
③ 答案忠实度 答案每句话有没有检索到的出处支撑 被上下文支撑的陈述数 / 总陈述数 生成层瞎编:材料对了却脑补,出现幻觉 RAGAS faithfulness
④ 答案相关性 答案有没有正面回答用户的问题 答案与问题的语义相关度 答非所问:材料对、也没编,但跑题了 RAGAS answer relevance

06-配图1.png

这四层是有先后顺序的漏斗:上一层塌了,下一层测了也没意义。检索没召回对文档(①塌),你再去测答案忠实度(③),只会得出「答案没有出处支撑」这个废话结论——因为压根就没有出处可用。

正确的排查姿势是从上往下逐层测,在第一个塌掉的层停下来,那就是病根所在。

三、金标准问答对:评测的地基

四层评测全都依赖同一样东西——金标准(ground truth):一批「问题 → 应该命中哪些文档 → 参考答案应该包含哪些要点」的人工标注样本。

没有金标准,所有指标都是空中楼阁。构造原则三条:

  • 量不用大,先跑起来。 三五十条覆盖高频问题的样本,就能把四层指标算出来,比空谈强一百倍。
  • 标注要标到「文档 ID」粒度。 每个问题标清楚「正确答案应该来自哪几篇/哪几段文档」,这是算 recall@k 的前提。
  • 样本要覆盖两类失败。 既要有「知识库里有答案」的题(测能不能召回),也要有「知识库里根本没答案」的题(测系统会不会硬编)。第二类题最容易被忽略,却最能暴露幻觉——一个健康的 RAG 系统在知识库里查无此答时,应该老实说「没有找到相关规定」,而不是拿一段沾边的材料硬凑出一个像模像样的答案。

还有一个务实建议:金标准不是一次性工程,要跟着线上 badcase 长。 每次客服机器人被投诉答错,就把那条问答补进金标准集,标清楚正确文档该是哪几篇。几个月下来,这份集合会变成你手里最值钱的资产——它记录的是一批「真实用户会怎么问、系统又是怎么答错的」样本,比任何公开榜单都贴合你自己的业务。

下面这份脚本,从构造金标准开始,一路算到 faithfulness,只依赖 Python 标准库,复制即可运行。

四、算 recall@k 与 MRR:先看检索层塌没塌

第一步永远是测检索层。这段代码构造一小份金标准,模拟检索器返回的排序结果,算出 recall@k 和 MRR:

# rag_eval.py —— 只依赖标准库,python rag_eval.py 直接跑
# 1) 金标准:每个问题 -> 应该命中的文档 ID 集合
GOLD = {
   
    "年假怎么折算": {
   "doc_annual_leave"},
    "病假需要哪些证明": {
   "doc_sick_leave", "doc_medical_cert"},
    "报销打车费上限": {
   "doc_expense_taxi"},
}

# 2) 模拟检索器:每个问题 -> 按相关度排序召回的文档 ID 列表(top-k)
RETRIEVED = {
   
    "年假怎么折算": ["doc_sick_leave", "doc_annual_leave", "doc_holiday"],
    "病假需要哪些证明": ["doc_sick_leave", "doc_medical_cert"],
    "报销打车费上限": ["doc_expense_general", "doc_expense_hotel"],
}

def recall_at_k(gold: set, retrieved: list, k: int) -> float:
    """top-k 里命中的金标准文档数 / 金标准文档总数"""
    hit = gold & set(retrieved[:k])
    return len(hit) / len(gold) if gold else 0.0

def reciprocal_rank(gold: set, retrieved: list) -> float:
    """首个相关结果排名的倒数;没命中记 0"""
    for rank, doc in enumerate(retrieved, start=1):
        if doc in gold:
            return 1.0 / rank
    return 0.0

def evaluate_retrieval(k: int = 3):
    recalls, rrs = [], []
    for q, gold in GOLD.items():
        ret = RETRIEVED.get(q, [])
        r = recall_at_k(gold, ret, k)
        rr = reciprocal_rank(gold, ret)
        recalls.append(r)
        rrs.append(rr)
        flag = "OK" if r > 0 else "检索层塌陷"
        print(f"[{flag}] {q}  recall@{k}={r:.2f}  RR={rr:.2f}")
    n = len(GOLD)
    print("-" * 40)
    print(f"平均 recall@{k} = {sum(recalls)/n:.2f}")
    print(f"MRR            = {sum(rrs)/n:.2f}")

if __name__ == "__main__":
    evaluate_retrieval(k=3)

跑完看两件事:

  • 平均 recall@k 偏低:说明大量正确文档根本没进 top-k,检索层就是病根。上面「年假怎么折算」虽然 recall 不为 0,但正确文档排在第 2 位,MRR 会被拉低——这意味着上下文里第一位塞的是病假文档,模型很可能被带偏。
  • 「报销打车费上限」直接标了「检索层塌陷」:recall 为 0,正确文档压根没召回。这种题无论生成层多强都答不对,别去动模型,回头改检索。

只有当 recall@k 和 MRR 都健康时,才有必要往下测生成层。 这一步能帮你省下大量「白换模型」的成本。

五、faithfulness:答案有没有出处支撑

检索层过了,才轮到测生成层最关键的指标——忠实度:答案里的每一句陈述,能不能在召回的上下文里找到支撑。

先用一个零成本的规则版做粗筛(判断答案的关键信息词是否落在上下文里),它抓不出所有幻觉,但能秒级定位「答案里出现了上下文根本没有的实体」:

def faithfulness_rule(answer: str, context: str, stopwords=None) -> float:
    """规则版忠实度:答案关键信息词被上下文覆盖的比例(粗筛,非严格判定)"""
    stopwords = stopwords or {
   "的", "了", "是", "在", "和", "与", "可以", "需要"}
    # 极简切分:实际项目请用分词器(如 jieba)替换这里
    tokens = [t for t in answer.replace(",", " ").replace("。", " ").split()
              if t and t not in stopwords]
    if not tokens:
        return 1.0
    supported = sum(1 for t in tokens if t in context)
    return supported / len(tokens)

# 演示:上下文只讲病假,答案却在讲年假折算 —— 规则版会立刻暴露低覆盖
ctx = "病假需要提供二级以上医院开具的诊断证明与病假条。"
ans_good = "病假 需要 医院 诊断证明 病假条"
ans_bad  = "年假 折算 按 入职 月份 比例 计算"
print("忠实答案覆盖:", faithfulness_rule(ans_good, ctx))  # 高
print("跑题答案覆盖:", faithfulness_rule(ans_bad, ctx))   # 低,暴露无出处陈述

规则版够快够便宜,适合放进 CI 做门禁粗筛。但它只能看字面覆盖,判断不了「语义上是否被支撑」。真正严格的 faithfulness 判定,通常交给一个裁判模型:把「问题 + 上下文 + 答案」丢给它,让它把答案拆成一条条陈述,逐条判断能否被上下文推出。RAGAS 这类开源评测库封装的就是这套逻辑,可以直接拿来当工具口径,不必自己从零写裁判 prompt。

但这里有一个必须讲明的坑:用模型判 faithfulness,裁判模型自己也会误判。 它会漏判隐含的幻觉,也会把合理改写误报成「无支撑」。所以在拿裁判模型的分数当结论之前,先用一批人工标注好的小样本校准它——算一下裁判判定和人工判定的一致率,一致率不达标,这个裁判就还不能上岗。否则你只是用一把没校准的尺子,去量另一把尺子。

六、上下文相关性与答案相关性:补齐另外两层

剩下两层测的是「质量」而非「有没有」:

  • 上下文相关性测召回的段落里有多少是噪声。命中了正确文档,但如果 top-k 里塞进七八段无关内容,既挤占上下文预算,又容易把模型带偏。算法简单:相关段落数 / 召回段落数。
  • 答案相关性测答案有没有正面回应用户的问题。它和忠实度是两件事——一个答案可以句句有出处(忠实度高),却完全答非所问(相关性低)。用户问折算规则,你答了一堆请假流程,每句都在文档里,但没解决问题。

四层各管一段,缺一不可。只看忠实度会漏掉跑题,只看答案相关性会漏掉幻觉,只看 recall 会漏掉「召回对了却瞎编」。

这也解释了为什么很多团队「上了评测却还是治不好 RAG」——他们往往只挑一个顺手的指标盯着看,比如只算答案相关性,觉得分数还行就收工。可答案相关性高不代表没幻觉:一个编得很圆、又恰好切题的答案,相关性可以很高,忠实度却是零。四层要一起看,缺哪层都会留下盲区。

七、分层定位:把力气用在塌掉的那一层

回到开头那个「问年假、答病假」的例子。分层测一遍,路径就清晰了:

先看①——recall@k 显示正确文档 doc_annual_leave 排在第 2 位,命中了但没排在首位;MRR 偏低。再看②——top-k 里病假文档排在年假文档前面,上下文相关性被噪声拉低。到这一步,病因已经定位:是检索排序的问题,不是生成的问题。 该做的是调整召回排序、优化 chunk 切分,而不是换模型。

如果①②都健康、正确答案稳稳排在上下文首位,用户却仍看到编造内容,那才轮到③忠实度塌了——这时候加生成约束、上裁判模型门禁才有的放矢。

RAG 评测最贵的不是指标本身,而是「不分层就开始优化」。 分层测的价值,是让你在动手改之前就知道该改哪一层——把有限的力气,精准砸在那个真正塌掉的地方。

如果你手上有个答非所问的 RAG 系统,留言区说说你测下来是塌在检索层还是生成层。

相关文章
|
2月前
|
存储 Web App开发 人工智能
【AI】Agent 全栈进阶|Agent 记忆机制
本文讲解 Agent 记忆系统,区分会话内短期记忆与跨会话长期记忆。短期记忆借助滑动窗口、摘要压缩管理上下文;长期记忆筛选有效事实外部存储,按需召回,附带完整实操代码
211 0
|
2月前
|
缓存 自然语言处理 运维
榨出高纯度 Prompt:大模型混合检索 Rerank 调优全流程
混合检索虽提升了召回率,但因量纲不一和双塔模型语义折损,易导致噪声挤占 Prompt 引发幻觉。 本文深入探讨“大模型知识库混合检索重排序 Rerank 实践”,拆解“多路粗召回 + RRF 融合 + Cross-Encoder 精确打分 + 动态阈值截断”的两阶段标准架构。同时横向对比 BGE、Cohere 等主流选型,并针对延迟优化与元数据注入提供实操调优技巧,助力系统实现高精度输出。
349 0
|
6月前
|
存储 设计模式 人工智能
从无状态到有状态:长时运行 Agent 的 5 种架构模式
本文详解长时运行AI Agent的5大生产级架构模式:Checkpoint-and-Resume实现断点续传;Delegated Approval支持原地暂停与人机协同;Memory-Layered Context分层管理长期记忆与工作记忆;Ambient Processing赋能无提示事件驱动;Fleet Orchestration实现多Agent协同治理——让Agent真正成为可靠、有状态、可运维的系统进程。
783 3
从无状态到有状态:长时运行 Agent 的 5 种架构模式
|
2月前
|
存储 关系型数据库 MySQL
大模型推理成本优化实战:vLLM 与 KV Cache 调优指南
大模型落地后,真正制约成本的常非模型本身,而是每生成1个Token的开销。长上下文与高并发下,KV Cache迅速吞噬显存,成为性能瓶颈。vLLM通过PagedAttention、Continuous Batching、Prefix Caching等系统性优化,显著提升GPU利用率与吞吐,降低单位Token成本。
391 0
大模型推理成本优化实战:vLLM 与 KV Cache 调优指南
|
14天前
|
存储 人工智能 算法
大模型长期记忆系统设计:记忆压缩、去重、动态遗忘、时间衰减与冲突处理应用实践24.0
本文系统阐述大模型记忆引擎设计,提出瞬时/短期/长期三层记忆架构,涵盖压缩精简、语义去重、版本更新、时间衰减与冲突消解等全生命周期治理机制,强调其非简单数据库,而是模拟人脑规律的智能信息筛选与管理能力。
149 3
|
11月前
|
存储 人工智能 自然语言处理
构建AI智能体:二十三、RAG超越语义搜索:如何用Rerank模型实现检索精度的大幅提升
本文介绍了重排序(Rerank)技术在检索增强生成(RAG)系统中的应用。Rerank作为初始检索和最终生成之间的关键环节,通过交叉编码器对初步检索结果进行精细化排序,筛选出最相关的少量文档提供给大语言模型。相比Embedding模型,Rerank能更精准理解查询-文档的语义关系,显著提高答案质量,降低Token消耗。文章详细比较了BGE-Rerank和CohereRerank等主流模型,并通过代码示例展示了Rerank在解决歧义查询(如区分苹果公司和水果)上的优势。
2464 5
|
21天前
|
人工智能 自然语言处理 Java
【AI】Agent 专项进阶|RAG 混合检索策略
本文介绍混合检索在知识召回中的应用,结合向量检索(语义匹配)与BM25关键词检索(精确匹配),克服单一方法的局限。通过建立双索引、并行召回、统一排名(采用RRF融合)及可选精排,显著提升召回准确率。实战测试显示,混合检索在顶1、顶3命中率上优于单一方案,尤其擅长处理术语、编号等关键信息。代码实现基于LangChain,强调领域词典加载与分词优化,适用于垂直场景下的高质量问答系统构建。
163 0
|
22天前
|
人工智能 数据库
LangChain 实现AdvancedRAG增强向量检索生成
Advanced-RAG是工业级RAG优化方案,在朴素RAG基础上不改架构,通过Multi-Query扩召回、MMR多样性检索、LLM上下文压缩、BGE重排序等多层增强,精准过滤噪声、提升上下文相关性与问答稳定性。(239字)
112 0
|
26天前
|
人工智能 开发者
RAG 检索中的语义重排序(Reranker):原理、实现与效果评估
本文详解Reranker如何解决RAG中“召回准、引用歪”问题:通过交叉编码器对问询与候选块逐对打分,将真正相关、可被AI引用的内容精准前置,显著提升答案准确性与引用率。
|
2月前
|
人工智能 安全 测试技术
AI红队测试是什么:转岗大模型评测的最短路径
本文详解AI红队测试——面向大模型与Agent的安全评测新方向。结合欧盟AI法案落地、前沿安全风险(如Prompt注入、越权调用)及企业工程需求,阐明其非传统渗透测试,而是覆盖对抗诱导、边界守卫与可控性验证的系统性质量工程。为测试工程师提供从自动化能力迁移至AI安全评测的清晰进阶路径。

热门文章

最新文章