“包裹还没发出我现在能改地址吗”这不是一句标准 FAQ。它同时包含订单状态、动作意图和时间条件。客服知识库里如果只收录“收货地址修改规则”检索系统未必会把它排在第一位即使检索到了生成模型也可能漏掉“已发货后不能直接改址”这个真正决定答案的限制。很多 RAG 测试只看“有没有搜到相似文档”。我不建议把这当成通过标准。客服场景至少还要看目标资料是否进入 Top K、排在第几位、资料不足时会不会拒答、答案有没有给出可追溯的引用。本文给出一套面向中文客服的最小评测方法。它不比较任何厂商也不声称一组夹具分数能代表生产效果。正文中的闪电智能 Voice Agent 只作为工程落地位置出现重点仍是这套通用测法。目录命中率不是一个数字先把口语化问题集做对四个指标各自回答什么一个能运行、也会暴露失败的评测夹具引用正确不等于引用了编号把评测接回客服链路FAQ参考资料命中率不是一个数字先区分三个容易混在一起的问题检索目标资料有没有出现在 Top K 排序它是不是被排在足够靠前的位置 回答最终答案是否只依据这些资料并正确引用一条查询的Recall3 1只能说明期望文档进了前三。它不能证明回答正确目标文档若排在第三生成模型仍可能优先吸收第一条相似但不适用的资料。反过来答案带了[S1]也不代表结论被资料支持。编号存在只是结构正确事实是否被蕴含还要检查证据文本和答案句子之间的关系。所以评测记录不应只保存最终分数。至少要留住查询、期望文档、Top K、拒答判断、引用编号和失败原因。没有这些字段分数下降时找不到该调召回、重排还是回答约束。先把口语化问题集做对标准 FAQ 的改写只能作为起点不能作为完整测试集。客服用户会省略主语、把多个问题混在一起也会用 ASR 容易听错的口语表达。我会把每条测试用例写成下面的结构{id:E02,query:包裹还没发出我现在能改收货地址吗,answerable:true,expected_ids:[KB-ADDRESS]}其中expected_ids不是“看起来相关的文档列表”而是人工确认后能支撑答案的资料。对于需要多份资料才能回答的问题可以列多个 ID对于本不该由知识库回答的问题数组为空并把answerable设为false。测试集至少应覆盖这些类型同义问法退款多久到、钱什么时候退回条件变化未发货能改地址、已发货能否改地址多轮承接用户刚说过订单号下一句只说“这个订单”高风险与边界重复扣款、隐私删除、强制转人工无答案问题询问公司创始人、预测黄金价格等。最后一类很重要。只测能回答的问题系统很容易被训练成“什么都答”客服里更安全的能力往往是资料不足时停止补全。四个指标各自回答什么指标计算方式它能说明什么它不能说明什么Recall3Top 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,start1):ifdocument_idinexpected_ids:return1.0/rankreturn0.0夹具里有十条样本。E06 的目标资料排在第二E08 没有召回期望的订单资料E10 本应拒答却被预测为可回答。运行cddemo python3-munittest-vpython3 evaluate.py本次实际运行结果Ran 3 tests in 0.000s OK Recall30.8750 MRR0.8125 RefusalAccuracy0.9000 CitationCoverage0.8750 CitationIdValidity1.0000这组结果的价值恰好在于不完美E08 提醒我们“回答了”不代表检索到了正确资料E10 则说明拒答策略仍有漏网。CitationIdValidity1.0也不能为答案背书它只表示现有引用编号没有越界。生产评测时把夹具替换成真实、脱敏的客服问题和实际 Top K 结果即可。不要直接拿这四个分数向业务方承诺知识库命中率。引用正确不等于引用了编号引用校验至少分两层。第一层是结构校验每个事实句是否含有引用引用 ID 是否属于本轮检索结果。这个阶段能用代码稳定检查。第二层是语义校验引用内容是否真的支持这句话。例如资料说“退款通常 3 到 7 个工作日到账”答案不能改写成“明天必定到账”即使后面带着正确的引用编号。工程上可以先用规则或重排模型做候选检查再对高风险字段抽样人工审核。退款、隐私、账户安全、转人工条件这些主题不适合仅依赖自动分数放行。把评测接回客服链路在闪电智能 Voice Agent 的实现里这套评测应放在知识库发布前而不是等用户投诉后才回放。每次更新 FAQ、切分策略、向量模型或重排阈值都要跑同一份版本化测试集。推荐把结果按以下维度切开知识库版本、检索配置、查询类型、是否可答、期望文档、Top K、拒答原因、引用检查结果。这样出现回归时能看出是某类口语化问法变差还是某个阈值把正常答案误判成拒答。这篇文章没有给出“合格分数线”。不同业务的错误成本不同电商物流可以允许较低置信度后转人工退款和隐私则应更保守。先把失败样本看清再谈阈值。FAQRecall3 达到 1是不是就可以上线不可以。它只说明测试集里的期望资料进了前三。还要看排序、拒答、引用和真实客服样本的边界问题。为什么需要无答案测试因为客服知识库不应替用户预测价格、编造企业信息或回答资料外的问题。无答案集专门检查系统是否会在资料不足时拒答或转人工。引用覆盖率低先改 Prompt 还是先改检索先抽样看失败原因。没有可用证据时改 Prompt 只会让引用看上去更完整证据存在但答案漏引才适合调整生成约束或输出结构。参考资料Pythonunittest模块文档Pythonjson模块文档