Wenn whisper.cpp den Satzanfang verschluckt — und das Glossar schuld ist

Martin Rau · · 5 Min. Lesezeit

Bei manchen Fehlern sucht man tagelang an der falschen Stelle, und am Ende stellt sich heraus: ausgerechnet die Funktion, die das Problem lösen sollte, hat es verursacht. So ein Fall war das hier. Unsere lokale Spracherkennung im boostN-CLI läuft über whisper.cpp, und damit das Modell unsere Fachbegriffe besser erkennt — Claude, RAG, MCP, boostN, DEVI Runner und so weiter —, geben wir ihm eine Keyword-Liste mit. Diese Liste wird whisper als sogenannter initial_prompt übergeben. Im Grunde ist das ein kleines Glossar, das vor der eigentlichen Transkription mitläuft.

Genau dieses Glossar hat mir am Satzanfang regelmäßig den halben Satz weggefressen. Und das Kuriose daran ist: Es passierte ausgerechnet bei den Sätzen, für die das Glossar überhaupt gedacht war.

Das Symptom: mal top, mal vorne abgeschnitten

Die Transkription lief lange Zeit unauffällig. Aber dann gab es immer wieder Aufnahmen, bei denen vorne ein ganzer Teil fehlte. Nicht ein einzelnes Wort, sondern der komplette Satzanfang. Die Ausgabe begann dann mittendrin, irgendwo in der Mitte des Gedankens.

Ein konkretes Beispiel aus dem Log: eine Aufnahme von 24 Sekunden, in die ich eine ganze Liste von Begriffen gesprochen hatte. Herausgekommen sind aber nur 11 Wörter — und zwar erst ab „RAG Update, Promptflow Studio, Superbase, Repository, Wave, Tickets …”. Der ganze vordere Teil war einfach weg.

Damit man eine Vorstellung von der Größenordnung hat: Über 128 echte Transkriptionen liegt mein normaler Durchsatz im Schnitt bei 22,6 Wörtern pro Sekunde, je nach Sprechtempo zwischen ungefähr 2,4 und 82,2. Diese eine 24-Sekunden-Aufnahme kam auf magere 5,2 Wörter pro Sekunde. Das ist rund ein Viertel des Normalen — und der Grund war nicht, dass ich langsam gesprochen hätte, sondern schlicht, dass die halbe Aussage fehlte.

Der falsche Verdacht: das Mikrofon

Mein erster Gedanke ging — wie wahrscheinlich bei den meisten — zum Eingangssignal. Klassischer Verdacht: Der Wortbeginn ist zu leise, man holt am Anfang noch Luft, das Mikro fängt die ersten Silben nicht sauber ein. Ich war sogar schon so weit, gedanklich „die ersten Wörter wegzuschießen”, weil ich fest davon ausging, dass das Audio am Anfang nicht taugt.

Ein zweiter Verdächtiger war ein bestimmter Schalter in unserem Aufruf, --suppress-nst, der Nicht-Sprach-Tokens unterdrückt. Vielleicht, so der Gedanke, schluckt der zu viel?

Beides klang plausibel. Beides war falsch.

Der A/B-Test: dieselbe Aufnahme, drei Varianten

Statt weiter zu raten, habe ich exakt dieselbe Aufnahme dreimal durch das kleine Modell geschickt — nur mit unterschiedlichen Schaltern:

  • (A) Mit Glossar: Anfang fehlt, Ausgabe ab „… RAG Update, Promptflow Studio …”, 11 von geschätzt über 40 Wörtern.
  • (B) Mit Glossar, aber ohne --suppress-nst: identisch, der Anfang fehlt weiterhin. Damit war dieser Schalter als Ursache raus.
  • (C) Ohne Glossar: der Satz vollständig — „Noch mal Boosten – Clouder, Notes, Hierarchie, Rack, Big Project, Orchestrator, Execution Pipeline, Commitment, LLM, MCP, Vision Board, … Wave, Tickets, Hierarchie und Sonnet.”

Der Vergleich von (A) und (C) ist der Beweis: Es lag nicht am Audio. Dasselbe Audio liefert mit Glossar einen abgeschnittenen Satz und ohne Glossar den vollständigen. Der Auslöser war also das Glossar selbst.

Die echte Ursache: whisper hält den Anfang für eine Wiederholung

Was passiert da technisch? whisper.cpp bekommt das Glossar als Vorlauf-Text. Wenn der gesprochene Satz dann selbst mit Wörtern beginnt, die in genau diesem Vorlauf stehen, hält das Modell den Anfang für eine Wiederholung des Prompts — und überspringt ihn. Es denkt sich sinngemäß: „Das hatten wir doch gerade schon.” Beim kleinen Modell (small) ist dieser Effekt besonders ausgeprägt, weil es mit geringerer Konfidenz arbeitet und schneller danebenliegt.

Und das ist der eigentliche Treppenwitz: Der Effekt trifft genau die Sätze, die mit Fachbegriffen anfangen — also exakt die Fälle, für die ich das Glossar überhaupt eingebaut hatte. Die Hilfe wird dann zum Saboteur.

Das deckt sich auch mit dem, was andere über das Verhalten von Whisper beschreiben: Der initial_prompt wirkt vor allem auf das erste Segment, und die Art, wie der Tokenizer Wortgrenzen über das vorangehende Leerzeichen erkennt, kann am Anfang zu solchen Aussetzern führen.

Was man daraus mitnehmen kann

Für alle, die selbst whisper.cpp mit initial_prompt einsetzen, sind ein paar Punkte hilfreich:

  • Größere Modelle (large-v3-turbo, large-v3) sind robust und zeigen den Skip kaum. Wer es sich leisten kann, ist mit ihnen auf der sicheren Seite.
  • Das Prompt-Limit von rund 224 Tokens gilt für alle Modellgrößen gleich. Ein größeres Modell erlaubt also nicht mehr Keywords — es verkraftet sie nur sauberer.
  • Wir staffeln unser Glossar inzwischen nach Modellgröße: 12 Keywords beim kleinen Modell, 20 bei medium/turbo, 25 bei large. Das ist bewusst eine Risiko-Staffelung, keine Kapazitätsrechnung — beim schwachen Modell halten wir das Glossar kurz, damit weniger schiefgehen kann.

Die eigentliche Lehre ist aber allgemeiner: Ein Hinweis, der die Erkennung verbessern soll, kann beim schwächeren Modell Text löschen. Das ist so kontraintuitiv, dass man von selbst nicht darauf kommt — man sucht beim Eingangssignal, dabei sitzt die Ursache im Prompt. Sichtbar gemacht hat es am Ende erst der nüchterne Vergleich der Zahlen: 22,6 Wörter pro Sekunde im Normalfall gegen 5,2 bei der abgeschnittenen Aufnahme. Ohne diese Messwerte hätte ich vermutlich weiter am Mikrofon geschraubt.

Entdecke mehr