Zum Inhalt springen

Echtzeit-Spracherkennung unter 200 ms: Ein Architekturleitfaden

Veröffentlicht
Zuletzt aktualisiert

AnhörenArtikel anhören

Echtzeit-Spracherkennung (STT) transkribiert Audio aktiv, während eine Person spricht, und gibt die gesprochenen Worte innerhalb weniger hundert Millisekunden als Text zurück. Eine niedrige STT-Latenz zu halten, ist jedoch ebenso eine Architektur- wie eine Modellfrage. Entwickler müssen Transport, Chunking, Endpunkt-Erkennung und Aufnahmepfad planen, da jeder dieser Bereiche zur Latenz beiträgt. Ineffizienz in nur einem Bereich kann Ihr Budget von 200 ms sprengen.

Dieser Leitfaden bietet ein praxistaugliches System zum Aufbau von Echtzeit-Spracherkennungs-Pipelines – von der Transportschicht an. Im Mittelpunkt steht Scribe v2 Realtime, das Teiltranskriptionen bei etwa 150 ms Modelllatenz liefert, mehr als 90 Sprachen unterstützt, PCM-Audio (8 kHz–48 kHz) und Mu-Law akzeptiert sowie Voice Activity Detection und manuelle Commit-Steuerung zur Segmentfinalisierung bietet.

Wir zeigen, wie Audio den Server erreicht, wie Hypothesen zu festgeschriebenem Text werden, welche Kosten In-Stream-Features verursachen und wie Sie Audio korrekt erfassen und weiterleiten.

Zusammenfassung

  • Echtzeit-Spracherkennungssysteme erfordern eine fein abgestimmte Architektur, damit die Latenz in der gesamten Pipeline niedrig bleibt.
  • WebSocket ist für die meisten Pipelines die richtige Standardwahl. WebRTC bietet zwar mehrere Vorteile, ist jedoch komplexer.
  • Voice Activity Detection ermöglicht eine freihändige Segmentierung. Mit manuellem Commit können Anwendungen eingreifen, wenn sie wissen, dass ein Sprecherzug beendet ist.
  • Partials sind vorläufig, Finals sind festgeschrieben. Sie sollten daher unterschiedlich dargestellt werden. 
  • Kleine PCM-Chunks von etwa 100 ms minimieren die Latenz bis zum ersten Partial.

WebSocket vs. WebRTC für Echtzeit-Spracherkennung

Bevor eine Transkription erfolgen kann, muss Audio von der Quelle zum Erkenner gelangen. Der gewählte Kanal bestimmt die minimale Latenz für alles, was danach folgt. Es gibt zwei praktikable Optionen, um Audio zur Transkriptionsschicht zu übertragen.

WebSocket ist ein langlebiger, geordneter, zuverlässiger bidirektionaler Kanal über TCP. Sie öffnen eine Verbindung, senden binäre Audio-Frames und empfangen Transkriptereignisse. Er ist auf Client und Server einfach umzusetzen, durchquert Unternehmens-Proxys und Firewalls, die HTTPS bereits zulassen, und wird von jeder Browser- und Serverlaufzeit unterstützt. 

Die Einschränkung von WebSocket ist TCP. Geht ein Paket verloren, überträgt TCP es erneut und hält spätere Daten zurück, bis die Lücke geschlossen ist. Bei guten Netzwerkbedingungen fällt das nicht auf. Bei Paketverlust entsteht jedoch Head-of-Line-Blocking: Audio staut sich kurz und kommt dann gebündelt an.

WebRTC wurde für Echtzeitmedien entwickelt. Es überträgt Medien über UDP (via SRTP), sodass ein verlorenes Paket den Stream nicht anhält; die Pipeline läuft weiter. Es umfasst einen Jitter Buffer, der Schwankungen bei Paketankunftszeiten auffängt, handelt NAT-Traversal mit ICE/STUN/TURN aus, damit Peers hinter Routern eine Verbindung herstellen können, und bringt eigene Mechanismen für Audioaufnahme und -kodierung mit. 

Für Clients ohne Direktverbindung benötigen Sie in der Regel TURN-Server. Serverseitig müssen Sie einen Medienstrom terminieren, statt einen Bytestrom zu lesen.

Die Abwägung auf einen Blick:

WebSocket
Transport
TCP (reliable, ordered)
Behavior under packet loss
Head-of-line blocking, bursty recovery
Jitter handling
Your responsibility
NAT traversal
Not needed (client-initiated)
Browser support
Universal, trivial
Server complexity
Low
WebRTC
Transport
UDP/SRTP (real-time, loss-tolerant)
Behavior under packet loss
Graceful degradation
Jitter handling
Built-in jitter buffer
NAT traversal
Requires ICE/STUN/TURN
Browser support
Universal, but more API surface
Server complexity
High (media server or SFU)

Für die meisten Anwendungsfälle ist WebSocket die richtige Wahl. Verwenden Sie es, wenn Ihre Clients eine gute Verbindung haben und Sie den Aufnahmepfad kontrollieren: Server-zu-Server-Pipelines, Desktop-Apps, Browser-Apps über Breitband sowie die meisten Contact-Center-Backends, bei denen Audio bereits auf anderem Weg bei Ihrem Server ankommt. 

Wählen Sie WebRTC, wenn Sie direkt von Endgeräten in unzuverlässigen Mobilfunknetzen aufnehmen, bereits einen WebRTC-Stack für bidirektionales Audio betreiben – etwa für einen Voice Agent, der auch antwortet – oder verlustrobustes Echtzeitverhalten wichtiger ist als eine einfache Implementierung.

Der Rest dieses Leitfadens verwendet WebSocket als Transport für die Erkennerverbindung. Damit bleiben die einzelnen Komponenten sichtbar, und für die meisten Teams ist es der richtige Ausgangspunkt. Nichts daran ist spezifisch für WebSocket: Sie können später einen WebRTC-Medienpfad davor schalten, das Audio auf dem Server in PCM dekodieren und dieselben Chunks in die Pipeline weiterleiten.

Partials und finale Transkripte: Zwischenergebnisse erklärt

Ein Echtzeiterkenner wartet nicht auf einen vollständigen Satz, bevor er Ergebnisse ausgibt. Stattdessen erzeugt er einen fortlaufenden Strom von Vermutungen, die mit weiterem Audio präziser werden, und schreibt sie dann fest. Der Unterschied zwischen diesen beiden Zuständen entscheidet darüber, ob ein Transkript lebendig oder fehlerhaft wirkt. 

Eine partielle (vorläufige) Hypothese ist die beste Schätzung des Modells auf Basis des bisher empfangenen Audios. Partials sind bewusst instabil. Mit weiterem Audio überarbeitet das Modell frühere Wörter: „Ich möchte“ kann zu „Ich möchte zwei Tickets“ werden, sobald der spätere Kontext die Mehrdeutigkeit auflöst. Sie treffen schnell ein – darauf bezieht sich die Latenzangabe von etwa 150 ms – und sollen überschrieben werden.

Eine finale Hypothese ist ein festgeschriebenes Segment, das sich nicht mehr ändert. Sobald ein Segment finalisiert ist, fährt der Erkenner fort, und nachfolgende Hypothesen beschreiben späteres Audio. Finals speichern Sie dauerhaft, senden sie an ein LLM oder legen sie als Transkript ab.

Die Unterscheidung zwischen Partials und Finals bestimmt drei Dinge, die Sie falsch umsetzen, wenn Sie sie verwischen:

  • Nutzererlebnis: Partials lassen ein Transkript live wirken: Nutzer sehen Wörter erscheinen, während sie sprechen. Das bestätigt, dass das Mikrofon funktioniert und das System zuhört.
  • Endpunkt-Erkennung: Partials liefern ein kontinuierliches Signal zur Sprachaktivität. Zusammen mit VAD können Sie damit bestimmen, wann der Sprecher tatsächlich aufgehört hat.
  • Timing nachgelagerter Prozesse: In einer Voice-Agent-Pipeline folgen auf eingehendes Audio Speech to Text, dann ein LLM, dann Text to Speech und schließlich ausgehendes Audio. Sie können auf Basis von Partials spekulative Arbeit beginnen und sie bei Finals bestätigen. Das reduziert die wahrgenommene Antwortzeit, kann aber bedeuten, dass spekulative Arbeit gelegentlich verworfen wird.

Stellen Sie Partials und Finals unterschiedlich dar. Ein einfaches, wirksames Muster ist eine einzelne veränderbare „aktuelle Zeile“, die an das neueste Partial gebunden ist und bei Eingang eines Finals an ein Transkript angehängt wird:

type TranscriptState = {
  committed: string[]; // finalized segments, never rewritten
  current: string;     // latest partial, overwritten on each update
};

const onPartial = (s: TranscriptState, text: string): TranscriptState =>
  ({ ...s, current: text });

const onFinal = (s: TranscriptState, text: string): TranscriptState =>
  ({ committed: [...s.committed, text], current: "" });

Stellen Sie festgeschriebenen Text visuell normal und die aktuelle Zeile heller oder kursiv dar, damit Nutzer erkennen, dass sie sich noch ändern kann.

Endpunkt-Erkennung und Voice Activity Detection (VAD)

Zu wissen, was gesagt wurde, ist nur die halbe Aufgabe. Ein Erkenner muss auch wissen, wann ein Gedanke beendet ist. Diese Entscheidung bestimmt, wann Sie ein Segment finalisieren und wann das System bei einem Agenten zu antworten beginnt. 

Endpunkt-Erkennung ist die Entscheidung, dass eine Äußerung beendet ist. Eine zu frühe Finalisierung unterbricht Nutzer mitten im Satz. Eine zu späte Finalisierung lässt einen Agenten schweigen, obwohl der Nutzer klar fertig ist.

Scribe v2 Realtime bietet dafür zwei sich ergänzende Mechanismen:

  • Voice Activity Detection segmentiert Audio anhand von Stille: Der Erkenner erkennt, wenn Sprache in anhaltende Stille übergeht, und nutzt diese Grenze zur automatischen Finalisierung eines Segments. VAD ist der richtige Standard für dialogorientierte Oberflächen, weil sie sich an den natürlichen Sprechrhythmus anpasst, ohne dass Sie Zeiten manuell verfolgen müssen.
  • Manuelle Commit-Steuerung: Die manuelle Commit-Steuerung ermöglicht Ihrer Anwendung, unabhängig von Stille zu entscheiden, wann das aktuelle Segment finalisiert wird. Sie senden ein Commit-Signal, der Erkenner schließt das aktuelle Segment und gibt ein Final aus. Das ist das richtige Werkzeug, wenn Ihre Anwendung bereits weiß, dass der Sprecherzug beendet ist: beim Loslassen einer Push-to-Talk-Taste, bei einer „Senden“-Aktion oder durch eine externe Turn-Taking-Richtlinie.

Beide lassen sich gut kombinieren. Ein typischer Voice Agent nutzt VAD für den freihändigen Betrieb und bietet manuellen Commit als Übersteuerung. So wird ein Nutzer, der zum Nachdenken pausiert, nicht unterbrochen, während ein Nutzer per Tastendruck sofort eine Segmentgrenze erhält.

Der Stille-Schwellenwert ist eine echte Abwägung ohne universell richtigen Wert:

  • Ein kurzes Timeout nach Sprachende – beispielsweise Finalisierung nach etwa 200–400 ms Stille – lässt das System reaktionsschnell wirken. Es unterbricht jedoch auch Nutzer, die zwischen Teilsätzen natürlich pausieren, teilt einen Gedanken in mehrere Segmente und kann bei einem Agenten eine verfrühte Antwort auslösen.
  • Ein langes Timeout – beispielsweise etwa 800–1200 ms – toleriert natürliche Pausen und hält Äußerungen zusammen, führt jedoch zu einer merklichen Verzögerung, bevor das System reagiert.

Es gibt hier keine globale Konstante. Stimmen Sie den Schwellenwert auf die Interaktion ab:

  • Diktieren und Notizen erlauben längere Pausen, da Nutzer mitten im Satz nachdenken. Bevorzugen Sie längere Timeouts und setzen Sie auf VAD.
  • Befehls- und Transaktionsagenten profitieren von kürzeren Timeouts plus manuellem Commit, da Sprecherzüge kurz und klar sind.
  • Mehrsprachige Sprecher oder Nichtmuttersprachler pausieren häufiger. Planen Sie daher vor der Finalisierung mehr Stille ein.

Mit diesen Hinweisen können Sie ein wirksames System zur Endpunkt-Erkennung aufbauen und sich einer Echtzeit-Spracherkennung annähern.

In-Stream-Features: Spracherkennung und Sprecherdiarisierung

Streaming-Erkennung kann mehr als nur Wörter erzeugen. Jedes zusätzliche angeforderte Signal beeinflusst jedoch Latenz und Stabilität. Als Faustregel gilt: Aktivieren Sie nur, was das Live-Erlebnis benötigt, und verschieben Sie den Rest auf einen Batch-Durchlauf.

Die automatische Spracherkennung ermöglicht Scribe v2 Realtime, die gesprochene Sprache unter mehr als 90 unterstützten Sprachen zu erkennen, statt dass Sie sie vorab angeben müssen. Dafür benötigt das Modell eine kurze Audiosequenz, um eine zuverlässige Entscheidung zu treffen. Die ersten Partials eines Streams können daher weniger stabil sein, während sich die Sprache festlegt. Wenn Sie die Sprache bereits kennen, beseitigt ihre Angabe diese Mehrdeutigkeit und führt meist zu stabileren frühen Partials.

Sprecherdiarisierung ordnet Sprache einzelnen Sprechern zu und identifiziert, wer was gesagt hat. Bei der Batch-Transkription ist das vergleichsweise einfach, da das Modell die gesamte Datei sieht. Beim Streaming ist es schwieriger: Der Erkenner muss anhand des bisher vorhandenen Audios ein Sprecherlabel vergeben, und ein für frühes Audio vergebenes Label muss möglicherweise korrigiert werden, sobald mehr von dieser Stimme zu hören ist. Behandeln Sie Sprecherlabels im Streaming wie partiellen Text: als vorläufig, bis das Segment finalisiert ist.

Wortgenaues Timing und Entitätskontext folgen derselben Logik. Je mehr Metadaten pro Token Sie anfordern, desto mehr müssen sowohl Modell als auch Übertragungsweg verarbeiten. Für die meisten Echtzeit-UIs benötigen Sie live nur Text und Segmentgrenzen. Detaillierte Metadaten können Sie in einem Batch-Durchlauf nach dem Anruf mit Scribe v2 ergänzen.

Audioformate für Streaming: PCM und Mu-Law

Transport- und Erkennungslogik erhalten meist die meiste Aufmerksamkeit. Ein überraschend großer Anteil realer Bugs entsteht jedoch eine Schicht darunter: bei der Kodierung und dem Chunking von Audio. Das richtige Format und die richtige Chunk-Größe sind die kostengünstigste Möglichkeit, die Speech-to-Text-Latenz zu senken.

PCM (linear, 16-Bit vorzeichenbehaftet, Little Endian) ist das richtige Format, wenn Sie die Aufnahme kontrollieren. Höhere Abtastraten enthalten mehr akustische Details: 16 kHz sind der Standard-Mindestwert für Spracherkennung und reichen meist aus; 8 kHz entsprechen Telefonqualität und verlieren hochfrequente Inhalte. Verwenden Sie die Abtastrate Ihrer Quelle. Das Hochskalieren von Telefonie-Audio mit 8 kHz auf 48 kHz bringt keinen Nutzen, da die fehlenden Informationen nicht wiederherstellbar sind.

Mu-Law mit 8 kHz ist das Telefonieformat. Wenn Sie Anrufe von einem Anbieter wie Twilio aufnehmen, kommt das Audio als Mu-Law mit 8 kHz an. Sie sollten es in diesem Format weiterleiten, statt es zweimal zu transkodieren. Das Quellformat beizubehalten vermeidet Resampling-Artefakte und einen unnötigen Konvertierungsschritt.

Die Chunk-Größe beeinflusst die wahrgenommene Latenz am direktesten. Sie senden Audio in Chunks, und der Erkenner erzeugt Partials, sobald Chunks eintreffen. Kleinere Chunks bedeuten häufigere Updates und geringere Latenz bis zum ersten Partial; größere Chunks bedeuten weniger Nachrichten und etwas mehr Kontext pro Inferenz. Ein praktischer Bereich liegt bei 20–250 ms Audio pro Chunk. Bei PCM mit 16 kHz, Mono und 16 Bit entspricht eine Sekunde Audio 32.000 Bytes. Ein Chunk von 100 ms hat also etwa 3.200 Bytes.

Mikrofoneingabe im Browser erfassen

Im Browser ist die Web-Audio API mit einem AudioWorklet das richtige Werkzeug. Das Worklet läuft im Audio-Rendering-Thread, empfängt Audio in kleinen Frames und ist nicht dem Main-Thread-Jank ausgesetzt wie der ältere ScriptProcessorNode. Seine Aufgabe ist, die nativen Float-Samples des Browsers in 16-Bit-PCM umzuwandeln und an den Main Thread zu übergeben, der sie über WebSocket weiterleitet.

Der Kern des Worklet-Prozessors ist die Float-zu-PCM-Konvertierung:

// pcm-worklet.ts - registered via audioContext.audioWorklet.addModule()
class PCMWorklet extends AudioWorkletProcessor {
  process(inputs: Float32Array[][]) {
    const channel = inputs[0]?.[0]; // mono; Float32, range [-1, 1]
    if (!channel) return true;
    const pcm = new Int16Array(channel.length);
    for (let i = 0; i < channel.length; i++) {
      const s = Math.max(-1, Math.min(1, channel[i]));
      pcm[i] = s < 0 ? s * 0x8000 : s * 0x7fff;
    }
    // Transfer the buffer to the main thread without copying.
    this.port.postMessage(pcm.buffer, [pcm.buffer]);
    return true;
  }
}
registerProcessor("pcm-worklet", PCMWorklet);

Die Pipeline im Code

Die Pipeline besteht aus drei Komponenten: einem Browser-Client, der das Mikrofon erfasst und PCM an Ihren Server streamt, einem Node-Server, der Audio an Scribe v2 Realtime und Transkripte zurück weiterleitet, sowie einem skriptfähigen Client, der PCM aus einer Datei oder Telefonie-Bridge streamt.

Der Server leitet weiter, statt den Erkenner direkt im Browser bereitzustellen – aus einem wichtigen Grund: Ihr ElevenLabs-API-Key ist geheim und darf nie im clientseitigen Code erscheinen. Der Server verwahrt den Key. Falls der Browser dennoch direkt mit dem Erkenner kommunizieren muss, erstellen Sie serverseitig ein kurzlebiges Einmal-Token und geben dieses statt des API-Keys an den Client weiter.

Browser-Client

Der Client öffnet einen WebSocket zu Ihrem Server, erfasst das Mikrofon über das obige Worklet und leitet jeden PCM-Frame sofort nach seiner Erzeugung weiter. Eingehende Ereignisse – vom Server bereits in { type, text } normalisiert – steuern den zuvor beschriebenen Partial-/Final-Status:

// client.ts - runs in the browser. ws is an open WebSocket to your server.
const audioContext = new AudioContext({ sampleRate: 16000 });
await audioContext.audioWorklet.addModule("pcm-worklet.js");

const mediaStream = await navigator.mediaDevices.getUserMedia({
  audio: { channelCount: 1, echoCancellation: true, noiseSuppression: true },
});

const source = audioContext.createMediaStreamSource(mediaStream);
const worklet = new AudioWorkletNode(audioContext, "pcm-worklet");

// Forward each PCM frame to the server the moment it is produced.
worklet.port.onmessage = (e: MessageEvent<ArrayBuffer>) => {
  if (ws.readyState === WebSocket.OPEN) ws.send(e.data);
};
source.connect(worklet);

// Manual commit: tell the server to finalize the current segment.
const commit = () => ws.send(JSON.stringify({ type: "commit" }));

Server-Relay

Der Server öffnet pro Client eine Erkennerverbindung, hält den API-Key auf dem Server, leitet binäres PCM direkt durch und normalisiert Erkennerereignisse in die stabile Form { type, text }, die der Client verarbeitet:

// server.ts - Node, using the `ws` library. ELEVENLABS_API_KEY and the
// recognizer URL come from the environment; see the Speech to Text reference
// for the exact path and query parameters.
import { WebSocketServer, WebSocket } from "ws";

new WebSocketServer({ port: 8080 }).on("connection", (client) => {
  // The API key stays on the server, never on the wire to the browser.
  const recognizer = new WebSocket(process.env.RECOGNIZER_WSS_URL!, {
    headers: { "xi-api-key": process.env.ELEVENLABS_API_KEY! },
  });

  // Browser -> recognizer: forward binary PCM, translate control messages.
  client.on("message", (data, isBinary) => {
    if (recognizer.readyState !== WebSocket.OPEN) return;
    if (isBinary) recognizer.send(data); // raw PCM bytes
    else if (JSON.parse(data.toString()).type === "commit")
      recognizer.send(sendCommit());
  });

  // Recognizer -> browser: normalize events into a stable shape.
  recognizer.on("message", (raw) => {
    const event = parseRecognizerEvent(raw.toString());
    if (event && client.readyState === WebSocket.OPEN)
      client.send(JSON.stringify(event));
  });

  // ... open handshake, queueing pre-open audio, and teardown on close/error
});

Alles Endpunktspezifische ist auf die beiden folgenden Adapterfunktionen beschränkt. Ersetzen Sie die Feldnamen durch die exakten Namen aus der Speech-to-Text-Referenz; der Rest der Pipeline bleibt unverändert:

// The single place that knows the recognizer's wire format.
const sendCommit = (): string => JSON.stringify({ type: "commit" });

type NormalizedEvent =
  | { type: "partial"; text: string }
  | { type: "final"; text: string }
  | { type: "vad"; speaking: boolean };

function parseRecognizerEvent(raw: string): NormalizedEvent | null {
  const msg = JSON.parse(raw);
  if (msg.is_final === true || msg.type === "final")
    return { type: "final", text: msg.text ?? "" };
  if (msg.type === "vad") return { type: "vad", speaking: !!msg.speaking };
  if (typeof msg.text === "string")
    return { type: "partial", text: msg.text };
  return null;
}

Skriptfähiger Backend-Client

Für Backend-Pipelines und den folgenden Benchmark funktioniert dieselbe Erkennerverbindung ohne Browser: Lesen Sie PCM aus einer beliebigen Quelle, takten Sie es im Echtzeit-Chunk-Rhythmus und lesen Sie Ereignisse zurück. API-Key und URL stammen wie beim Server aus der Umgebung.

// stream-stt.ts - pace ~100ms chunks at real time, then commit the tail.
const SAMPLE_RATE = 16000, CHUNK_MS = 100;
const CHUNK_BYTES = (SAMPLE_RATE * 2 * CHUNK_MS) / 1000; // 3200 bytes
const ws = new WebSocket(process.env.RECOGNIZER_WSS_URL!, {
  headers: { "xi-api-key": process.env.ELEVENLABS_API_KEY! },
});

// Send: walk the PCM buffer in 100ms chunks, sleeping between to mimic a
// live source. For audio that already arrives in real time, drop the sleep.
async function sendAudio(pcm: Buffer) {
  for (let off = 0; off < pcm.length; off += CHUNK_BYTES) {
    ws.send(pcm.subarray(off, off + CHUNK_BYTES));
    await new Promise((r) => setTimeout(r, CHUNK_MS));
  }
  ws.send(JSON.stringify({ type: "commit" })); // finalize the trailing segment
}

// Receive: print partials in place, append finals.
ws.on("message", (raw) => {
  const e = parseRecognizerEvent(raw.toString());
  if (e?.type === "final") console.log(`[final]   ${e.text}`);
  else if (e?.type === "partial") process.stdout.write(`[partial] ${e.text}\r`);
});

Speech-to-Text-Latenz und Wortfehlerrate benchmarken

Latenz und Wortfehlerrate variieren je nach Sprecher, Sprache, akustischen Bedingungen, Audiolänge, Netzwerkpfad zur nächstgelegenen Region jedes Anbieters und aktueller Auslastung des jeweiligen Dienstes. 

Ein Ergebnis, das auf einem Laptop in einer Stadt gemessen wurde, lässt sich nicht auf Ihre Produktionsinfrastruktur in einer anderen übertragen. Führen Sie das Test-Harness auf produktionsnaher Infrastruktur mit Audio aus, das Ihren tatsächlichen Eingaben entspricht, und berichten Sie Bereiche und Verteilungen statt einzelner Werte.

Die einzigen relevanten Latenz- und Genauigkeitswerte sind jene, die Sie mit Ihrem eigenen Audio auf produktionsnaher Infrastruktur messen. Hier ist ein Leitfaden zum Benchmarking der Speech-to-Text-Latenz.

Was Sie bei der Speech-to-Text-Latenz messen sollten

Im Folgenden finden Sie die wichtigsten Metriken für das Benchmarking der Echtzeit-Spracherkennungslatenz:

  • Zeit bis zum ersten Partial: Von der Übertragung des ersten Audio-Chunks bis zum Empfang des ersten nicht leeren Partials.
  • Partial-zu-Final-Verzögerung: Vom letzten Audio-Chunk einer Äußerung bis zur finalen Hypothese.
  • Wortfehlerrate (WER): WER des finalisierten Transkripts im Vergleich zu einer menschlichen Referenz, für alle Systeme identisch berechnet.
  • Stabilitätsänderungen: Wie viele Partials vor der Finalisierung umgeschrieben werden. Diese Metrik ist ein Indikator dafür, wie stark sich die Live-UI scheinbar verändert.

Kontrollen

Um unzuverlässige Daten zu vermeiden, sollten Sie mehrere Kontrollen in Ihren Versuch einbauen, damit die Bedingungen konsistent bleiben.

Dies sind die wichtigsten Kontrollen für das Benchmarking der Latenz von Speech to Text:

  • Identisches Audio: Verwenden Sie für jedes System dieselben Dateien, dieselbe Abtastrate und dieselbe Kodierung.
  • Identischer Takt: Streamen Sie jedes System mit derselben Echtzeit-Chunk-Kadenz, beispielsweise Chunks von 100 ms.
  • Wiederholen und Verteilungen berichten: Führen Sie jede Datei tagsüber mehrfach aus; berichten Sie Median und Randbereich (p50/p95).
  • Identische Referenzen und Bewertung: Normalisieren Sie Text vor der WER-Berechnung auf dieselbe Weise – Groß- und Kleinschreibung, Interpunktion und Zahlen.
  • Region und Netzwerk offenlegen: Geben Sie an, wo das Harness lief und welchen Pfad es zu jedem Anbieter nahm.

Wenn Sie all diese Elemente gleich halten, erhalten Sie präzisere Metriken.

Grundgerüst des Harness

Der Messkern akzeptiert einen Anbieteradapter und erfasst Zeit bis zum ersten Partial, Finalisierungsverzögerung und Partial-Änderungen:

// benchmark.ts - measurement core; one StreamFn adapter per provider.
type StreamFn = (
  audioPath: string,
  onEvent: (kind: "partial" | "final", text: string) => void,
  result: RunResult
) => Promise<void>; // adapter sets result.lastChunkSentAt on the final chunk

interface RunResult {
  firstPartialMs?: number;
  finalLagMs?: number;
  hypothesis: string;
  partialEdits: number;
  lastChunkSentAt: number;
  startedAt: number;
}

async function measure(streamFn: StreamFn, audioPath: string): Promise<RunResult> {
  const result: RunResult = {
    hypothesis: "", partialEdits: 0, lastChunkSentAt: 0,
    startedAt: performance.now(),
  };
  let prevPartial = "";

  await streamFn(audioPath, (kind, text) => {
    const now = performance.now();
    if (kind === "partial") {
      if (text && result.firstPartialMs === undefined)
        result.firstPartialMs = now - result.startedAt;
      if (text !== prevPartial) { result.partialEdits++; prevPartial = text; }
    } else { // final
      result.hypothesis = result.hypothesis ? `${result.hypothesis} ${text}` : text;
      if (result.lastChunkSentAt)
        result.finalLagMs = now - result.lastChunkSentAt;
    }
  }, result);

  return result;
}

Die Wortfehlerrate ist eine standardmäßige Levenshtein-Distanz auf Token-Ebene über normalisierten Text. Schreiben Sie sowohl Referenz als auch Hypothese kleingeschrieben und entfernen Sie die Interpunktion auf identische Weise, bevor Sie sie berechnen. Andernfalls messen Sie Ihren Normalisierer statt des Modells. Führen Sie diese Messung in einer Schleife aus, die jede Datei pro Anbieter etwa zehnmal verarbeitet, und berichten Sie die mediane Zeit bis zum ersten Partial sowie die mediane WER (p50/p95), da einzelne Stichproben stark von Netzwerkschwankungen beeinflusst werden.

Damit es läuft, benötigen Sie zwei Dinge. Erstens schreiben Sie pro System einen StreamFn-Adapter. Der obige skriptfähige Client ist bereits einer; die Adapter für andere Systeme folgen demselben Vertrag (audioPath, onEvent, result) und setzen result.lastChunkSentAt, wenn der finale Audio-Chunk gesendet wird. Zweitens laden Sie Ihre Audiodateien und Referenzen und rufen measures dafür auf. Führen Sie es auf einer Maschine aus, die Ihrem Deployment entspricht, mit Audio, das Ihre Nutzer repräsentiert, und Sie erhalten einen reproduzierbaren Vergleich.

Zusammenfassung: So erreichen Sie Echtzeit-Spracherkennung 

In diesem Artikel haben wir viele Architekturänderungen behandelt, mit denen Sie Ihr System schrittweise verbessern und sich der Echtzeit-Spracherkennung annähern können.

Ein produktives Echtzeit-STT-System hängt von einer Handvoll Entscheidungen ab:

  • Transport: Wählen Sie WebSocket für Einfachheit und kontrollierte Netzwerke und WebRTC, wenn Sie Verlusttoleranz benötigen und von Endgeräten aufnehmen.
  • Partials und Finals: Behandeln Sie Partials als vorläufig und Finals als festgeschrieben. Stellen Sie sie unterschiedlich dar, damit Nutzer dem Live-Text vertrauen.
  • Endpunkt-Erkennung: Verwenden Sie VAD für freihändige Segmentierung, manuellen Commit als Übersteuerung und stimmen Sie den Stille-Schwellenwert auf die Interaktion statt auf eine feste Konstante ab.
  • In-Stream-Features: Aktivieren Sie In-Stream-Features nur, wenn das Live-Erlebnis sie benötigt, und verschieben Sie den Rest auf einen Batch-Durchlauf mit Scribe v2.
  • Audioformat: Nehmen Sie in kleinen PCM-Frames auf, senden Sie Chunks von etwa 100 ms und verwenden Sie für Telefonie das Quellformat.
  • Benchmarking: Stimmen Sie die Regler für Genauigkeit und Latenz empirisch auf Ihr eigenes Audio und Ihre Zielmetrik ab.
  • API-Sicherheit: Bewahren Sie Ihren API-Key auf dem Server auf oder erstellen Sie Einmal-Tokens für direkte Clientverbindungen.

Wenn Sie erfahren möchten, wie Sie die Latenz eines Voice Agents optimieren, finden Sie dazu ebenfalls einen Leitfaden von uns.

Echtzeit-Spracherkennungssysteme mit Scribe v2 Realtime entwickeln

Scribe v2 Realtime liefert Partials bei etwa 150 ms Modelllatenz. Ob Ihre Nutzer diesen Wert oder eine höhere Latenz erleben, hängt von der umgebenden Architektur ab – und diese kontrollieren Sie. Mit den in diesem Artikel beschriebenen Strategien bauen Sie eine bessere Pipeline-Architektur, die Latenz reduziert und das Kundenerlebnis verbessert. 

Wenn Sie tiefer einsteigen möchten, entdecken Sie die Übersicht zu Speech-to-Text-Funktionen, lesen Sie unsere Modellreferenz mit der vollständigen Liste der Features und Sprachen und besuchen Sie die Echtzeit-Produktseiten: Echtzeit-Speech-to-Text-API und Echtzeit-Speech-to-Text.

Wenn Sie bereit sind, loszulegen, erstellen Sie ein kostenloses ElevenLabs-Konto und streamen Sie noch heute Ihr erstes Transkript.

FAQ zur Latenz von Echtzeit-Spracherkennung

Ähnliche Artikel

Erstellen Sie mit hochwertiger KI-Audio