news 2026/10/2 7:16:48

AI 幻觉怎么量化:用 Python 算 AI 客服与知识库输出的假阳性率

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI 幻觉怎么量化:用 Python 算 AI 客服与知识库输出的假阳性率

AI 幻觉怎么量化:用 Python 算 AI 客服与知识库输出的假阳性率

做 AI 客服和知识库,最容易踩的坑不是"模型不会回答",而是它编了一条看起来完全合理的话,而你没有当场发现。

这类错有个专业说法:假阳性(false positive)——报了一个根本不存在的毛病,或者给了一个不存在的事实。业务上更常见的三种形态:

  • 编条款:问"退货运费谁出""保修几年",它不说不知道,而是给一句措辞规范、数字具体的答复
  • 编引用:问某条规定怎么写,它引用一段"原文"还带条款编号,回原文件一翻不存在
  • 依据错位:结论对,但出处是另一份文档或已作废版本

这三种错的共同点是都不像错:有格式、有细节、有出处,恰好绕过人的下意识判断。所以靠"感觉它准不准"是不可用的,得把它变成数字。

这个判断有官方依据

第 48 届世界技能大赛(2026 年 9 月 22-27 日,上海)首次设立软件测试赛项。官方对赛题的解释是(世界技能大赛中国(上海)研究中心主任王迪):

赛题设置盲盒任务,要求选手自主确定测试范围、选择工具、设计测试策略。AI 仅用于生成脚本、批量执行、日志分析等重复性工作。裁判核查选手对 AI 输出结果的校验、甄别 AI 生成内容中的错误与假阳性缺陷,评估选手对 AI 参数、提示词、自动化流程的自主设计等。

也就是说:AI 干重复活,人负责甄别它编出来的那部分。这是赛题评分点,不是感想。

度量方法:把"发现"对到 ground truth 上

做法很朴素:人工先逐条核对原文,得到真实问题清单(ground truth);再把 AI 的每条"发现"和它比对,统计四个数:

指标含义业务读法
命中 TPAI 报了,人工确认真实存在有效产出
假阳性 FPAI 报了,原文里没这回事直接消耗人力与信任
漏报 FN人工找到的问题,AI 没报风险敞口
精确率 / 召回率 / 假阳性率由前三个数算决定这类活能不能放手

可跑代码(Python 3.13,无第三方依赖)

# -*- coding: utf-8 -*- """AI 输出甄别:假阳性 / 漏报 度量脚手架""" import json from dataclasses import dataclass @dataclass class Finding: item: str # 被检查的对象(文档名 / 接口路径 / 问答条目) issue: str # AI 声称存在的问题 evidence: str # AI 给出的依据(原文片段或行号)——空字符串 = 没给依据 # ── 人工确认过的真实问题(ground truth)──────────────────────── GROUND_TRUTH = [ ("docs/refund.md", "退款到账时间写成 7 个工作日,与实际 15 天不符"), ("docs/warranty.md", "整机保修写 2 年,售后口径是 1 年"), ("docs/invoice.md", "未写明专票需要税号"), ("docs/shipping.md", "偏远地区不发货,正文没有说明"), ("kb/faq-12.md", "答非所问:问的是运费,答的是时效"), ] # ── AI 输出的「发现」清单 ──────────────────────────────────── AI_FINDINGS = [ Finding("docs/refund.md", "退款到账时间写成 7 个工作日,与实际 15 天不符", "原文第 3 段"), Finding("docs/warranty.md", "整机保修写 2 年,售后口径是 1 年", "原文第 1 段"), Finding("docs/invoice.md", "未写明专票需要税号", "原文第 2 段"), Finding("docs/shipping.md", "偏远地区不发货,正文没有说明", "原文第 4 段"), Finding("kb/faq-12.md", "答非所问:问的是运费,答的是时效", ""), # 真问题,没给依据 Finding("docs/refund.md", "退款条款缺失「超过 30 天不予受理」的约定", "原文第 6 段"), # 假阳性 Finding("docs/warranty.md", "保修范围未包含人工费", "原文第 9 段"), # 假阳性 Finding("kb/faq-30.md", "该条目引用已作废的旧版政策", "原文第 1 段"), # 假阳性 ] def norm(f: Finding) -> tuple: return (f.item.strip(), f.issue.strip()) def measure(truth, findings, require_evidence=False): """require_evidence=True 时,没给依据的发现不计入命中(下游要能追溯)。""" tset = {(i.strip(), s.strip()) for i, s in truth} kept, dropped = [], [] for f in findings: if require_evidence and not f.evidence.strip(): dropped.append(f); continue kept.append(f) hit = [f for f in kept if norm(f) in tset] fp = [f for f in kept if norm(f) not in tset] reported = {norm(f) for f in kept} miss = [(i, s) for (i, s) in tset if (i, s) not in reported] tp, fpn = len(hit), len(fp) precision = tp / (tp + fpn) if (tp + fpn) else 0.0 recall = tp / len(tset) if tset else 0.0 return { "AI 报出总数": len(findings), "计入核查": len(kept), "无依据被拦下": len(dropped), "命中真实问题": tp, "假阳性(编出来的)": fpn, "漏报(人发现AI没报)": len(miss), "精确率": round(precision, 3), "召回率": round(recall, 3), "假阳性率": round(fpn / (tp + fpn), 3) if (tp + fpn) else 0.0, } if __name__ == "__main__": print("【A】照单全收:AI 报什么就信什么") a = measure(GROUND_TRUTH, AI_FINDINGS) print(json.dumps(a, ensure_ascii=False, indent=2)) print("\n【B】加一道闸:没给依据的发现不进下游") b = measure(GROUND_TRUTH, AI_FINDINGS, require_evidence=True) print(json.dumps(b, ensure_ascii=False, indent=2)) print("\n【逐条看】") tset = {(i.strip(), s.strip()) for i, s in GROUND_TRUTH} reported_b = {norm(f) for f in AI_FINDINGS if f.evidence.strip()} for f in AI_FINDINGS: if not f.evidence.strip(): print(f" [B 拦下(没给依据)] {f.item} :: {f.issue}") if norm(f) in tset: print(" ↑ 注意:这是一条真问题,闸门把真问题也拦了") for f in AI_FINDINGS: if norm(f) not in tset: print(f" [假阳性(原文里没有这回事)] {f.item} :: {f.issue}") for i, s in GROUND_TRUTH: key = (i.strip(), s.strip()) if key in reported_b: continue if any(norm(f) == key for f in AI_FINDINGS): print(f" [B 因闸门漏掉] {i} :: {s}") else: print(f" [AI 从未报出] {i} :: {s}") print(f"\n【结论】A 假阳性率 {a['假阳性率']:.1%}|B 假阳性率 {b['假阳性率']:.1%}," f"但 B 的召回率从 {a['召回率']:.1%} 掉到 {b['召回率']:.1%}")

运行结果:

【A】照单全收:AI 报什么就信什么 { "AI 报出总数": 8, "计入核查": 8, "无依据被拦下": 0, "命中真实问题": 5, "假阳性(编出来的)": 3, "漏报(人发现AI没报)": 0, "精确率": 0.625, "召回率": 1.0, "假阳性率": 0.375 } 【B】加一道闸:没给依据的发现不进下游 { "AI 报出总数": 8, "计入核查": 7, "无依据被拦下": 1, "命中真实问题": 4, "假阳性(编出来的)": 3, "漏报(人发现AI没报)": 1, "精确率": 0.571, "召回率": 0.8, "假阳性率": 0.429 } 【逐条看】 [B 拦下(没给依据)] kb/faq-12.md :: 答非所问:问的是运费,答的是时效 ↑ 注意:这是一条真问题,闸门把真问题也拦了 [假阳性(原文里没有这回事)] docs/refund.md :: 退款条款缺失「超过 30 天不予受理」的约定 [假阳性(原文里没有这回事)] docs/warranty.md :: 保修范围未包含人工费 [假阳性(原文里没有这回事)] kb/faq-30.md :: 该条目引用已作废的旧版政策 [B 因闸门漏掉] kb/faq-12.md :: 答非所问:问的是运费,答的是时效 【结论】A 假阳性率 37.5%|B 假阳性率 42.9%,但 B 的召回率从 100.0% 掉到 80.0%

结果解读

一、假阳性率可以量化。8 条发现里 3 条是编的,假阳性率 37.5%。这个数字的意义不是给模型打分,而是判断某一类活到底能不能交给 AI 单独跑。

二、加闸门会连真问题一起拦。B 方案要求"每条发现必须给出依据",被拦下的那条恰好是真实存在、只是没标依据的问题——召回率从 100% 掉到 80%。阈值不是越严越好:收紧的同时必须配人工兜底,否则你会把"没报出问题"误当成"没有问题"。

三、反向指标比正向指标重要。大家习惯统计"AI 帮我发现了多少问题",很少统计"它编了多少"。但后者才决定下游还敢不敢信这份交付物。

落地建议

  1. 分档定策略:同一类活连跑两周,假阳性率稳定在低位(例如 5% 以内)才考虑减免人工复核,高位环节保留人审。
  2. 按来源分桶:把假阳性分"编条款 / 编引用 / 依据错位"三类计数。编引用通常出现在文档结构混乱、版本多的库里——先去治库,比反复调提示词有效。
  3. 给依据设门槛:要求每条发现指出原文位置,做不到的不进下游;require_evidence一个参数即可切换。

参考来源

  • 世界技能组织官网竞赛与 Skills 页面(worldskills2026.com)
  • 世界技能大赛中国(上海)研究中心主任王迪对软件测试赛项的官方解读(2026-09-22)
  • WorldSkills International《Software Testing — Technical Description》(WSC2026_TD11_en)

我们是谁:我们做企业知识库与 AI 客服落地,日常工作是给 AI 的输出加可核验的环节——让「客户天天问的问题」答得准,并且能追溯到原文。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 7:16:18

【TC4x】SOTA功能

- 本文是本人在学习TC4x SOTA 功能时整理的一份笔记,主要记录 A/B Swap 的地址映射关系、相关 UCB 配置,以及 SOTA 初始化流程。 - 文章中的理解仍在逐步完善,部分内容可能存在疏漏或错误。一、SOTA简介Software updates Over The Air (SOTA)…

作者头像 李华
网站建设 2026/10/2 7:16:17

陕西消防灭火器材品牌供应商用户力荐:本地靠谱服务机构排行榜

陕西闽峰消防有限公司是一家立足西安、辐射西北的一站式消防建材与工程服务供应商,专注为厂房、园区、商业楼宇、市政基建等各类项目提供消防灭火器材、消防报警系统、给排水消防配套器材、防爆防暴安防器材等全品类物资供应,同时承接消防工程、机电安装…

作者头像 李华
网站建设 2026/10/2 7:16:13

南宁亭子码头附近不错民宿出差住宿怎么订?

南宁亭子码头附近出差住宿怎么订?这篇攻略帮你把江南区民宿一次说清楚来南宁出差,住在江南区、晚上想散步去亭子码头吹吹江风,又不想住进空间局促、没法洗衣做饭的传统酒店——这大概是很多差旅人的真实想法。这篇文章就围绕亭子码头附近怎么订到合适的…

作者头像 李华
网站建设 2026/10/2 7:15:47

2026营养实训室建设标准与实施方案

1 营养实训室建设背景随着职业教育高质量发展推进,全国各大院校食品营养、健康管理、烹饪工艺与营养等专业持续扩招,传统理论授课简易实训的模式,已无法满足新时代职业教育岗课赛证融合要求。营养实训室作为营养类专业的核心实训载体&#xf…

作者头像 李华
网站建设 2026/10/2 7:13:27

057二分查找

二分查找 - 每次消灭一半可能性 057二分搜索:对半分的艺术📰 5W1H 发明者故事 Who(何人)- 发明者是谁? 发明者:约翰莫奇利(John Mauchly,ENIAC发明者之一,1946年提出&a…

作者头像 李华