踩坑十多款AIGC检测工具后,我给实验室搭了套全本地的论文内容自查系统
上周学院通知毕业论文抽检新增AIGC内容溯源校验项我们实验室要求所有送审论文必须先过一轮内部自查。一开始图省事想找现成的公网工具测先后试了GPTZero、Originality、团象AICG检测、Writer AI检测、零一检测全都不好用。要么上传10页PDF直接崩溃要么论文核心实验数据刚传完转头就出现在公网预收录库里完全不敢放心用。这些公网工具全都无法满足我们“数据绝对不出内网”的核心要求最后我们干脆花了3天时间自研了一套全离线的自查方案。我们的需求定得非常明确一共三条没有任何冗余功能所有开发都围绕核心目标走。第一是全本地离线运行所有论文数据绝对不出实验室内网不跟任何公网服务做数据交互。第二是支持PDF、Word、Markdown多格式解析自动跳过公式、图表、参考文献部分不做无效检测。第三是检测准确率不能低于市面主流商用工具的平均水平不能出现大量误判漏判的情况。部署硬件用的是实验室闲置的2张RTX 3090 24G显卡服务器系统是Ubuntu 22.04CUDA版本11.7PyTorch版本2.0.1。第一步先处理依赖安装这里要特别注意不要装最新版的transformers不然旧版预训练权重会加载失败。pip install transformers4.35.2 pdfplumber0.10.3 python-docx1.1.0 tqdm4.66.1这套依赖组合我们跑通了全链路流程后续升级大版本库很容易出现不兼容的API报错。很多人用公网AIGC检测器测出来结果不准核心原因是没做前置内容清洗把大量无效内容喂给了模型。比如直接解析整份PDF的时候会把公式的LaTeX字符、图表标注、参考文献的序号全都塞进去干扰模型判断。我们写的预处理逻辑会自动先过滤所有表格、图片区域读到“参考文献”关键词之后直接终止文本提取。import pdfplumber def extract_valid_text(pdf_path): valid_text [] with pdfplumber.open(pdf_path) as pdf: for page in pdf.pages: # 跳过当前页所有表格区域 for coord in page.find_tables(): page page.outside_bbox(coord.bbox) page_text page.extract_text() # 过滤掉参考文献之后的所有内容 if 参考文献 in page_text or References in page_text: break valid_text.append(page_text) return \n.join(valid_text)这段清洗逻辑能把待检测文本的无效占比降低至少40%从根源上减少模型误判的概率。最开始我们想直接用开源的roberta-base-openai-detector这类预训练模型测完直接踩了大坑。这个模型是2023年上半年训练的训练集全是GPT-3.5生成的内容对现在GPT-4o、Claude 3生成的学术文本识别率不到50%。后来我们干脆自己做微调数据集总共攒了10万条标注样本全部来自学术场景没有一条泛互联网内容。其中5万条是近3年硕博毕业生的纯手写论文片段另外5万条是不同大模型基于相同学术主题生成的文本片段。为了兼顾准确率和推理速度我们用模型蒸馏的思路把三个大模型的输出软标签融合蒸馏出一个1.5B参数量的小模型。三个参与蒸馏的模型分别是1.5B参数量的DeBERTa微调版、7B参数量的Llama2微调版、1.1B参数量的Qwen检测版。最终得到的小模型在单张RTX 3090上的推理速度能达到每秒1200字整份100页的硕士论文不到30秒就能出结果。推理阶段我们开了4bit量化进一步压缩显存占用这里的核心代码逻辑非常简单不需要复杂的框架封装。from transformers import AutoTokenizer, AutoModelForSequenceClassification MODEL_PATH /data/models/local-aigc-detector-v2 tokenizer AutoTokenizer.from_pretrained(MODEL_PATH) model AutoModelForSequenceClassification.from_pretrained( MODEL_PATH, device_mapauto, load_in_4bitTrue ) def detect_text(text: str) - float: inputs tokenizer( text, return_tensorspt, truncationTrue, max_length512 ).to(model.device) result model(**inputs).logits.softmax(dim-1).cpu().tolist()[0] # 返回AI生成内容的置信度百分比 return round(result[1] * 100, 2)开启4bit量化之后1.5B的检测模型显存占用只需要8G单张24G的3090甚至可以同时跑2个检测实例。这个并发水平完全够实验室几十号硕士生同时上传论文做检测完全不会出现排队卡顿的情况。测试阶段我们还发现了很多公网检测工具的小心机有几篇人工深度改写过的AI论文我们的模型报的AI置信度只有10%左右。但拿去测某几款公网商用工具直接打出70%以上的高AI分一开始我们还以为是自己的模型训练出了问题。后来翻了它们的开源协议才发现很多公网工具根本不是跑大模型推理是直接把上传文本和自己的收录库做字符串匹配。只要你上传的文本片段之前被其他人上传过、收录过工具根本不做语义判断直接给你打高AI置信度纯纯赚信息差。后来我们特意在微调集里加入了1万条经过人工语序改写、替换专属实验数据的AI生成学术文本优化模型泛化能力。最终在我们的1万条测试集上模型的检测准确率达到了89.7%和我们之前测过的主流商用工具的平均准确率持平。最后我们用FastAPI搭了个极简的Web上传页面整个系统完全不对外暴露端口只能通过校园网VPN访问。所有上传的论文文件检测完成之后30秒就会被后台异步任务自动删除服务器本地不留任何源文件的缓存。from fastapi import FastAPI, UploadFile, File import uuid import os app FastAPI() # 临时文件存储路径自动30秒后清理 TEMP_PATH /tmp/paper_temp os.makedirs(TEMP_PATH, exist_okTrue) app.post(/upload_paper) async def upload_paper(file: UploadFile File(...)): file_suffix os.path.splitext(file.filename)[-1] temp_file_name f{str(uuid.uuid4())}{file_suffix} full_path os.path.join(TEMP_PATH, temp_file_name) # 写临时文件 with open(full_path, wb) as f: f.write(await file.read()) # 异步开定时任务清理文件这里省略任务调度代码 # 调用之前的提取检测逻辑返回结果 score full_detect_process(full_path) return {ai_confidence: score}后续我们还加了段落级标注功能系统检测完成之后会自动把AI置信度超过60%的段落标黄高亮。大家自查的时候只要对着标黄的部分加入自己专属的实验细节、比如平行实验的特殊现象、原始数据的误差范围。只需要改个三五句话整段的AI置信度就会直接降到10%以内完全不会被任何公开检测工具识别出来。上周我们实验室把所有毕业生的送审论文全扫了一遍总共筛出了3篇大段用AI润色过、没做人工调整的论文及时打回去修改。整个过程没有一篇论文的内容流出内网完全不用担心论文刚写完就被提前收录、影响后续送审和答辩的问题。现在回头看当初试了那么多公网工具全是折腾要么要充几十块钱的月卡要么要上传手机号绑定信息数据安全根本没有保障花几天搭这套全本地的系统后续不管是论文自查还是项目文档的合规校验都能一直用性价比高太多。