
上周项目组接的甲方外包文档终稿提交后直接被那边的风控系统打回标注AI生成占比超过60%要我们3天内整改完重交。 当时第一反应是找降AI率软件来救场试了3个网上随便搜的改完结果反而更糟最高一次AI检测率直接干到92%差点以为系统出bug了。我当时蹲在工位上对着报告愣了十分钟完全想不通为什么越改越高。 之前的逻辑是AI生成的文本有很多AI专属的词我把同义词替换掉不就完事了结果我自己写了个简单的替换脚本把所有高频词全部换成近义词跑出来的内容扔去检测反而比原生AI生成的分数还高。 后来翻了好几篇检测模型的开源论文才搞懂现在主流的检测逻辑早就不是靠词频匹配了。 现在大部分商用AI检测模型都是基于微调后的Roberta类大模型做特征提取判断维度至少包含三个核心指标 第一个是n-gram重复概率AI生成文本的3字重复片段占比远低于人类大模型解码时会主动规避生成已经出现过的语义片段 第二个是语义熵的均匀度AI输出的每一句话的信息增量几乎是平的人类写东西会突然蹦出一大段干货又突然扯两句无关的闲话 第三个是指代跳跃性人类写嗨了会随便给之前提过的概念起外号AI只会规规矩矩沿用最开始的正式命名。我随手写了个小脚本测了下手里的几份样本结果完全对得上原生AI写的文档3-gram重复率只有0.03我自己手写的技术博客重复率是0.15之前用同义词替换改出来的垃圾文本重复率直接掉到0.02等于主动把AI特征拉到满格不判你是AI才怪。from collections import defaultdict def calc_ngram_repeat(text: str, n: int 3) - float: # 中文按单字切分统计n-gram不需要额外安装分词库跑起来没有依赖 chars list(text.replace( , ).replace(\n, )) ngram_count defaultdict(int) for i in range(len(chars) - n 1): ngram .join(chars[i:in]) ngram_count[ngram] 1 # 统计出现次数2的ngram占总ngram数的比例 repeat_total sum(1 for v in ngram_count.values() if v 2) total len(ngram_count) return round(repeat_total / total, 4) if total 0 else 0大家可以拿自己写的东西跑下正常人类输出的中文技术文本3-gram重复率基本稳定在0.12-0.18区间低于0.05的几乎全是纯AI生成的内容。 之前网上传的什么“中文转西班牙语再转回来”的偏方我也踩过坑改完之后3-gram重复率倒是达标了但是语义熵直接崩了每一句的信息增量忽上忽下反而刚好命中了多轮翻译畸变的特征库检测率还是卡在70%以上下不来。现在2024年的检测模型早就把这类偏方的生成特征全喂进训练集了用等于主动送人头。 后来我们团队花了两天摸出一套完全不依赖第三方黑盒工具的手动优化流程跑了十几份文档全过了效率比瞎折腾高太多。第一步先做段落打碎每一个大段下面删掉1-2个无关紧要的专业限定词顺手插一句完全没有信息增量的个人踩坑碎碎念。比如讲完“接口要做128位字段校验”之后补一句“我上周测这个逻辑的时候还把字段名拼错了调了半小时才找到问题”这种私人化的碎碎念是大模型绝对不会主动生成的。 第二步打破AI的线性叙事逻辑AI写技术内容永远是“先搭环境再引依赖最后写单测”的严格先后顺序你随便把顺序打乱改成“我当时图省事先把单测用例的空壳写完了回头才补依赖最后再搭环境反过来跑也完全不影响结果”直接把AI最标志性的线性逻辑链干碎。 第三步把所有超过25字的无标点长句全部拆成短句大模型生成的时候天生偏好输出长复合句人类写技术笔记根本不会堆那种绕半天气都喘不过来的长句。我写了个批量拆句的小脚本改完之后自己手动扫一遍修正下不通顺的地方就行3万字的内容10分钟就能处理完。import re def split_long_sentence(text: str, max_len: int 25) - str: # 把长度超过max_len的无断句长句在中间第一个逗号处拆成两句 sentences re.split(r([。]), text) processed [] for i in range(0, len(sentences)-1, 2): raw_sent sentences[i] sentences[i1] if len(raw_sent) max_len: processed.append(raw_sent) continue # 优先在句子中间位置的逗号处断句没有逗号就硬拆到对应位置 split_pos raw_sent.find(, len(raw_sent)//2) if split_pos -1: split_pos len(raw_sent)//2 processed.append(raw_sent[:split_pos1] 。) processed.append(raw_sent[split_pos1:]) return .join(processed)这里有个很少有人注意到的细节拆完句子之后别用语法校验工具把所有不通顺的地方全部改得完美无缺。人类写的东西本来就会留1%-2%的小瑕疵比如多打一个“的”量词用错个无关紧要的地方故意留一两个完全不影响理解的小语病反而能把AI占比压得更低。 把所有内容手动过一遍确认语义没有问题之后我习惯性地丢到团象AI检测里跑一遍确认检测率降到阈值以下再往下走。之前我以为要改全文才能把分数压下来后来发现根本不用检测报告飘红的那些段落就是AI特征最密集的地方你针对性给那一两百个字加一句私人碎碎念调整下句子顺序分数直接就掉下来根本不用大动干戈。 之前改那份3万字的甲方文档初始检测率92%拆完长句之后降到57%把所有AI偏好的连接词全部删掉之后再改完飘红段落最终的检测率稳定在7%甲方那边的风控系统直接给过了。 对了有个非常容易踩的小坑AI对于“综上所述”“值得一提的是”“由此可见”这类过渡词的使用频率是普通人类开发者的8倍以上。你改文档的时候把这些词全部删掉换成最口语化的过渡比如“最后测下来”“顺便说一句”效果立竿见影。 哪怕是改代码注释这类短内容这个逻辑也通用。AI生成的注释永远是“// 实现用户登录逻辑校验”这种规整到极致的表述你改成“// 这里写登录逻辑上次忘加验证码校验了别踩坑”带点私人吐槽的味道任何检测系统都不可能把这段判定成AI生成的。别信一键降AI率工具的伪优化很多人图省事直接找市面上的降AI率工具一键生成改写内容我同事之前花了几十块钱试了个结果改完的内容AI检测率反而从68%涨到89%。 这类工具本质上就是套了个大模型的文本改写接口输出的内容完完整整保留了大模型所有的生成特征等于你用AI去改AI的内容特征只会越来越纯根本不可能骗过检测系统。 上周还有个学弟问我有没有什么批量处理几万字的快速方法我试了好几个开源的文本改写模型跑出来的内容全都能被直接识别最后还是乖乖手动每一千字插一句自己的碎碎念花了一晚上也改完了。 之前还见过有人为了降率把文本里的所有汉字都换成同音字再改回来折腾完文本全是语病交付给甲方之后直接被打回重写反而赔了超时的违约金。 最后提醒一句改完的文本别全选直接复制粘贴用自己手动敲个十几二十个字的开头结尾把首尾两段最容易被抓特征的地方换成完全手写的内容基本就稳了。