AI生成内容带来的最大风险不是文字不够流畅,而是错误信息被包装成事实。一篇模型生成的财经分析可能引用不存在的研报,一段自动生成的医疗建议可能混淆药物相互作用。事实核查插件试图把发布前验证变成和拼写检查一样自然的步骤,内容溯源则从来源侧提供可信信号,说明内容由谁生成、经过哪些修改。两类技术并不互斥,组合使用才能在内容生产链路中形成相对完整的治理闭环。

事实核查插件的基本流程与核心模块
事实核查插件通常运行在文本发布前或浏览器侧,接收一段待验证文本,输出可信度评分和证据列表。它的处理链路可以拆成三个模块:声明提取、证据检索、评分裁决。声明提取的目标是把段落中可验证的陈述句识别出来,例如某公司上季度营收增长多少、某药物是否通过临床试验。与关键词匹配不同,这里更适合使用命名实体识别和依存句法分析,避免把背景描述误判为事实声明。可以对spaCy的中文模型进行轻量微调,也可以直接调用大模型接口做少样本抽取。工程上更稳定的做法是先用规则过滤掉过于主观或不可验证的句子,再让模型处理剩余部分。
证据检索模块接收声明列表,向多个来源发起查询。来源可以包括权威新闻数据库、政府公报、学术元数据、维基数据以及商业事实库。查询构造很关键,直接把整句作为搜索词往往效果较差,需要提取主体、时间范围和数值范围,再生成若干候选查询。每个来源返回的摘要会被送入相关性排序模型,保留与声明最接近的三到五条证据。评分模块再对声明和证据进行细粒度推理,输出支持、反驳或信息不足三类结论,并给出0到1之间的置信度。评分不能只依赖关键词重叠,因为反讽和否定表达会带来明显误判。
import hashlib
import json
import re
import requests
FACT_CHECK_API = 'http://127.0.0.1:8000/verify'
CANDIDATE_PATTERNS = [
r'(\d+(?:\.\d+)?%?)',
r'(?:\d{4})年',
r'[A-Z][a-z]+(?:[-\s][A-Z][a-z]+)*'
]
def extract_claims(text):
sentences = re.split(r'[。!?]', text)
claims = []
for sent in sentences:
sent = sent.strip()
if len(sent) < 8:
continue
if any(p in sent for p in ['认为', '可能', '或许']):
continue
claims.append(sent)
return claims
def verify_claim(claim):
payload = json.dumps({'text': claim}, ensure_ascii=False)
resp = requests.post(FACT_CHECK_API, data=payload, timeout=8)
data = resp.json()
claim_hash = hashlib.sha256(claim.encode('utf-8')).hexdigest()
data['content_hash'] = claim_hash
return data
def run_check(text):
results = []
for claim in extract_claims(text):
result = verify_claim(claim)
results.append({
'claim': claim,
'verdict': result.get('verdict'),
'score': result.get('score'),
'sources': result.get('sources', [])
})
return results
该实现只展示了同步调用的情况,生产环境通常会引入异步队列和缓存。重复的声明不必每次都请求外部证据源,可以先根据内容哈希和标准化文本查缓存。缓存命中后直接返回上一次的结论,但需要记录证据版本,避免旧证据长期影响判断。另一个容易忽略的环节是来源可信度加权。不同证据源的历史准确率差异很大,不能简单按命中数量投票。给每个来源维护一个动态权重,并根据后续人工复核结果更新,能显著降低误报率。
内容溯源技术:从指纹、元数据到链上存证
事实核查解决的是内容是否可信,溯源解决的是内容从哪来。如果没有稳定的来源标识,核查结论也很难长期绑定到具体内容上。溯源技术可以分成三层。最底层是内容指纹,用哈希或感知哈希表示一段内容。SHA-256可以直接对字节串生成唯一摘要,但对轻微修改极其敏感,哪怕改一个字哈希就完全不同。感知哈希更适合图像和音频,文本侧则常用SimHash或MinHash来判断近似重复。对于AI生成文本,还可以附加模型水印或生成时的采样特征,不过这类指纹稳定性仍受改写和翻译影响。
中间层是元数据锚定。C2PA规范定义了一套可验证的内容来源信息结构,把拍摄设备、生成软件、编辑操作和作者信息写入文件头或单独清单,并通过数字签名绑定。图像领域已经有相机厂商和Adobe等工具支持,文本领域也在探索类似机制。对于纯文本,可以把来源元数据与正文一起写入JSON结构,生成签名后分发给下游系统。浏览器插件或内容平台读取该结构时,先验证签名是否有效,再展示来源信息。
import hashlib
import hmac
import json
import os
import time
def build_provenance(text, author, model_name):
content_hash = hashlib.sha256(text.encode('utf-8')).hexdigest()
record = {
'content_hash': content_hash,
'author': author,
'model': model_name,
'created_at': int(time.time()),
'edits': []
}
secret = os.environ.get('PROVENANCE_SECRET', 'dev-secret')
payload = json.dumps(record, sort_keys=True, ensure_ascii=False)
signature = hmac.new(secret.encode('utf-8'), payload.encode('utf-8'), hashlib.sha256).hexdigest()
record['signature'] = signature
return record
def verify_provenance(record):
record_copy = dict(record)
signature = record_copy.pop('signature', None)
payload = json.dumps(record_copy, sort_keys=True, ensure_ascii=False)
secret = os.environ.get('PROVENANCE_SECRET', 'dev-secret')
expected = hmac.new(secret.encode('utf-8'), payload.encode('utf-8'), hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature or '')
最上层是链式存证。把内容指纹和元数据摘要写入区块链或可信时间戳服务,可以防止发布后篡改。区块链不适合存储大段正文,但可以存哈希和签名,成本可控。实际系统中常用双层结构:本体存于对象存储或内容库,链上只存指纹和更新指针。这样既能获得不可篡改性,又避免链上数据膨胀。需要注意,链上存证只能证明某个哈希在某个时间点存在过,不能自动证明内容真实。它必须和事实核查结论配合使用,否则只是给虚假内容提供了一份不可篡改的出生证明。
浏览器端事实核查插件的工程实现
把核查能力嵌入编辑器或浏览器,可以覆盖更多非技术用户。浏览器插件通常由content script、background service worker和可选的后台API组成。用户在网页上选中文本或提交评论时,插件提取选中内容,发送到本地或远程核查服务,然后在页面侧边栏或浮动卡片中展示结论。为了不打断用户操作,插件应使用异步消息传递,并设置合理的请求超时。对于AI生成内容平台,也可以在提交按钮前增加一个核查步骤,但需要避免前端直接暴露API密钥。
下面这段扩展代码展示了content script如何向background发送选中文本,并接收核查结果。真实项目中还需要处理跨域、权限声明和用户隐私问题。例如,不要把用户选中的文本发送到未加密的第三方服务,也不要在本地长期保存原文。对于高敏感场景,可以让核查服务以本地模型方式运行,只把标准化声明摘要发往外部证据源。
function getSelectedText() {
return window.getSelection ? window.getSelection().toString() : '';
}
function requestCheck(text) {
return new Promise(function(resolve, reject) {
chrome.runtime.sendMessage(
{type: 'CHECK_TEXT', text: text},
function(response) {
if (chrome.runtime.lastError) {
reject(chrome.runtime.lastError);
return;
}
resolve(response);
}
);
});
}
async function showVerdict() {
const text = getSelectedText();
if (!text || text.length < 10) return;
try {
const result = await requestCheck(text);
const label = document.createElement('span');
label.setAttribute('class', 'fc-verdict');
label.textContent = result.verdict + ' (' + Math.round(result.score * 100) + '%)';
document.body.appendChild(label);
} catch (err) {
console.warn(err);
}
}
插件侧的性能优化重点在缓存和降级。用户不会等待超过一秒钟的核查响应,因此可以把常用声明缓存到浏览器存储中,命中后直接展示。对长文本,可以只提取前几个高置信声明做核查,而不是全文逐句请求。若后台API不可用,插件应降级为只展示本地规则命中的风险提示,例如发现文本中出现未经验证的数值断语或来源缺失,而不是完全静默。还可以在设置中允许用户关闭对特定网站的核查,减少无关请求。
误报、跨语言与工程取舍
事实核查插件最常见的工程难题是误报。把正确的边缘信息判为虚假,会让用户对系统失去信任。误报往往来自证据源覆盖不足、时间错配和跨语言翻译误差。比如中文声明需要查询英文证据库,机器翻译可能改变数值单位或否定词位置。对此可以在评分模型中引入语言一致性特征,并限制证据检索只使用与声明同语种的来源,必要时再做跨语言二次验证。对于时间敏感声明,证据发布早于声明日期可能意味着伪造,但也要处理引用旧数据的情况。
跨语言核查还需要考虑实体消歧。同一个公司名在中文、英文和本地简称中可能完全不一样。实体链接模块应使用多语言知识库和别名表,把声明主体映射到统一标识。若无法高置信度消歧,则宁可输出信息不足,也不要强行匹配。另一个工程取舍是核查粒度。段落级核查快但会漏掉句中错误,句子级核查更精准但请求量更大。可以通过先做段落级粗筛,再对高风险段落做句子级细查,来控制成本和延迟的平衡。
从治理角度看,事实核查插件不能替代平台责任。插件提供的是信号和证据,最终是否拦截、标注还是允许发布,应由平台根据自身规则决定。尤其在涉及公共表达的场景,过度拦截可能带来反效果。更合理的做法是提供分级提示,例如高风险、需复核、来源可信、已通过事实核查等,让编辑和用户自主判断。内容溯源技术的价值也体现在这里,它让标注结果能够跟随内容流转,而不是只停留在最初的发布页面。
随着AI生成内容占比继续上升,把事实核查和溯源能力下沉到工具链,比事后集中清理更有效。但工具本身也需要持续评估误报率、覆盖范围和隐私影响,否则核查系统也可能成为新的信息噪声源。