最近我在做一件有意思的事情:拿AI生成的新闻稿去跑事实核查器,看它到底能不能识别出哪些是编造的。起因很简单,我手头收到一条AI写的科技新闻,说某公司发布了一款量子芯片,运算速度提升1000倍,还引用了一位“专家”的原话。整篇稿子结构完整、数据详实,读起来毫无破绽,但我觉得不对劲,一查发现那家公司根本不存在。从那以后我就开始系统性地搭建一套基于事实核查器的AI新闻验证流程,这篇文章就是这次实践探索的完整记录。如果你也在做内容审核、AI安全、新闻风控,或者单纯好奇“AI怎么分辨AI编的故事”,这篇文章应该能给到你一些能直接落地的思路。
先说结论:事实核查器不是万能的,但它能帮你把“看起来很像真的”的AI新闻,快速拆成一个个可验证的声明,再通过外部证据链做交叉比对,最后告诉你哪些可信、哪些存疑、哪些基本可以断定是编的。整个过程有清晰的套路可循,也能用开源工具搭一个小型demo跑起来。
1. AI生成新闻为什么容易“一本正经地胡说八道”
1.1 三类最常见的“虚假”表现
AI生成新闻的虚假,不是传统意义上的“谎话”,它更像是一种“自信的臆想”。我拆了很多条AI生成稿,发现虚假信息主要落在三个类别里。
第一类是事实性幻觉,也就是硬伤。人名、地名、日期、数字、机构名称搞错,或者干脆凭空捏造。最典型的就是“引用幻觉”,AI会虚构一篇论文标题、一个研究报告,甚至一个专家的姓名和头衔。我在测试中遇到过AI一本正经地引用“2024年《自然·能源》上发表的某项研究”,但那期的目录里根本没有这篇文章。这类错误在纯文本模型里尤其常见,因为模型在生成时会基于概率补齐“最合理”的引用格式,而不是检索真实的文献库。
第二类是逻辑性幻觉,也就是因果链断裂或者过度推断。比如“因为这家公司申请了一项专利,所以它一定已经推出成熟产品”,明显是跳跃式推导。AI在长文本生成中容易把“可能”“预计”等词在日常训练中高频出现,所以最终成稿里那些看似严谨的推论,其实底层只是一串概率选择。
第三类是时效性错乱。AI训练语料有截止时间,它无法区分“现在的”和“过去的”情况。比如一条新闻说“某城市正在建设大型数据中心”,但事实是该项目五年前就已完工,AI只是把语料里的“未来时态”直接当成了现在进行时。这类错误用静态模型很难发现,必须结合外部实时数据才能识别。
1.2 幻觉的根源:从生成机制里找线索
要理解为什么AI会编造,就得从它的生成机制说起。大语言模型本质上是在做“下一个token预测”,它学到的不是“世界的真实状态”,而是“语料里文本的分布规律”。所以当一个事实在训练语料中出现次数足够多时,模型能“记住”它;但如果某个信息是稀疏的、或者被语料中的噪声污染了,模型就会按最平滑、最连贯的方式“补齐”,这就是幻觉的来源。
举个例子:模型看到一批关于“人工智能辅助诊断癌症”的语料,其中有几篇提到“准确率达到95%”,那么当你问它相关问题时,它很可能就脱口而出“AI辅助诊断的准确率可达95%”,哪怕放在特定医院场景下这个数字根本不成立。因为它不是在“回忆”某一篇特定论文,而是在“合成”一个看起来最像答案的文本。
另外,RLHF(基于人类反馈的强化学习)阶段也会放大这个问题。训练时人类标注员往往更喜欢“表述流畅、信息密度高”的回答,而这类回答天然倾向于给出确定性的数字和结论,而不是“不清楚”“需要进一步核实”。于是模型就更倾向于自信地编造,而不是诚实地承认知识缺口。
理解这一点很重要,因为你没法靠“让AI自己检查自己”来杜绝幻觉——它检查时用的还是同一套概率机制,错误模式是相关的。这也是为什么事实核查器一定要引入外部证据源,而不是单纯用另一个AI去“阅读”原新闻并判断真假。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 事实核查器的整体设计思路:从单点判断走向全链路验证
2.1 事实核查器到底在做什么
事实核查器(Fact Checker)并不是一个单一模型,而是一套流水线。它的核心任务可以拆成三个子问题:这条新闻里有哪些可被验证的“声明”?每个声明能找到哪些外部证据?根据证据,该声明应该被判定为“支持”“矛盾”还是“证据不足”?
如果你去读学术论文,会发现这个任务有个专门的名字叫“Automated Fact-Checking”,主流框架就是刚才说的三段式:Claim Extraction(声明抽取)、Evidence Retrieval(证据检索)、Veracity Classification(真实性判定)。我最初以为最核心的是第三步判定模型,但实际跑下来发现,证据检索才决定了整个系统的上限。检索不到正确证据,后面的判断再强也是白搭。
这个框架和人类记者的核查流程非常像。记者拿到一条线索,不会直接信,而是先拆解出“谁说”“在哪”“什么时候”“什么数据”几个可查点,然后去公开资料库、采访记录、官方文件里找对照,最后判断每条陈述是否站得住脚。事实核查器只不过是把这套流程自动化了。
2.2 为什么不能只靠“AI判断AI”
很多人第一反应是:既然AI会编,那就拿另一个AI来审它,不就行了吗?这个思路方向上是对的,但实践中有两个坑。
第一个坑叫自我偏好。大模型在判断“另一个模型生成的内容是否可信”时,会对“与自身输出风格相似”的文本给出更高的可信度。而我测试中的AI新闻稿,风格恰恰也是标准的大模型“公文风”,所以让同一个系列的模型去审,它很容易给出“表述合理、内容可信”的误判。
第二个坑是事实锁定效应。如果你把整条新闻原文直接喂给判断模型,并让它判断真假,模型很容易被原文里的“细节”带走,陷入“细节越丰富越可信”的偏见。它会优先关注句子是否流畅、逻辑是否自洽,而不是去验证外部事实。这在认知科学里叫“流畅性启发”——我们人类也一样,越读着顺的内容越容易信。所以判断环节必须把原文中的单个声明单独拆出来,与独立检索到的证据文本并排比对,而不是让模型“通读全文后凭感觉打分”。
2.3 一条实用的核查流水线
经过几轮迭代,我最终采用的流水线是这样:
- 声明切分:把整篇AI新闻拆成若干个独立、完整、可验证的短句或片段。拆分的粒度很关键,太粗(整段)会导致判断困难,太细(半句话)又会丢失上下文。
- 查询构造:基于每个声明生成一个或多个查询词。这个查询词既要包含核心实体(公司名、人名、地名、数字范围),也要加上限定词(年份、领域、事件类型)。
- 证据检索:用查询词去检索百科、新闻数据库、搜索引擎,拿到3-5条候选证据片段。证据的质量远比数量重要,我一般会过滤掉个人博客、论坛等低权威来源。
- 证据-声明配对判断:把“声明 + 证据文本”作为输入给判定模型,让模型输出三个标签之一:支持(SUPPORTED)、矛盾(REFUTED)、证据不足(NOT ENOUGH INFO)。
- 聚合输出:如果一条新闻里的关键声明中有超过半数被判为“矛盾”或“证据不足”,我就把它标记为“高风险疑似虚假新闻”。
这套流程看着简单,但每一个环节都有不少细节坑,下面我用一个真实的测试样本把整个实操过程走一遍。
3. 实操:搭建一个可复现的AI新闻事实核查流程
3.1 环境准备与开源工具选型
我这次搭建的demo完全基于Python,所有工具尽量选开源的,方便你直接复制去跑。我的环境是Python 3.10,主要用到了这么几个库:
requests:调用百科API和搜索引擎接口,做证据检索,不引入过重的爬虫框架。transformers+torch:加载开源NLI(自然语言推理)模型做声明-证据的蕴含关系判断。我测试时用了MoritzLaurer/mDeBERTa-v3-base-mnli-xnli,它支持多语种,能覆盖中英文新闻。duckduckgo_search:一个DuckDuckGo搜索的Python封装,适合快速抓取网页摘要作为候选证据。langchain(可选):如果你打算接GPT系列或Claude做判断,langchain能减少很多prompt拼接的样板代码。
安装命令很简单:
bash复制pip install requests duckduckgo-search transformers torch
如果你的机器没有GPU也没关系,这个NLI模型很小,跑CPU也能在几十秒内完成单条判断。
提示:依赖OpenAI或Claude API做判断也可以,而且对“非规范化表述”的纠错能力更强,但费用和隐私是两道坎。自托管开源NLI模型的好处是敏感新闻文本不需要离开自己的服务器。
3.2 第一步:把新闻拆成可核查的声明
我准备了一条用于演示的AI生成新闻,内容如下:
“艾克能源公司于2025年3月正式发布了新型固态电池,能量密度达到每公斤600瓦时,号称是当前商用电池的两倍以上。该公司首席技术官张伟表示,这款电池已通过安全测试,将在2025年第四季度量产。”
第一步是声明切分。我并不是简单按句号切,而是把句子拆成“事实单元”。例如第一句里就藏着三个事实单元:
- 艾克能源公司发布了新型固态电池
- 发布时间是2025年3月
- 能量密度达到每公斤600瓦时
第二句里也藏着两个:
- 公司首席技术官是张伟
- 张伟声称电池已通过安全测试
为什么不能直接把整句丢进去判断?因为一个长句可能一半为真一半为假,模型给出的“支持/矛盾”标签等于在混合信号里猜权重,准确率很不稳定。拆成事实单元后,每个标签都有明确的指向,聚合时也更可控。
你可以写一个简单的正则或基于语言模型的拆分器,但我实践中发现,对于中文AI新闻,用LLM做拆分是最省事的。让模型输出JSON数组,每个单元是“主谓宾”清晰的一句话。如果你不想引入LLM,也可以退而求其次,按标点切分后用命名实体识别(NER)筛出包含关键实体的子句。
3.3 第二步:证据检索
拿到声明后,我会构造检索query。核心原则是:**query里必须包含“最有辨识度的实体”,而不要带上太多修饰词。**例如“能量密度达到每公斤600瓦时”这个声明,检索query可以构造为“固态电池 600瓦时 能量密度 商用”;而“艾克能源公司 2025年3月 固态电池发布会”则用来查公司本身是否真实存在。
我用两套检索源互相校验:
第一套是百科类API。以中文百科为例,用 requests 直接请求:
python复制def search_wiki(keyword):
url = "https://zh.wikipedia.org/w/api.php"
params = {
"action": "query",
"list": "search",
"srsearch": keyword,
"format": "json",
"srlimit": 3
}
resp = requests.get(url, params=params, timeout=10)
data = resp.json()
results = [item["snippet"] for item in data["query"]["search"]]
return results
这套接口需要能正常访问百科服务,如果在内网环境就不适用,所以我又加了第二套兜底:用 duckduckgo_search 抓常规网页摘要。
python复制from duckduckgo_search import DDGS
def search_web(keyword, max_results=5):
with DDGS() as ddgs:
results = list(ddgs.text(keyword, max_results=max_results))
return [r["body"] for r in results]
一个很实用的细节是:在检索“公司是否存在”这类声明时,别只看搜索结果里“有没有”这个词,还要看结果源的类型。如果返回的全是招聘网站、企业黄页、自媒体软文,那这个“公司”很可能是刚注册的壳,新闻里描述的“重磅发布会”就高度可疑。如果返回结果里有技术论坛的原帖、实体产品的测评页面,那可信度就明显更高。
3.4 第三步:可信度判定
证据检索完成后,进入判定环节。我把“声明 + 证据文本”拼成一个prompt,交给NLI模型判断蕴含关系。以mDeBERTa模型为例:
python复制from transformers import pipeline
classifier = pipeline(
"zero-shot-classification",
model="MoritzLaurer/mDeBERTa-v3-base-mnli-xnli",
device=0 # 没有GPU就写-1
)
def verify_claim(claim, evidence_list):
# 把多段证据合并成一段,限定长度避免超限
evidence_text = "\n".join(evidence_list)[:2000]
result = classifier(
claim,
candidate_labels=["支持", "矛盾", "证据不足"],
hypothesis_template="这段证据{}。"
)
return result["labels"][0], result["scores"][0]
这个模型本质上是一个多语种的NLI模型,输入是“前提(evidence)”和“假设(claim)”,输出是“蕴含/矛盾/中立”的概率。在zero-shot模式下,我通过candidate_labels把它包装成三分类。跑出来的结果一般比较接近我人工判断。
另外,如果判断结果出现“支持”,我还会看一个东西:证据里是否真的出现了和声明一致的“数值”或“时间”。NLI模型有可能会因为语义相近而给出“支持”,比如声明是“能量密度600Wh/kg”,证据里是“实验室环境下能量密度达610Wh/kg”,这其实是接近但不完全一致,严格来说应该判“证据不足”。所以我后来加了一条规则:如果声明中包含明确的数字、日期、人名,程序会自动做一次字符串匹配,标准不一致时把NLI的“支持”强制降级为“证据不足”。这个小改动让我的整体准确率提升了近8%。
3.5 一个完整的示例流程
我把上面三步串起来,写成一个简单的核查函数,用开头那条“艾克能源公司”的新闻跑了一遍。结果如下:
- 声明1“艾克能源公司发布固态电池”:证据检索没有找到任何公司官网或权威科技媒体报道,只有几个垃圾SEO页面,判定为“证据不足”,但还不能断定是假。
- 声明2“发布时间2025年3月”:同样没有独立来源,结合声明1的结果,这两个事实单元互相强化了“不存在该公司”的嫌疑。
- 声明3“能量密度600Wh/kg”:检索到了多篇关于固态电池能量密度的科普文章,但最高到500Wh/kg左右,没看到600Wh/kg的量产或实验室数据,判定为“矛盾”。
- 声明4“CTO张伟”:搜索结果里的张伟是互联网行业的人,与电池公司无关,判定为“矛盾”。
5个关键声明里2个矛盾、3个证据不足,最终这条新闻被打上“高风险疑似虚假”标签。后续我用人工复核,确认这个公司确实不存在。这个例子充分说明,事实核查器不需要在单条声明上做到100%的“铁口直断”,聚合多个弱信号也能得出可靠结论。
4. 实测结果与三类典型失败模式
4.1 我在三组测试样本上的实测数据
为了验证这套流程的可靠程度,我准备了三组测试数据,每组10条新闻:
- A组:完全由AI生成,内容属于“技术突破类”,包含大量编造的公司名和引文。
- B组:真新闻改写,把真实科技新闻的发布方、数值改掉一部分,制造“半真半假”的效果。
- C组:真实新闻原文,来自权威科技媒体,未做改动。
跑完一遍整体结果如下:
| 测试组 | 正确识别为可疑 | 误判为可信 | 误判为可疑 | 准确率 |
|---|---|---|---|---|
| A组(完全AI编造) | 9 | 1 | - | 90% |
| B组(半真半假) | 6 | 4 | - | 60% |
| C组(真实新闻) | - | 9 | 1 | 90% |
B组的准确率掉到60%,这是一个很重要的信号:事实核查器目前最大的软肋,是识别“半真半假”的新闻。A组的编造内容往往在实体和数字上有硬伤,检索时很容易现出原形;但B组只在关键数字或细节上做手脚,其他内容都是真的,证据检索经常会找到“支持”的证据片段,从而漏判。这也意味着,如果你的业务场景是审核那些“改写真实事件”的AI媒体稿,这套自动化流程只能作为辅助,必须叠加更细粒度的人工复核。
4.2 典型失败模式一:证据缺失但不代表虚假
我第一次跑A组测试时,有两条AI新闻被判成了“证据不足”而不是“矛盾”。原因在于,检索API没有返回足够的相关页面,NLI模型直接给了“证据不足”标签。但当我人工搜索后,发现这些AI新闻完全是在真实公司基础上做了夸张化处理,真实公司的新闻稿是存在的,只是关键词组合方式太独特,检索引擎没能匹配上。
这个问题的根源是“证据检索覆盖率不足”。解决办法有两个方向:一是增加查询变体,比如用“公司英文名 + 技术名”再搜一次;二是放宽检索结果的数量,从5条扩大到10条。经过这两项调整后,A组遗漏的两条都被捞了回来。记住一个原则:“证据不足”不直接等于“虚假”,它只是说当前证据对判断没有帮助,需要进一步换检索方式。
4.3 典型失败模式二:宏观与微观混淆
还有一类失败案例是模型把“行业普遍情况”和“这家公司的具体情况”混为一谈。测试样本里有一条AI新闻说“某公司的新型电池能量密度达到1000Wh/kg”,证据检索返回的是一篇行业综述,里面写着“未来十年固态电池有望达到1000Wh/kg”。NLI模型判断为“支持”,但仔细看,证据描述的是“未来可能性”,而声明描述的是“当前已经实现”,这明显是概念偷换。
这类问题单纯靠NLI模型很难解决,需要额外增加一个“模态判断”模块,区分“事实陈述”“未来预测”“主观评价”三者的关系。我在实践中做了一个粗糙但有效的规则:如果在声明中出现“已经”“正式”“完成”等完成时态标记,而证据中出现“可能”“预计”“有望”等推测性词语,则强制判定为“矛盾”。
4.4 典型失败模式三:反事实表达
第三类失败更隐蔽。AI生成的新闻有时会包含“此前从未有公司实现XXX”这种表述,这类声明的验证逻辑是“全称否定”。理论上,只要找到一例“某公司实现了XXX”的证据,就可以判定声明为假,但NLI模型在处理否定句时表现并不好,经常会因为语义框架相似而误判为“支持”。
我试过专门用中文反事实数据集微调NLI模型,但成本太高。更务实的做法是在预处理阶段对声明里的否定词(“没有”“从未”“不再”)做标记,然后把反事实声明拆成“否定部分 + 被否定的事实”,先去检索被否定的事实是否成立,再反过来判断原声明的真假。这一步在代码里实现也不复杂,但对于准确率的提升非常明显。
5. 常见问题与排查技巧实录
5.1 检索阶段:检索不到相关证据怎么办
这是出现频率最高的问题。我遇到过两种情况:一种是新闻里的实体太新,搜索引擎的索引还没跟上;另一种是声明描述得太模糊,比如“某研究机构近期发布报告显示”,完全没法定位是哪个机构。
我的处理套路是这样的:
- 尝试提取声明中的“实体名词”,只拿实体去检索,而不是拿整个长句。比如“某研究机构近期发布报告”就去提取“研究机构”的指代,看前文是否提到过具体名字。
- 如果实体提取为空,就把query改成“声明主题词 + 年份”,比如“固态电池 2025 能量密度”,扩大检索范围。
- 如果检索结果还是不理想,换一个检索源,我经常在百科API、DuckDuckGo、Bing Search三个源之间交叉切换。
另外,DuckDuckGo的搜索结果在短时间内请求频繁会被限流,我在代码里增加了一个随机延时,平均每次请求间隔2-3秒,能明显降低被封的概率。
5.2 判断阶段:模型置信度很低怎么办
NLI模型输出的三个标签概率如果都很接近(比如支持0.34、矛盾0.33、证据不足0.33),那说明模型自己也在“瞎猜”。这时候千万不要硬选概率最高的那个,我建议直接把这条声明标记为“待人工复核”。
模型置信度过低通常有两种原因:一是声明里含有多重否定或嵌套修饰,超出了模型的语义理解范围;二是证据文本和声明讨论的是同一个主题,但角度完全对不上。你可以试试把证据片段截短到300字以内再跑一次,往往置信度会有明显提升。长证据会让模型注意力分散,被不相关的细节拉低判断质量。
5.3 一个关于成本的实用建议
最后聊一下成本。我在测试时尝试过两种判断方案:第一种是本地跑开源NLI模型,零成本,但准确率大约在80%左右;第二种是调用GPT-4o或Claude的API做judge,准确率能到90%以上,但每条新闻的核查成本大约在0.2到0.5元人民币,取决于证据片段数量和声明的数量。
如果你要处理的是大规模新闻流,我建议采用“两级漏斗”:先用本地NLI模型做粗筛,把置信度高的声明直接采信;只有置信度中等和偏低的声明才送进大模型API做二次判断。这样能把成本降低60%以上,同时保住大部分准确率。
我个人在实际操作中最深的感受是:事实核查器不是用来替代人类判断的,它的价值在于帮你把“需要人工重点看的地方”精准地圈出来。纯自动化100%正确目前不现实,但把AI新闻的存稿量缩小到原来的1/10,完全没问题。这套流程我跑了将近一个月,最大的变化是我不再容易被那些“细节丰富、语气笃定”的AI稿带跑了——面对新闻,先拆声明,再找证据,最后下判断,这个习惯值得所有人培养。
