AI幻觉检测与事实性校验完全教程

教程简介

零基础AI幻觉检测与事实性校验完全教程,涵盖LLM幻觉类型与成因分析、事实性校验方法论、RAG事实增强、Self-Consistency校验、外部知识库验证、FActScore评估指标、幻觉检测工具链、企业级事实性保障方案、与人工审核结合、幻觉防护最佳实践等核心技能,适合AI开发者和质量工程师系统学习。

AI幻觉检测与事实性校验完全教程

系统化理解 LLM 幻觉问题,掌握从事前预防到事后检测的全链路事实性保障方案


目录

  1. 理解 AI 幻觉:现象与危害
  2. 幻觉类型与成因深度分析
  3. 事实性校验方法论
  4. RAG 事实增强:从根源降低幻觉
  5. Self-Consistency 校验
  6. 外部知识库验证
  7. FActScore 评估指标体系
  8. 幻觉检测工具链
  9. 企业级事实性保障方案
  10. 与人工审核结合
  11. 幻觉防护最佳实践

1. 理解 AI 幻觉:现象与危害

什么是 AI 幻觉

AI 幻觉(Hallucination)是指大语言模型(LLM)生成的内容看似合理、流畅,但实际上包含事实错误、捏造信息或与现实不符的陈述。这些错误输出往往以极高的置信度呈现,使得非专业人士难以辨别。

幻觉的真实危害

场景 危害 严重程度
医疗咨询 错误用药建议可能导致生命危险 🔴 致命
法律文书 捏造判例引用导致案件败诉 🔴 严重
金融分析 错误数据导致投资决策失误 🟠 高
新闻报道 虚假信息传播引发社会恐慌 🟠 高
技术文档 错误配置导致系统故障 🟡 中
教育内容 错误知识误导学生 🟡 中
客服回复 错误承诺引发客户投诉 🟢 低

幻觉的统计数据

根据多项学术研究的综合数据:

  • GPT-4 在事实性问答中的幻觉率约为 15-20%
  • 在长文本生成中,幻觉率随文本长度增加而上升
  • 涉及数字、日期、引用等具体事实时,幻觉率显著提高
  • 经过 RLHF 训练的模型幻觉率低于基础模型,但远未消除

2. 幻觉类型与成因深度分析

2.1 幻觉分类体系

AI 幻觉
├── 事实性幻觉 (Factual Hallucination)
│   ├── 内在矛盾型 —— 生成内容与自身知识冲突
│   └── 外在矛盾型 —— 生成内容与现实世界冲突
├── 忠实度幻觉 (Faithfulness Hallucination)
│   ├── 指令偏离 —— 未遵循用户指令
│   ├── 上下文偏离 —— 与提供的上下文矛盾
│   └── 逻辑偏离 —— 推理过程存在逻辑错误
└── 捏造型幻觉 (Fabrication)
    ├── 虚构引用 —— 捏造不存在的论文、法律条文
    ├── 虚构实体 —— 捏造不存在的人物、机构
    └── 虚构事件 —— 捏造从未发生的历史事件

2.2 成因分析

训练数据层面

# 训练数据质量问题示意
training_data_issues = {
    "噪声数据": "互联网文本包含大量错误信息",
    "过时数据": "知识截止日期后的信息缺失",
    "分布偏差": "某些领域数据稀缺导致知识空白",
    "重复偏见": "高频出现的错误信息被强化学习",
    "标注错误": "人工标注过程中引入的错误"
}

模型架构层面

  1. 自回归生成机制:模型基于概率逐词生成,一旦某个 token 出错,后续内容会沿错误方向延续
  2. 注意力机制局限:长文本中关键信息可能被稀释,导致"遗忘"重要事实
  3. 知识存储方式:知识以参数形式分布式存储,无法精确检索特定事实
  4. 解码策略影响:高温度采样增加创造性,但也增加幻觉概率

推理阶段因素

# 温度参数对幻觉率的影响
temperature_vs_hallucination = {
    0.0: {"creativity": "低", "hallucination_risk": "最低", "use_case": "事实问答"},
    0.3: {"creativity": "中低", "hallucination_risk": "低", "use_case": "知识总结"},
    0.7: {"creativity": "中", "hallucination_risk": "中", "use_case": "一般对话"},
    1.0: {"creativity": "高", "hallucination_risk": "高", "use_case": "创意写作"},
    1.5: {"creativity": "极高", "hallucination_risk": "极高", "use_case": "不推荐"},
}

3. 事实性校验方法论

3.1 校验框架总览

事实性校验框架
├── 事前预防 (Prevention)
│   ├── RAG 知识增强
│   ├── Prompt 工程约束
│   └── 模型选择与配置
├── 事中检测 (Detection)
│   ├── Self-Consistency 检测
│   ├── 外部知识库验证
│   ├── 交叉模型校验
│   └── 分子句事实提取
└── 事后修正 (Correction)
    ├── 人类反馈循环
    ├── 自动修正管道
    └── 置信度标记

3.2 原子事实分解

将 LLM 输出分解为最小可验证的事实单元(Atomic Facts),逐条校验:

from openai import OpenAI

client = OpenAI()

def decompose_into_facts(text: str) -> list[str]:
    """将文本分解为原子事实"""
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {
                "role": "system",
                "content": """将以下文本分解为独立的、可验证的原子事实。
每个事实应该是最小粒度的陈述,能够单独判断真假。
输出格式为 JSON 数组,每个元素是一个事实字符串。"""
            },
            {"role": "user", "content": text}
        ],
        response_format={"type": "json_object"},
        temperature=0.0
    )
    
    result = json.loads(response.choices[0].message.content)
    return result["facts"]

# 示例
text = """
OpenAI 于 2022 年 11 月发布了 ChatGPT,该模型基于 GPT-3.5 架构,
在发布后两个月内用户数突破 1 亿,成为历史上增长最快的消费级应用。
"""

facts = decompose_into_facts(text)
# 输出:
# [
#   "OpenAI 于 2022 年 11 月发布了 ChatGPT",
#   "ChatGPT 基于 GPT-3.5 架构",
#   "ChatGPT 在发布后两个月内用户数突破 1 亿",
#   "ChatGPT 是历史上增长最快的消费级应用"
# ]

3.3 基于 NLI 的事实校验

使用自然语言推理(NLI)模型判断事实是否被上下文支持:

from transformers import pipeline

# 加载 NLI 模型
nli_pipeline = pipeline(
    "text-classification",
    model="cross-encoder/nli-deberta-v3-large"
)

def verify_fact_with_context(fact: str, context: str) -> dict:
    """使用 NLI 验证事实是否被上下文支持"""
    result = nli_pipeline(f"{context} [SEP] {fact}")
    
    label_map = {
        "entailment": {"verdict": "SUPPORTED", "confidence": result[0]["score"]},
        "contradiction": {"verdict": "CONTRADICTED", "confidence": result[0]["score"]},
        "neutral": {"verdict": "UNVERIFIABLE", "confidence": result[0]["score"]}
    }
    
    return label_map.get(result[0]["label"].lower(), {"verdict": "UNKNOWN", "confidence": 0})

# 批量验证
def batch_verify_facts(facts: list[str], context: str) -> list[dict]:
    """批量验证多个事实"""
    results = []
    for fact in facts:
        verification = verify_fact_with_context(fact, context)
        verification["fact"] = fact
        results.append(verification)
    return results

4. RAG 事实增强:从根源降低幻觉

4.1 RAG 降低幻觉的原理

传统 LLM:问题 → 模型参数知识 → 回答(可能幻觉)
RAG 增强:问题 → 检索外部知识 → 模型基于知识回答 → 有据可循

RAG 通过将外部知识注入上下文,将模型的"自由创作"转变为"基于资料的回答",从根本上降低幻觉概率。

4.2 高质量 RAG 管道实现

from openai import OpenAI
import chromadb

client = OpenAI()
chroma_client = chromadb.PersistentClient(path="./knowledge_base")

class FactualRAG:
    """事实增强 RAG 系统"""
    
    def __init__(self, collection_name: str = "knowledge"):
        self.collection = chroma_client.get_or_create_collection(
            name=collection_name,
            metadata={"hnsw:space": "cosine"}
        )
    
    def add_documents(self, documents: list[dict]):
        """添加知识文档"""
        for i, doc in enumerate(documents):
            # 生成 Embedding
            embedding = client.embeddings.create(
                model="text-embedding-3-small",
                input=doc["content"]
            ).data[0].embedding
            
            self.collection.add(
                ids=[doc["id"]],
                embeddings=[embedding],
                documents=[doc["content"]],
                metadatas=[doc.get("metadata", {})]
            )
    
    def retrieve(self, query: str, top_k: int = 5) -> list[dict]:
        """检索相关知识"""
        query_embedding = client.embeddings.create(
            model="text-embedding-3-small",
            input=query
        ).data[0].embedding
        
        results = self.collection.query(
            query_embeddings=[query_embedding],
            n_results=top_k,
            include=["documents", "metadatas", "distances"]
        )
        
        return [
            {
                "content": doc,
                "metadata": meta,
                "relevance": 1 - dist
            }
            for doc, meta, dist in zip(
                results["documents"][0],
                results["metadatas"][0],
                results["distances"][0]
            )
        ]
    
    def generate_with_citations(self, query: str) -> dict:
        """生成带引用的回答"""
        # 检索相关知识
        sources = self.retrieve(query, top_k=5)
        
        if not sources:
            return {
                "answer": "未找到相关知识,无法回答此问题。",
                "sources": [],
                "confidence": "none"
            }
        
        # 构建带引用的上下文
        context_parts = []
        for i, source in enumerate(sources):
            context_parts.append(f"[来源{i+1}] {source['content']}")
        context = "\n\n".join(context_parts)
        
        # 生成回答
        response = client.chat.completions.create(
            model="gpt-4o",
            messages=[
                {
                    "role": "system",
                    "content": f"""你是一个严谨的知识问答助手。请根据以下参考资料回答问题。

规则:
1. 只使用参考资料中的信息回答问题
2. 回答时必须引用来源编号,格式为 [来源N]
3. 如果参考资料不足以回答问题,请明确说明
4. 不要编造或推测参考资料中没有的信息
5. 如果不同来源的信息有矛盾,请指出矛盾之处

参考资料:
{context}"""
                },
                {"role": "user", "content": query}
            ],
            temperature=0.1,  # 低温度减少幻觉
            max_tokens=1000
        )
        
        answer = response.choices[0].message.content
        
        # 评估回答的事实性
        confidence = self._assess_confidence(answer, sources)
        
        return {
            "answer": answer,
            "sources": sources,
            "confidence": confidence
        }
    
    def _assess_confidence(self, answer: str, sources: list[dict]) -> str:
        """评估回答的置信度"""
        # 计算来源的平均相关度
        avg_relevance = sum(s["relevance"] for s in sources) / len(sources)
        
        # 检查是否有引用标记
        has_citations = "[来源" in answer or "[" in answer
        
        if avg_relevance > 0.8 and has_citations:
            return "high"
        elif avg_relevance > 0.6 and has_citations:
            return "medium"
        elif avg_relevance > 0.4:
            return "low"
        else:
            return "very_low"

4.3 Prompt 工程防幻觉策略

ANTI_HALLUCINATION_PROMPTS = {
    "strict_factual": """你是一个严格基于事实的助手。请遵守以下规则:
1. 只回答你确信正确的信息
2. 如果不确定,请说"我不确定"或"我没有相关信息"
3. 区分事实和观点,明确标注
4. 提供信息来源或说明依据
5. 避免使用"可能"、"也许"等模糊词汇来掩盖不确定性
6. 如果问题超出你的知识范围,直接说明""",
    
    "with_confidence": """回答问题时,请为每个关键陈述标注置信度:
- [确定] 你有充分把握的信息
- [较确定] 你有一定把握但可能有误的信息
- [不确定] 你在推测或记忆模糊的信息
- [无法确认] 你无法验证的信息""",
    
    "source_based": """请基于以下原则回答问题:
1. 只使用提供的参考资料中的信息
2. 如果参考资料不足以回答,请明确说明
3. 不要添加参考资料中没有的信息
4. 引用具体的参考资料编号
5. 如果参考资料相互矛盾,请指出"""
}

5. Self-Consistency 校验

5.1 原理

Self-Consistency 的核心思想:如果一个陈述是事实正确的,那么模型在多次独立生成中应该给出一致的答案。如果多次生成结果不一致,说明模型对这个事实"不确定",可能存在幻觉。

5.2 实现方案

import json
from collections import Counter
from openai import OpenAI

client = OpenAI()

class SelfConsistencyChecker:
    """基于自一致性的幻觉检测器"""
    
    def __init__(self, model: str = "gpt-4o-mini", n_samples: int = 5):
        self.model = model
        self.n_samples = n_samples
    
    def check_consistency(self, question: str) -> dict:
        """多次生成并检查一致性"""
        answers = []
        for _ in range(self.n_samples):
            response = client.chat.completions.create(
                model=self.model,
                messages=[{"role": "user", "content": question}],
                temperature=0.7, max_tokens=500
            )
            answers.append(response.choices[0].message.content)
        
        facts_per_answer = [self._extract_key_facts(a) for a in answers]
        consistency_scores = self._calculate_consistency(facts_per_answer)
        
        return {
            "question": question,
            "answers": answers,
            "consistency_scores": consistency_scores,
            "overall_consistency": sum(consistency_scores.values()) / len(consistency_scores) if consistency_scores else 0,
            "flagged_facts": [f for f, s in consistency_scores.items() if s < 0.6]
        }
    
    def _extract_key_facts(self, text: str) -> list[str]:
        """从回答中提取关键事实"""
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": "从文本中提取关键事实,每行一个。只提取可验证的事实陈述。"},
                {"role": "user", "content": text}
            ], temperature=0.0
        )
        return [f.strip("- ").strip() for f in response.choices[0].message.content.strip().split("\n") if f.strip()]
    
    def _calculate_consistency(self, facts_per_answer: list[list[str]]) -> dict[str, float]:
        """计算每个事实的一致性分数"""
        import re
        all_fact_sets = []
        for facts in facts_per_answer:
            normalized = {re.sub(r'[^\w\s]', '', f.lower()).strip() for f in facts}
            all_fact_sets.append(normalized)
        unique_facts = set().union(*all_fact_sets)
        return {fact: sum(1 for fs in all_fact_sets if fact in fs) / len(all_fact_sets) for fact in unique_facts}

5.3 多模型交叉校验

class CrossModelValidator:
    """使用多个模型交叉验证事实"""
    
    def __init__(self):
        self.models = ["gpt-4o-mini", "gpt-4o"]
    
    def validate_fact(self, fact: str) -> dict:
        """让多个模型判断事实正确性"""
        results = {}
        for model in self.models:
            response = client.chat.completions.create(
                model=model,
                messages=[
                    {"role": "system", "content": '判断以下事实是否正确。JSON格式:{"verdict":"correct/incorrect/uncertain","confidence":0.0-1.0}'},
                    {"role": "user", "content": fact}
                ],
                response_format={"type": "json_object"},
                temperature=0.0
            )
            results[model] = json.loads(response.choices[0].message.content)
        
        verdicts = [r["verdict"] for r in results.values()]
        return {
            "fact": fact,
            "majority_verdict": Counter(verdicts).most_common(1)[0][0],
            "is_consistent": len(set(verdicts)) == 1,
            "model_results": results
        }

6. 外部知识库验证

6.1 维基百科验证管道

import requests

class WikipediaVerifier:
    """使用维基百科验证事实"""
    
    API_URL = "https://zh.wikipedia.org/w/api.php"
    
    def search(self, query: str, limit: int = 5) -> list[dict]:
        """搜索维基百科条目"""
        params = {
            "action": "query",
            "list": "search",
            "srsearch": query,
            "srlimit": limit,
            "format": "json"
        }
        response = requests.get(self.API_URL, params=params)
        data = response.json()
        
        return [
            {
                "title": item["title"],
                "snippet": item["snippet"],
                "page_id": item["pageid"]
            }
            for item in data["query"]["search"]
        ]
    
    def get_page_content(self, page_id: int) -> str:
        """获取维基百科页面内容"""
        params = {
            "action": "query",
            "pageids": page_id,
            "prop": "extracts",
            "explaintext": True,
            "format": "json"
        }
        response = requests.get(self.API_URL, params=params)
        pages = response.json()["query"]["pages"]
        return pages[str(page_id)].get("extract", "")
    
    def verify_claim(self, claim: str) -> dict:
        """验证一个事实声明"""
        # 提取搜索关键词
        keywords = self._extract_keywords(claim)
        
        # 搜索相关维基百科条目
        all_context = ""
        for keyword in keywords[:3]:
            results = self.search(keyword, limit=2)
            for result in results:
                content = self.get_page_content(result["page_id"])
                all_context += f"\n\n--- {result['title']} ---\n{content[:2000]}"
        
        if not all_context.strip():
            return {
                "claim": claim,
                "verdict": "UNVERIFIABLE",
                "reason": "未找到相关维基百科条目"
            }
        
        # 使用 LLM 判断事实是否被支持
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {
                    "role": "system",
                    "content": f"""基于以下维基百科内容,判断给定的事实声明是否正确。

维基百科内容:
{all_context[:8000]}

请以 JSON 格式回答:
{{
  "verdict": "SUPPORTED" | "REFUTED" | "UNVERIFIABLE",
  "confidence": 0.0-1.0,
  "evidence": "支持或反驳的证据摘要",
  "source": "引用的维基百科条目标题"
}}"""
                },
                {"role": "user", "content": f"验证以下声明:{claim}"}
            ],
            response_format={"type": "json_object"},
            temperature=0.0
        )
        
        result = json.loads(response.choices[0].message.content)
        result["claim"] = claim
        return result
    
    def _extract_keywords(self, text: str) -> list[str]:
        """从文本中提取关键词用于搜索"""
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {
                    "role": "system",
                    "content": "从以下文本中提取 3-5 个关键词或短语,用于维基百科搜索。每行一个关键词。"
                },
                {"role": "user", "content": text}
            ],
            temperature=0.0
        )
        
        keywords = response.choices[0].message.content.strip().split("\n")
        return [k.strip("- ").strip() for k in keywords if k.strip()]

6.2 专业数据库验证

针对特定领域(医学、法律、科学),可调用专业 API 进行验证。以医学领域查询 PubMed 为例:

def verify_medical_claim(claim: str) -> dict:
    """通过 PubMed API 验证医学声明"""
    search_url = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi"
    params = {"db": "pubmed", "term": claim, "retmax": 5, "retmode": "json"}
    response = requests.get(search_url, params=params)
    ids = response.json().get("esearchresult", {}).get("idlist", [])
    
    return {
        "verdict": "EVIDENCE_FOUND" if ids else "NO_EVIDENCE",
        "domain": "medical",
        "pmid_count": len(ids),
        "pmids": ids
    }

其他领域可类似接入 Semantic Scholar(科学)、中国裁判文书网(法律)等数据源。核心思路是:将 LLM 输出中的事实声明映射到可验证的外部数据源


7. FActScore 评估指标体系

7.1 FActScore 概述

FActScore(Factual Precision in Atomicity Score)是由 Min et al. (2023) 提出的事实性评估指标。它将 LLM 输出分解为原子事实,然后计算每个事实的精确率。

7.2 计算实现

@dataclass
class AtomicFact:
    text: str
    is_supported: bool
    confidence: float = 0.0

class FActScoreCalculator:
    """FActScore 计算器"""
    
    def calculate(self, response: str, reference_knowledge: str = None) -> dict:
        """计算 FActScore:分解 → 验证 → 统计"""
        atomic_facts = self._decompose(response)
        verified = self._verify_facts(atomic_facts, reference_knowledge)
        
        total = len(verified)
        supported = sum(1 for f in verified if f.is_supported)
        precision = supported / total if total > 0 else 0
        
        return {
            "factscore": precision,
            "total_facts": total,
            "supported_facts": supported,
            "unsupported_facts": total - supported,
            "details": [{"fact": f.text, "supported": f.is_supported, "confidence": f.confidence} for f in verified]
        }
    
    def _decompose(self, text: str) -> list[str]:
        """将文本分解为原子事实"""
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": "将文本分解为独立的、可验证的原子事实。输出JSON:{\"facts\": [\"事实1\", ...]}"},
                {"role": "user", "content": text}
            ],
            response_format={"type": "json_object"},
            temperature=0.0
        )
        return json.loads(response.choices[0].message.content).get("facts", [])
    
    def _verify_facts(self, facts: list[str], knowledge: str = None) -> list[AtomicFact]:
        """验证每个原子事实"""
        verified = []
        for fact in facts:
            result = (self._verify_against_knowledge(fact, knowledge) if knowledge 
                     else self._verify_with_llm(fact))
            verified.append(AtomicFact(text=fact, is_supported=result["supported"], confidence=result["confidence"]))
        return verified
    
    def _verify_against_knowledge(self, fact: str, knowledge: str) -> dict:
        """基于给定知识验证事实"""
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": f"基于以下参考资料判断事实是否被支持。\n参考资料:{knowledge[:6000]}\nJSON格式:{{\"supported\": true/false, \"confidence\": 0.0-1.0}}"},
                {"role": "user", "content": fact}
            ],
            response_format={"type": "json_object"},
            temperature=0.0
        )
        return json.loads(response.choices[0].message.content)
    
    def _verify_with_llm(self, fact: str) -> dict:
        """使用 LLM 自身知识验证"""
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": '判断事实是否正确。JSON:{"supported": true/false, "confidence": 0.0-1.0}'},
                {"role": "user", "content": fact}
            ],
            response_format={"type": "json_object"},
            temperature=0.0
        )
        return json.loads(response.choices[0].message.content)


# 使用示例
calculator = FActScoreCalculator()
result = calculator.calculate(
    "爱因斯坦于 1879 年出生于德国乌尔姆,他提出了相对论,获得了 1921 年的诺贝尔物理学奖。"
)
print(f"FActScore: {result['factscore']:.2%}")  # 输出: FActScore: 100.00%

7.3 FActScore 的局限性

局限 说明 缓解方案
依赖 LLM 进行验证 验证模型本身可能犯错 使用多个模型交叉验证
原子事实分解不一致 不同模型分解粒度不同 标准化分解 Prompt
无法验证主观性内容 观点、推测无法评估 区分事实与观点
计算成本高 每个事实需要独立验证 批量处理、缓存结果
知识库覆盖有限 可能缺乏某些领域知识 使用专业数据库补充

8. 幻觉检测工具链

8.1 工具全景图

幻觉检测工具链
├── 开源框架
│   ├── DeepEval —— 综合 LLM 评估框架
│   ├── Ragas —— RAG 专用评估
│   ├── TruLens —— LLM 应用可观测性
│   └── Guardrails AI —— 输出验证框架
├── 商业平台
│   ├── Arthur AI —— 企业级 AI 监控
│   ├── Weights & Biases —— 实验追踪
│   ├── LangSmith —— LangChain 追踪
│   └── Patronus AI —— 幻觉检测 API
└── 自建工具
    ├── NLI 管道
    ├── 事实提取器
    └── 一致性检查器

8.2 DeepEval 集成

# pip install deepeval
from deepeval import evaluate
from deepeval.metrics import HallucinationMetric, FaithfulnessMetric
from deepeval.test_case import LLMTestCase

# 创建测试用例
test_case = LLMTestCase(
    input="什么是量子计算?",
    actual_output="量子计算利用量子力学原理进行计算,量子比特可以同时处于 0 和 1 的叠加态。",
    retrieval_context=[
        "量子计算是利用量子力学原理(如叠加和纠缠)进行信息处理的计算方式。",
        "量子比特(qubit)是量子计算的基本单位,与经典比特不同,它可以同时处于多个状态。"
    ]
)

# 幻觉检测
hallucination_metric = HallucinationMetric(
    threshold=0.5,  # 幻觉比例阈值
    model="gpt-4o-mini",
    include_reason=True
)

# 忠实度检测
faithfulness_metric = FaithfulnessMetric(
    threshold=0.7,
    model="gpt-4o-mini",
    include_reason=True
)

# 运行评估
evaluate(
    test_cases=[test_case],
    metrics=[hallucination_metric, faithfulness_metric]
)

8.3 Ragas 评估框架

# pip install ragas
from ragas import evaluate
from ragas.metrics import (
    faithfulness,
    answer_relevancy,
    context_precision,
    context_recall
)
from datasets import Dataset

# 准备评估数据
eval_data = {
    "question": ["什么是机器学习?", "深度学习和机器学习的区别是什么?"],
    "answer": [
        "机器学习是人工智能的分支,使计算机能够从数据中学习。",
        "深度学习是机器学习的子集,使用多层神经网络进行学习。"
    ],
    "contexts": [
        ["机器学习是人工智能的一个子领域,它使计算机系统能够从数据中自动学习和改进。"],
        ["深度学习是机器学习的一个子集,它使用多层人工神经网络来模拟人脑的学习过程。"]
    ],
    "ground_truth": [
        "机器学习是人工智能的分支,通过算法使计算机从数据中学习模式。",
        "深度学习是机器学习的子集,使用深层神经网络进行特征学习。"
    ]
}

dataset = Dataset.from_dict(eval_data)

# 运行评估
results = evaluate(
    dataset=dataset,
    metrics=[
        faithfulness,       # 忠实度:回答是否基于上下文
        answer_relevancy,   # 相关性:回答是否与问题相关
        context_precision,  # 上下文精确度:检索的内容是否相关
        context_recall      # 上下文召回率:是否检索到所有相关信息
    ]
)

print(results)
# 输出类似:
# {
#   'faithfulness': 0.92,
#   'answer_relevancy': 0.89,
#   'context_precision': 0.85,
#   'context_recall': 0.78
# }

8.4 Guardrails AI 输出验证

Guardrails AI 提供声明式的输出验证,可以在 LLM 输出返回给用户之前自动检测幻觉:

from guardrails import Guard
from guardrails.hub import DetectHallucination

guard = Guard().use(
    DetectHallucination(
        query="用户问题",
        documents=["参考文档1", "参考文档2"],
        on_fail="exception"  # 检测到幻觉时抛出异常
    )
)

# 验证 LLM 输出
try:
    result = guard.validate(llm_output="待验证的输出")
except Exception as e:
    print("检测到幻觉:", str(e))

9. 企业级事实性保障方案

9.1 保障架构设计

企业级事实性保障架构
│
├── 第一道防线:输入层
│   ├── 用户查询意图识别
│   ├── 敏感话题检测
│   └── 查询改写与标准化
│
├── 第二道防线:生成层
│   ├── RAG 知识注入
│   ├── 系统 Prompt 约束
│   ├── 低温度参数配置
│   └── 结构化输出约束
│
├── 第三道防线:检测层
│   ├── 原子事实分解
│   ├── NLI 事实校验
│   ├── Self-Consistency 检测
│   └── 外部知识库验证
│
├── 第四道防线:输出层
│   ├── 置信度标记
│   ├── 来源引用
│   ├── 敏感内容过滤
│   └── 格式标准化
│
└── 持续改进:监控层
    ├── 用户反馈收集
    ├── 幻觉率统计
    ├── A/B 测试
    └── 模型迭代

9.2 管道式实现

class EnterpriseHallucinationGuard:
    """企业级幻觉防护管道"""
    
    def __init__(self, config: dict):
        self.config = config
        self.rag = FactualRAG(config.get("collection_name", "knowledge"))
        self.consistency_checker = SelfConsistencyChecker(
            n_samples=config.get("consistency_samples", 3)
        )
        self.factscore_calc = FActScoreCalculator()
    
    async def process_query(self, query: str, context: dict = None) -> dict:
        """完整的幻觉防护管道"""
        
        # 第一道防线:输入检查
        input_check = self._check_input(query)
        if input_check["blocked"]:
            return {"error": input_check["reason"], "stage": "input_filter"}
        
        # 第二道防线:RAG 增强生成
        rag_result = self.rag.generate_with_citations(query)
        
        # 第三道防线:事实性检测
        detection_result = await self._detect_hallucination(
            query, rag_result["answer"], rag_result["sources"]
        )
        
        # 第四道防线:输出包装
        output = self._format_output(
            answer=rag_result["answer"],
            sources=rag_result["sources"],
            detection=detection_result,
            confidence=rag_result["confidence"]
        )
        
        # 记录监控数据
        self._log_metrics(query, output)
        
        return output
    
    def _check_input(self, query: str) -> dict:
        """输入层检查:敏感话题过滤"""
        for topic in self.config.get("sensitive_topics", []):
            if topic in query:
                return {"blocked": True, "reason": f"查询涉及敏感话题: {topic}"}
        return {"blocked": False}
    
    async def _detect_hallucination(self, query: str, answer: str, sources: list) -> dict:
        """综合幻觉检测:FActScore + Self-Consistency + 忠实度"""
        results = {}
        knowledge = "\n".join([s["content"] for s in sources])
        
        # 三项检测并行执行(实际生产中可用 asyncio.gather)
        results["factscore"] = self.factscore_calc.calculate(answer, knowledge)["factscore"]
        results["consistency"] = self.consistency_checker.check_consistency(query)["overall_consistency"]
        results["faithfulness"] = self._check_faithfulness(answer, sources)
        
        scores = [results["factscore"], results["consistency"], results["faithfulness"]]
        overall = sum(scores) / len(scores)
        
        results["overall_score"] = overall
        results["risk_level"] = "high" if overall < 0.6 else "medium" if overall < 0.8 else "low"
        return results
    
    def _check_faithfulness(self, answer: str, sources: list) -> float:
        """检查回答对来源的忠实度(0-1分)"""
        if not sources:
            return 0.0
        
        context = "\n".join([s["content"] for s in sources])
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {
                    "role": "system",
                    "content": f"""评估以下回答相对于参考资料的忠实度(0-1分)。
1.0=完全基于资料,0.6=有明显推测,0.2=大部分编造。
参考资料:{context[:4000]}

以 JSON 回答:{{"score": 0.0-1.0, "reason": "理由"}}"""
                },
                {"role": "user", "content": f"回答:{answer[:2000]}"}
            ],
            response_format={"type": "json_object"},
            temperature=0.0
        )
        return json.loads(response.choices[0].message.content)["score"]
    
    def _format_output(self, answer: str, sources: list, detection: dict, confidence: str) -> dict:
        """格式化最终输出,附加风险标记和来源引用"""
        risk_level = detection.get("risk_level", "unknown")
        warnings = []
        if risk_level == "high":
            warnings.append("⚠️ 警告:此回答的事实性评分较低,请谨慎参考。")
        elif risk_level == "medium":
            warnings.append("⚡ 注意:此回答部分信息可能不够准确,建议进一步验证。")
        
        return {
            "answer": answer,
            "confidence": confidence,
            "risk_level": risk_level,
            "factuality_score": detection.get("overall_score", 0),
            "warnings": warnings,
            "sources": [{"content": s["content"][:200]+"...", "relevance": s.get("relevance",0)} for s in sources[:3]],
            "detection_details": {k: detection.get(k) for k in ["factscore","consistency","faithfulness"]}
        }
    
    def _log_metrics(self, query: str, output: dict):
        """记录监控指标"""
        import time
        metric = {
            "timestamp": time.time(),
            "query_length": len(query),
            "risk_level": output["risk_level"],
            "factuality_score": output["factuality_score"],
            "confidence": output["confidence"],
            "source_count": len(output["sources"])
        }
        # 发送到监控系统(示例)
        print(f"[METRIC] {json.dumps(metric)}")

10. 与人工审核结合

10.1 人机协作审核模型

完全自动 ──────────────────────────────────── 完全人工
    │                                              │
    ▼                                              ▼
 低风险查询                                      高风险查询
 (事实问答)                                    (医疗/法律)
    │                                              │
    ▼                                              ▼
 自动处理 ──→ 低置信度标记 ──→ 人工审核 ──→ 高置信度直接输出

10.2 分级审核策略

class HumanInTheLoopReviewer:
    """人机协作审核系统"""
    
    # 审核级别定义
    REVIEW_LEVELS = {
        "auto_approve": {
            "description": "自动通过,无需人工审核",
            "conditions": ["factuality_score > 0.9", "risk_level == 'low'"]
        },
        "auto_with_flag": {
            "description": "自动通过,但标记供抽检",
            "conditions": ["factuality_score > 0.7", "risk_level == 'low'"]
        },
        "queue_for_review": {
            "description": "排队等待人工审核",
            "conditions": ["factuality_score > 0.5", "risk_level == 'medium'"]
        },
        "require_review": {
            "description": "必须人工审核后才能发布",
            "conditions": ["factuality_score < 0.5", "risk_level == 'high'"]
        },
        "block_and_escalate": {
            "description": "阻断并升级处理",
            "conditions": ["涉及敏感话题", "涉及法律责任"]
        }
    }
    
    def determine_review_level(self, output: dict) -> str:
        """确定审核级别"""
        score = output.get("factuality_score", 0)
        risk = output.get("risk_level", "high")
        warnings = output.get("warnings", [])
        
        if any("敏感" in w or "法律" in w for w in warnings):
            return "block_and_escalate"
        elif score < 0.5 or risk == "high":
            return "require_review"
        elif score < 0.7 or risk == "medium":
            return "queue_for_review"
        elif score < 0.9:
            return "auto_with_flag"
        else:
            return "auto_approve"
    
    def create_review_ticket(self, output: dict, review_level: str) -> dict:
        """创建审核工单"""
        return {
            "id": str(uuid.uuid4()),
            "created_at": datetime.now().isoformat(),
            "review_level": review_level,
            "answer_preview": output["answer"][:500],
            "factuality_score": output["factuality_score"],
            "risk_level": output["risk_level"],
            "sources": output["sources"],
            "status": "pending",
            "assigned_to": None,
            "resolution": None
        }

10.3 反馈循环机制

收集用户反馈是持续改进幻觉防护的关键。核心数据模型:

feedback_record = {
    "query_id": "唯一查询标识",
    "rating": "1-5 分",
    "is_accurate": "布尔值,用户判断是否准确",
    "correction": "用户提供的修正内容",
    "category": "问题分类(事实错误/过时信息/逻辑错误等)"
}

反馈分析要点

  • 定期统计准确率趋势,按领域/问题类型细分
  • 对低分反馈进行根因分析,识别高频幻觉模式
  • 将修正数据用于知识库补充或模型微调
  • 当准确率突然下降时触发告警,排查知识库或模型变更

11. 幻觉防护最佳实践

11.1 设计原则

原则 说明 实施建议
宁可拒绝,不可编造 宁愿说"不知道"也不给出错误信息 在 Prompt 中明确要求模型承认不确定性
有据可循 每个关键陈述都应有来源支撑 使用 RAG + 引用机制
分级处理 根据风险级别采用不同的防护策略 高风险场景强制人工审核
持续改进 通过反馈循环不断降低幻觉率 收集用户反馈,定期评估
透明可控 用户应知道回答的事实性水平 提供置信度和风险标记

11.2 Prompt 工程最佳实践

BEST_PRACTICE_PROMPTS = {
    # 1. 明确知识边界
    "knowledge_boundary": """请基于你确定的知识回答问题。
如果你不确定或没有相关信息,请明确说明:
- "我没有关于这个话题的可靠信息"
- "这超出了我的知识范围"
- "我无法确认这个信息的准确性"
请不要猜测或编造信息。""",
    
    # 2. 要求引用来源
    "require_citations": """回答时请标注信息来源。
如果基于参考资料,请引用具体来源编号。
如果基于你的训练知识,请说明"基于我的训练数据"。
如果不确定来源,请标注"[待验证]"。""",
    
    # 3. 区分事实与观点
    "fact_vs_opinion": """请在回答中明确区分:
- [事实] 可验证的客观信息
- [观点] 主观判断或推测
- [共识] 业界普遍接受但可能有争议的内容""",
    
    # 4. 结构化输出
    "structured_output": """请以以下结构化格式回答:
{
  "answer": "核心回答",
  "confidence": "high/medium/low",
  "key_facts": ["关键事实1", "关键事实2"],
  "caveats": ["注意事项", "限制条件"],
  "sources": ["来源说明"]
}"""
}

11.3 技术实施清单

## 事前预防 ✅

- [ ] 实施 RAG 管道,将外部知识注入模型上下文
- [ ] 配置低温度参数(0.0-0.3)用于事实性任务
- [ ] 设计防幻觉系统 Prompt,明确要求承认不确定性
- [ ] 实现文档分块策略,确保检索质量
- [ ] 建立知识库更新机制,保持知识时效性

## 事中检测 ✅

- [ ] 实现原子事实分解与验证
- [ ] 集成 NLI 模型进行事实校验
- [ ] 实施 Self-Consistency 检测
- [ ] 建立外部知识库验证管道(维基百科、专业数据库)
- [ ] 集成 FActScore 评估指标
- [ ] 使用多模型交叉验证

## 事后监控 ✅

- [ ] 建立用户反馈收集机制
- [ ] 实现幻觉率统计与告警
- [ ] 定期进行 A/B 测试评估改进效果
- [ ] 维护幻觉案例库,用于模型微调
- [ ] 建立人工审核流程

## 持续改进 ✅

- [ ] 分析反馈趋势,识别高频幻觉模式
- [ ] 优化 RAG 管道,提高检索准确率
- [ ] 更新系统 Prompt,覆盖新发现的幻觉模式
- [ ] 评估新模型/工具的幻觉表现
- [ ] 定期培训团队,提高幻觉识别能力

11.4 常见陷阱与应对

陷阱 说明 应对方案
过度信任 RAG RAG 检索的内容本身可能有误 验证知识库质量,多源交叉验证
忽略长尾幻觉 只关注高频场景,忽略低频但高危场景 建立全面的测试用例集
检测 ≠ 修正 检测到幻觉但没有修正机制 建立自动修正或人工介入流程
成本过高 全面检测的 API 调用成本高 分级检测,低风险场景简化流程
延迟过高 多重检测增加响应时间 异步检测,先返回再补充验证
误判正常内容 过于严格的检测将正确内容标记为幻觉 调优检测阈值,人工审核边界案例

附录:参考资源

学术论文

  • Min et al., "FActScore: Fine-grained Atomic Evaluation of Factual Precision in Long Form Text Generation" (2023)
  • Ji et al., "Survey of Hallucination in Natural Language Generation" (2023)
  • Zhang et al., "Siren's Song in the AI Ocean: A Survey on Hallucination in Large Language Models" (2023)

工具与框架

社区资源


本教程系统性地覆盖了 AI 幻觉检测与事实性校验的完整知识体系。幻觉问题是当前 LLM 应用最核心的挑战之一,需要技术、流程、人员三位一体的综合应对。建议根据业务场景选择合适的防护策略,持续迭代优化。

内容声明

本文内容为AI技术学习教程,仅供学习参考。如涉及技术问题,欢迎通过 xurj005@163.com 与我们交流。

目录