Build an AI Text Detector, Then Test If It Can Ship
Build an AI text detector with small local models, stress-test it on short and human-edited text, and use the error rates to decide if it ships.

In this article
- 1.What Detectors Actually Deliver Today
- 2.Three Ways to Build an AI Text Detector
- 3.Building the Local Model Step by Step
- 4.Construct paired training data
- 5.Choose a backbone
- 6.A LoRA config that trains on a consumer GPU
- 7.Pick a threshold, not a default
- 8.An Evaluation Protocol Beyond Accuracy
- 9.Stress Testing Short and Human-Edited Text
- 10.The Base-Rate Math Behind Ship or Kill
- 11.Guardrails If You Ship It Anyway
- 12.Honest Limits and What to Build Instead
Somewhere between vendors advertising 98 percent accuracy and skeptics declaring detection dead sits the detector you can actually build yourself. Fine-tune a 1.5B model on a consumer GPU and mid-90s accuracy on clean, in-domain text is a realistic outcome. That number feels shippable right up until the model flags a 40-word support reply a human dashed off, or an essay that only went through a grammar checker.
Stay in the loop.
Get the latest posts and exclusive content delivered to your inbox.
Join 3 readers. No spam. Unsubscribe in one click, anytime.
This guide covers the full arc: build an AI text detector with small local models, stress-test its false positives on short and human-edited text, then convert measured error rates into a ship-or-don't-ship decision. Detection behaves like any classification problem, with one nasty twist: the base rate of AI text in your traffic decides whether a given accuracy figure is usable or worthless. Three questions run through everything below. Can a small local model compete with commercial detectors? Where do its errors concentrate? When is deployment defensible? Each one gets a number by the end.
What Detectors Actually Deliver Today
Start with the honest scoreboard. OpenAI launched a text classifier in early 2023, then pulled its own classifier in July 2023, citing its low rate of accuracy. The company that built GPT-4 could not ship a detector it trusted. Meanwhile Turnitin, which processes student submissions at enormous scale, advertises roughly 98 percent accuracy with a false positive rate around one percent. Both facts are true at once, and the gap between them is where your project lives.
Independent testing keeps finding the same pattern: commercial numbers hold on clean, full-length, in-domain prose and fray on everything else. Peer-reviewed studies document meaningful false positives on real human writing, falling hardest on non-native English writers. So the right frame for AI-generated text detection is neither hype nor fatalism. It is a measurable classification task with known, testable failure modes. Your job is not to beat Turnitin. It is to measure your own error curve against your own traffic before anything ships.
Three Ways to Build an AI Text Detector
| Path | Privacy | Marginal cost | Latency | Realistic ceiling | Dominant failure |
|---|---|---|---|---|---|
| Commercial API detector | Text leaves your machine | Per-call fee, scales with volume | Network round trip | High on clean prose, vendor-tuned | Opaque false positive behavior, no threshold control |
| Fine-tuned local LLM classifier | Text never leaves the box | One-time GPU time, then free | Tens of ms on a consumer GPU | Mid-90s in-domain, degrades off-domain | Distribution shift, unseen generators |
| Stylometric features plus classic ML | Fully local | Near zero, CPU only | Sub-millisecond | Often 80s to low 90s in-domain | Light paraphrasing guts the signal |
Each path wins somewhere. The API route needs no training loop and makes sense when you want a baseline fast and can accept the privacy trade. Stylometric detection features, meaning sentence-length variance, type-token ratio, function-word n-grams, and punctuation habits fed to logistic regression or gradient boosting, are explainable, nearly free, and double as a sanity check on what the neural model actually learned. Raschka's from-scratch build with a DistilBERT encoder is a good reference for how little machinery the neural path needs.
But if your goal is to detect ChatGPT text locally, control the threshold, and keep user text on the machine, the case for choosing to fine-tune a small language model yourself is structural: no per-call fees, no data leaving your infrastructure, and full ownership of the operating point. Its lower accuracy ceiling is the price, and the rest of this guide measures whether that price is worth paying.
Building the Local Model Step by Step

This is where you actually build an AI text detector. Training a model to detect AI-generated text comes down to three decisions: what paired data it sees, which backbone you fine-tune, and where you put the threshold.
Construct paired training data
Classifiers learn the contrast you show them, so build pairs. The HC3 corpus is the canonical starting point: human answers and ChatGPT answers to the same questions, tens of thousands of pairs deep. Three rules matter more than volume:
- Balance the classes so the model learns style, not base rates.
- Split by question, not by row. If both answers to one question land in different splits, the model memorizes topics instead of writing style.
- Augment with your own domain. Generate answers to your users' actual prompts with the exact models you expect in production. A detector trained only on generic ChatGPT answers is guessing the moment traffic contains Claude or Llama output.
Choose a backbone
Two viable routes. A decoder model (Qwen2.5-1.5B or Llama 3.2 1B with a sequence-classification head) handles long context and trains cheaply with adapters. An encoder (RoBERTa-base, DistilBERT) trains in minutes on a modest GPU and is consistently competitive at this task. Start with the encoder. Upgrade only if long documents or multilingual traffic demand it.
A LoRA config that trains on a consumer GPU
LoRA fine-tuning for binary text classification is forgiving; the defaults below are a sane start, not a tuning exercise.
from peft import LoraConfig, get_peft_model
from transformers import AutoModelForSequenceClassification
base = AutoModelForSequenceClassification.from_pretrained(
"Qwen/Qwen2.5-1.5B", num_labels=2, torch_dtype="bfloat16")
cfg = LoraConfig(r=16, lora_alpha=32, lora_dropout=0.05,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"],
task_type="SEQ_CLS")
model = get_peft_model(base, cfg) # ~1% of weights trainable
# Trainer: lr 2e-4, cosine schedule, 5% warmup, 2 epochs,
# effective batch 16, max_len 1024, bf16
Hugging Face PEFT ships the adapter machinery, and the Transformers training guide covers the surrounding Trainer plumbing. Expect mid-90s accuracy on a clean, in-domain held-out split; RoBERTa-class encoders land in the same range. That result is real, and it is also the last easy number you will get.
Pick a threshold, not a default
Never ship argmax. Sweep thresholds on the validation split and select an operating point by false-positive budget: if you can tolerate 2 percent, find the threshold that delivers it, then record the recall you get at that point. That pair, recall at a fixed false positive rate, is the only accuracy claim worth writing down.
An Evaluation Protocol Beyond Accuracy

Top-line accuracy misleads three ways at once. It hides class balance, it ignores which class you failed on, and it averages over text lengths that behave completely differently. To evaluate an AI text detector with precision and recall honestly, report per-class precision and recall, false positive rate at your chosen operating point, and calibration: a score of 0.85 should mean roughly 85 percent of such texts are AI, and neural classifiers are routinely overconfident. Wrapping the model with Platt scaling or isotonic regression is a small job with scikit-learn's calibration guide.
Then bucket by length, because errors are not uniform:
| Length bucket | Typical false positive pattern | Typical false negative pattern |
|---|---|---|
| 500+ words | Low, near the headline rate | Low |
| 100 to 200 words | Several times higher | Noticeably higher |
| Under 50 words | Often an order of magnitude worse | High |
Directional illustration of the pattern this harness reliably surfaces; your absolute numbers will differ, which is exactly why you must measure them.
Finally, test across generators and domains. The M4 benchmark spans multiple generators, domains, and languages precisely because training on one generator and testing on the same one overstates robustness. Cross-generator and cross-domain drops are the norm, not the exception.
Stress Testing Short and Human-Edited Text
Your held-out set, however honest, is still clean data. Production is not. AI detector false positives are not evenly distributed, and AI detector accuracy on human-edited text is the number almost no vendor publishes. Four stress conditions, in rising order of pain:
- Length. Recompute the false positive rate per word-count bucket on your human set. Short human text (chat replies, comments, ticket responses) is where detectors embarrass themselves, because style signal accumulates with length.
- Human editing. Apply realistic edits to AI passages: grammar fixes, a swapped phrase, a human intro stapled to an AI body. SemEval-2024 Task 8 ran a dedicated subtask on mixed human-machine text, and results there sit well below clean-text numbers.
- Paraphrase attacks. Ask any strong model to rewrite your AI set. Sadasivan et al. showed paraphrasing can drive even strong detectors toward random performance, and Krishna et al. demonstrated the same attack broadly, proposing retrieval-based defenses as a partial answer. If a free rewrite breaks your detector, assume motivated users will find that out.
- Writer bias. The Patterns study on detectors found popular detectors flagged the majority of TOEFL essays by non-native English writers as AI-generated, with average false positive rates above 60 percent. Test against writing by non-native speakers in your own user base before trusting any aggregate number.
Any evaluation that skips these conditions overstates ship-readiness. That is not a caveat; it is the finding.
The Base-Rate Math Behind Ship or Kill
Most detector deployments die on arithmetic, not modeling. Suppose your detector is excellent: 99 percent sensitivity, 99 percent specificity. What a flag means still depends entirely on how much AI text you actually have.
| Prevalence of AI text | PPV of a flag | Practical reading |
|---|---|---|
| 1 percent | ~50 percent | A flag is a coin flip |
| 10 percent | ~92 percent | About 1 flag in 12 is wrong |
| 50 percent | ~99 percent | About 1 flag in 100 is wrong |
At 1 percent prevalence, a flag from a 99/99 detector is wrong about half the time.
Walk the 1 percent case. Of 10,000 submissions, about 100 are AI. The detector catches 99 of them, and it also flags about 99 of the 9,900 human texts. The flag queue is half innocent. This is where the AI text detector false positive rate meets the base rate, and no amount of fine-tuning fixes it, because the numbers are already excellent. Prevalence does the damage.
The deployment asymmetry decides the rest: in a review workflow, a false accusation (a student penalized, a contributor banned) costs far more than a missed detection. So the rubric:
- High prevalence, symmetric cost. Spam pre-filtering where a false positive is a held message, not an accusation. A verdict can be defensible.
- Moderate prevalence with review capacity. Ship as assist-only triage: scores route to humans, a low-confidence band abstains.
- Low prevalence, high stakes. Academic integrity, account bans. Do not ship a verdict.
At realistic prevalence, most single-verdict deployments fail this table. That is the point where the question of when an AI detector is too unreliable to deploy stops being philosophical and becomes arithmetic.
Guardrails If You Ship It Anyway
If the math clears triage, earn the deployment:
- Abstain band. Scores between two thresholds return "unclear" rather than a class. Triage tools get to say they don't know.
- Confidence tiers. Only high-confidence AI scores route anywhere. The middle band logs for monitoring and never auto-penalizes anyone.
- Human in the loop. A flag opens a review queue. Detector output is evidence in a human decision, never the decision itself.
- Drift monitoring. Track the score distribution weekly. A generator you never trained on shows up as distribution shift long before your dashboards notice. Retrain on a cadence and fold in new generators as they appear.
- Show score and length. Short, high-confidence flags deserve extra skepticism. Make reviewers see both numbers.
Honest Limits and What to Build Instead
Close the loops. Can a small local model compete? On clean, in-domain text, yes: mid-90s with LoRA on a 1.5B backbone or a RoBERTa-class encoder is a normal result, and the local build wins structurally on privacy and cost, since user text never leaves the machine and inference is free. Where do errors concentrate? Short inputs, human-edited and mixed text, paraphrased output, and non-native writing. When is shipping defensible? At moderate prevalence with a human in the loop and an abstain option, or at high prevalence when a false positive is cheap and recoverable.
What a local detector is genuinely good for: spam and low-quality content triage, corpus cleaning, internal tooling where a human adjudicates, and writing feedback that warns you your own draft reads machine-polished. When the base rate says no, build signals detection cannot fake instead: draft version history, editing provenance, consented session telemetry, watermarking when you control the generation side, and disclosure flows that make honesty cheaper than evasion.
The correct output of this build is a triage instrument with an abstain option, not a judge, plus a table of numbers that tells you honestly whether even that much ships.
Stay in the loop.
Get the latest posts and exclusive content delivered to your inbox.
Join 3 readers. No spam. Unsubscribe in one click, anytime.
About the author
Tyler Brooks
Tools Analyst
Tyler has tested developer tooling for a decade, first as a platform engineer and now as an independent analyst. He reviews models, frameworks, and APIs the way he would want them reviewed before relying on them for real work.
Related Posts
Fine-Tuning vs RAG vs Prompt Engineering Decision Framework
Fine-tuning vs RAG vs prompt engineering: run this eval-gated framework before training a custom model and inheriting its hidden maintenance tax.
LLM Context Window Management With a Token Budget
Learn LLM context window management with a token budget ledger, a stepwise compression ladder, and the prompt cache trap that punishes trimming.
Structured Output Local LLM Tactics That Survive Production
Structured output local LLM enforcement means choosing JSON mode, grammar decoding, or tool-calling. Each trades latency, throughput, and reliability.


