# verify_ai_output.py
import re
import json
from typing import List, Dict, Any, Optional
from datetime import datetime
import hashlib

class AIOutputVerifier:
    """AI输出验证框架 - 用于检测和防范AI幻觉"""
    
    def __init__(self):
        self.verification_rules = {
            "法律条文": {
                "pattern": r"(《[^》]+》|第[零一二三四五六七八九十百千万\d]+条)",
                "max_confidence": 0.7
            },
            "历史事件": {
                "pattern": r"(\d{4}年|\d+世纪|[古今中外出])",
                "max_confidence": 0.8
            },
            "数学公式": {
                "pattern": r"([\d\+\-\*\/\=\^\(\)]+|[a-z]+[\d\^]+)",
                "max_confidence": 0.9
            }
        }
    
    def fact_check(self, content: str, fact_sources: Dict[str, List[str]]) -> Dict[str, Any]:
        """
        事实核查:对比可信来源
        
        Args:
            content: AI生成的内容
            fact_sources: 可信来源字典,格式如 {"法律": ["法条数据库"], "百科": ["维基百科"]}
        
        Returns:
            事实核查结果
        """
        findings = []
        confidence_scores = []
        
        # 提取内容中的关键声明
        statements = self._extract_statements(content)
        
        for statement in statements:
            # 检查每个声明是否在可信来源中
            verified = self._verify_statement_against_sources(statement, fact_sources)
            findings.append({
                "statement": statement,
                "verified": verified["found"],
                "source": verified["source"],
                "similarity": verified["similarity"]
            })
            confidence_scores.append(verified["similarity"])
        
        # 计算平均可信度
        avg_confidence = sum(confidence_scores) / len(confidence_scores) if confidence_scores else 0
        
        return {
            "平均可信度": avg_confidence,
            "核查声明数": len(findings),
            "已验证声明数": sum(1 for f in findings if f["verified"]),
            "详细结果": findings
        }
    
    def check_logic_consistency(self, content: str) -> Dict[str, Any]:
        """
        逻辑一致性检查
        
        Args:
            content: AI生成的内容
        
        Returns:
            逻辑一致性检查结果
        """
        inconsistencies = []
        
        # 检查时间矛盾
        time_contradictions = self._check_time_contradictions(content)
        inconsistencies.extend(time_contradictions)
        
        # 检查因果关系
        causal_issues = self._check_causal_logic(content)
        inconsistencies.extend(causal_issues)
        
        # 检查数字一致性
        number_inconsistencies = self._check_number_consistency(content)
        inconsistencies.extend(number_inconsistencies)
        
        # 检查自我矛盾
        self_contradictions = self._check_self_contradictions(content)
        inconsistencies.extend(self_contradictions)
        
        return {
            "逻辑一致": len(inconsistencies) == 0,
            "发现问题数": len(inconsistencies),
            "问题详情": inconsistencies,
            "可信度惩罚": min(0.3, len(inconsistencies) * 0.05)
        }
    
    def verify_citations(self, content: str, citation_database: Optional[Dict[str, str]] = None) -> Dict[str, Any]:
        """
        引用溯源验证
        
        Args:
            content: AI生成的内容
            citation_database: 引用数据库,格式如 {"引用原文": "来源"}
        
        Returns:
            引用验证结果
        """
        citations = self._extract_citations(content)
        verified_citations = []
        fake_citations = []
        
        for citation in citations:
            if citation_database and citation in citation_database:
                verified_citations.append({
                    "citation": citation,
                    "source": citation_database[citation],
                    "verified": True
                })
            else:
                fake_citations.append({
                    "citation": citation,
                    "verified": False,
                    "reason": "未在引用数据库中找到"
                })
        
        citation_score = len(verified_citations) / len(citations) if citations else 1.0
        
        return {
            "总引用数": len(citations),
            "已验证引用": len(verified_citations),
            "可疑引用": len(fake_citations),
            "可疑引用详情": fake_citations,
            "可信度评分": citation_score
        }
    
    def cross_validate(self, content: str, models_output: List[str]) -> Dict[str, Any]:
        """
        多模型交叉验证
        
        Args:
            content: 原始AI生成的内容
            models_output: 多个其他模型对同一问题的输出
        
        Returns:
            交叉验证结果
        """
        agreements = []
        
        for other_output in models_output:
            similarity = self._calculate_similarity(content, other_output)
            agreements.append(similarity)
        
        avg_agreement = sum(agreements) / len(agreements) if agreements else 0
        
        return {
            "平均一致性": avg_agreement,
            "各模型一致性": agreements,
            "可信度评分": avg_agreement,
            "建议": "高度一致" if avg_agreement > 0.8 else "存在分歧" if avg_agreement > 0.5 else "严重不一致"
        }
    
    def verify_ai_output(self, output: str, fact_sources: Dict[str, List[str]]) -> Dict[str, Any]:
        """
        主验证函数:综合验证AI输出
        
        Args:
            output: AI生成的内容
            fact_sources: 可信来源字典
        
        Returns:
            完整的验证结果
        """
        verification_result = {
            "可信度评分": 0.0,
            "存疑内容": [],
            "建议操作": "",
            "详细分析": {},
            "时间戳": datetime.now().isoformat()
        }
        
        # 1. 事实核查
        fact_check_result = self.fact_check(output, fact_sources)
        fact_score = fact_check_result["平均可信度"]
        
        # 2. 逻辑一致性检查
        logic_result = self.check_logic_consistency(output)
        logic_score = 1.0 - logic_result["可信度惩罚"]
        
        # 3. 引用溯源验证
        citation_result = self.verify_citations(output)
        citation_score = citation_result["可信度评分"]
        
        # 4. 内容类型识别(检测可疑内容类型)
        suspicious_contents = self._detect_suspicious_content(output)
        
        # 综合评分(加权平均)
        total_score = (fact_score * 0.4 + logic_score * 0.3 + citation_score * 0.3)
        verification_result["可信度评分"] = round(total_score, 3)
        
        # 收集存疑内容
        if fact_check_result["已验证声明数"] < fact_check_result["核查声明数"]:
            unverified = [
                f"未验证声明: {s['statement']}" 
                for s in fact_check_result["详细结果"] 
                if not s["verified"]
            ]
            verification_result["存疑内容"].extend(unverified[:5])
        
        if logic_result["发现问题数"] > 0:
            verification_result["存疑内容"].extend(logic_result["问题详情"][:5])
        
        if citation_result["可疑引用"]:
            suspicious_citations = [
                f"可疑引用: {c['citation']}" 
                for c in citation_result["可疑引用详情"][:3]
            ]
            verification_result["存疑内容"].extend(suspicious_citations)
        
        if suspicious_contents:
            verification_result["存疑内容"].extend(suspicious_contents)
        
        # 建议操作
        if total_score >= 0.8:
            verification_result["建议操作"] = "可直接使用,可信度高"
        elif total_score >= 0.6:
            verification_result["建议操作"] = "建议人工复核存疑内容后使用"
        elif total_score >= 0.4:
            verification_result["建议操作"] = "需人工验证主要声明,谨慎使用"
        else:
            verification_result["建议操作"] = "不建议使用,存在大量虚假或矛盾内容"
        
        verification_result["详细分析"] = {
            "事实核查": fact_check_result,
            "逻辑检查": logic_result,
            "引用验证": citation_result,
            "可疑内容检测": suspicious_contents
        }
        
        return verification_result
    
    # 辅助方法
    def _extract_statements(self, content: str) -> List[str]:
        """提取内容中的关键声明(简化版)"""
        # 按句子分割
        sentences = re.split(r'[。!?;]', content)
        # 过滤掉短句和明显不是声明的句子
        statements = [s.strip() for s in sentences if len(s.strip()) > 10]
        return statements[:10]  # 限制数量
    
    def _verify_statement_against_sources(self, statement: str, sources: Dict[str, List[str]]) -> Dict[str, Any]:
        """验证声明是否在可信来源中"""
        # 简化实现:检查关键词匹配
        for source_type, source_content in sources.items():
            for source_item in source_content:
                # 计算相似度(简化版:关键词重叠)
                statement_words = set(statement)
                source_words = set(source_item)
                if len(statement_words) > 0:
                    similarity = len(statement_words & source_words) / len(statement_words)
                    if similarity > 0.6:
                        return {"found": True, "source": source_type, "similarity": similarity}
        
        return {"found": False, "source": None, "similarity": 0.0}
    
    def _check_time_contradictions(self, content: str) -> List[str]:
        """检查时间矛盾"""
        contradictions = []
        # 提取所有年份
        years = re.findall(r'(\d{4})年', content)
        
        if len(years) >= 2:
            # 检查时间顺序是否合理
            for i in range(len(years) - 1):
                if int(years[i]) > int(years[i + 1]):
                    contradictions.append(f"时间矛盾: {years[i]}年出现在{years[i+1]}年之后")
        
        return contradictions
    
    def _check_causal_logic(self, content: str) -> List[str]:
        """检查因果逻辑"""
        issues = []
        # 检测因果词
        causal_patterns = [
            (r'因为.*所以', '因果关系不完整'),
            (r'由于.*导致', '因果关系需验证'),
        ]
        
        for pattern, msg in causal_patterns:
            if re.search(pattern, content):
                issues.append(msg)
        
        return issues
    
    def _check_number_consistency(self, content: str) -> List[str]:
        """检查数字一致性"""
        issues = []
        # 提取所有数字
        numbers = re.findall(r'(\d+(?:\.\d+)?)(?:万|亿|%)?', content)
        
        if len(numbers) >= 2:
            # 检查明显的数字矛盾
            for i in range(len(numbers) - 1):
                try:
                    num1 = float(numbers[i])
                    num2 = float(numbers[i + 1])
                    # 如果数字相差太大且内容相近
                    if abs(num1 - num2) > 1000 and num1 > 0 and num2 > 0:
                        if num2 / num1 > 10 or num1 / num2 > 10:
                            issues.append(f"数字矛盾: {numbers[i]}{numbers[i+1]} 差异过大")
                except ValueError:
                    pass
        
        return issues
    
    def _check_self_contradictions(self, content: str) -> List[str]:
        """检查自我矛盾"""
        contradictions = []
        # 检测A是B和A不是B同时出现
        sentences = re.split(r'[。!?;]', content)
        
        for i, sent1 in enumerate(sentences):
            for sent2 in sentences[i+1:]:
                if self._are_contradictory(sent1, sent2):
                    # 截取前30个字符避免过长
                    sent1_short = sent1[:30] + "..." if len(sent1) > 30 else sent1
                    sent2_short = sent2[:30] + "..." if len(sent2) > 30 else sent2
                    contradictions.append(f"矛盾: '{sent1_short}' vs '{sent2_short}'")
        
        return contradictions[:3]
    
    def _are_contradictory(self, sent1: str, sent2: str) -> bool:
        """判断两个句子是否矛盾(简化版)"""
        # 检测简单的肯定/否定模式
        positive_patterns = ['是', '属于', '为', '即', '就是']
        negative_patterns = ['不是', '不属于', '并非', '不为', '不是']
        
        has_pos1 = any(p in sent1 for p in positive_patterns)
        has_neg1 = any(n in sent1 for n in negative_patterns)
        has_pos2 = any(p in sent2 for p in positive_patterns)
        has_neg2 = any(n in sent2 for n in negative_patterns)
        
        # 如果一个是肯定一个是否定,且主语相似,可能矛盾
        if (has_pos1 and has_neg2) or (has_neg1 and has_pos2):
            # 提取主语(简化版:取前10个字符)
            subject1 = sent1[:10]
            subject2 = sent2[:10]
            if subject1 == subject2 or subject1 in sent2 or subject2 in sent1:
                return True
        
        return False
    
    def _extract_citations(self, content: str) -> List[str]:
        """提取引用内容"""
        citations = []
        # 匹配引号内的内容
        citations.extend(re.findall(r'[\'"]([^\'"]+)[\'"]', content))
        # 匹配括号引用
        citations.extend(re.findall(r'[((]([^))]+)[))]', content))
        # 匹配书名号
        citations.extend(re.findall(r'《([^》]+)》', content))
        return list(set(citations))  # 去重
    
    def _calculate_similarity(self, text1: str, text2: str) -> float:
        """计算两个文本的相似度(简化版)"""
        words1 = set(text1)
        words2 = set(text2)
        
        if not words1 or not words2:
            return 0.0
        
        intersection = len(words1 & words2)
        union = len(words1 | words2)
        
        return intersection / union if union > 0 else 0.0
    
    def _detect_suspicious_content(self, content: str) -> List[str]:
        """检测可疑内容类型"""
        suspicious = []
        
        for content_type, rule in self.verification_rules.items():
            matches = re.findall(rule["pattern"], content)
            if len(matches) > 3:  # 如果某个类型出现太频繁
                suspicious.append(f"大量{content_type}相关内容,建议重点验证")
        
        # 检测过度绝对化的表述
        absolute_words = ['所有', '全部', '绝对', '永远', '从不', '总是', '一定', '肯定']
        for word in absolute_words:
            if word in content:
                suspicious.append(f"使用了绝对化表述'{word}',可能过于武断")
        
        return suspicious[:5]


# 使用示例
if __name__ == "__main__":
    # 初始化验证器
    verifier = AIOutputVerifier()
    
    # 测试AI输出(包含幻觉的例子)
    ai_output = """
    根据《人工智能管理法》第250条规定,所有AI系统必须注册。这项法律在2025年正式生效。
    实际上,AI永远不可能产生真正的创造力。爱因斯坦曾经说过:"人工智能是未来最大的威胁"。
    这个观点在《AI与未来》一书中有详细论述,该书出版于2018年,销售额达到500万册。
    但是统计数据又显示AI创造力相关论文从2019年的100篇增长到2020年的200篇,增长率为150%。
    """
    
    # 定义可信来源
    fact_sources = {
        "法律": ["《人工智能法》", "《数据安全法》", "《个人信息保护法》"],
        "百科": ["爱因斯坦是著名物理学家", "AI创造力研究是热点领域"],
        "事实": ["2025年尚未到来", "AI正在辅助人类创造"]
    }
    
    # 执行验证
    result = verifier.verify_ai_output(ai_output, fact_sources)
    
    # 打印结果
    print("=" * 60)
    print("AI输出验证报告")
    print("=" * 60)
    print(f"时间戳: {result['时间戳']}")
    print(f"可信度评分: {result['可信度评分']}/1.0")
    print(f"建议操作: {result['建议操作']}")
    print(f"\n存疑内容 ({len(result['存疑内容'])}条):")
    for i, doubt in enumerate(result['存疑内容'], 1):
        print(f"  {i}. {doubt}")
    
    print("\n详细分析:")
    fact_check = result['详细分析']['事实核查']
    print(f"  事实核查: 已验证 {fact_check['已验证声明数']}/{fact_check['核查声明数']} 条声明")
    
    logic_check = result['详细分析']['逻辑检查']
    if logic_check['逻辑一致']:
        print(f"  逻辑检查: 通过")
    else:
        print(f"  逻辑检查: 发现{logic_check['发现问题数']}个问题")
    
    citation_check = result['详细分析']['引用验证']
    print(f"  引用验证: 可信度 {citation_check['可信度评分']:.2f}")
    
    print("\n" + "=" * 60)

运行结果:

(ai_env) $ python3 verify_ai_output.py
============================================================
AI输出验证报告
============================================================
时间戳: 2026-04-04T19:41:23.058535
可信度评分: 0.24/1.0
建议操作: 不建议使用,存在大量虚假或矛盾内容

存疑内容 (16条):
  1. 未验证声明: 根据《人工智能管理法》第250条规定,所有AI系统必须注册
  2. 未验证声明: 这项法律在2025年正式生效
  3. 未验证声明: 实际上,AI永远不可能产生真正的创造力
  4. 未验证声明: 爱因斯坦曾经说过:"人工智能是未来最大的威胁"
  5. 未验证声明: 这个观点在《AI与未来》一书中有详细论述,该书出版于2018年,销售额达到500万册
  6. 时间矛盾: 2025年出现在2018年之后
  7. 数字矛盾: 2019 和 100 差异过大
  8. 数字矛盾: 100 和 2020 差异过大
  9. 数字矛盾: 2020 和 200 差异过大
  10. 可疑引用: AI与未来
  11. 可疑引用: 人工智能是未来最大的威胁
  12. 可疑引用: 人工智能管理法
  13. 大量历史事件相关内容,建议重点验证
  14. 大量数学公式相关内容,建议重点验证
  15. 使用了绝对化表述'所有',可能过于武断
  16. 使用了绝对化表述'永远',可能过于武断

详细分析:
  事实核查: 已验证 0/6 条声明
  逻辑检查: 发现4个问题
  引用验证: 可信度 0.00

============================================================
(ai_env) $ 
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐