客服知识库怎么测 RAG 命中率?从口语化问题到引用准确性
2026/7/22 17:29:38 网站建设 项目流程

“包裹还没发出,我现在能改地址吗?”

这不是一句标准 FAQ。它同时包含订单状态、动作意图和时间条件。客服知识库里如果只收录“收货地址修改规则”,检索系统未必会把它排在第一位;即使检索到了,生成模型也可能漏掉“已发货后不能直接改址”这个真正决定答案的限制。

很多 RAG 测试只看“有没有搜到相似文档”。我不建议把这当成通过标准。客服场景至少还要看:目标资料是否进入 Top K、排在第几位、资料不足时会不会拒答、答案有没有给出可追溯的引用。

本文给出一套面向中文客服的最小评测方法。它不比较任何厂商,也不声称一组夹具分数能代表生产效果。正文中的闪电智能 Voice Agent 只作为工程落地位置出现,重点仍是这套通用测法。

目录

  • 命中率不是一个数字
  • 先把口语化问题集做对
  • 四个指标各自回答什么
  • 一个能运行、也会暴露失败的评测夹具
  • 引用正确,不等于引用了编号
  • 把评测接回客服链路
  • FAQ
  • 参考资料

命中率不是一个数字

先区分三个容易混在一起的问题:

检索:目标资料有没有出现在 Top K? 排序:它是不是被排在足够靠前的位置? 回答:最终答案是否只依据这些资料,并正确引用?

一条查询的Recall@3 = 1,只能说明期望文档进了前三。它不能证明回答正确;目标文档若排在第三,生成模型仍可能优先吸收第一条相似但不适用的资料。

反过来,答案带了[S1]也不代表结论被资料支持。编号存在只是结构正确,事实是否被蕴含还要检查证据文本和答案句子之间的关系。

所以评测记录不应只保存最终分数。至少要留住查询、期望文档、Top K、拒答判断、引用编号和失败原因。没有这些字段,分数下降时找不到该调召回、重排还是回答约束。

先把口语化问题集做对

标准 FAQ 的改写只能作为起点,不能作为完整测试集。客服用户会省略主语、把多个问题混在一起,也会用 ASR 容易听错的口语表达。

我会把每条测试用例写成下面的结构:

{"id":"E02","query":"包裹还没发出,我现在能改收货地址吗?","answerable":true,"expected_ids":["KB-ADDRESS"]}

其中expected_ids不是“看起来相关的文档列表”,而是人工确认后能支撑答案的资料。对于需要多份资料才能回答的问题,可以列多个 ID;对于本不该由知识库回答的问题,数组为空并把answerable设为false

测试集至少应覆盖这些类型:

  • 同义问法:退款多久到、钱什么时候退回;
  • 条件变化:未发货能改地址、已发货能否改地址;
  • 多轮承接:用户刚说过订单号,下一句只说“这个订单”;
  • 高风险与边界:重复扣款、隐私删除、强制转人工;
  • 无答案问题:询问公司创始人、预测黄金价格等。

最后一类很重要。只测能回答的问题,系统很容易被训练成“什么都答”;客服里更安全的能力往往是资料不足时停止补全。

四个指标各自回答什么

指标计算方式它能说明什么它不能说明什么
Recall@3Top 3 是否包含任一期望资料召回有没有漏掉目标资料最终答案是否正确
MRR第一条期望资料排名的倒数均值目标资料通常排得多靠前排名靠前资料是否真的足够回答
RefusalAccuracy拒答/应答判断是否与标注一致无答案时会不会乱答回答内容是否逐句有据
CitationCoverage应答样本中是否给了引用答案是否保留可检查入口引用是否真正支持结论

我会另外记录CitationIdValidity,检查答案里的引用 ID 是否在本轮可用证据中。这个值只能抓到“引用了不存在的编号”,不能替代语义蕴含校验。两者不要混为一谈。

一个能运行、也会暴露失败的评测夹具

本篇项目中的demo/evaluate.py不依赖向量库或模型,它读取固定夹具,专门验证指标口径。这样做是为了先把分数算对,并保留失败样本;不是为了伪造检索性能。

核心逻辑只看目标资料在 Top K 的位置:

defreciprocal_rank(retrieved_ids:list[str],expected_ids:set[str])->float:forrank,document_idinenumerate(retrieved_ids,start=1):ifdocument_idinexpected_ids:return1.0/rankreturn0.0

夹具里有十条样本。E06 的目标资料排在第二,E08 没有召回期望的订单资料,E10 本应拒答却被预测为可回答。运行:

cddemo python3-munittest-vpython3 evaluate.py

本次实际运行结果:

Ran 3 tests in 0.000s OK Recall@3=0.8750 MRR=0.8125 RefusalAccuracy=0.9000 CitationCoverage=0.8750 CitationIdValidity=1.0000

这组结果的价值恰好在于不完美:E08 提醒我们“回答了”不代表检索到了正确资料;E10 则说明拒答策略仍有漏网。CitationIdValidity=1.0也不能为答案背书,它只表示现有引用编号没有越界。

生产评测时,把夹具替换成真实、脱敏的客服问题和实际 Top K 结果即可。不要直接拿这四个分数向业务方承诺知识库命中率。

引用正确,不等于引用了编号

引用校验至少分两层。

第一层是结构校验:每个事实句是否含有引用;引用 ID 是否属于本轮检索结果。这个阶段能用代码稳定检查。

第二层是语义校验:引用内容是否真的支持这句话。例如资料说“退款通常 3 到 7 个工作日到账”,答案不能改写成“明天必定到账”,即使后面带着正确的引用编号。

工程上可以先用规则或重排模型做候选检查,再对高风险字段抽样人工审核。退款、隐私、账户安全、转人工条件这些主题,不适合仅依赖自动分数放行。

把评测接回客服链路

在闪电智能 Voice Agent 的实现里,这套评测应放在知识库发布前,而不是等用户投诉后才回放。每次更新 FAQ、切分策略、向量模型或重排阈值,都要跑同一份版本化测试集。

推荐把结果按以下维度切开:知识库版本、检索配置、查询类型、是否可答、期望文档、Top K、拒答原因、引用检查结果。这样出现回归时,能看出是某类口语化问法变差,还是某个阈值把正常答案误判成拒答。

这篇文章没有给出“合格分数线”。不同业务的错误成本不同:电商物流可以允许较低置信度后转人工,退款和隐私则应更保守。先把失败样本看清,再谈阈值。

FAQ

Recall@3 达到 1,是不是就可以上线?

不可以。它只说明测试集里的期望资料进了前三。还要看排序、拒答、引用和真实客服样本的边界问题。

为什么需要无答案测试?

因为客服知识库不应替用户预测价格、编造企业信息或回答资料外的问题。无答案集专门检查系统是否会在资料不足时拒答或转人工。

引用覆盖率低,先改 Prompt 还是先改检索?

先抽样看失败原因。没有可用证据时,改 Prompt 只会让引用看上去更完整;证据存在但答案漏引,才适合调整生成约束或输出结构。

参考资料

  • Pythonunittest模块文档
  • Pythonjson模块文档

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询