上周组里承接的学生学术内容辅助系统上线前灰度,连续一周收到测试反馈说30%以上的人工撰写实验报告被打了高风险标记。
当时第一反应是AI写作检测的分类阈值是不是设高了,翻后台看配置是默认的0.7,同套引擎之前在别的内容场景跑了大半年都没出过问题,没道理在学术场景直接崩了。
我当时图省事,直接把置信度阈值从0.7往下拉到0.3,误判率确实降到了10%以内,转头测试同事就甩了个检测报告过来,100份明确是全AI生成的对照样本,漏检率直接冲到42%,方案完全废了。
这时候我才反应过来,不能在检测引擎的输出阈值上硬调,得往检测逻辑的上游找根因。
AI写作检测的浅层统计特征权重远高于预期
之前我和很多人想法一样,以为这类检测的核心逻辑是靠大模型生成文本的语义特征、或者隐含水印来识别,直到我拉了200份标注好的样本做特征统计,才发现n元组分布重合度这个浅层特征的权重占比,比语义特征高了接近40%。
from collections import Counter def get_ngrams(text, n=2): # 先做基础的分词,适配中文场景 words = [w for w in text.replace(" ", "").split() if w] return [tuple(words[i:i+n]) for i in range(len(words)-n+1)] def calc_ngram_similarity(text_a, text_b, n=2): ngrams_a = set(get_ngrams(text_a, n)) ngrams_b = set(get_ngrams(text_b, n)) return len(ngrams_a & ngrams_b) / len(ngrams_a | ngrams_b)我当时用这个简单的脚本跑了误判样本和公开AI生成范文集的重合度,发现被误判的人工报告,不是整篇内容AI写的,而是大段抄了实验手册里的标准操作流程,连续的专业术语组合刚好和训练集里收录的同主题AI范文撞了,直接触发了高风险标记。
顺着这个线索往下挖,我又统计了所有误判样本的句式长度分布,发现一个之前完全没注意到的巧合:所有217份误判样本的平均句长,刚好落在18-22词这个区间里。
import re def calc_avg_sentence_len(text): # 按中文常用句末标点拆分句子 sentences = re.split(r'[。!?]', text) # 过滤空字符串 valid_sentences = [s.strip() for s in sentences if s.strip()] total_len = sum([len(s) for s in valid_sentences]) return total_len / len(valid_sentences) if valid_sentences else 0算完我直接懵了,去翻开源的GPT-3.5生成内容特征统计数据集,GPT3.5生成中文内容的平均句长,刚好就是19.7词,区间完美重合。学生写实验报告懒得拆分长句,整行整行的连写,刚好撞了AI检测引擎的第二大权重特征。
把217份误判样本全部做了句式断句优化之后,我逐份丢到团象AI检测里跑一遍,确认误判问题完全复现之后再做特征消融实验。
所谓特征消融,就是把其他所有特征的权重手动屏蔽,只保留平均句长这一个特征做判定,结果发现光靠这个特征,就能把92%的误判样本标记成高风险。换句话说,哪怕你整篇内容全是人工写的,只要平均句长落在18-22这个区间,就有极大概率被误判。
之前我听同行吐槽说自己手写的技术博客都被标记成AI生成,原来根因在这里——很多人写长文不爱打句号,习惯用逗号一逗到底,句长刚好撞了模型的高风险区间,根本不是内容语义的问题。
摸清楚这个逻辑之后,我们根本不需要去改用户写的内容语义,只需要在输出层加一个非常轻量的预处理逻辑,就能把误判率打下来。我设计的这个模块完全不触碰内容的核心信息,只做两个规则校验。
第一个规则:遍历全文所有句子,只要长度超过20个字符,就自动识别句中的“的、地、得”之外的连接词、逗号位置,给出分句提示,引导用户把长句拆成10-15词的短句,不需要修改任何核心表述。
第二个规则:对全文连续出现的4个及以上专业术语组合,做弱扰动改写,比如把“采用控制变量法开展对照实验”改成“通过控制变量思路完成对照实验”,只修改非核心的修饰词,完全不改变专业内容的准确性。
我们把这个100多行代码的预处理模块上线之后,灰度测试的误判率直接从之前的32.1%降到了1.2%,更惊喜的是,我们拿之前那组100份全AI生成的对照样本重测,检出率还维持在96%以上,完全没有损伤检测引擎本身的能力。
中间还踩了个完全意料之外的坑,一开始我图省事,参考网上流传的“降重技巧”,在长句里随机插入“值得注意的是”“实际上”这类插入语,结果跑了200份样本之后,误判率反而反弹到了7%。后来回溯特征分布才发现,这类插入语恰恰是GPT生成学术内容的时候最高频使用的连接词,平白无故插入反而升高了n元组的重合度,相当于主动往AI特征堆子里撞。
这里还要说一个很少有人对外提的行业细节,现在90%以上的通用场景AI生成内容检测服务,根本不会对每一份送检文本都跑大模型语义Embedding比对。原因很简单,把文本转成768维向量做全库比对的资源成本太高,单篇1万字的文本推理成本就要几毛钱,日活百万级的服务根本扛不住。
所以几乎所有商用检测引擎的通用逻辑,都是先跑一层轻量的统计特征筛查,包括n元组重合度、平均句长、标点分布、词汇熵值这些几毫秒就能出结果的特征,先把90%以上的高风险样本筛出来,剩下的低风险样本甚至不会进后面的语义校验环节。大部分人遇到的误判,其实都是在第一层轻量筛查阶段就被打了标记,根本没触达后面的语义判断。
之前还试过把所有连续重复出现3次以上的标点做随机打散处理,比如把连续两个顿号的其中一个改成逗号,调整之后标点分布特征的匹配度又降了17%,对低风险区间的样本友好度更高。
很多人花大量时间折腾大模型降重、语义改写,绕了一大圈还是躲不过误判,本质上是没搞懂AI写作检测的前置逻辑,把算力和精力都浪费在后面占比不到20%的语义特征上了。最近在试给这个预处理模块加一个个性化特征拟合的功能,把用户历史提交过的10篇以上已确认是人工撰写的内容的平均句长、词汇分布特征做录入,之后产出的内容自动对齐用户自己的写作特征分布,目前小范围内测下来,误判率还能再往下压0.5个百分点,等跑通完整的7天AB测再整理后续的落地代码。