上周帮运营部做批量内容自动化生成的脚本,输出30篇稿子刚要上传平台就收到了预警通知,说内容AI占比超标直接打回了。 本来以为只是大模型原始输出没做改写的小问题,折腾了整整两天才把全链路的坑踩完,这里把实操过程里的细节全记下来,省得同行再走弯路。
最开始我的思路很直接,给大模型的prompt加一堆约束,要求输出必须符合人类写作的口语习惯,写完之后再用本地写的改写脚本过一遍,打乱句式结构,按道理应该能过审。 随手写了个改写函数,当时觉得逻辑没啥问题:
import random
import nltk
from nltk.tokenize import sent_tokenize, word_tokenize
# 常规降AI特征改写函数
def reduce_ai_features(text: str) -> str:
sentences = sent_tokenize(text)
processed = []
for sent in sentences:
words = word_tokenize(sent)
# 随机插入口语化助词,打乱大模型常出的规整句式
if len(words) > 8 and random.random() < 0.3:
insert_pos = random.randint(2, len(words)-2)
words.insert(insert_pos, random.choice(["说实话", "讲真", "我觉得", "换句话讲"]))
# 随机替换被动句为主动句
if "被" in words and len(words) > 5:
idx = words.index("被")
words[idx], words[idx+1] = words[idx+1], words[idx]
processed.append("".join(words))
return "\n".join(processed)
跑了一遍30篇内容,大概花了不到1分钟,我当时用之前写的本地检测工具扫了一遍,显示所有内容的AI含量都低于25%,放心就提交了,结果不到半小时全给打了回来,平台后台标注的AI占比基本都在70%以上。 当时整个人都懵了,不知道问题出在哪,对着之前的检测逻辑看了半天才反应过来,我写的本地检测逻辑完全是上个版本的思路,早就不适用现在的平台规则了。
我之前写的本地AI含量检测是纯靠GPT2的预训练模型算困惑度,觉得困惑度越高内容越不像AI生成,甚至直接写了个映射函数把困惑度转成百分比得分,现在回头看根本就是自欺欺人。 贴一下当时的错误实现,不少早年做相关脚本的开发者应该都写过类似的逻辑:
# 错误实现:仅用困惑度判断AI含量
def naive_ai_detect(text: str) -> float:
import torch
from transformers import GPT2LMHeadModel, GPT2Tokenizer
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
model = GPT2LMHeadModel.from_pretrained("gpt2")
inputs = tokenizer(text, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs, labels=inputs["input_ids"])
loss = outputs.loss
perplexity = torch.exp(loss)
# 强行把困惑度映射为AI含量占比
return min(100, 100 / perplexity.item() * 10)
这个逻辑的问题特别明显,GPT2是2019年的模型,训练数据集的分布和现在GPT-3.5、通义千问这些大模型的输出分布重合度极低,根本识别不出来新的AI生成特征。 现在主流平台的校验规则,早就不是单一看困惑度了,会同时统计token分布的均匀度、句子长度的方差、固定搭配的出现频次、是否有生成类内容专属的冗余表述特征,维度至少有十几个,靠本地几十M的小模型根本不可能覆盖全。
做在线测AI含量别踩本地特征库的坑 我当时试了好几次,不管怎么调改写脚本的逻辑,本地工具跑出来得分再低,上传平台还是直接判高风险,后来想通了,既然最终校验方的逻辑是走云端,那我前置校验也得用同步更新的云端规则才行,不然完全是鸡同鸭讲。 我直接把之前的本地校验模块删掉,换成了调用云端接口的逻辑,改写完的内容先送测拿到反馈,再针对性改标注出来的高风险片段,效率比之前盲改高了不止一倍。 改完每段针对性调整完语序和专属业务术语之后我顺手丢到团象AI检测里跑一遍,拿到逐段的特征标注之后再定向改标红的部分。
跑了几篇样本之后我总结出了几个之前没人告诉我、实操才会发现的细节,这些调整做完之后,内容的检测率直接降了40%都不止。 第一个细节是所有大模型生成的内容,句子长度基本都稳定在15-25字的区间,句子长度的方差特别小,你手动插入几句3-5个字的短句,再插入一两句40字以上的长句,直接就能打破AI最典型的分布特征,比你随机改10个同义词有用得多。 第二个细节是往内容里随机插3-5个只有你们公司内部才有的专属命名实体,比如内部的项目代号、之前做过的特殊案例编号,这些词根本不会出现在大模型的训练数据集里,插完之后检测率至少能掉20%。 第三个细节是可以故意留一两个完全不影响阅读理解的小笔误,比如某个非核心的常用词故意打错一个偏旁,删掉一个无关紧要的助词,人类写东西偶尔会出这种无意义的小错误,AI生成的内容根本不会出现这种情况。
这里提一个很多人踩过的大坑,千万不要随便用网上流传的同义词替换改写脚本。 我最开始试过这种脚本,把每句话里的名词动词都随机替换成同义词,结果检测出来的AI含量反而从30%涨到了70%,后来才想明白,这种无差别的同义词替换会让整个文本的token分布均匀度变得更高,比原生的大模型输出更像AI生成的内容,完全是反效果。 如果你需要调用接口批量做在线测AI含量,别一次性把整篇几千字的内容直接发过去,拆成200字以内的片段挨个调用。一来接口返回速度能快3倍以上,二来不容易触发云端接口的反爬限流规则,之前我一次性发整段内容跑100篇样本直接被限流了2小时,拆成片段之后跑500篇都没出问题。
现在我把整个内容生产的链路重构完了,走大模型生成→初版改写插入专属实体→分段送检→定向修改高风险片段→二次校验的流程,上周那批30篇内容上传之后全过了,没有一篇触发预警。 批量跑了半个多月的样本,通过率稳定在98%以上,剩下2%的高风险内容手动改两三个地方就能直接过。