ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI文本检测实战:用困惑度与突发性识别AI生成内容

AI文本检测实战:用困惑度与突发性识别AI生成内容 有读者最近在 HN 上提了一个很有意思的问题Discovery探索频道是不是在大量使用 AI这个问题表面上是媒体观察但对技术人员来说它背后藏着一个非常实际的课题——当 AI 生成的内容越来越多地出现在信息流、短视频、节目旁白甚至纪录片脚本里我们能不能用工程手段判断“这段内容到底是不是 AI 生成的”。本文会把这个问题拆解成一个可落地的工程实践先从 AI 内容生成的原理讲起再带大家实现一个基于困惑度Perplexity和突发性Burstiness的 AI 文本检测小工具最后结合开源 AI 小镇类项目聊聊 AI 生成内容在模拟场景中的实际应用。无论你是刚开始接触大模型的初学者还是已经在做内容风控、数据标注的开发者都能从这篇文章里拿到一套可以跑的代码和排查思路。1. 从“Discovery 是否用 AI”到 AI 内容识别1.1 一个提问背后的三个层面标题中的问题“Ask HN: Is discovery channel using AI?”如果只看表面似乎只需要回答“是”或“不是”。但真正深入进去问题会拆成三个层面媒体机构是否把 AI 用在选题策划、字幕生成、剪辑辅助上频道内容是否由 AI 自动生成比如旁白稿、新闻快讯、短视频解说词作为一个普通观众或平台运营者如何判断一段内容是否由 AI 生成第一个层面是业务流程问题很多内容平台确实已经在内部使用 AI 辅助工具这并不稀奇。第二个层面是内容生产方式问题涉及 AI 生成内容的比例和质量。第三个层面才是技术人员能真正发挥价值的地方用算法检测 AI 生成文本而不是靠肉眼猜。在公开信息不足的情况下直接断言某个频道是否使用了 AI 并不严谨但我们完全可以掌握一套判断内容是否由 AI 生成的技术方案。这也是本文的出发点。1.2 AI 内容生成是什么AI 内容生成通俗地说就是让大语言模型基于海量语料学习到的统计规律逐个 token词或字地预测下一个最可能出现的词从而拼出一段完整文本。以 ChatGPT、Claude、文心一言等为代表的生成式 AI本质上都在做同一件事根据上文计算下一个词的概率分布。这种生成方式有一个明显的特征模型倾向于输出“概率较高”的词整体文本非常流畅、连贯很少出现人类写作中常见的犹豫、反复和跳跃。因此AI 生成文本通常在语言层非常平滑但这并不意味着它是真实、准确的。这里需要区分两个容易混淆的概念AI 辅助内容由人类写作者主导AI 帮忙优化措辞、生成大纲、校正语法。AI 生成内容模型直接生产核心文本人类只是做筛选或轻度编辑。从检测角度来说前者往往更难识别因为它混合了人类和机器的写作模式。本文实现的工具主要面向后者也就是“完整段落由模型生成”的场景。1.3 AI 幻觉对检测的影响在讨论 AI 内容生成时不得不提“AI 幻觉”。所谓幻觉是指模型生成了一段看似合理、语法完全正确但事实错误或凭空捏造的内容。比如让模型描述一个不存在的 API它可能会编出像模像样的参数列表。幻觉和高流畅度是两个叠加的信号流畅度让 AI 文本容易被当成真内容。幻觉让 AI 文本在事实核查时露出破绽。因此在实际项目中检测 AI 生成内容通常不是单一维度而是把文本统计特征、事实一致性、发布渠道信息结合起来看。下面我们会从文本统计特征入手先实现一个能跑的检测工具。2. 判断 AI 生成内容的四种技术路线2.1 统计特征困惑度与突发性在 AI 文本检测领域有两个非常经典的统计指标困惑度PerplexityPPL和突发性Burstiness。困惑度衡量的是模型对一段文本的“意外程度”。如果一段文本是某个生成模型写出来的那么用同一个模型去计算它的困惑度通常会比较低因为模型输出的内容本身就符合它自己的概率分布。反过来人类写作的句子有更多变化模型预测起来更吃力困惑度通常更高。突发性衡量的是一段文本中词语出现频率分布的波动程度。用比较容易理解的话说AI 生成文本往往用词比较均匀高频词和低频词的差异相对稳定而人类写作时经常会出现某个词在一段里反复出现、换个段落又完全消失的情况。突发性指标就是捕捉这种“时多时少”的波动。这两个指标都可以用 Python 自己实现不需要调用商业 API这也是本教程选择它的原因。2.2 分类器与微调第二种思路是训练一个二分类器准备一批人类写作文本和一批 AI 生成文本提取特征后训练模型判断新文本属于哪一类。这种方法在思路上很直接但工程上有一个绕不开的坑训练数据的标签本身会过期。AI 模型两三个月就更新一次新的生成文本分布和旧样本差异很大分类器很容易出现“训练时准确率很高、上线后快速衰减”的情况。因此分类器方案更适合做内部辅助工具而不是长期稳定运行的风控系统。2.3 水印与溯源还有一种更可靠的思路是“水印”。生成模型在输出文本时可以在 token 选择过程中嵌入一种肉眼不可见、但算法可验证的统计规律。只要内容是通过支持水印的模型生成的检测方就能高置信度地判断来源。水印方案的优点是误报率极低缺点是它只对“特定模型生成的内容”有效如果文本来自没有水印机制的开源模型检测方就无能为力了。在实际落地中水印通常用于平台自产内容的管理而不是识别全网内容。2.4 实际场景如何组合真实的内容风控系统不会只依赖一种方法。常见的组合方式是先用统计特征困惑度 突发性做粗筛把明显疑似 AI 生成的文本捞出来。对粗筛命中的内容做分类器二次打分。如果是平台自营模型产生的内容再核验水印。最后人工复核高置信度样本并把复核结果回填到训练数据中。本文的实战部分会完整实现第一步也就是统计特征粗筛。这是后续所有方案的基础也是最容易上手的部分。3. 环境准备与依赖安装3.1 运行环境与版本说明本文代码以 Python 3.9 以上版本为例操作系统不限Windows、macOS、Linux 都可以运行。需要安装的核心依赖如下transformersHugging Face 的模型加载与推理库。torchPyTorch作为模型运行后端。numpy数值计算。jieba中文分词工具用于处理中文文本。版本需要根据你的项目实际情况调整。本文示例以常见环境为例重点演示配置思路。如果你的设备没有 GPUCPU 也能运行只是模型推理速度会慢一些建议选择参数量较小的模型做实验。3.2 安装依赖建议先创建一个虚拟环境避免依赖冲突python -m venv ai_detect_env source ai_detect_env/bin/activate # Windows 上使用 ai_detect_env\Scripts\activate然后安装依赖pip install transformers torch numpy jieba如果网络环境允许也可以直接安装对应版本。安装完成后检查 transformers 是否能正常导入python -c from transformers import AutoTokenizer, AutoModelForCausalLM; print(ok)如果输出ok说明环境就绪。3.3 项目结构我们的项目结构非常简单适合作为小型工具直接使用ai_detect/ ├── detector.py # 核心检测函数 ├── run_detection.py # 命令行运行入口 ├── data/ │ └── sample.txt # 待检测文本 └── requirements.txt # 依赖清单实际使用时你可以把data/sample.txt替换成任意一段从网页、视频字幕或文档中提取的文本。4. 核心实现——基于困惑度和突发性的检测工具4.1 困惑度Perplexity如何计算困惑度的计算原理并不复杂。简单来说我们用语言模型给一段文本打分模型认为这段文本越“正常”困惑度越低。数学形式可以理解成模型对每个 token 预测概率的平均倒数。在代码里我们可以借助AutoModelForCausalLM直接拿到模型的交叉熵损失再对损失做指数运算得到困惑度。为了方便处理长文本这里加入了一个滑窗逻辑避免文本长度超过模型输入上限。4.2 突发性Burstiness如何计算突发性的实现相对简单。我们先对文本做分词统计每个词出现的次数然后计算这些次数分布的标准差与均值的比值。如果比值较高说明词语出现频率波动明显更像是人类写作风格如果比值偏低说明用词比较均匀疑似 AI 生成。4.3 完整检测工具代码下面是核心代码可以直接保存为detector.py# 文件路径ai_detect/detector.py import numpy as np import torch import jieba from transformers import AutoTokenizer, AutoModelForCausalLM def compute_perplexity(text, tokenizer, model, max_length512, stride128): 计算文本困惑度。 思路用语言模型对文本进行打分困惑度越低说明文本越符合模型分布。 encodings tokenizer(text, return_tensorspt) input_ids encodings.input_ids.to(model.device) seq_len input_ids.size(1) nll_sum 0.0 token_count 0 prev_end 0 for begin in range(0, seq_len, stride): end min(begin max_length, seq_len) chunk_ids input_ids[:, begin:end] if chunk_ids.size(1) 2: continue target_ids chunk_ids.clone() with torch.no_grad(): outputs model(chunk_ids, labelstarget_ids) loss outputs.loss.item() nll_sum loss * (end - begin) token_count (end - begin) if end seq_len: break if token_count 0: return 0.0 avg_nll nll_sum / token_count perplexity np.exp(avg_nll) return perplexity def tokenize_text(text, languageauto): 对文本做分词。中文使用 jieba英文/其他语言按空格切分。 if language zh or ( language auto and any(\u4e00 ch \u9fff for ch in text) ): return list(jieba.cut(text)) return text.split() def compute_burstiness(text, languageauto): 计算文本突发性。 思路统计分词后词频分布的波动程度。 标准差 / 均值 越大说明词频波动越明显更像人类写作。 tokens tokenize_text(text, language) if len(tokens) 2: return 0.0 freq {} for token in tokens: freq[token] freq.get(token, 0) 1 counts np.array(list(freq.values()), dtypenp.float64) mean counts.mean() if mean 0: return 0.0 std counts.std() return std / mean def analyze_text(text, model_namegpt2, languageauto, deviceNone): 综合分析文本返回困惑度和突发性指标。 if device is None: device cuda if torch.cuda.is_available() else cpu print(f加载模型{model_name} (device{device})) tokenizer AutoTokenizer.from_pretrained(model_name) model AutoModelForCausalLM.from_pretrained(model_name).to(device) model.eval() if tokenizer.pad_token is None: tokenizer.pad_token tokenizer.eos_token ppl compute_perplexity(text, tokenizer, model) burst compute_burstiness(text, language) return { perplexity: round(ppl, 4), burstiness: round(burst, 4), text_length: len(text), }再写一个命令行入口run_detection.py# 文件路径ai_detect/run_detection.py import sys from detector import analyze_text def main(): if len(sys.argv) 2: print(用法python run_detection.py 文本内容或文件路径) return arg sys.argv[1] if arg.endswith(.txt): with open(arg, r, encodingutf-8) as f: text f.read() else: text arg # 模型名可按需替换例如 uer/gpt2-chinese-cluecorpussmall 用于中文 result analyze_text(text, model_namegpt2, languageauto) print(result) if __name__ __main__: main()4.4 参数说明与阈值调整代码中有几个关键参数需要关注max_length模型单次输入的最大 token 数。不同模型上限不同GPT-2 是 1024一般取 512 比较稳妥。stride滑窗步长。步长越小重叠越多困惑度计算越平滑但速度会变慢。model_name使用的模型。英文文本可以用gpt2中文文本可以换成中文 GPT 类模型比如uer/gpt2-chinese-cluecorpussmall。throttle阈值文章里没有固定阈值因为不同模型、不同语言、不同领域困惑度分布差异很大。这里要特别注意一个误区不要直接把网上别人写的阈值拿来用。比如有人告诉你“困惑度低于 30 就是 AI 生成的”但这个值很可能是在某个特定模型和特定数据集上统计出来的换一个场景就不适用。正确做法是先找一批人工标注的文本统计出当前场景下的分布再画一个分位点作为参考阈值。5. 完整实战——检测一段疑似 AI 生成文本5.1 准备测试文本我们在data/sample.txt中放一段文本。为了演示这里用一段“看起来很像 AI 生成”的中文内容人工智能正在改变内容生产的各个环节。从自然语言生成到多模态理解技术不断推动创作效率的提升。随着大模型能力的增强生成内容的质量也越来越接近人类水平。与此同时如何识别和管理AI生成内容成为内容平台面临的重要课题。这里需要注意的是如果我们的检测模型是英文 GPT-2处理中文时会先经过 tokenizer 转成英文子词效果会打折扣。所以更严谨的做法是使用中文模型。下面运行命令时我们直接演示中文模型的用法。5.2 运行检测下载中文模型可能比较耗时这里以uer/gpt2-chinese-cluecorpussmall为例python run_detection.py data/sample.txt但在运行之前需要确认代码里的model_name已替换为中文模型。或者你可以临时在命令行中执行python -c from detector import analyze_text with open(data/sample.txt, r, encodingutf-8) as f: text f.read() result analyze_text(text, model_nameuer/gpt2-chinese-cluecorpussmall, languagezh) print(result) 预期输出会类似下面这样实际数值会因模型版本和文本长度而变化加载模型uer/gpt2-chinese-cluecorpussmall (devicecpu) {perplexity: 58.3321, burstiness: 0.827, text_length: 96}如果困惑度明显低于同场景人工文本的平均水平而且突发性也比较低那就说明这段文本在统计特征上更接近 AI 生成。5.3 结果解读只看两个数字是不够的关键是要做对比。建议准备三组文本你亲自写的一段相同主题内容。你让某个大模型写的一段相同主题内容。待检测的文本。把这三组文本分别跑一遍检测工具记录困惑度与突发性。如果待检测文本明显落在“大模型生成”这一侧那么它就有较高概率是 AI 生成内容。这种做法比单独看一个数字要可靠得多。在实际的工程项目中这种对比实验应该做成自动化流程把历史数据沉淀下来不断调整阈值。这也是从“跑通脚本”走向“上线服务”的关键一步。6. 生成端实践——AI 小镇类项目中的内容生成6.1 AI 小镇项目是什么输入材料里提到了一个开源项目my_ai_town这类“AI 小镇”项目在 GitHub 上并不少见。它们通常模拟一个小镇里的多位 AI 角色每个角色有自己的身份、记忆、日常安排和社交关系系统按照时间推进这些角色的行动和对话最终生成一段连续的“小镇生活记录”。这类项目最大的特点是所有角色台词和旁白都是由大语言模型实时生成的因此它是 AI 生成内容的典型试验场。如果你想研究 AI 生成文本的特征自己跑一个 AI 小镇项目会非常有帮助因为它能让你看到同样一批角色、同一个模型在不同 prompt 和上下文下生成内容的差异。由于我没有深入分析该项目的具体源码这里不做具体代码层面的断言只讨论这类项目通用的生成流程。6.2 一个简化的 AI 角色对话生成示例为了更直观地理解生成端逻辑我写了一个简化版示例。它用transformers的pipeline接口加载一个轻量模型模拟一个角色对某个事件的回应# 文件路径ai_detect/generate_demo.py from transformers import pipeline # 加载一个轻量级文本生成模型 generator pipeline(text-generation, modeldistilgpt2) role 图书管理员 state 时间是上午九点小镇图书馆刚刚开门 event 一位背着书包的年轻人走进图书馆问有没有关于人工智能的入门书籍 prompt ( f设定{role}。\n f场景{state}。\n f事件{event}。\n 请用一句话自然回应 ) result generator( prompt, max_new_tokens64, do_sampleTrue, temperature0.8, top_p0.9, )[0][generated_text] print(result)这段代码展示了一个很简化的 AI Agent 内容生成流程设定角色、读取当前状态、接收事件、生成回应。真实的 AI 小镇项目里还会有记忆检索、计划生成、行动评估等多个环节但核心仍然是“用模型生成文本”。6.3 为什么 Agent 项目会产生大量 AI 内容一个 AI 小镇项目运行一天可能会产生几百甚至几千条角色对话和事件描述。这些内容的共同点是由同一个模型生成风格高度统一。用词偏向平稳很少出现人类口语中的插话、重复和情绪波动。一旦某条内容偏离了设定还可能产生“幻觉”也就是生成不符合世界观的描述。如果你把 AI 小镇生成的内容喂给第四节实现的检测工具大概率会得到“低困惑度 低突发性”的结果。这正好印证了检测端的统计原理同一个生成模型产出的文本在概率分布上会形成一种稳定的“写作指纹”。从学习角度来看建议同时跑通生成端和检测端。生成端让你理解“AI 内容是怎么来的”检测端让你理解“这些内容有什么统计特征”两者配合起来才算完整掌握了 AI 内容识别的基础能力。7. 常见问题与排查思路7.1 常见问题速查表问题现象常见原因解决思路模型加载很慢首次下载权重文件较大提前下载模型到本地缓存或使用较小的模型GPU 显存不足模型参数量过大或 batch 过大改用 CPU或使用小模型比如distilgpt2困惑度输出为 0文本过短token 数量不足增加待检测文本长度最少 50 个 token 以上中文检测结果不准使用了英文模型处理中文换成中文预训练模型或中文 GPT 模型突发性始终很低文本是高度格式化的短句结合困惑度综合判断不要单独看突发性运行时报tokenizer没有pad_token部分模型未设置 pad_token设置tokenizer.pad_token tokenizer.eos_token7.2 模型加载与显存问题很多新手第一次跑 transformers 项目时最头疼的就是模型下载和显存问题。我的建议是第一次运行建议使用 CPU 小型模型先把流程跑通。不要一开始就上几十亿参数的模型显存消耗大而且本地机器很难跑动。如果确实需要大模型可以考虑把推理放到服务端本地只做 API 调用但要注意数据隐私和权限边界不要随意把内部数据发送到第三方服务。7.3 检测结果不可信怎么办如果你发现检测结果经常“误报”比如把人类写的内容判定为 AI 生成通常有三个原因检测文本太短统计特征不稳定。领域差异太大比如你的文本是诗或歌词而检测模型是在新闻语料上训练的。阈值设置不合理缺少本场景的基准数据。解决办法也很直接增加文本长度、准备领域内的正负样本、用分位点代替固定阈值。记住检测工具的输出应该是一个“疑似概率”而不是一个“绝对答案”。最终判断权应该交给人工审核流程而不是交给脚本自动拦截。8. 最佳实践与工程建议8.1 内容合规与人工复核AI 内容生成与识别领域发展很快生产环境一定要有合规意识。如果公司业务涉及 AI 生成内容建议在发布流程中增加“AI 生成标注”和“人工审核”两个环节。不要试图用检测工具替代人工检测工具只是降低人工复核成本的手段。这里还要特别强调所有涉及内容审核、数据采集、用户数据处理的环节都要遵循合法授权和最小权限原则。不要在未获得授权的情况下抓取大量内容用于模型训练更不要把用户文本直接送入外部 API 而不做脱敏处理。8.2 模型选型与性能优化在工程落地时模型选型要考虑三件事速度、效果、维护成本。如果只需要粗筛选择 1 亿参数以内的小模型就够了。如果希望提升准确率可以加载多个不同结构的模型做投票但要接受额外的延迟。如果公司内部有私有化大模型更推荐用内部模型计算困惑度因为自产内容通常来自同一个模型检测效果会更好。性能优化上建议把模型加载一次后常驻内存避免每次请求都重新加载。还可以把 tokenizer 结果缓存起来文本预处理和模型推理解耦这样系统可以承载更大的检测量。8.3 安全边界与数据隐私把检测工具接入生产环境时一定要设置好安全边界。比如只允许经过授权的服务调用检测接口。不让用户上传过大的文本文件防止内存溢出。对文本内容做日志脱敏避免敏感信息落盘。在请求量较大时加入限流机制防止接口被刷。如果使用云服务上的模型 API还要确认数据是否会被用于服务商的模型训练如果会应优先选择数据隔离方案或本地模型。8.4 从检测到治理的演进单点检测工具只是开端。实际业务中更好的做法是把检测结果接入内容管理后台形成“检测-人工复核-反馈-模型调优”的闭环。每次人工复核的结果都应该回填到样本池中定期重新评估检测阈值和模型效果。这样AI 生成内容识别能力才会随着时间推移越来越准而不是上线三个月后就失效。9. 总结与下一步学习路线9.1 本文核心收获这篇实战教程从“Discovery 频道是否使用 AI”这个问题切入落到了 AI 内容生成和检测的工程实现上。你应该已经掌握AI 内容生成的基本原理语言模型逐个 token 预测下一个词。AI 幻觉的定义以及它和内容检测的关系。四种 AI 内容识别技术路线统计特征、分类器、水印、组合方案。如何用 Python 实现困惑度和突发性计算。如何用 transformers 加载模型对一段中文或英文文本做检测。如何解读检测结果以及为什么不能迷信固定阈值。AI 小镇类项目为什么是 AI 内容生成的典型场景。9.2 建议的学习路线如果你刚接触这个方向下一步可以按顺序这么做把本文的detector.py跑通换成你自己的文本感受困惑度和突发性的变化。准备 20 段人类文本和 20 段 AI 生成文本做一个小样本对比实验画出两个指标分布。学习transformers的Trainer接口尝试用标注好的数据微调一个二分类检测模型。了解检索增强生成RAG的基本思路把它用于事实一致性校验弥补纯统计特征检测的不足。找一个小型 AI Agent 项目尝试生成内容并对生成结果做检测形成闭环。9.3 动手建议与其纠结某个频道到底有没有用 AI不如先自己动手做一个检测工具然后拿几段真实内容测一测。你会发现检测 AI 生成内容并没有想象中那么神秘它本质上就是“用模型的特征去观察模型自己生产的内容”。只要把环境搭好、数据备好、阈值调好这个小工具就能在工作里真正帮你节省时间。遇到问题也不要慌按上文第 7 节的排查表一步一步来基本都能解决。
返回列表