Als eine Kundin am 3. Juni 2024 während eines Live-Gesprächs nach einer Antwort des Agenten fragte, vergingen 1,4 Sekunden Stille – eine Ewigkeit im Voice-KI-Bereich. Obwohl alle gemessenen Spannen in der Trace unter 400 Millisekunden lagen, war die Kundin bereits frustriert. Die Ursache? Die tote Zeit zwischen dem Ende der Sprachäußerung und dem Start der automatischen Spracherkennung (ASR) blieb unsichtbar – denn sie wurde nicht gemessen.
Die Illusion der Messbarkeit: Warum APM-Systeme hier versagen
Sprach-KI-Systeme bestehen aus vielen Komponenten: Sprachaktivitätserkennung (VAD), ASR, Sprachmodelle (LLM) und Text-to-Speech (TTS). Moderne APM-Tools (Application Performance Monitoring) wie Honeycomb verfolgen zwar die Verarbeitungszeiten jeder Komponente. Doch sie ignorieren die Lücken dazwischen – etwa die Wartezeit auf eine Verbindung oder die Zeit bis zur Weiterleitung der Audio-Daten. Das Ergebnis: Die Messdaten zeigen ein optimistisches Bild, während Nutzer eine schlechte Erfahrung machen.
In diesem Fall summierten sich die gemessenen Spannen auf ein akzeptables p95 von 980 Millisekunden. Doch die 1,4 Sekunden Stille wurden nicht erfasst, weil der Code-Pfad zwischen VAD/Sprachende-Erkennung und ASR-Stream-Start keinen Span eröffnete. Stattdessen wartete ein Coroutine auf eine Verbindung, die unter Last blockiert war. Erst als die ASR-Span begann, lief alles wieder normal – zu spät für die Kundin.
Die falsche Sicherheit der aggregierten Daten
Häufig wird die Leistung eines Sprachsystems anhand von p50-, p95- oder p99-Werten gemessen. Doch diese Werte basieren auf der Summe der gemessenen Spannen – und ignorieren die kritischen Lücken. Die folgende Tabelle zeigt die gemessenen Zeiten für eine typische Sprachinteraktion:
- VAD / Sprachende-Erkennung: p50 60 ms, p95 120 ms, p99 180 ms (Orchestrator)
- ASR (Streaming): p50 180 ms, p95 310 ms, p99 540 ms (ASR-Client)
- LLM TTFT (Time to First Token): p50 220 ms, p95 380 ms, p99 720 ms (Modell-Client)
- LLM Vollständige Antwort: p50 140 ms, p95 260 ms, p99 430 ms (Modell-Client)
- TTS (Erstes Audio-Byte): p50 90 ms, p95 190 ms, p99 360 ms (TTS-Client)
- Netzwerk (beide Richtungen): p50 40 ms, p95 90 ms, p99 150 ms (Gateway)
Die Summe dieser p95-Werte ergibt etwa 1.340 Millisekunden. Doch selbst dieser Wert täuscht, da er nicht die tatsächliche End-to-End-Latenz widerspiegelt. Die 1,4 Sekunden Stille blieben unsichtbar – weil sie nicht gemessen wurden.
Die unsichtbare Lücke: Warum Trace-Tools versagen
In einer typischen Trace-UI werden die gemessenen Spannen als farbige Balken dargestellt. Die intuitive Reaktion: Den längsten Balken optimieren. Doch in diesem Fall ergaben sich nach zwei Tagen Optimierung keine Verbesserungen – weil der Fehler nicht in den gemessenen Spannen lag. Die tatsächliche Lücke lag vor dem ersten Span, in der Wartezeit auf die ASR-Verbindung.
Ein Whiteboard-Diagramm half, das Problem zu visualisieren:
[Sprachende-Erkennung] ----- [1,4s Stille] ----- [ASR-Stream-Start]Die gemessenen Spannen begannen erst nach der 1,4-Sekunden-Lücke. Das Problem: Der Code-Pfad zwischen "Sprachende erkannt" und "ASR-Stream geöffnet" öffnete keinen Span. Eine Coroutine wartete auf eine Verbindung, die unter hoher Last blockiert war. Erst als die ASR-Span begann, lief alles wieder normal – doch der Schaden war bereits angerichtet.
Die Lösung: Handoff-Spans und Pool-Optimierung
Um solche Lücken künftig zu vermeiden, müssen zwei Schritte umgesetzt werden:
- Handoff-Spans einführen: Ein Span muss die Zeit zwischen Sprachende-Erkennung und ASR-Start messen. Nur so wird die Wartezeit sichtbar und messbar.
- Verbindungs-Pool optimieren: Die Blockade trat auf, weil der ASR-Client eine Verbindung erst bei Bedarf aufbaute. Unter hoher Last führte dies zu Konkurrenz um die Verbindung. Eine Anpassung der Pool-Größe und der Verbindungsstrategie kann solche Engpässe verhindern.
Der folgende Code-Ausschnitt zeigt, wie der fehlende Span implementiert werden kann – mit OpenTelemetry in Python:
from opentelemetry import trace
from opentelemetry.trace import SpanKind, Status, StatusCode
tracer = trace.get_tracer("voice.turn")
async def handle_turn(audio_in, ctx):
# Äußerer Span für die gesamte Sprachinteraktion, verankert am Sprachende
with tracer.start_as_current_span(
"voice.turn",
kind=SpanKind.SERVER,
) as turn_span:
turn_span.set_attribute("call.id", ctx.call_id)
turn_span.set_attribute("turn.index", ctx.turn_index)
# Der fehlende Span: Übergabe von VAD zu ASR-Start
with tracer.start_as_current_span("voice.handoff.vad_to_asr") as hs:
hs.set_attribute("handoff.from", "turn_detection")
hs.set_attribute("handoff.to", "asr")
try:
asr_stream = await asr_client.open_stream(ctx)
except Exception as exc:
hs.set_status(Status(StatusCode.ERROR, str(exc)))
hs.record_exception(exc)
raise
# Markiert den Moment, in dem die Audio-Daten in den ASR-Stream fließen
hs.add_event("asr_stream_ready")
# ASR-Verarbeitung (gemessen und optimiert)Fazit: Sichtbarkeit ist der erste Schritt zur Optimierung
Sprach-KI-Systeme sind komplex, und ihre Leistung hängt nicht nur von den gemessenen Komponenten ab. Die kritischen Lücken liegen oft in den Übergängen zwischen den Systemen – in den Wartezeiten, die APM-Tools ignorieren. Ohne entsprechende Spans bleiben diese Lücken unsichtbar, selbst wenn die gemessenen Werte optimistisch wirken.
Die Lösung liegt in der Einführung von Handoff-Spans und der Optimierung der Systemarchitektur, um solche Engpässe zu vermeiden. Nur so lässt sich sicherstellen, dass die Nutzererfahrung nicht unter unsichtbaren Wartezeiten leidet – und die Kundin nicht nach einer Antwort fragen muss, weil die Stimme des Agenten zu spät kommt.
KI-Zusammenfassung
Discover how traditional APM tools overlook hidden latency in voice AI pipelines, causing silent delays that hurt user experience despite healthy-looking metrics.