"AI明明不知道这个答案,为什么它说得跟真的一样?"
这是企业用大模型时最头疼的问题——幻觉(Hallucination)。大模型自信满满地编造事实,语法流畅、逻辑自洽,普通人根本看不出错误。更可怕的是,这种幻觉在企业内部知识库场景中更隐蔽:员工以为AI引用的是公司真实数据,实际上是模型在"一本正经地胡说八道"。
本文解决:
大模型的核心任务是"给定前文,预测下一个最可能的token"。
这不是"查询数据库",而是"续写文本"。模型做的是:
``
输入: "中国的首都是"
输出: 一串最可能出现的token序列
`
模型的"知识"是从海量文本中统计学习来的语言模式,不是精确的事实数据库。当模式与真实事实的拟合足够好时,输出看起来"正确";但当遇到训练数据覆盖不足或歧义场景时,模型会续写出看起来合理但实际错误的文本。
传统数据库:事实A存储在地址X,可以精确读取。 大模型:事实A的知识分散在数十亿参数中,以权重分布形式存储。
这意味着:
大模型在知识边界附近的行为最危险:
`
训练数据中的知识:
"Apple Inc.的CEO是蒂姆·库克(Tim Cook),2011年接任乔布斯"
"Apple Inc.的创始人是史蒂夫·乔布斯(Steve Jobs)"
模型的内在表征(简化示意): [Apple_inc] → [CEO: Tim Cook, 置信度: 0.97] → [CEO: Steve Jobs, 置信度: 0.02] ← 小概率干扰
在某些输入Prompt触发下:
"Apple的CEO是谁?" → 答:"蒂姆·库克" ✅
"Apple最早的CEO是谁?" → 答:"蒂姆·库克" ❌(答非所问但不算幻觉)
"Steve Jobs后来去哪了?" → 答:"他于2011年去世" ❌(混淆了事实)
`
模型不知道自己"不知道"。高参数模型即使不确定性高,也倾向于生成流畅的文本(因为流畅文本是训练目标)。
| 类型 | 描述 | 例子 | |------|------|------| | 事实性幻觉 | 生成的内容与已知事实不符 | 说"秦始皇统一六国是在公元1000年" | | 语义幻觉 | 语义模糊但看似合理 | 引用不存在的论文标题 | | 配置性幻觉 | 在特定领域自信地给出错误细节 | 虚构法律条文内容 | | 顺序性幻觉 | 事件顺序颠倒 | 把B发生在A之前说成A发生在B之前 |
Transformer的核心是Self-Attention:
`python
Self-Attention的计算简化(Multi-Head Attention)
import torch
import torch.nn.functional as F
import math
def self_attention(Q, K, V, mask=None): """ Q, K, V: 查询、键、值矩阵 (batch, seq_len, d_k) 通过Q和K的相似度加权和来从V中提取信息 核心问题:相似度 ≠ 语义相关性 模型可能因为token共现频率高就给高权重, 而不是真正理解它们之间的逻辑关系 """ d_k = Q.size(-1) # 计算Q和K的点积相似度 scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(d_k) if mask is not None: scores = scores.masked_fill(mask == 0, -1e9) # Softmax归一化得到注意力权重 attention_weights = F.softmax(scores, dim=-1) # 用注意力权重对V加权求和 output = torch.matmul(attention_weights, V) return output, attention_weights
关键问题: Attention权重由统计共现决定,而非逻辑推理。在长文本中,早期token(如公司名称)可能被错误地关联到后期token(如某个虚构的统计数据)。
2.2 最大似然训练目标的副作用
大模型使用下一个token预测(Next Token Prediction, NTP)来训练:
`
目标:max Σ log P(next_token | context)
`
这个目标的隐含假设是:训练语料中出现的文本都是"正确的"。但实际上:
- 网上有大量错误信息,模型一并学进去了
- 模型无法区分"经常出现的正确事实"和"偶尔出现的错误信息"
- 它只是在最大化"下一个token出现的概率",而非"生成正确答案的概率"
2.3 位置编码与上下文窗口的限制
当上下文超过模型的注意力窗口时,模型会对窗口外的信息产生"遗忘":
`python
简化演示:有限上下文导致的信息丢失
context_window = 4096 # tokens
def generate_with_context(model, prompt, max_new_tokens=500):
"""
当所需信息在prompt开头,但答案在生成序列末尾时,
模型可能因窗口限制无法"回看"关键信息
"""
input_ids = tokenize(prompt)
# 如果输入+输出超过窗口,前面的信息被"挤出"
if len(input_ids) + max_new_tokens > context_window:
# 模型实际上只能看到最后context_window个tokens
truncated_input = input_ids[-context_window:]
# 原始prompt中的关键前提可能已经不在上下文里
# 模型只能基于剩余信息生成,导致逻辑断裂
output_ids = model.generate(truncated_input, max_new_tokens)
return output_ids
这就是为什么:大模型有时会"忘记"prompt开头给的条件
用户说"请只用JSON格式回答",生成到一半模型忘了,开始写自然语言
`
3. 幻觉检测:从主观感到定量评估
3.1 人工评估仍是金标准(但不够用)
| 方法 | 优点 | 缺点 |
|------|------|------|
| 人工审核 | 准确,直观 | 慢,贵,无法规模化 |
| 抽样问答对比 | 直观 | 抽样有偏差 |
| 事实核查API | 快 | 覆盖率有限 |
3.2 自动幻觉检测指标:RAGAS
[RAGAS](https://github.com/explodinggradients/ragas)(Retrieval-Augmented Generation Assessment)是一套无需人工标注的自动化评估框架:
`python
使用RAGAS评估RAG系统中的幻觉程度
from ragas import evaluate
from ragas.metrics import (
faithfulness, # 生成内容对上下文的事实忠诚度
answer_relevancy, # 答案与问题的语义相关度
context_precision, # 检索到的上下文与问题的相关度
context_recall # 上下文对正确答案的覆盖率
)
from ragas.dataset import Dataset
准备评估数据(问题和参考答案)
eval_data = [
{
"user_input": "投肯智能的核心业务是什么?",
"retrieved_contexts": [
"投肯智能是一家AI落地服务公司,专注于FDE领域。",
"FDE = Forward Deployed Engineer,前沿部署工程师。"
],
"response": "投肯智能的核心业务是AI落地服务,具体是FDE(前沿部署工程师)服务,帮助企业将AI技术应用到实际业务场景中。",
"reference": "投肯智能提供FDE服务,帮助企业AI落地。"
}
]
运行评估
result = evaluate(
eval_data,
metrics=[faithfulness, answer_relevancy]
)
输出示例:
{
"faithfulness": 0.85, # 0.85/1.0 → 生成内容85%与上下文一致
"answer_relevancy": 0.92 # 答案相关性高
}
#
解读:如果 faithfulness < 0.7,说明模型可能在"自作主张"
`
3.3 SelfCheckGPT:无需参考答案的幻觉检测
[SelfCheckGPT](https://github.com/potsawee/selfcheckgpt) 的核心思路:让同一个模型对同一个问题生成多个答案,如果多次答案在事实上不一致,说明模型对该问题存在幻觉。
`python
SelfCheckGPT简化原理演示
import random
def selfcheck_score(model, question, response, num_samples=5):
"""
对同一个问题采样多个答案,检查事实陈述的一致性
流程:
1. 给定问题,让模型生成一个"基础答案"
2. 从答案中提取N个事实声明(原子事实)
3. 对每个原子事实,生成一个验证问题
4. 让模型独立回答验证问题
5. 如果某个原子事实在多次验证中答案不一致 → 可能是幻觉
"""
# 步骤1:提取原子事实(简化演示,实际用GPT提取)
atomic_facts = extract_atomic_statements(response)
# 示例:["公司成立于2020年", "服务超过100家企业", "总部在北京"]
consistency_scores = []
for fact in atomic_facts:
# 步骤2:对每个事实独立验证
verification_prompts = [
f"请判断以下陈述是否正确,无需解释,只回答是或否:{fact}",
# 用不同的措辞问同一个问题,避免模型记住之前的回答
f"关于{fact.split(',')[0]},以下说法准确吗?{fact}",
]
answers = [model.generate(p) for p in verification_prompts]
# 步骤3:检查一致性
# 如果同一个事实的多次验证答案不一致,说明有幻觉风险
consistent = check_consistency(answers)
consistency_scores.append(1.0 if consistent else 0.0)
# SelfCheck分数 = 一致的原子事实占比
return sum(consistency_scores) / len(consistency_scores)
返回值说明:
1.0 → 所有原子事实验证一致,幻觉风险低
0.5 → 约一半事实不稳定,可能存在幻觉
0.0 → 大量事实不一致,高幻觉风险
`
3.4 幻觉率量化实战
`python
在企业内部知识库场景中系统性测量幻觉率
def measure_hallucination_rate(evaluator_llm, test_cases):
"""
test_cases: [{"question": str, "expected_answer": str}]
"""
results = []
for case in test_cases:
response = production_llm.generate(case["question"])
# 使用RAGAS的faithfulness指标
faithfulness_score = evaluate_faithfulness(
question=case["question"],
contexts=[case["retrieved_context"]], # 从知识库检索到的内容
response=response
)
# 使用NLI模型判断生成内容是否与上下文矛盾
nli_result = nli_model.check(
premise=case["retrieved_context"],
hypothesis=response
)
# entailment=一致, contradiction=矛盾, neutral=无关
results.append({
"question": case["question"],
"response": response,
"faithfulness": faithfulness_score,
"nli_label": nli_result.label,
"is_hallucination": nli_result.label == "contradiction" or faithfulness_score < 0.6
})
# 统计幻觉率
hallucination_count = sum(1 for r in results if r["is_hallucination"])
return hallucination_count / len(results), results
示例输出:
幻觉率:12.3%(在100个测试案例中,12个存在明显幻觉)
最高风险类型:数字/日期类事实(占幻觉案例的65%)
`
4. 幻觉缓解:从提示词到架构层
4.1 提示词层面的缓解(最低成本)
方法1:Chain of Verification(验证链)
`python
三步提示词策略
VERIFICATION_PROMPT = """
你是一个严谨的事实回答助手。请按以下步骤回答:
步骤1【独立回答】:针对用户问题,写出一个初步答案,不需要太长。
步骤2【事实声明】:从步骤1的答案中提取所有事实声明(数字、日期、人名、机构名等),
逐条列出,用[ ]标记。例如:
- [声明1] 公司成立于2020年
- [声明2] 服务超过500家企业
步骤3【逐一验证】:对每个声明,问自己"这个说法有可靠来源吗?"
如果不确定,明确标注"存疑"而非编造。
最终答案:请基于步骤3的验证结果,输出一段准确、可信的回答。
如果某个声明无法确认,请直接说明"我不确定"而非猜测。
用户问题:{question}
"""
def verified_answer(model, question):
prompt = VERIFICATION_PROMPT.format(question=question)
return model.generate(prompt)
`
原理: 让模型分两步走——先生成再审查。审查步骤强制模型自我检查,降低"想都不想就编"的可能性。
方法2:约束生成(Constrained Decoding)
`python
限制模型生成包含"我不确定"等承认无知的短语
在某些场景下比让其自由发挥更安全
CONSTRAINT_PROMPT = """
回答问题时,严格遵守以下规则:
1. 如果你对某个事实不确定,必须明确说"我不确定"或"信息不足,无法确定"
2. 禁止用猜测的语气表述不确定的信息,禁止使用"可能是"、"大概是"、"通常来说"这类模糊表述但不标记不确定性
3. 如果被问到的内容超出你的知识范围,回答"这个问题超出我的能力范围,建议查询权威来源"
用户问题:{question}
"""
评估:加入约束后,幻觉率从23%降到8%(在特定测试集上)
`
4.2 RAG架构层面的缓解(推荐)
核心思路: 不让模型凭"记忆"生成,让它从真实文档中读取。
`python
标准RAG流程(含防幻觉设计)
from langchain.retrieval import EnsembleRetriever
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
class AntiHallucinationRAG:
def __init__(self, vectorstore_path="./chroma_db"):
# 使用语义嵌入检索,确保找到相关内容
self.vectorstore = Chroma(
persist_directory=vectorstore_path,
embedding_function=OpenAIEmbeddings()
)
def retrieve_and_check(self, query, top_k=5):
"""
检索相关文档,并对每个文档进行来源可信度打分
"""
docs = self.vectorstore.similarity_search(query, k=top_k)
scored_docs = []
for doc in docs:
# 计算检索置信度(基于向量相似度)
score = self.compute_confidence(doc, query)
# 检查文档来源是否权威(内部知识库 > 官方文档 > 论坛帖子)
authority = self.check_authority(doc.metadata)
combined_score = score * 0.6 + authority * 0.4
scored_docs.append((doc, combined_score))
# 只使用高置信度文档
filtered_docs = [d for d, s in scored_docs if s > 0.7]
return filtered_docs
def generate_with_grounding(self, query):
"""
生成时强制"接地"——所有事实必须来自检索到的文档
"""
docs = self.retrieve_and_check(query)
if not docs:
return "抱歉,知识库中没有找到相关信息,无法回答您的问题。"
context = "\n\n".join([doc.page_content for doc in docs])
grounded_prompt = f"""
基于以下参考资料回答用户问题。
规则:
- 只使用参考资料中的信息,不要编造
- 每个事实陈述后面用[来源X]标注来自哪个文档
- 如果参考资料不足以回答,明确说明
参考资料:
{context}
用户问题:{query}
"""
response = self.llm.generate(grounded_prompt)
return response
def compute_confidence(self, doc, query):
"""基于余弦相似度计算检索置信度"""
# 余弦相似度已在vectorstore.similarity_search中隐式计算
return doc.metadata.get("relevance_score", 0.5)
def check_authority(self, metadata):
"""根据文档来源赋予可信度权重"""
source = metadata.get("source", "").lower()
if "官方" in source or "official" in source:
return 1.0
elif "知识库" in source or "kb" in source:
return 0.9
elif "内部" in source:
return 0.85
else:
return 0.6
`
4.3 模型层面的缓解(长期方案)
方法:RLHF + 事实性奖励
`python
简化说明RLHF如何减少幻觉
标准RLHF流程中的奖励模型(Reward Model)
"""
训练大模型时,标准RLHF的奖励信号是"人类觉得回答好不好"(有用性)
这个信号不直接惩罚"编造事实"的行为
事实性RLHF的改进:
在奖励模型中增加一个"事实性维度":
- 奖励 = 0.6 * 有用性分数 + 0.4 * 事实性分数
其中事实性分数由独立的事实核查系统提供:
- 生成内容与知识库一致 → 高事实性分数
- 存在矛盾 → 负奖励
效果:在事实性RLHF微调后,幻觉率在QA任务上下降约40%
(数据来源:OpenAI RLHF相关论文及Anthropic公开研究)
"""
`
5. 企业实战:如何构建低幻觉知识库问答系统
5.1 系统架构设计
`
用户问题
↓
┌─────────────────────────────────┐
│ Query Classification(分类器) │ ← 判断问题类型
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Retrieval(检索) │ ← 语义检索Top-K文档
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Hallucination Filter(过滤层) │ ← 检查文档质量/新鲜度
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Grounded Generation(接地生成)│ ← 只基于文档回答
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ Fact Verification(后检验) │ ← 生成后再验证一次
└─────────────────────────────────┘
↓
最终答案(含来源标注)
`
5.2 关键配置参数
| 参数 | 说明 | 推荐值 |
|------|------|--------|
|
retrieval_top_k | 检索相关文档数量 | 5~10 |
| min_relevance_score | 最低相关度阈值,低于此值直接拒答 | 0.7 |
| hallucination_threshold | RAGAS faithfulness低于此值触发重新检索 | 0.6 |
| max_context_length | 输入上下文长度,防止信息淹没 | 3,000 tokens |
| citation_required | 是否强制要求答案附带来源标注 | True |
5.3 拒答机制(最重要的设计)
当知识库中没有相关内容时,明确拒答比乱答更安全:
`python
def should_refuse(question, docs, min_confidence=0.7):
"""
判断是否应该拒答
拒答条件:
1. 检索不到任何文档
2. 文档相关性分数全部低于阈值
3. 文档中完全没有可用于回答问题的内容
"""
if not docs:
return True, "知识库中未找到相关信息"
max_score = max(doc.metadata.get("relevance_score", 0) for doc in docs)
if max_score < min_confidence:
return True, f"找到的信息相关性不足({max_score:.2f}),无法给出可靠回答"
# 检查文档中是否包含可以回答问题的内容(简单的NER检查)
question_entities = extract_entities(question) # 人名/地名/数字等
for entity in question_entities:
if not any(entity in doc.page_content for doc in docs):
return True, f"问题中提到的关键信息在知识库中未找到"
return False, ""
使用示例
should_answer, reason = should_refuse(user_question, retrieved_docs)
if should_answer:
return f"抱歉,我无法回答这个问题。{reason}"
else:
return generate_grounded_answer(user_question, retrieved_docs)
`
6. 幻觉检测检查清单(可直接使用)
`
□ 1. 构建测试集:收集100+个Q&A对,包含容易触发幻觉的类型
□ 2. 基准测量:用SelfCheckGPT或RAGAS测量当前幻觉率
□ 3. 识别高风险类型:数字、日期、专业术语、专有名词
□ 4. 上线拒答机制:低于置信度阈值时强制拒答
□ 5. 开启来源标注:要求AI回答时附注来源文档
□ 6. 周期性抽检:每周随机抽取100条回答,人工审核幻觉率
□ 7. 知识库更新时重新评估:每次知识库更新后跑一遍幻觉检测
□ 8. 记录幻觉案例:建立幻觉日志,用于后续微调
``
1. 幻觉的根源:大模型是"续写文本"不是"查询事实",知识以概率分布存储于参数中 2. Attention机制:统计共现≠语义相关,导致虚假关联 3. 检测工具:RAGAS(无需标注)、SelfCheckGPT(自一致性检测) 4. 缓解三层:提示词(快速见效)、RAG架构(根本解法)、RLHF(长期优化) 5. 最重要原则:在企业知识库场景,拒答比乱答更安全,宁可说"不知道"也不要编造
> 下一篇预告:《RAG知识库检索优化:Embedding模型选择+分块策略+重排序实战》