ealeng
Menu

Episode 03 of 10

Catching speech-to-text hallucinations

30 seconds of silence became "Meghalaya, India". Why speech models write text nobody said, why WER can't see it, and how to catch it in production without a reference transcript.

Lab 03 · Hallucinations & Runaways8 min read
Video transcript7:53

0:00Cold open

0:01

This is thirty seconds of silence. Nobody is talking.

0:05

🔊 (silence)

0:08

I sent it to a speech-to-text model: gpt-4o-transcribe. I set the language to English.

0:15

What do you think it wrote?

0:18

Meghalaya, India.

0:21

That’s a state in India. From thirty seconds of nothing.

0:25Intro

0:27

Hands-on voice AI evals, episode three.

0:30

In a real product, nobody tells you a transcript is wrong. So how do I catch a made-up one?

0:3601 · Why the score misses it

0:38

In episode one, we measured word error rate.

0:41

It compares the transcript with an answer key: what was really said.

0:45

But here, nothing was said. Zero words.

0:49

And you can’t divide by zero. So test sets usually just leave these clips out.

0:54

On real speech, it’s rare: one bad clip in hundreds. So the average hardly moves.

1:00

But the customer who reads that transcript thinks your product is broken.

1:0502 · Writing over nothing

1:06

So I made twenty-four clips with nobody at the microphone. Silence, hold music, keypad tones, clicks, and voices far away.

1:14

The right transcript for all of them is: nothing.

1:18

Here’s what six models did. Each cell counts the clips where a model wrote something.

1:23

Two models, gpt-transcribe and nova-3, wrote nothing at all. Perfect.

1:28

Whisper wrote something on about a third of the clips.

1:32

And gpt-4o-transcribe? Seventeen out of nineteen.

1:36

The distant voices are different. That’s real speech, just far away. So I count them separately.

1:4302 · What they wrote

1:44

Whisper’s favorite is one word: you. On silence. On keypad beeps. On a dial tone.

1:50

And on hold music, like this one…

1:52

🔊 hold music

1:57

it wrote: Thanks for watching!

2:01

gpt-4o-transcribe is stranger. The language was set to English.

2:06

But it wrote in other languages: Romanian, Croatian, Arabic, Japanese.

2:11

And over keyboard clicks, in Chinese: I have a little cat.

2:16

Why does this happen? These models learned from internet videos with captions.

2:20

And in those videos, silence and end-credit music often come with a caption like: thanks for watching.

2:27

So when there’s nothing to hear, the model writes what usually goes there.

2:3203 · Fix one: a voice detector

2:34

The standard first fix is a voice activity detector. It’s a small, separate model that asks one question: is someone speaking right now?

2:42

It runs first, and cuts out every stretch where nobody is speaking.

2:46

So the transcription model never hears the silence, and has nothing to make up.

2:51

I put one in front of Whisper small. The clips with made-up text dropped from ten to four.

2:58

And on real speech, the error rate didn’t change at all. So it costs nothing.

3:02

What still gets through? The distant voices, because those are speech. And one hold-music clip it mistook for a voice.

3:10

So it helps. But I still need a way to catch what slips past.

3:1404 · Text vs. audio

3:16

Now: how do I catch it without an answer key? The trick is to compare the text with the audio.

3:21

People speak at a steady pace: about two to three words a second.

3:25

And a voice detector tells me how many seconds of speech there were. So I know roughly how many words to expect.

3:33

Take this clip: ten seconds of speech. At that pace, I’d expect about twenty-seven words. The model wrote twenty-nine.

3:40

Divide the words written by the words expected, and you get the length ratio. Here it’s about one. That’s normal.

3:47

Now the silence. Zero seconds of speech, so almost no words expected. But two were written. A ratio of ten.

3:56

It’s like a taxi meter running while the car is parked.

3:59

And remember nova-3’s empty answer, from last episode? Three and a half seconds of speech: about nine words expected. It wrote none. A ratio of zero.

4:10

So one number catches both: the made-up answer, and the empty one. And it never needed an answer key.

4:1805 · Whisper’s own check

4:19

The length ratio is one signal: a simple check that needs no answer key. I tried a few more. Does the text look like English? Is it a known phrase, like “thanks for watching”?

4:30

To grade the signals, I used twelve hundred transcripts where I do have the answer key, so I know which ones are bad.

4:37

Each signal gets a score: how often it rates a bad transcript as more suspicious than a good one. One means always. A half is a coin flip.

4:46

The length ratio, on made-up text: zero point nine seven. Nearly perfect.

4:52

Now, Whisper has its own check. It zips the text, like a zip file. Text stuck in a loop, the same phrase again and again, shrinks a lot. So if the text shrinks too much, Whisper calls it bad. How well does that catch made-up text?

5:09

Zero point zero eight. Worse than a coin flip. It points the wrong way.

5:14

Why? Made-up text is short, like “you”. A single word can’t shrink. That check was built for long loops, and it’s blind to short inventions.

5:23

So each signal catches one kind of failure. Next, I combine them.

5:2806 · A detector

5:30

Now I combine them into a detector. It flags a transcript if any rule fires: too much text, too little text, not English, or a known phrase.

5:39

Each rule needs a threshold: the line where it fires. For example, flag it if the ratio is above three.

5:46

I chose the thresholds on half of the clips. That’s the tuning half.

5:51

Then I tested once, on the other half, which the detector had never seen. If I tested on the same clips, it would be like grading an exam you’ve already seen the answers to.

6:01

Whisper’s own check, by itself, caught none.

6:04

The length ratio alone caught about half of the bad transcripts.

6:08

All the rules together caught nearly four out of five. And when it raised a flag, it was almost always a real failure.

6:16

Each flag can get a retry with another model, or go to a person.

6:2106 · Too good to be true

6:22

But something bothered me.

6:24

Normally, a detector does a bit worse on clips it has never seen. Its thresholds were fitted to the tuning clips.

6:31

Mine did better on the test half. That’s not good news. It usually means the test half was easier.

6:38

So I counted what was in each half.

6:41

Cut-off answers: seventeen in the tuning half. Just two in the test half. They came from a few phone calls, and the split put almost all of them on one side.

6:50

So the test half says almost nothing about cut-off answers. It looked good because the hard cases were missing.

6:58

And its one false alarm? A sentence that was half German. The answer key called it fine. The detector was right.

7:0607 · What I’d ship

7:07

So here’s what I’d ship. A voice detector in front of the model. Then the length ratio and a language check on every transcript.

7:15

Anything flagged gets a retry, or a person.

7:18

It can’t catch everything. A misheard sentence of the right length looks normal. For that, I still check a sample against an answer key.

7:27

One more thing kept nagging me. Run the same model twice, and the numbers change a little.

7:33

So when a new model scores better, is it really better? Or just luck? That’s next time.Yuki: Real, or just luck? 🤔

7:39Summary

7:41

No answer key? Compare the text with the audio. Check the language. And test your detector on clips it hasn’t seen.

7:48

Then made-up transcripts stop slipping through.Yuki: Thanks! 😄

Key takeaways

  • ✓Hallucinations are rare and large: an average WER barely moves, but the customer sees nonsense.
  • ✓WER can't even score them: on a clip with no speech, the reference is empty and there's nothing to divide by.
  • ✓A voice activity detector (VAD) in front of the model cut invented text from 10 of 24 clips to 4, with no cost to speech WER.
  • ✓In production, use reference-free signals. The length ratio caught invented text with an AUC of 0.97.
  • ✓Zero failures in 100 clips still allows a rate up to 3%. Report rare failures with intervals.

Chapter 1 showed that WER can pass 100% when a model invents words. This chapter is about those inventions, and the failures that look like them: text written over silence, runaway loops, transcripts that stop early, repeated speech collapsed into one copy, and output in the wrong language. They're rare and large: they don't happen often, but when they do, the transcript is badly wrong, and the customer notices.

Why WER can't see them

WER has two blind spots, and these failures live in both:

  • It needs a reference. On a clip with no speech, the reference is empty, so WER can't be computed: there are zero words to divide by. Such clips are often left out of test sets entirely, and they're exactly where models invent text.
  • It's an average. One clip that repeats "thank you" 500 times barely moves the WER of 200 clips. A customer who sees that transcript thinks the product is broken.
Failure What it looks like Why WER misses it
Invented text "You", "Thanks for watching!", a plausible sentence over silence The reference is empty, so WER is undefined
Runaway A phrase repeated until the output limit One clip, averaged with hundreds of good ones
Truncation The first sentence, then nothing Looks like ordinary deletions
Collapsed repetition "no, no, no, no" becomes "no" Looks like cleaning up
Wrong language Another language, or a mix ("Für die Separation of…") Just a clip with high WER

What models write on nothing

Why would a model write text when nobody is talking? Whisper-style models learned from internet audio with captions, and videos often have captions like "Thanks for watching" over silence and end credits. For no speech, those are likely outputs. The model writes one token at a time, each based on what it already wrote, so once it has started a phrase it can also get stuck repeating it.

The lab played six models 24 clips with no speech: silence, room tone, hold music, phone tones, clicks, and distant voices. Click any cell:

Try it · What models wrote on nothingReal results from Lab 03 · click a cell
Non-speech clipwhisper-basewhisper-smallgpt-4o-minigpt-4o-transcribegpt-transcribenova-3
Silence
Room tone
Hold music
Keypad, dial, ringback tones
Clicks, loud noise
Distant talkersvoices, so arguably speech
Clips with no voices, any text7/196/191/1917/190/190/19

gpt-4o-transcribe · silence

Wrote text on 2 of 2 clips. Example: "Meghalaya, India" (for 30 s of silence)

The spread is huge. gpt-transcribe and nova-3 wrote nothing on any clip without voices. gpt-4o-transcribe wrote something on 22 of 24, often in other languages, with language="en" set: "Meghalaya, India" for 30 seconds of silence. The bottom row is a product question rather than a model one: every model transcribed distant voices, and whether that's an error depends on whether your customers want "what the caller said" or "what was said in the room".

Two more findings worth knowing:

  • The fix is cheap. A voice activity detector (VAD) is a small model that answers only "is someone speaking here?". Putting Silero VAD in front of whisper-small.en cut the clips with invented text from 10 of 24 to 4, with speech WER unchanged at 4.6%. It can't fix background voices, because those are speech.
  • Isolated silence is the harsher test. When real speech was followed by 20 s of silence or music, no model wrote a single word after the speech. The speech just before seems to suppress inventions.

Loops, gaps, and collapsed repetition

Whisper reads long audio in 30-second windows, and by default each window gets the previous window's text as a hint (condition on previous text). That helps names and sentences carry across window boundaries. On a silent window, though, the model may simply copy the hint: in a clip with 15-second pauses, Whisper wrote "They were to proceed immediately to the election." into the silent gaps, twice, taking WER from 4% to 34%.

The opposite failure is quieter. When the lab played the same sentence six times in a row, most models deleted real repetition. gpt-4o-transcribe wrote every sentence exactly once; nova-3 was the only model that kept all six copies every time. For a caller who reads an account number twice, or says "no, no, no", that's lost speech that looks like tidying up.

Catching it without a reference

In production there's no reference transcript. What you do have is the audio and the output, and that's enough for several signals:

Signal Catches How
Length ratio Invented text (high), truncation (low) Words written ÷ words expected from the speech a VAD found
Compression ratio Long loops Repetitive text compresses well. Whisper's own rule is "above 2.4"
Repeated n-grams Loops Share of 4-word sequences seen before
Language check Wrong-language output A language identifier on the output
Known phrases Classic inventions "Thanks for watching", or an output that is just "you"

Reference-free signals and detectors: ASR failure types on silence, VAD-based detector architecture, length ratio formulas, and classifier performance. Reference-free signals and detectors — VAD duration, length ratios, and classifier performance in production.

The strongest is the length ratio: people speak about 2.7 words per second, so 10 seconds of speech should produce about 27 words.

ratio = words written ÷ (2.7 × seconds of speech + 0.2)

Zero seconds of speech and the output "You" gives 1 ÷ 0.2 = 5.0: far too much text for the audio. Try the lab's cases, or type your own:

Try it · A detector without a referenceSignals and thresholds from Lab 03
Words written
1
Expected words
0
Length ratio
5.00
Compression
0.0

ratio = 1 ÷ (2.7 × 0 + 0.2) · repeated 4-grams: 0%

  • ⚑ Invented text · length ratio 5.00 > 3.0: far more words than the speech can hold
  • ⚑ Known phrase · a lone "you": a classic invention on silence

Each signal catches one kind of failure, and the lab measured how well with AUC (0.5 is a coin flip, 1 is perfect). The length ratio scored 0.97 on invented text. Compression scored 0.08: it points the wrong way, because invented outputs are short ("You"), and short text never compresses. Whisper's 2.4 rule is only for long loops.

Every signal can be fooled, too. A correct transcript of a fast phone-menu prompt gets a high length ratio, and earnings talk ("minus 18, then minus 15… in Q3") can look non-English to a language identifier. And one failure no reference-free signal can catch: a misheard English sentence of the right length.

Measure the detector like a classifier

A detector says "suspicious" or "fine", so measure it with precision (of the flags, how many are really bad?) and recall (of the bad outputs, how many get flagged?). Choose thresholds on one set of clips (dev) and score once on another (holdout). In the lab, the combined detector reached 0.96 precision and 0.78 recall on the holdout. Whisper's compression rule alone caught nothing.

One catch worth remembering: the holdout scored better than dev (F1 0.86 vs 0.58). That's a warning sign, not good news. The holdout contained only 2 truncation failures against 17 in dev, so it said very little about truncation.

Rare failures need big numbers

Some failures are deterministic: a Cockney clip ("see 'im crost the road there") came back in another language on all 5 runs for all three OpenAI models, identically every time. Others are random: one model switched language on "where's Milicent" 1 time in 5. Either way, to measure something that happens to 2% of clips you need many clips, repeated runs, and intervals:

Try it · How rare is rare?Wrong-language outputs from Lab 03, or your own counts
Observed rate
0.0%
95% interval
0.0%–3.7%
Rule of three
≤ 3.0%

Zero failures in 100 clips still allows a true rate up to about 3.0%.

Settings matter per model, too. For the OpenAI models, forcing language="en" made no difference to the switch rate. For nova-3 it was the whole difference: 0 of 100 with English forced, 10 of 100 with automatic detection. And even that zero only means "very likely under 3.7%". To promise a customer "under 0.5%", you need zero failures in about 600 clips.

Practice: build the signals

Implement the lab's reference-free signals and the Wilson interval: length_ratio(), compression_ratio(), repeated_ngrams() and wilson(). The tests use the lab's numbers: "You" on silence scores 5.0, a 40-times "I'm fine." loop compresses past 2.4, and 23 failures in 100 gives 15.8%–32.2%.

Try it · Practice in PythonRuns in your browser · ⌘/Ctrl + Enter to run
signals_practice.py60 lines

Quiz

Try it · Check your understanding0 of 6 answered
  1. 1.A model writes "Thanks for watching!" on 20 seconds of hold music. What does WER say about this clip?

  2. 2.Why do Whisper-style models write "You" or "Thanks for watching!" on silence?

  3. 3.You put a voice activity detector (VAD) in front of the model. What won't it fix?

  4. 4.Whisper flags loops with "compression ratio above 2.4". In the lab, this signal had an AUC of 0.08 for invented text. What does that mean?

  5. 5.Your detector scores F1 0.58 on dev and 0.86 on the holdout. Good news?

  6. 6.A model produced zero wrong-language outputs in 100 clips. What can you promise a customer?

Check your understanding

Try each question before opening its answer.

What are hallucinations, runaways, truncation, collapsed repetition, and language switches—and why can WER hide them?

They are distinct failures: invented text, repeated loops, incomplete output, omitted repeated speech, and output in another language. They may occur on empty-reference audio or a small number of clips, so track dedicated rates and limits instead of relying on average WER.

Why do Whisper-style models write text on silence, and what does VAD fix or miss?

Training data often pairs silence or music with captions, making familiar text a plausible output. VAD removes much non-speech, but can miss music, cannot remove real background talkers, and may cut quiet speech.

What does “condition on previous text” do, and how can it cause loops?

It supplies the previous window's transcript as context, helping continuity but also priming a silent window to repeat prior text. Test it on long, pause-heavy audio.

Which signals can flag a bad transcript without a reference, and what fools them?

Length ratios can flag likely runaways or truncation; language checks and foreign letters can flag switches; compression and repeated n-grams can find loops; known phrases catch familiar inventions. Short prompts, numbers, jargon, and background speakers can fool these signals.

How do you choose detector thresholds and measure them honestly?

Label examples, split dev and holdout by speaker/call/type, tune thresholds only on dev, and report precision and recall by failure type on holdout. Compare simple baselines and ensure each failure type appears in both splits.

How do you measure a failure that happens on 2% of clips, and what does zero failures prove?

Use enough examples and repeated runs, report a rate with an interval, and distinguish stable from random failures. Zero events in n trials only bounds the rate at roughly 3/n (rule of three); it does not prove zero risk.

When is transcribing background voices an error?

It depends on the product: background speech is noise for “what did the caller say?” but content for meeting transcription. Define that policy explicitly; an audio-only detector cannot decide whether real speech is relevant.

Next up: a new model version scores 30% better. Chapter 4 asks whether it really is, or whether that's noise.

Learning something useful?

New labs, articles, and videos on evaluating and testing AI systems come out regularly. Follow along so you don't miss the next one.