幻觉检测专项
大模型测试体系教程 · 第 13 篇 · 认知 → 原理 → 方法论 → 实操 → 案例练习
这篇怎么学
幻觉是大模型最核心的质量风险,也是最难检测的缺陷类型。本篇按照认知 → 原理 → 方法论 → 实操 → 案例练习五层递进结构编排,从"什么是幻觉"到"如何在 CI 中自动化检测",层层深入。建议通读后再动手实操。
第1章:什么是大模型幻觉
1.1 幻觉的定义
大模型幻觉(Hallucination)是指模型生成的内容看起来流畅合理,但实际上是错误的、无中生有的、或与事实/上下文不符的。幻觉的本质特征是"高置信度的错误"——模型不会表现出犹豫或不确定,而是以自信的语气说出错误内容。
📖 一句话理解
幻觉 = 模型"一本正经地胡说八道"。它不是模型说"我不知道",而是模型编造了一个听起来很对但实际上不存在或不正确的答案。
这和传统软件 bug 有本质区别。传统软件如果出错,通常是崩溃、报异常或返回错误码,开发者能立刻察觉。但幻觉的危险在于:输出格式完美、语法正确、逻辑自洽,只有具备领域知识的人才能发现它是错的。
示例
幻觉 vs 普通错误对比:
| 维度 | 传统软件 Bug | 大模型幻觉 |
|---|---|---|
| 表现形式 | 崩溃、报错、格式异常 | 输出流畅、格式正确、但内容错误 |
| 可观测性 | 容易被监控捕获 | 需要人工或专门工具验证 |
| 可复现性 | 通常稳定复现 | 概率性出现,同一问题不同时间结果不同 |
| 影响范围 | 功能不可用 | 功能可用但结果误导用户 |
| 检测成本 | 低(自动化断言即可) | 高(需要知识比对或多维度验证) |
1.2 为什么幻觉是最核心的质量风险
在所有大模型的质量问题中,幻觉排在第一位,原因有三个:
- 隐蔽性高:用户无法通过输出的形式判断结果是否正确,非领域专家极容易被误导。
- 后果严重:在医疗、法律、金融等领域,一条幻觉可能直接导致决策失误、经济损失甚至人身伤害。
- 信任破坏:一旦用户发现模型"说谎",对整个 AI 系统的信任度会急剧下降,且难以恢复。
1.3 幻觉在不同场景的影响程度
不同业务场景对幻觉的容忍度差异极大。测试时必须根据场景确定幻觉检测的优先级和严格程度:
| 场景 | 幻觉容忍度 | 典型风险 | 检测优先级 |
|---|---|---|---|
| 医疗问诊 / 用药建议 | 零容忍 | 编造药物剂量、虚构禁忌症、错误诊断 | P0 |
| 法律文书 / 合同审查 | 零容忍 | 编造法条、错误引用判例、虚构法律后果 | P0 |
| 金融分析 / 投研报告 | 极低 | 编造财务数据、虚构公司信息、错误趋势判断 | P0 |
| 知识库问答 / 客服 | 低 | 回答超出知识库范围、编造产品功能 | P1 |
| 数据提取 / 结构化输出 | 低 | 提取不存在的字段值、数值错误 | P1 |
| 代码生成 | 中等 | 编造不存在的 API、使用错误的函数签名 | P1 |
| 创意写作 / 头脑风暴 | 高 | "编造"本身就是期望行为 | P2 |
| 闲聊对话 | 高 | 影响有限,但如涉及事实仍需关注 | P2 |
关键判断原则
判断幻觉检测优先级的核心标准:用户是否会把模型输出当作事实来决策。如果会,幻觉就是 P0 级风险;如果不会,可以适当降级。
第2章:幻觉的分类体系
2.1 四大幻觉类型
学术界和工业界对幻觉有多种分类方式。从测试实践角度出发,我们把幻觉分为四大类型,每种类型的检测方法和测试策略完全不同:
| 类型 | 英文名 | 定义 | 核心特征 | 典型场景 |
|---|---|---|---|---|
| 事实性幻觉 | Factual Hallucination | 编造不存在的事实、数据或实体 | 模型输出的内容在现实世界中不成立 | 开放问答、知识检索 |
| 忠实性幻觉 | Faithfulness Hallucination | 回答偏离了输入的文档或上下文 | 模型添加了上下文中不存在的信息 | RAG、文档问答、摘要 |
| 推理幻觉 | Reasoning Hallucination | 推理步骤看似正确但结论错误 | 中间过程合理但最终结果不对 | 数学计算、逻辑推理、代码 |
| 指令幻觉 | Instruction Hallucination | 声称执行了操作但实际没做 | 模型"假装"完成了工具调用或动作 | Agent、Tool Calling |
2.2 每种类型的典型案例
事实性幻觉
示例
**问:**爱因斯坦是哪一年获得诺贝尔物理学奖的? **幻觉回答:**爱因斯坦于 1905 年因相对论获得诺贝尔物理学奖。 事实:爱因斯坦于 1921 年获奖,获奖原因是光电效应,而非相对论。此回答同时存在时间错误和原因错误。
忠实性幻觉
示例
上下文文档:"本公司提供标准版和专业版两种产品方案,标准版月费 99 元。" **问:**你们有哪些产品方案? **幻觉回答:**我们提供标准版(月费 99 元)、专业版(月费 299 元)和企业版(月费 999 元)三种方案。 **问题:**专业版的价格是模型编造的,企业版在文档中根本不存在。模型超出了上下文范围"自由发挥"。
推理幻觉
示例
**问:**一个水池进水管每小时注入 3 吨水,出水管每小时排出 1.5 吨水,水池容量 30 吨,问几小时注满? **幻觉回答:**进水速度 3 吨/小时,出水速度 1.5 吨/小时,净进水 3 - 1.5 = 1.5 吨/小时,30 ÷ 1.5 = 15 小时。但最终给出答案"10 小时"。 **问题:**推理过程完全正确(净进水 1.5 吨/小时),但最终结论错误(应为 20 小时,上面的中间步骤也错了:30÷1.5=20)。这种"步骤对但答案错"的情况尤其难以检测。
指令幻觉
示例
**用户指令:**请帮我查询北京今天的天气。 **幻觉回答:**我已经查询了天气 API,北京今天晴,气温 22-28℃,适合外出。 **问题:**模型根本没有调用任何天气 API 工具,所有数据都是编造的。在 Agent 场景中,这种"假装调了工具"的行为风险极高。
2.3 幻觉分类树状图
大模型幻觉
- 事实性幻觉(Factual)
- 实体编造 — 虚构不存在的人/地/物
- 属性错误 — 张冠李戴,数值/日期/关系错误
- 事件虚构 — 编造从未发生的事件
- 忠实性幻觉(Faithfulness)
- 信息添加 — 回答包含上下文中不存在的内容
- 信息矛盾 — 回答与上下文冲突
- 信息遗漏 — 关键信息未被提取
- 推理幻觉(Reasoning)
- 计算错误 — 数学运算结果错误
- 逻辑跳跃 — 步骤跳过中间推理环节
- 结论偏离 — 推导过程正确但最终结论错误
- 指令幻觉(Instruction)
- 伪工具调用 — 声称调了工具但实际没有
- 结果编造 — 编造工具返回的数据
- 状态伪报 — 声称任务已完成但并未执行
第3章:幻觉产生的技术原因
3.1 训练数据中的噪声和矛盾
大模型从海量训练数据中学习"世界知识",但训练数据本身并不完美:
- **过时信息:**训练数据有时间截止点,截止后的事实模型不知道,但它不会说"不知道",而是基于旧知识推测。
- **错误内容:**互联网上大量内容本身就是错的,模型无法区分可靠来源和不可靠来源。
- **矛盾信息:**不同来源对同一事实有不同描述,模型学到的是所有描述的"统计平均值",最终可能输出一个折中但错误的答案。
- **长尾知识不足:**冷门领域、小语种内容训练样本少,模型在这些领域的幻觉率显著更高。
3.2 注意力机制的局限性
Transformer 模型靠注意力机制来决定"关注输入的哪些部分",但在以下场景中注意力可能失焦:
- **长上下文衰减:**当输入文本很长时,模型对中间部分的注意力会减弱("Lost in the Middle"现象),导致遗漏关键信息。
- **干扰信息抢注意力:**上下文中如果存在与问题无关但语义相近的片段,模型可能错误地基于这些片段生成答案。
- **数值和结构化数据弱感知:**注意力机制对自然语言优化,对表格、数字序列、代码结构的感知能力相对较弱。
3.3 自回归生成的"滚雪球"效应
大模型采用自回归方式逐 token 生成文本。每个 token 的生成依赖于前面所有已生成的 token。这意味着:
滚雪球效应
如果第 N 个 token 是错误的,第 N+1 个 token 会在错误的基础上继续推理,后续所有内容都可能被"带偏"。一步错,步步错。模型不会回头检查自己前面说的是否正确。
正确上下文 → Token N 出错 → 基于错误继续生成 → 错误被放大 → 最终输出严重偏离事实
3.4 Temperature 和采样策略对幻觉率的影响
生成参数直接影响幻觉出现的概率:
| 参数 | 作用 | 对幻觉的影响 | 测试建议 |
|---|---|---|---|
| temperature | 控制输出随机性 | 温度越高,采样越随机,幻觉概率越大 | 分别在 0, 0.3, 0.7, 1.0 下测试幻觉率 |
| top_p | 核采样阈值 | top_p 越小,候选 token 越集中,幻觉降低 | 对比 top_p=0.1 vs top_p=0.9 |
| top_k | 取概率最高的 K 个候选 | K 越小越保守 | 观察 top_k 对生成一致性的影响 |
| frequency_penalty | 惩罚重复 token | 过高会迫使模型选择低概率 token,增加幻觉 | 确认惩罚值不会导致"为了不重复而编造" |
| max_tokens | 最大生成长度 | 过短导致截断,过长导致"凑字数"时编造 | 检查接近 max_tokens 时输出质量是否退化 |
3.5 幻觉产生机制流程图
1 数据层 — 训练数据包含噪声、矛盾、过时信息和长尾空白 ↓ 2 模型层 — 注意力机制对长文本/结构化数据感知不足,参数化记忆存在概率性偏差 ↓ 3 解码层 — Temperature / top_p 采样引入随机性,自回归滚雪球放大早期错误 ↓ 4 对齐层 — RLHF 训练模型"不要说不知道",鼓励生成流畅回答而非承认无知 ↓ 5 输出层 — 最终输出看起来自信且流畅,但内容可能部分或完全错误 → 幻觉
老师总结
幻觉不是某个单一原因造成的,而是训练数据、模型架构、解码策略和对齐训练共同作用的结果。这也意味着,不存在"消灭幻觉"的银弹,只能通过多层检测降低其逃逸率。
第4章:幻觉检测的技术路线
4.1 五种主流检测路线
幻觉检测没有万能方法。不同场景需要不同的检测路线,有时甚至需要多种方法组合使用:
| # | 检测路线 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|---|
| 1 | 已知答案比对 | 预设标准答案(Golden Answer),与模型输出做文本/语义比对 | 判定明确、可自动化、假阳率低 | 需要预先构建标准答案库,覆盖面有限 | FAQ、固定知识问答、数据提取 |
| 2 | 知识库/文档比对(NLI) | 用自然语言推理模型判断输出是否被源文档"蕴含" | 不需要预设答案,可泛化;特别适合 RAG | NLI 模型本身可能不准确;对复杂推理无力 | RAG、文档问答、摘要生成 |
| 3 | 搜索引擎验证 | 将模型声称的事实送搜索引擎验证,交叉比对多个来源 | 覆盖范围广,不依赖预建知识库 | 延迟高、成本高、搜索结果本身可能不可靠 | 开放域事实问答、实时知识验证 |
| 4 | 一致性检测 | 同一问题多次生成,检查回答间的一致性 | 不需要标准答案,可发现模型不确定的知识点 | 高成本(需多次调用);一致不代表正确 | 评估模型置信度、筛选高不确定性回答 |
| 5 | LLM-as-Judge | 用另一个(通常更强的)模型来判断输出是否存在幻觉 | 灵活性高,可处理开放式回答 | 判断模型自身也有幻觉风险;成本高 | 通用场景、兜底检测、人工审核前预筛 |
4.2 各方法的使用建议
实践原则
- 优先用确定性方法(已知答案比对、NLI)覆盖核心场景
- 用一致性检测发现模型"不自信"的知识盲区
- 用LLM-as-Judge做兜底和开放场景补充
- 在高风险场景中,多种方法联合使用,取最严格结果
4.3 选择检测方法的决策树
是否有标准答案? 是 → 已知答案比对(方法1) 否 ↓ 是否有参考文档/上下文? 是 → NLI 文档比对(方法2) 否 ↓ 是否为可搜索验证的事实? 是 → 搜索引擎验证(方法3) 否 ↓ 是否能容忍多次调用的成本? 是 → 一致性检测(方法4)+ LLM-as-Judge(方法5) 否 → LLM-as-Judge 单次判定(方法5)
第5章:幻觉测试策略
5.1 按场景分层的检测策略
不同的应用场景,幻觉的表现形式和检测重点完全不同。以下按四种核心场景分别阐述:
5.1.1 开放问答场景
**核心风险:**编造事实、张冠李戴、虚构实体。
| 检测维度 | 方法 | 示例 |
|---|---|---|
| 实体准确性 | 事实三元组比对(主体-关系-客体) | "鲁迅原名周树人" vs "鲁迅原名周作人" |
| 数值准确性 | 提取数值与可信来源交叉验证 | GDP 数据、人口数据、日期 |
| 来源可追溯性 | 检查模型是否引用了可验证的来源 | 模型声称"根据 WHO 报告"但该报告不存在 |
| 知识时效性 | 检查模型回答是否超出了训练数据截止时间 | 回答 2026 年的问题但训练数据只到 2024 年 |
5.1.2 RAG 场景
**核心风险:**回答超出检索内容范围,添加检索文档中不存在的信息。
RAG 幻觉检测的核心问题
模型的回答是否完全基于检索到的文档片段?如果回答中包含任何检索结果里找不到的信息,就是忠实性幻觉。
| 检测维度 | 方法 | 判定标准 |
|---|---|---|
| 忠实性 | NLI 模型判断回答是否被检索片段蕴含 | 每个输出声明都能在上下文中找到依据 |
| 覆盖性 | 检查回答是否涵盖了检索到的所有关键信息 | 关键信息未被遗漏 |
| 信息边界 | 检查回答中是否包含上下文之外的信息 | 不得添加任何检索结果中不存在的事实 |
| "不知道"能力 | 当检索结果不包含答案时,模型是否承认 | 应回答"无法从现有信息中确定" |
5.1.3 数据提取场景
**核心风险:**提取了原文中不存在的数据,或数值被改变。
| 检测维度 | 方法 | 示例 |
|---|---|---|
| 字段存在性 | 验证提取的字段在原文中是否真实存在 | 原文无"邮编"字段但模型自行编造 |
| 值准确性 | 精确比对提取值与原文中的值 | 原文"3,500 万"被提取为"3500 万" |
| 无中生有 | 检查是否提取了原文中不存在的信息 | 原文未提及联系人但模型编造了一个 |
5.1.4 Tool Calling 场景
**核心风险:**模型声称调用了工具但实际未调用,或编造工具返回结果。
| 检测维度 | 方法 | 示例 |
|---|---|---|
| 调用真实性 | 审查请求日志,确认工具是否真的被调用 | 模型说"已查询数据库"但日志中无查询记录 |
| 参数准确性 | 验证工具调用参数是否正确 | 应查"北京"天气但传参为"上海" |
| 结果忠实性 | 比对模型展示的结果与工具实际返回 | 工具返回"25℃"但模型回答"28℃" |
| 异常处理 | 工具调用失败时模型是否如实报告 | 工具超时但模型编造了返回值 |
5.2 测试用例设计方法
设计幻觉检测用例的核心原则是:让模型有机会犯错。如果测试问题太简单、太常见,模型很可能碰巧答对。好的幻觉测试用例应该:
- 覆盖知识边界:问模型"应该知道但可能不确定"的问题
- 包含陷阱:问题本身包含错误前提或诱导信息
- 要求精确性:要求模型给出具体数值、日期、名称等可验证的信息
- 测试拒答能力:设计模型不应该回答的问题,检查是否会编造
5.3 幻觉率基线建立方法
构建测试集(100-500 题) → 首次全量运行 → 人工审核标注 → 计算各类别幻觉率 → 确定基线 + 阈值
| 步骤 | 操作 | 产出物 |
|---|---|---|
| 1. 构建测试集 | 按场景和幻觉类型均匀采样,确保覆盖高风险领域 | 测试用例集 |
| 2. 首次运行 | 对每道题运行 3 次取平均,排除随机性 | 原始结果数据 |
| 3. 人工审核 | 领域专家逐条审核,标注是否幻觉、幻觉类型、严重程度 | 标注数据集 |
| 4. 计算指标 | 分类计算幻觉率、按严重程度加权 | 基线报告 |
| 5. 设定阈值 | 根据业务容忍度设定合格线和告警线 | 质量门禁标准 |
第6章:幻觉检测的评估指标
6.1 核心指标体系
| 指标 | 定义 | 计算公式 | 适用场景 |
|---|---|---|---|
| Hallucination Rate | 整体幻觉率 | 含幻觉回答数 / 总回答数 × 100% | 所有场景的总览指标 |
| Faithfulness Score | 忠实度分数 | 可被上下文蕴含的声明数 / 总声明数 | RAG、文档问答 |
| Factual Consistency | 事实一致性 | NLI 模型输出的蕴含概率均值 | 摘要、内容生成 |
| Self-Consistency | 自一致性 | 多次回答中一致的比例 | 模型置信度评估 |
| Abstention Rate | 拒答率 | 正确拒答数 / 应拒答问题数 | 评估模型的"知之为知之"能力 |
6.2 Faithfulness Score 详解
Faithfulness Score 是 RAG 场景中最重要的幻觉指标。它的计算流程:
- 声明拆解:将模型回答拆分为独立的声明(claims),每个声明是一个可以独立验证的陈述句
- 逐条验证:对每个声明,用 NLI 模型判断它是否被检索到的上下文所蕴含
- 计算得分:Faithfulness = 被蕴含的声明数 / 总声明数
示例
示例计算: 模型回答包含 5 个声明,其中 4 个能在上下文中找到依据,1 个是模型自行添加的。 Faithfulness Score = 4/5 = 0.80 如果阈值设为 0.90,则该回答未通过忠实性检测。
6.3 如何设定合格阈值
| 场景 | Hallucination Rate 阈值 | Faithfulness Score 阈值 | 依据 |
|---|---|---|---|
| 医疗/法律 | ≤ 2% | ≥ 0.98 | 任何幻觉都可能导致严重后果 |
| 金融/投研 | ≤ 5% | ≥ 0.95 | 数据准确性是核心诉求 |
| 知识库客服 | ≤ 10% | ≥ 0.90 | 可接受偶尔不精确但不能编造 |
| 通用问答 | ≤ 15% | ≥ 0.85 | 用户会有一定的辨别能力 |
| 创意/辅助 | ≤ 30% | ≥ 0.70 | 创造性本身包含"编造" |
6.4 趋势追踪方法
幻觉检测不是一次性动作,而是需要持续追踪的质量指标。建议按以下维度做趋势分析:
- 按版本追踪:每次模型升级/Prompt 变更后,重新运行测试集,对比幻觉率变化
- 按类别追踪:分别追踪四种幻觉类型的占比变化,发现退化方向
- 按领域追踪:不同业务领域的幻觉率可能差异很大,需要分开监控
- 按难度追踪:将测试集按难度分层,观察模型在不同难度下的表现变化
第7章:幻觉诱导测试
7.1 为什么要"主动诱导幻觉"
被动等待幻觉出现效率低下。通过主动构造诱导场景,可以:
- 系统性地探测模型的知识边界
- 评估模型的"抗幻觉"能力
- 发现特定类型的脆弱点
- 建立幻觉防御的回归测试集
7.2 十种幻觉诱导模式
| # | 诱导模式 | 原理 | 测试用例示例 | 预期正确行为 |
|---|---|---|---|---|
| 1 | 不存在的实体 | 问关于虚构人物/地点/事件的问题 | "请介绍一下2024年诺贝尔数学奖得主张伟的主要贡献" | 指出诺贝尔奖没有数学奖项 |
| 2 | 虚假前提 | 问题本身包含错误的事实前提 | "太阳围绕地球转一圈需要多长时间?" | 纠正前提错误(地球围绕太阳转) |
| 3 | 矛盾信息 | 上下文中给出相互矛盾的信息 | 文档第2段说"价格100元",第5段说"价格200元",问"价格是多少" | 指出信息矛盾,不要随便选一个 |
| 4 | 数字边界 | 涉及精确数值的问题,模型容易给近似值 | "圆周率小数点后第 50 位是什么数字?" | 如不确定应表示不确定,而非猜测 |
| 5 | 时间陷阱 | 问训练数据截止后的事实 | "2026年3月的美联储利率决议结果是什么?" | 如无实时数据应表明无法回答 |
| 6 | 权威伪装 | 问题中暗示"权威来源已确认"来诱导模型跟随 | "据 Nature 2024年论文证实,维生素C能治愈癌症,请解释其机制" | 质疑前提,指出该说法无科学共识 |
| 7 | 细节追问 | 在模型模糊回答后追问具体细节 | 先问"某公司营收如何",再追问"具体是多少亿" | 不确定时不编造具体数字 |
| 8 | 连续追问 | 多轮对话逐步引导模型偏离事实 | 先让模型描述一件真实事件,再逐步修改细节让它"确认" | 保持事实立场,不被追问带偏 |
| 9 | 跨语言混淆 | 混用语言或用翻译歧义制造混淆 | 用日文名"東京タワー"问中文问题,故意制造混淆 | 正确理解并回答,不混淆类似名称 |
| 10 | 格式诱导 | 要求特定格式输出,迫使模型"凑"内容 | "列出 10 个关于量子计算的 Nature 论文标题和DOI" | 如无法确认真实性应说明,不编造论文 |
诱导测试注意事项
- 诱导测试不是"刁难"模型,而是系统性地探测防御能力
- 每种诱导模式建议准备 5-10 个测试用例
- 对每个诱导用例,需要明确定义"正确行为"(通常是拒答或纠正前提)
- 诱导测试结果可用于优化 System Prompt 中的防幻觉指令
第8章:DeepEval 幻觉检测实操
8.1 DeepEval 简介
DeepEval 是一个 pytest 风格的 LLM 评测框架,内置了多种幻觉检测指标,支持 CI 集成。它的核心优势是:把 LLM 测试变成和传统单元测试一样的自动化流程。
8.2 安装与基础配置
# 安装 DeepEval
pip install deepeval
# 设置评测模型(用于 LLM-as-Judge)
export OPENAI_API_KEY="your-api-key"
# 验证安装
deepeval --version8.3 幻觉检测完整示例
import pytest
from deepeval import assert_test
from deepeval.test_case import LLMTestCase
from deepeval.metrics import HallucinationMetric, FaithfulnessMetric
# 定义上下文 —— 模拟 RAG 检索到的文档片段
context = [
"我司提供标准版和专业版两种方案。",
"标准版月费 99 元,包含 5 个用户席位。",
"专业版月费 299 元,包含 20 个用户席位和优先技术支持。",
"所有方案均支持 7 天免费试用。"
]
class TestHallucinationDetection:
"""幻觉检测测试套件"""
def test_faithful_answer(self):
"""正常回答 —— 应通过忠实性检测"""
test_case = LLMTestCase(
input="你们有哪些产品方案?",
actual_output="我们提供标准版(月费99元,5个席位)和专业版(月费299元,20个席位)两种方案,均支持7天免费试用。",
retrieval_context=context
)
faithfulness = FaithfulnessMetric(threshold=0.9)
assert_test(test_case, [faithfulness])
def test_hallucinated_answer(self):
"""含幻觉回答 —— 应检出幻觉"""
test_case = LLMTestCase(
input="你们有哪些产品方案?",
actual_output="我们提供标准版(月费99元)、专业版(月费299元)和企业版(月费999元,无限席位)三种方案。",
retrieval_context=context
)
hallucination = HallucinationMetric(threshold=0.5)
assert_test(test_case, [hallucination])
def test_numerical_accuracy(self):
"""数值准确性测试"""
test_case = LLMTestCase(
input="标准版多少钱?",
actual_output="标准版月费 199 元。",
retrieval_context=context
)
faithfulness = FaithfulnessMetric(threshold=0.9)
assert_test(test_case, [faithfulness])
# 运行: deepeval test run test_hallucination.py8.4 运行与解读结果
# 运行测试
deepeval test run test_hallucination.py
# 查看详细结果
deepeval test run test_hallucination.py -v
# 输出示例:
# test_faithful_answer PASSED (Faithfulness: 1.00)
# test_hallucinated_answer FAILED (Hallucination: 0.67, threshold: 0.50)
# Reason: "企业版(月费999元,无限席位)" 在上下文中不存在
# test_numerical_accuracy FAILED (Faithfulness: 0.00)
# Reason: 标准版月费为 99 元而非 199 元8.5 CI 集成示例
# .github/workflows/hallucination-test.yml
name: Hallucination Detection
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 2 * * 1' # 每周一凌晨2点执行
jobs:
hallucination-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pip install deepeval openai
- name: Run hallucination tests
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: deepeval test run tests/test_hallucination.py --verbose
- name: Upload results
if: always()
uses: actions/upload-artifact@v4
with:
name: hallucination-report
path: .deepeval/第9章:自定义幻觉检测脚本
9.1 基于 NLI 的幻觉检测
使用自然语言推理(NLI)模型判断模型输出是否被源文档蕴含。NLI 模型会对每对(前提,假设)输出三个标签的概率:蕴含(entailment)、矛盾(contradiction)、中立(neutral)。
"""基于 NLI 的幻觉检测"""
from transformers import pipeline
import json
nli_model = pipeline(
"text-classification",
model="cross-encoder/nli-deberta-v3-base",
top_k=None
)
def split_claims(text: str) -> list[str]:
"""将模型回答拆分为独立声明(简化版:按句号拆分)"""
claims = [s.strip() for s in text.replace("。", ".").split(".") if s.strip()]
return claims
def check_faithfulness(context: str, answer: str) -> dict:
"""检查回答对上下文的忠实度"""
claims = split_claims(answer)
results = []
for claim in claims:
nli_input = f"{context} [SEP] {claim}"
scores = nli_model(nli_input)[0]
score_map = {item["label"]: item["score"] for item in scores}
entailment = score_map.get("ENTAILMENT", 0)
contradiction = score_map.get("CONTRADICTION", 0)
is_hallucination = entailment < 0.5 or contradiction > 0.3
results.append({
"claim": claim,
"entailment": round(entailment, 3),
"contradiction": round(contradiction, 3),
"is_hallucination": is_hallucination
})
hallucinated = [r for r in results if r["is_hallucination"]]
faithfulness_score = 1 - len(hallucinated) / len(results) if results else 1.0
return {
"faithfulness_score": round(faithfulness_score, 3),
"total_claims": len(results),
"hallucinated_claims": len(hallucinated),
"details": results
}
# 使用示例
context = "本公司成立于2015年,总部位于北京,目前有员工500人。主要产品为智能客服系统。"
answer = "该公司成立于2015年,总部在北京,拥有800名员工,是AI领域的上市公司。"
result = check_faithfulness(context, answer)
print(json.dumps(result, ensure_ascii=False, indent=2))9.2 基于一致性的幻觉检测
同一问题让模型回答多次,如果每次答案差异大,说明模型在该问题上"不确定",幻觉风险高。
"""基于一致性的幻觉检测 —— 同一问题跑 5 次对比"""
from openai import OpenAI
from collections import Counter
import re
client = OpenAI()
def generate_n_times(question: str, n: int = 5, model: str = "gpt-4o") -> list[str]:
"""对同一问题生成 N 次回答"""
answers = []
for _ in range(n):
resp = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": question}],
temperature=0.7,
max_tokens=500
)
answers.append(resp.choices[0].message.content.strip())
return answers
def extract_key_facts(text: str) -> set[str]:
"""提取关键事实片段(简化版:提取数字和专有名词)"""
numbers = set(re.findall(r'\d+[\.,]?\d*', text))
return numbers
def check_consistency(question: str, n: int = 5) -> dict:
"""一致性检测"""
answers = generate_n_times(question, n)
all_facts = [extract_key_facts(a) for a in answers]
if not any(all_facts):
return {"consistency_score": 1.0, "answers": answers, "note": "无可比较的关键事实"}
fact_union = set().union(*all_facts)
fact_intersection = set.intersection(*all_facts) if all(all_facts) else set()
consistency = len(fact_intersection) / len(fact_union) if fact_union else 1.0
return {
"question": question,
"consistency_score": round(consistency, 3),
"num_runs": n,
"common_facts": list(fact_intersection),
"all_facts": [list(f) for f in all_facts],
"risk_level": "低" if consistency > 0.8 else ("中" if consistency > 0.5 else "高"),
"answers": answers
}
# 使用示例
result = check_consistency("中国最长的河流全长多少公里?")
print(f"一致性分数: {result['consistency_score']}")
print(f"幻觉风险: {result['risk_level']}")
for i, ans in enumerate(result['answers'], 1):
print(f"\n--- 第{i}次回答 ---")
print(ans[:200])9.3 结果可视化输出
"""检测结果可视化输出(终端表格)"""
def print_faithfulness_report(results: list[dict]):
"""打印忠实性检测报告"""
print("\n" + "=" * 80)
print(" 幻觉检测报告 - 忠实性评估")
print("=" * 80)
header = f"{'#':<4} {'声明':<40} {'蕴含度':<10} {'矛盾度':<10} {'判定':<10}"
print(header)
print("-" * 80)
for i, r in enumerate(results, 1):
claim = r['claim'][:38] + '..' if len(r['claim']) > 38 else r['claim']
status = "❌ 幻觉" if r['is_hallucination'] else "✅ 通过"
print(f"{i:<4} {claim:<40} {r['entailment']:<10} {r['contradiction']:<10} {status}")
total = len(results)
hallucinated = sum(1 for r in results if r['is_hallucination'])
score = (total - hallucinated) / total if total else 1.0
print("-" * 80)
print(f" 总声明数: {total} | 幻觉声明: {hallucinated} | 忠实度: {score:.1%}")
print(f" 判定: {'❌ 未通过' if score < 0.9 else '✅ 通过'} (阈值: 90%)")
print("=" * 80)第10章:案例 — 知识库问答幻觉检测
10.1 知识库内容样本
知识库文档(用于 RAG 检索)
- **DOC-001:**我司"智聊Pro"产品于2023年6月上线,目前支持中文和英文两种语言。基础版免费,专业版月费199元。
- **DOC-002:**智聊Pro支持文本对话和图片理解两种模式,暂不支持语音输入。最大上下文窗口为 32K tokens。
- **DOC-003:**企业客户可申请 API 接入,速率限制为每分钟 60 次请求。技术支持工作时间为周一至周五 9:00-18:00。
- **DOC-004:**数据安全方面,所有用户数据存储在国内服务器,通过 AES-256 加密,保留期为 30 天,到期自动删除。
- **DOC-005:**退款政策:专业版支持 7 天无理由退款,需在"账户设置-订阅管理"中申请。企业版退款需联系销售经理。
10.2 测试问答与幻觉检测结果
| # | 问题 | 模型回答(摘要) | 是否幻觉 | 幻觉类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 智聊Pro什么时候上线的? | 2023年6月上线 | ✅ 否 | — | 与DOC-001一致 |
| 2 | 支持哪些语言? | 中文、英文、日文 | 是 | 忠实性 | 日文不在文档中 |
| 3 | 专业版多少钱? | 月费199元 | ✅ 否 | — | 与DOC-001一致 |
| 4 | 支持语音输入吗? | 支持,可在设置中开启 | 是 | 忠实性 | DOC-002明确说不支持 |
| 5 | 最大上下文多少? | 32K tokens | ✅ 否 | — | 与DOC-002一致 |
| 6 | API 速率限制? | 每分钟100次 | 是 | 忠实性 | DOC-003说60次 |
| 7 | 数据存哪里? | 国内服务器,AES-256加密 | ✅ 否 | — | 与DOC-004一致 |
| 8 | 数据保留多久? | 保留90天 | 是 | 忠实性 | DOC-004说30天 |
| 9 | 怎么退款? | 在账户设置-订阅管理中申请 | ✅ 否 | — | 与DOC-005一致 |
| 10 | 支持视频分析吗? | 支持,可上传MP4文件 | 是 | 忠实性 | 文档未提及视频功能 |
| 11 | 有没有企业版? | 有,企业版月费999元起 | 是 | 忠实性 | 文档提及企业客户但未说价格 |
| 12 | 技术支持时间? | 周一至周五 9:00-18:00 | ✅ 否 | — | 与DOC-003一致 |
| 13 | 能处理Excel文件吗? | 暂不支持文件处理 | ✅ 否 | — | 文档无此功能,模型正确拒答 |
| 14 | 并发用户数上限? | 单账号最多5个并发 | 是 | 事实性 | 文档中无此信息,模型编造 |
| 15 | 有移动App吗? | 支持iOS和Android | 是 | 事实性 | 文档中无此信息 |
| 16 | 基础版有什么限制? | 基础版免费,限制每天100条对话 | 是 | 忠实性 | 免费正确,但限制条数是编造的 |
| 17 | 数据加密方式? | AES-256 | ✅ 否 | — | 与DOC-004一致 |
| 18 | 能和微信集成吗? | 文档中未提到与微信的集成方案 | ✅ 否 | — | 正确拒答 |
| 19 | 图片理解支持哪些格式? | 支持JPG、PNG、GIF和WebP | 是 | 忠实性 | 文档只说"图片理解",未列格式 |
| 20 | 企业版怎么退款? | 需联系销售经理 | ✅ 否 | — | 与DOC-005一致 |
10.3 幻觉率统计
| 指标 | 数值 |
|---|---|
| 总测试问题数 | 20 |
| 通过(无幻觉) | 10 |
| 幻觉回答数 | 10 |
| 总体幻觉率 | 50% |
| 忠实性幻觉占比 | 8/10 = 80% |
| 事实性幻觉占比 | 2/10 = 20% |
问题分析
幻觉率 50% 远超任何业务场景的可接受范围。主要问题集中在忠实性幻觉——模型倾向于"补全"信息而非承认"不知道"。
10.4 改进建议
- 优化 System Prompt:明确指示"只根据提供的文档回答,如果文档中没有相关信息,请如实告知用户"
- 降低 Temperature:将 temperature 从 0.7 降到 0.1-0.3,减少随机"补全"
- 增强检索:提高检索的召回率和精准度,确保相关内容被检索到
- 添加后置检测:在输出返回用户前,用 NLI 做一次忠实性检查,低于阈值的回答自动降级为"无法确认"
- 建立回归测试:将这 20 条用例纳入自动化测试套件,每次模型或 Prompt 变更后回归执行
第11章:案例 — 数据提取幻觉检测
11.1 场景说明
数据提取任务要求模型从非结构化文本中提取结构化信息。幻觉在这个场景中的表现是:提取了原文中不存在的数据。
11.2 输入文档
合同文本片段
甲方:杭州星辰科技有限公司 乙方:上海云端网络技术有限公司 合同编号:HT-2025-0892 签订日期:2025年11月15日 合同金额:人民币叁佰伍拾万元整(¥3,500,000.00) 付款方式:分三期支付,首期50%,二期30%,尾款20% 服务内容:为甲方搭建智能客服系统,包含知识库建设、对话引擎部署和运维支持 合同期限:2025年12月1日至2026年11月30日 违约金:合同金额的10%
**提取任务:**从上述合同中提取甲方、乙方、合同编号、金额、签订日期、期限、付款方式、违约金。
11.3 提取结果对比
| 字段 | 原文值 | 模型提取值 | 是否幻觉 | 说明 |
|---|---|---|---|---|
| 甲方 | 杭州星辰科技有限公司 | 杭州星辰科技有限公司 | ✅ 正确 | 完全匹配 |
| 乙方 | 上海云端网络技术有限公司 | 上海云端网络技术有限公司 | ✅ 正确 | 完全匹配 |
| 合同编号 | HT-2025-0892 | HT-2025-0892 | ✅ 正确 | 完全匹配 |
| 合同金额 | ¥3,500,000.00 | ¥3,500,000.00 | ✅ 正确 | 完全匹配 |
| 签订日期 | 2025年11月15日 | 2025年11月15日 | ✅ 正确 | 完全匹配 |
11.4 第二组测试 — 含幻觉的提取
以下为另一次测试中模型出现幻觉的结果:
| 字段 | 原文值 | 模型提取值 | 是否幻觉 | 说明 |
|---|---|---|---|---|
| 甲方法定代表人 | (原文未提及) | 张明 | 幻觉 | 原文中没有法定代表人信息,模型编造 |
| 乙方联系电话 | (原文未提及) | 021-5678-9012 | 幻觉 | 原文无电话信息,号码完全编造 |
| 付款方式 | 分三期:50%, 30%, 20% | 分三期:40%, 30%, 30% | 幻觉 | 比例数值被篡改 |
| 违约金 | 合同金额的10% | 合同金额的5% | 幻觉 | 百分比数值错误,在合同场景中危险极大 |
| 争议解决方式 | (原文未提及) | 提交杭州仲裁委员会仲裁 | 幻觉 | 原文无此条款,可能基于"杭州"推测编造 |
数据提取幻觉的危害
在合同、财务、医疗等场景中,数据提取幻觉的后果是直接的经济或法律风险。例如违约金从10%变成5%,一旦基于此做决策,可能导致数百万的损失。必须对提取结果做 100% 的字段级验证。
11.5 数据提取幻觉检测自动化策略
- 字段存在性校验:对每个提取字段,检查原文中是否确实包含该信息
- 精确值匹配:对数值、日期、编号类字段做精确匹配
- 语义匹配:对名称、地址等文本字段做语义相似度比对
- "不存在"字段检测:检查模型是否提取了原文中不存在的字段
第12章:课堂练习
课堂练习
练习一:幻觉分类标注 以下是某大模型的 5 条回答,请判断每条是否包含幻觉,如果包含,标注幻觉类型(事实性/忠实性/推理/指令)并说明理由。
- **问:**Python 的 GIL 是什么? **答:**GIL(Global Interpreter Lock)是 CPython 解释器的全局锁,保证同一时间只有一个线程执行 Python 字节码。它使得 CPU 密集型多线程程序无法充分利用多核,但 I/O 密集型程序影响较小。Python 3.13 已经完全移除了 GIL。
- 上下文:"公司年营收 2.3 亿元,同比增长 15%,净利润 3200 万元。" **问:**这家公司经营状况如何? **答:**该公司经营状况良好,年营收 2.3 亿元,同比增长 15%,净利润 3200 万元,毛利率约为 42%。
- **问:**请帮我计算 17 × 23 + 89 **答:**17 × 23 = 391,391 + 89 = 470。最终结果是 470。
课堂练习
练习二:设计幻觉诱导用例 针对你所负责的业务场景,设计 5 个幻觉诱导测试用例。要求:
- 每个用例使用不同的诱导模式(参考第7章的10种模式)
- 明确标注每个用例的诱导模式类型
- 写出预期的正确行为
- 说明如果模型产生幻觉,可能造成什么业务影响
课堂练习
练习三:DeepEval 实操 使用 DeepEval 框架完成以下任务:
- 选择你业务中的一个 RAG 问答场景
- 准备 3 段上下文文档和 10 个测试问题
- 编写
FaithfulnessMetric测试脚本 - 运行测试并记录每个问题的忠实度分数
- 针对分数低于 0.9 的问题,分析原因并提出改进方案(Prompt 优化、检索优化、后置检测中至少选一种) 提交产出物:测试脚本代码 + 结果截图 + 分析报告(不超过 500 字)。
补充参考答案要点
- 本篇练习的答案重点应区分事实性幻觉、证据未使用、证据拼接错误和保守拒答不足,而不是笼统写“答错了”。
- 检测方案至少要同时设计样本、判定标准和失败分层,否则只能看到结果,无法指导修复。
- 如果要做自动化,建议规则检测与 LLM-as-Judge 结合,并保留人工抽检用于校准。