我让大模型帮我答用户的专业问题,它一本正经地编了个根本不存在的政策条款,还说得有理有据,我对着大模型的幻觉排查了大半天的复盘
那是我做的一个智能客服:用大模型回答用户关于我们产品政策的问题。测试时它对答如流、专业又自信,我很满意就上线了。结果没几天,客诉来了:有用户拿着机器人给的"退款政策第 7 条"来找我们理论,可我们的政策里压根没有第 7 条,那段话是机器人凭空编造的——而且编得有模有样、引用了条款号、语气笃定,用户完全信了。我又惊又怕:模型不是挺聪明的吗?怎么会一本正经地胡说八道、还编得这么像真的?排查了大半天,我才真正理解了大模型那个绕不开的本质问题:幻觉(Hallucination)。这篇就把这场"AI 一本正经编造事实"的事故,从头复盘一遍。
故障现场:自信满满,内容却是编的
先看现场。模型的回答流畅、专业、笃定,唯一的问题是——它是编的:
# 用户问: "你们的退款政策具体是怎样的?"
# 我的实现(问题根源):
prompt = f"你是专业客服, 回答用户关于产品政策的问题。\n用户问题: {question}"
answer = llm.chat(prompt) # ✗ 直接让模型"凭它自己的知识"回答
return answer
# 模型的回答(流畅、专业、自信, 但是编的!):
# "根据我们的退款政策第7条规定, 商品在签收后15天内, 若符合
# 无理由退货条件, 可申请全额退款; 第7条第2款特别说明, 定制类
# 商品需扣除20%的工本费..."
# ↑ 条款号、款项、百分比, 一应俱全, 说得有理有据。
# 但真相是:
# - 我们的退款政策根本没有"第7条"。
# - "15天""20%工本费"这些数字, 全是模型编的(我们实际是7天、无工本费)。
# - 模型把"它训练数据里见过的、各种电商的退款政策"杂糅、脑补,
# 生成了一个"听起来非常合理、但和我们实际政策完全不符"的答案。
# 现象拼图:
# - 大模型的本质: 它是一个"根据上文预测下一个最可能的词"的概率模型。
# - 它的目标是"生成流畅、合理的文本", 而【不是】"陈述真实的事实"。
# - 当它"不知道"准确答案时, 它不会说"我不知道", 而会"脑补"一个
# 最像那么回事的答案 —— 这就是幻觉(Hallucination)。
# - 最危险的是: 它幻觉时的语气, 和它说真话时【一模一样】地自信!
# 你无法从"语气/流畅度"上判断它说的是真是假。
# - ★ 我把模型当成了"知道我们政策的知识库", 但它其实只是个
# "会把话说得很像真的"的语言生成器 —— 它不知道我们的真实政策!
看清真相后,我冒了一身冷汗。模型编造的那段"退款政策第 7 条",条款号、款项、百分比一应俱全、说得有理有据,可我们的政策根本没有第 7 条,那些数字全是它编的。它做的,是把训练数据里见过的各种电商退款政策,杂糅、脑补成一个"听起来非常合理、却和我们实际政策完全不符"的答案。根源在于大模型的本质:它是一个"根据上文预测下一个最可能的词"的概率模型,目标是"生成流畅合理的文本",而不是"陈述真实的事实"。所以,当它"不知道"准确答案时,它不会说"我不知道",而会"脑补"一个最像那么回事的答案——这就是幻觉。而最危险的是:它幻觉时的语气,和它说真话时一模一样地自信,你无法从语气/流畅度上判断真假。我犯的根本错误,是把模型当成了"知道我们政策的知识库",可它其实只是个"会把话说得很像真的"的语言生成器,它根本不知道我们的真实政策。
第一件事:搞懂大模型为什么会"幻觉"
要解决它,得先理解幻觉不是 bug,而是大模型工作原理的"固有特性"。
大模型幻觉(Hallucination)的本质
# 大模型到底在做什么?
# - 它本质是个"语言模型": 根据已有的文本, 预测"下一个最可能的词"。
# - 它通过海量文本训练, 学会了语言的模式、知识的"统计性关联"。
# - 但它存储的不是"事实数据库", 而是"词与词之间的概率关系"。
# 为什么会幻觉? —— 三个根本原因:
# 1. 它的目标是"流畅合理", 不是"真实正确"。
# - 它要生成"读起来最顺、最像那么回事"的文本。
# - "编一个合理的答案" 和 "说真话", 对它而言都是"生成可能的词序列",
# 它分不清(也不以"真假"为优化目标)。
# 2. 它没有"我不知道"的机制(默认情况下)。
# - 训练数据里, "自信地回答"远多于"承认不知道"。
# - 所以它倾向于"总能给个答案", 哪怕是编的。
# 3. 它不知道"自己知道什么、不知道什么"(缺乏自我认知)。
# - 它对"它编的"和"它真学过的", 没有可靠的内部区分。
# - 所以编造时, 它"自己"也"以为"在合理作答 → 语气同样自信。
# 关键认知:
# - 幻觉不是"偶尔的bug", 而是"概率生成"这个机制的【固有产物】。
# - 你不能指望"模型更聪明就不幻觉了" —— 再强的模型也会幻觉,
# 只是概率不同。它的本质决定了它"可能编"。
# - 尤其在: 它训练数据里没有/很少的"私有、专业、最新"信息上,
# 幻觉率最高(比如"你们公司的具体政策"——它根本没学过)。
# 核心: 幻觉是大模型"按概率生成流畅文本"机制的固有产物, 它以"合理"而非"真实"
# 为目标、缺乏"不知道"机制和自我认知; 在私有/专业/最新信息上幻觉率最高。
原来,幻觉不是模型"偶尔犯的错",而是它工作原理的固有特性。大模型本质是个语言模型:根据已有文本预测"下一个最可能的词";它存储的不是"事实数据库",而是"词与词之间的概率关系"。它会幻觉,有三个根本原因:一、它的目标是"流畅合理"不是"真实正确"——"编一个合理答案"和"说真话",对它而言都是"生成可能的词序列",它分不清;二、它没有"我不知道"的机制——训练数据里"自信回答"远多于"承认不知道",所以它倾向于总给个答案哪怕是编的;三、它不知道"自己知道什么、不知道什么"——对"它编的"和"它真学过的"没有可靠区分,所以编造时它自己也"以为"在合理作答、语气同样自信。关键认知是:幻觉不是偶尔的 bug,而是"概率生成"机制的固有产物;你不能指望"模型更聪明就不幻觉",再强的模型也会幻觉,只是概率不同;尤其在私有/专业/最新信息上(如"你们公司的政策"——它根本没学过),幻觉率最高。
第二件事:正解——给模型"接地"的事实,而不是让它凭记忆答
搞懂了原理,正解就清晰了:用 RAG 把真实资料喂给模型让它基于资料答、要求引用出处、允许说"不知道"、降 temperature、关键答案做校验。
# ====== 正解一(核心): RAG —— 把真实资料检索出来, 让模型"基于资料"回答 ======
def answer_with_rag(question):
# 1. 从"我们自己的政策文档"里, 检索出与问题最相关的片段
docs = retrieve_from_knowledge_base(question) # 向量检索我们的真实政策
context = "\n".join(docs)
# 2. 把真实资料放进 prompt, 让模型【只根据这些资料】回答
prompt = f"""你是客服。请【仅根据】下面提供的资料回答用户问题。
资料:
{context}
用户问题: {question}
要求:
- 只能依据上面的资料回答, 不要使用资料之外的任何知识。
- 如果资料里没有相关信息, 必须明确说"抱歉, 我没有查到相关政策, 请联系人工"。
- 回答时注明依据的是资料中的哪一条。"""
return llm.chat(prompt, temperature=0) # ✓ 基于真实资料, 而非凭空记忆
# → RAG 的本质: 把"让模型凭记忆答(会幻觉)"变成"给它真实资料、让它基于资料答"。
# 它的知识不再来自"飘忽的训练记忆", 而来自"你提供的、可控的真实文档"。
# ====== 正解二: 显式允许并鼓励模型说"我不知道" ======
# 在 prompt 里明确: "如果不确定/资料里没有, 就说不知道, 不要编造。"
# → 对抗它"总要给个答案"的倾向, 给它"承认无知"的许可。
# ====== 正解三: 要求"引用出处", 让答案可溯源、可验证 ======
# 让模型回答时附上"依据的原文片段/文档链接"。
# → 一是逼它"基于真实资料"(编的话没法给出处), 二是让人能核对真伪。
# ====== 正解四: 降低 temperature(对事实性任务)======
answer = llm.chat(prompt, temperature=0)
# → temperature 高 = 更随机更有创意(也更容易跑偏编造);
# 事实问答用 temperature=0(最确定、最保守), 减少"自由发挥"。
# ====== 正解五: 关键信息做"事后校验" / 结构化约束 ======
# - 涉及金额、条款号、日期等关键事实, 答案生成后用规则/数据库再校验一遍。
# - 或让模型输出结构化结果(如"条款号"字段), 程序去真实政策表里核对存在性。
# - 高风险场景(医疗/法律/金额): 加"人工复核"或"免责声明 + 引导人工"。
# 核心: 用RAG给模型接地真实资料(基于资料答而非凭记忆)+ 允许说不知道 + 要求引用出处
# + 事实任务降temperature + 关键信息事后校验; 把"凭记忆生成"变成"基于事实作答"。
修复的核心,是"别让模型'凭它飘忽的记忆'答事实,而要给它'真实的资料'让它'基于资料'答"。正解一(核心):RAG——先从我们自己的政策文档里检索出与问题最相关的片段,把真实资料放进 prompt,让模型"仅根据这些资料"回答;RAG 的本质是把"让模型凭记忆答(会幻觉)"变成"给它真实资料、让它基于资料答",它的知识不再来自飘忽的训练记忆,而来自你提供的、可控的真实文档。正解二:显式允许并鼓励模型说"我不知道"(对抗它"总要给答案"的倾向)。正解三:要求引用出处——让答案可溯源可验证(编的话给不出出处,人也能核对)。正解四:事实任务降 temperature(=0 最确定保守,减少自由发挥编造)。正解五:关键信息事后校验/结构化约束——金额、条款号等让程序去真实政策表里核对存在性,高风险场景加人工复核或引导人工。归根结底:用 RAG 接地真实资料 + 允许说不知道 + 要求引用 + 事实任务降 temperature + 关键信息事后校验;把"凭记忆生成"变成"基于事实作答"。
第三件事:哪些场景幻觉高发、风险高
排查后我系统梳理了幻觉的高发场景和高风险场景,帮自己判断"哪里必须严防幻觉"。
幻觉的高发场景 与 高风险场景
# 一、幻觉"高发"的场景(模型最容易编):
# 1. 私有/专属信息: "你们公司的政策/数据"——它训练时根本没见过。
# 2. 最新信息: 训练截止之后的事(新事件/新版本)——它不知道。
# 3. 专业细节: 精确的数字、条款、引用、API签名、函数名、参数。
# 4. 长尾/冷门知识: 训练数据里出现极少的内容。
# 5. 被诱导时: 用户问"第7条说了啥?"(假设了第7条存在)→ 它顺着编。
# 二、幻觉"高风险"的场景(编了后果严重):
# 1. 涉及金额、合同、法律、医疗、政策 → 错了会造成实际损失/纠纷。
# 2. 代码生成: 编造不存在的API/库/函数 → 程序跑不起来(还好这个能立刻发现)。
# 3. 对外的、用户会直接相信并采取行动的回答(如本文客服)。
# 三、"高发 × 高风险" = 必须严防幻觉的雷区:
# - 对外客服答政策、AI答医疗法律、AI生成关键代码/配置... 这些场景,
# 【绝不能】让模型凭记忆裸答, 必须 RAG接地 + 引用 + 校验 + 人工兜底。
# 四、相对安全的场景(幻觉影响小):
# - 创意写作、头脑风暴、文案润色、代码思路启发(本就要"发挥")。
# - 这些场景"编"一点反而是"创意", 风险低。
# 核心: 私有/最新/专业/冷门信息上幻觉高发; 金额法律医疗政策代码等场景幻觉高风险;
# "高发×高风险"的雷区必须RAG接地+引用+校验+人工兜底; 创意类场景则相对安全。
梳理清楚后,我对"该在哪里严防幻觉"有了清晰的判断。一、幻觉"高发"的场景:私有/专属信息(你们公司的政策——它没见过)、最新信息(训练截止之后)、专业细节(精确数字/条款/API 签名)、长尾冷门知识、被诱导时(用户问"第 7 条说了啥"假设了它存在,它就顺着编)。二、幻觉"高风险"的场景:涉及金额/合同/法律/医疗/政策(错了有实际损失)、代码生成(编造不存在的 API)、对外且用户会直接相信并行动的回答(如本文客服)。三、"高发 × 高风险" = 必须严防的雷区——对外客服答政策、AI 答医疗法律、AI 生成关键代码,绝不能让模型凭记忆裸答,必须 RAG 接地 + 引用 + 校验 + 人工兜底。四、相对安全的场景:创意写作、头脑风暴、文案润色(本就要发挥,"编"一点反而是创意)。下面这张图,是这次 AI 编造政策的成因与解法:
第四件事:幻觉缓解手段速查
这次踩坑后,我把对抗幻觉的各种手段整理成一张表,按场景选用。
| 手段 | 作用 | 适用 |
|---|---|---|
| RAG 检索增强 | 给模型真实资料,基于资料答 | 私有/专业/最新信息(最有效) |
| 要求引用出处 | 可溯源、逼它基于资料 | 事实问答 |
| 允许说"不知道" | 对抗"总给答案"倾向 | 所有事实场景 |
| 降低 temperature | 减少随机发挥 | 事实性任务 |
| 事后校验/规则核对 | 对关键事实兜底验证 | 金额/条款/API 等 |
| 结构化输出+程序核对 | 把答案拆成字段去库里验 | 可结构化的事实 |
| 人工复核/引导人工 | 终极兜底 | 高风险场景 |
这张表,把对抗幻觉的"武器库"摆全了。核心优先级是:RAG(给真实资料)是最有效的根治手段;要求引用、允许说不知道、降 temperature 是配套的"约束";事后校验和人工复核是关键/高风险场景的"兜底"。它给我的最大启发是:对抗幻觉,本质是一个"把'不可靠的生成'约束到'可靠的范围'内"的工程问题;你无法让模型"本身不幻觉"(那是它的天性),但你可以通过给它真实的依据(RAG)、限制它的自由度(低 temperature、基于资料)、要求它可溯源(引用)、并在出口处校验(事后核对),层层设防,把幻觉的概率和危害降到可接受的程度。更深一层,这让我理解了一个用好 AI 的关键心态:大模型是一个"能力极强但不可全信"的助手;正确的用法,不是"无条件相信它的输出",也不是"因为它会出错就不用",而是"用它的能力,但用工程手段约束和验证它的输出"——既借力于它的强大,又不把缰绳完全交给它。
第五件事:用 AI 时该有的"信任态度"
这次事故也彻底校准了我对 AI 输出的信任态度。我把不同输出该有的态度整理了一下。
| AI 输出类型 | 该有的态度 | 怎么用 |
|---|---|---|
| 事实性陈述(数字/政策/引用) | 默认怀疑 | 必须核实/RAG接地 |
| 代码/API 调用 | 怀疑,验证 | 跑一遍/查文档确认API存在 |
| 推理/分析过程 | 半信,检查逻辑 | 看推理链是否站得住 |
| 创意/文案/思路 | 可放松 | 当灵感,自己筛选 |
| "我很确定""根据xx规定" | 更要警惕 | 自信≠正确,反而常是幻觉信号 |
这张表,校准了我对 AI 各类输出的"信任刻度"。核心原则是:越是"客观、可验证、后果严重"的输出(事实、数字、代码、API),越要默认怀疑、主动核实;越是"主观、创意、低风险"的输出(文案、思路),越可以放松。而最反直觉、也最重要的一条是:模型"语气越自信"(说"我很确定""根据 xx 规定"),反而越要警惕——因为它幻觉时和说真话时一样自信,"自信"根本不是"正确"的信号;甚至,那种"引用了具体条款号、给出了精确数字"的"细节感",恰恰是幻觉最具欺骗性的伪装。它给我的最大启发,是一种与 AI 协作的"成熟心态":把 AI 当成一个"知识渊博、表达流畅、但偶尔会一本正经胡说八道、且自己意识不到"的聪明实习生——你欣赏并善用它的能力,但你永远是那个最终把关、对结果负责的人;对它产出的、会影响真实决策的关键信息,你必须保留"核实"这道工序,而不能因为它"看起来很专业"就直接采信。用 AI 而不盲信 AI,借它的力又守住自己的判断——这,是 AI 时代每个使用者都该修炼的基本功。
第六件事:用 AI 答事实问题时,我现在的决策习惯
现在每当我要用大模型回答"事实性"问题,我都会按这张图先想清楚怎么防幻觉:
这张图的精髓,是"按'事实vs创意'和'风险高低',决定防幻觉的力度"。第一问 "事实还是创意":创意类放松直接用;事实类再看风险。事实类:低风险至少降 temperature + 允许说不知道;高风险(金额/法律/对外)必须 RAG 接地真实资料 + 要求引用 + 事实校验 + 人工复核。而贯穿始终的底线是:绝不直接采信模型的事实性输出,重要的一定核实一遍。最后一步是我现在的硬习惯:上线前,专门用"它训练时没学过的私有问题"(如我们公司的具体政策)去测它会不会幻觉(这次的坑正是因为测试时没测这种"它根本不可能知道答案"的问题)。这套习惯,让我用 AI 答事实时,从"它答得挺好就信了"变成了"先想清楚怎么防它编"——核心始终是:大模型会自信地编造事实,事实性问题必须接地真实资料并核实,绝不裸信。
我立下的几条规矩
这场"AI 一本正经编造政策"的事故,换来了我做 AI 应用时,刻进骨子里的几条铁律:
- 大模型是文本生成器,不是知识库。它以"流畅合理"为目标,不以"真实"为目标。
- 幻觉是固有特性,不是偶发 bug。再强的模型也会编,私有/专业/最新信息上最严重。
- 事实问题必须 RAG 接地。给它真实资料让它基于资料答,别让它凭记忆裸答。
- 允许它说"不知道"、要求它给出处。对抗"总给答案"、让答案可溯源可验证。
- 事实任务降 temperature,关键信息事后校验。金额/条款/API 程序核对存在性。
- 自信≠正确。它幻觉时和说真话时一样自信,语气笃定+精确细节反而要警惕。
- 上线前用"它没学过的私有问题"测幻觉。别只测它答得出的,要测它会不会编。
附:一个带RAG接地+引用+校验的防幻觉问答实现
口说无凭。下面把 RAG 接地、允许说不知道、要求引用、关键事实校验合到一个问答函数里:
import json
SYSTEM = """你是严谨的客服助手。请严格遵守:
1. 只能依据【参考资料】回答, 禁止使用资料之外的任何知识。
2. 如果资料中没有相关信息, 必须回答 {"answer": "未查到相关政策, 请联系人工", "found": false}。
3. 回答必须以 JSON 返回, 包含: answer(答案)、found(是否在资料中找到)、
citations(引用的资料原文片段列表)。
4. 不要编造任何条款号、数字、百分比 —— 资料里没有的, 一律不能出现。"""
def safe_qa(question: str) -> dict:
# 1. RAG: 从我们自己的真实政策库检索相关片段(接地的关键)
docs = retrieve_from_kb(question, top_k=5)
if not docs:
return {"answer": "未查到相关政策, 请联系人工", "found": False, "citations": []}
context = "\n".join(f"[{i}] {d}" for i, d in enumerate(docs))
prompt = f"参考资料:\n{context}\n\n用户问题: {question}"
# 2. 低 temperature + 结构化输出, 基于资料回答
resp = llm.chat(system=SYSTEM, user=prompt, temperature=0,
response_format="json")
result = json.loads(resp)
# 3. 没找到就直接走人工, 不强答
if not result.get("found"):
return {"answer": "未查到相关政策, 请联系人工", "found": False, "citations": []}
# 4. 关键校验: 引用的片段, 必须真的来自我们检索出的资料(防它编引用)
valid_citations = [c for c in result.get("citations", [])
if any(c.strip() in d for d in docs)]
if not valid_citations:
# 它声称found但给不出真实引用 -> 大概率在编, 不可信 -> 转人工
return {"answer": "为确保准确, 请联系人工客服", "found": False, "citations": []}
# 5. 关键事实抽查(如答案里出现的"百分比/天数"是否在原文出现过)
for token in extract_numbers(result["answer"]): # 抽出答案里的数字
if not any(token in d for d in docs):
# 答案里有个资料中根本没出现的数字 -> 疑似幻觉 -> 标记/转人工
log.warning(f"疑似幻觉数字: {token}")
return {"answer": "为确保准确, 请联系人工客服", "found": False, "citations": []}
result["citations"] = valid_citations
return result # ✓ 接地 + 找到 + 引用真实 + 数字可核 -> 才返回给用户
# 核心: RAG检索接地 + 结构化输出(found/citations)+ 校验引用真实存在
# + 抽查答案数字是否在资料中 + 任何疑点都转人工; 多道关卡把幻觉拦在用户之前。
这个 safe_qa,把这篇文章的防幻觉思路,落成了一个层层设防的实现。它设了好几道关卡:第一道,RAG 检索——没检索到资料就直接转人工,不让模型凭空答;第二道,低 temperature + 结构化输出(强制返回 found/citations 字段);第三道,found=false 就走人工、不强答;第四道,也是最关键的——校验它给出的引用,必须真的来自我们检索出的资料(防它连"引用"都编);第五道,抽查答案里出现的数字,是否在原文里真的出现过(防它在引用真实资料的同时,偷偷篡改/编造关键数字)。任何一关有疑点,都宁可转人工,也不把可疑答案给用户。这,正是我想用这个实现,留给每个做 AI 应用的人的最后一课:对抗幻觉,不能指望"一个 prompt 就搞定",而要像设计安全系统一样,建立"纵深防御"——多道独立的关卡,层层过滤。因为幻觉是概率性的,任何单一手段都有漏网的可能;而多道关卡叠加(接地 + 引用校验 + 数字核对 + 人工兜底),才能把"编造的内容流到用户面前"的概率,压到足够低。更重要的是那个贯穿始终的设计哲学:在高风险场景下,"宁可少答(转人工)、也不错答(编造)"——一个诚实地说"我去帮您问问人工"的 AI,远胜过一个自信地编造答案、把用户带沟里的 AI。让 AI 学会"知之为知之,不知为不知",并用工程把这份"诚实"强制兜底——这,才是负责任地把大模型用到生产里的正确姿势。
写在最后
回头看,这场由"AI 幻觉"引发的、编造政策引发客诉的事故,真正教给我的,远不止"用 RAG 防幻觉"这一套技巧。它彻底校准了我对"大模型到底是什么"的根本认知。我犯错的根源,是一个美丽的误解:我看到大模型对答如流、博古通今、专业自信,就下意识地把它当成了一个"无所不知、且诚实可靠的智者"。可这次事故狠狠地告诉我:它更像一个"语言天才",而非一个"知识权威"——它精通的是"如何把话说得流畅、合理、像那么回事",而不是"所说内容的真实性"。这两者,在它表现好的时候高度重合(说得好听又恰好是真的),却在它"不知道"的时候彻底分裂(说得依然好听、但却是编的)。这让我领悟到一个使用任何强大工具时都至关重要的道理:要真正用好一个工具,必须准确理解它"到底是什么、它的能力边界在哪",而不能被它"表面呈现出的样子"所迷惑。大模型"表现得像"一个全知的智者,但它"本质上是"一个概率语言生成器;如果我用"对待智者"的方式(无条件信任)去用一个"语言生成器",就必然会在它"编造"的时候栽跟头。真正的"会用 AI",不是"把它当人、当神一样信",而是清醒地认识它的本质——既充分利用它"语言能力极强"的长处,又时刻警惕它"不保证真实"的短处,并用工程手段(RAG、校验、人工)为这个短处兜底。看清工具的本质、而非被它的表象迷惑——这,是我用一次"AI 编造政策"的事故,换来的、关于 AI、也关于"认清工具本质"的、最朴素也最深刻的领悟。如果这篇复盘,能让你下次用 AI 答事实问题时,先想一句"它真的知道,还是在编?我接地真实资料了吗?",那我对着那条被编造出来的"退款政策第 7 条"熬的这大半天,就值了。
—— 别看了 · 2026