Paste the opening paragraph of the US Constitution into a few AI detection tools and some of them will tell you, with real confidence, that a language model wrote it. This has been passed around developer forums for a couple of years now as proof that detectors are snake oil. I read it as a very clean demonstration of what these tools measure, and once you see the mechanism the result stops being surprising.
Most developers I talk to treat an ai detector as a black box that outputs a percentage. The internals are less mysterious than that, and if you build anything that touches user-generated text (a CMS, an LMS plugin, a moderation queue, a hiring pipeline) it helps to know what the number means and where it breaks.
The core idea: how surprised is a model by this text?
A language model, at the lowest level, is a function that takes a sequence of tokens and returns a probability distribution over the next token. Give GPT-2 the string “The cat sat on the” and it assigns a high probability to ” mat,” a lower one to ” floor,” and a vanishingly small one to ” photosynthesis.”
You can run that in reverse on any existing text. Walk through the passage token by token and, at each position, ask the model how likely the actual next token was. Multiply those probabilities together (or, more practically, add the log probabilities) and you get a measure of how predictable the whole passage was to that model.
That measure, normalised for length, is perplexity. Low perplexity means the model found the text unsurprising. High perplexity means the text kept doing things the model didn’t expect.
Here’s the gist in Python, using Hugging Face Transformers and the small GPT-2 model:
import torch from transformers import GPT2LMHeadModel, GPT2TokenizerFast
tok = GPT2TokenizerFast.from_pretrained("gpt2") model = GPT2LMHeadModel.from_pretrained("gpt2").eval()
def perplexity(text: str) -> float: enc = tok(text, return_tensors="pt") with torch.no_grad(): out = model(**enc, labels=enc["input_ids"]) # out.loss is mean negative log-likelihood per token return torch.exp(out.loss).item()
print(perplexity("The cat sat on the mat.")) print(perplexity("The cat sat on the photosynthesis."))
The second sentence will score much higher. Nothing clever is happening: the loss the model was trained to minimise is being read back as a score.
This works as an AI signal because LLMs, when generating with typical sampling settings, tend to pick high-probability tokens. Their output sits in the comfortable middle of the distribution. Human writing wanders more. People pick odd words, make jokes, break grammar, switch registers mid-paragraph. So, on average, machine text has lower perplexity than human text when scored by a similar model.
“On average” is carrying a lot of weight in that sentence.
Burstiness: perplexity over time
A single perplexity number for a whole document throws away information. Burstiness is the name detection tools popularised for how much perplexity varies across the text, usually measured sentence by sentence.
Human writing tends to be uneven. A short punchy sentence, then a long winding one with three clauses and a parenthetical, then a fragment. Some sentences are predictable, some aren’t. Model output, especially from older or more conservatively sampled models, tends to be steadier: sentences of similar length and similar predictability, one after another.
A simple burstiness score might look like this:
import re, statistics
def burstiness(text: str) -> float: sents = [s for s in re.split(r'(?<=[.!?])\s+', text) if len(s.split()) > 3] ppls = [perplexity(s) for s in sents] return statistics.stdev(ppls) if len(ppls) > 1 else 0.0
Real tools are more careful (they deal with very short sentences, normalise by length, and often look at token-level variance rather than sentence-level), but the intuition holds. Flat perplexity across a document is treated as a machine signal. Spiky perplexity is treated as a human one.
Combine low average perplexity with low variance and you have the two features that the first wave of public detectors, GPTZero included, built their early explanations around.
Why the Constitution gets flagged
Back to the opening example. The preamble to the US Constitution appears, verbatim and in fragments, an enormous number of times in the text that language models are trained on. To a model, “We the People of the United States, in Order to form a more perfect Union” is about as predictable as text gets. Each next token is almost certain. Perplexity is extremely low.
The detector measured correctly and then drew the wrong inference. Low perplexity means “this text is predictable to a model,” and the tool then assumes predictable text was machine-generated. Famous text, boilerplate legal language, heavily templated writing, and simple prose by people writing in a second language can all be predictable for reasons that have nothing to do with AI.
Classifiers: the second generation
Pure perplexity scoring is a zero-shot method. You don’t train anything, you just score text against an existing model. It’s easy to build and easy to fool, and its accuracy depends on how similar the scoring model is to whatever generated the text.
Most commercial detectors now use supervised classifiers instead of, or on top of, raw perplexity. The recipe is familiar to anyone who has trained a text classifier:
- Collect a large corpus of human-written text across many genres.
- Generate a matching corpus with several LLMs, using similar prompts and topics.
- Fine-tune a transformer encoder (RoBERTa-style models were a common early choice) to label each passage as human or AI.
- Calibrate the output so the probability means something, and tune the decision threshold.
The classifier learns whatever features separate the two sets. Some of those overlap with perplexity and burstiness. Others are harder to name: favourite transition words, characteristic list structures, how often a paragraph ends with a summarising sentence, the distribution of punctuation. Em-dashes became a notorious tell in 2024 and 2025 for exactly this reason. Models used them a lot, classifiers picked up on it, and people started stripping them out.
Classifiers have two practical consequences for developers. Their accuracy depends heavily on how close your text is to the training distribution, so a detector trained mostly on student essays may behave oddly on API documentation. And they have to be retrained as new models ship, because each model family has its own stylistic habits. A detector that was excellent against one generation of models can drift as the next one arrives.
Some tools also go past a binary label. Quillbot’s detector, for instance, separates text that’s entirely AI-written, entirely human-written, and human-written with some AI refinement, and highlights results at the sentence level rather than returning one number for the whole block. That’s a more accurate framing of how text gets produced in 2026, since very little writing is purely one or the other anymore.
Sampling settings matter here too. A model generating at a high temperature picks less likely tokens more often, which pushes perplexity up and makes its output look more human to a perplexity-based scorer. A model at temperature zero produces the most predictable text it can. Most chat products sit somewhere in the middle and don’t tell you where, so the same model can produce text that’s easy to detect on one day and harder on another, depending on product settings the person typing never sees. Classifiers trained on outputs from a range of temperatures cope with this better than raw perplexity scoring does.
Watermarking is a different approach entirely
Detection after the fact is statistical guesswork. Watermarking tries to bake a signal into the text at generation time. The best-known academic scheme splits the vocabulary into a pseudo-random “green list” and “red list” at each step, seeded by the previous token, and nudges the model toward green tokens. A reader who knows the seeding scheme can count green tokens and check whether there are far more than chance would allow.
Google DeepMind has published work on SynthID for text, which uses a related idea. The catch is that watermarking only works if the model provider applies it, and only survives as long as the text isn’t heavily paraphrased or translated. It tells you nothing about text from an open-weights model someone runs locally.
False positives, and who gets hit by them
Every detector trades false positives (human text flagged as AI) against false negatives (AI text passing as human). Move the threshold one way and you catch more AI text while accusing more humans. Move it the other way and the reverse happens. There’s no setting that eliminates both.
The false positives aren’t spread evenly. A 2023 Stanford study by Liang and colleagues found that several popular detectors flagged essays by non-native English speakers as AI-generated far more often than essays by native speakers. The mechanism follows directly from perplexity: writers with a smaller working vocabulary in English tend to use common words and standard constructions, and that produces low-perplexity text.
Other groups that score as “too predictable” for structural reasons:
- Technical writers following a strict style guide
- People writing very short texts (a two-sentence product review has too few tokens for a stable estimate)
- Neurodivergent writers who prefer very regular sentence patterns
- Anyone writing in a heavily templated format, such as a medical discharge summary or a standard legal notice
Short text deserves its own warning. Below a few hundred words, most detectors become unreliable, and several vendors say so in their documentation. If you’re building a feature that scores tweet-length content, the scores are close to noise.
What this means if you’re building with detectors
If you’re integrating detection into a product, a few design choices go a long way.
Never auto-act on a score. A detection result should route content to a human, not reject it. Treat it like a spam score on a borderline email: a signal for triage.
Show the reasoning, or at least the uncertainty. “72% likely AI” invites people to read it as a verdict. Sentence-level highlighting and a confidence band are more useful to a reviewer.
Set a minimum length. Refuse to score, or clearly mark as low-confidence, anything under a threshold. A few hundred words is a common floor.
Log the model version. Detectors get retrained. If a user disputes a result six months later, you want to know which version produced it.
Test on your own data. Pull a few hundred known-human samples from your platform (from before LLMs were widely available, if you have them) and run them through. The false positive rate you see on your real users is the one that matters, and it may differ a lot from a vendor’s headline figure.
Various AI detection methods each have distinct requirements, strengths, and weaknesses. Perplexity scoring does not need training and is praised for being simple and explainable, though its main weakness is that it can be fooled by paraphrasing and sometimes incorrectly flags predictable human text. Similarly, burstiness analysis does not require training and effectively catches uniform styles, but it remains weak when applied to short text. On the other hand, supervised classifiers do require training to learn subtle stylistic cues; however, their main weaknesses are that they drift as new models are released and are sensitive to specific domains. Finally, watermarking requires provider-side implementation and offers a strong signal when present, but it is absent from most models and can be removed entirely through paraphrasing.
Paraphrasing and the arms race
Every detection method above can be weakened by rewriting. Paraphrase a passage, and perplexity goes up, burstiness changes, and the stylistic fingerprints a classifier learned get scrambled. That’s why detectors now train on paraphrased AI text too, and why humanizing tools and detectors keep chasing each other.
For developers this means detection is a probabilistic input with a shelf life, not a fixed property of text. I wouldn’t build a system where anything important depends on it alone. I would use one, carefully, as one signal among several: account history, submission timing, version history in a document editor, or a quick follow-up conversation.
FAQ
Can I build a decent detector myself? A perplexity-plus-burstiness prototype takes an afternoon with the code above. Getting it to perform well across genres and against current models takes labelled data and ongoing retraining, which is why most teams use a hosted ai detector or API rather than maintaining their own.
Does code get detected the same way? The same principles apply, but code is highly predictable by nature, so perplexity-based signals are weak. Most general-purpose text detectors aren’t designed for source code and shouldn’t be trusted on it.
Why do two detectors give different scores for the same text? They use different scoring models, different training data, and different thresholds. A 40-point disagreement between tools on the same paragraph is common.
Try it on your own writing
Run the perplexity function above on three things: a paragraph you wrote quickly in Slack, a paragraph from your project’s README, and a paragraph a chatbot wrote for you. Then run the burstiness function on each. You’ll probably find the README scores closer to the chatbot than to your Slack message, because documentation is supposed to be predictable. Sitting with that result for a minute is the fastest way I know to stop treating a detection percentage as a fact about who wrote something.
Further Reading
Discover more articles on similar topics across our network

Comments
Loading comments…