Zum Hauptinhalt springen
Lektion 5 von 18 · Realtime API und Voice Agents

Unterbrechungen und Sprechwechsel-Management

Lektion 5 von 18 Aktualisiert am 3. November 2026 Entwickler
Auf dieser Seite
  1. Unterbrechungen und Sprechwechsel-Management
  2. Sprachaktivitätserkennung (VAD)
  3. Behandlung von Unterbrechungen
  4. Manueller Steuerungsmodus
  5. Architektur des Zustandsmanagements
  6. Kernaussagen

Aktualisiert am 2. November 2026 — Audio-Modelle. Mehrere Modelle in diesem Kurs wurden eingestellt: tts-1, tts-1-hd und gpt-4o-mini-tts werden am 6. Januar 2027 nicht mehr funktionieren (Ersatz: gpt-realtime-2.1-mini, wobei die OpenAI-TTS-Richtlinien angeben, dass dies nicht durch /v1/audio/speech unterstützt wird: Die Migration der Spracherstellung erfolgt über die Realtime API); gpt-realtime, gpt-4o-realtime und Legacy-Audiomodelle am 20. Januar 2027 (gpt-realtime-2.1, gpt-realtime-2.1-mini, gpt-audio-1.5); whisper-1, gpt-4o-transcribe und /v1/audio/translations am 26. Februar 2027 (gpt-transcribe, gpt-live-transcribe, v1/realtime/translations). Für die Voll-Duplex-Stimme ist GPT-Live 1 seit dem 10. September 2026 in der API verfügbar.

Korrigiert am 3. November 2026. session.update-Ereignisse platzierten zuvor turn_detection am Session-Wurzel, ein Format aus der alten Beta: Mit der aktuellen Realtime API befindet sich die Einstellung in session.audio.input.turn_detection, und die Session trägt "type": "realtime". Die Behandlung von Unterbrechungen sandte zuvor response.cancel, aber mit VAD storniert der Server die Antwort selbst, und der Code verwendete eine undefinierte Variable. Diese Lektion behandelt nun semantic_vad, create_response und interrupt_response und unterscheidet zwischen WebSocket und WebRTC. Die Ereignisformen wurden gegen openai SDK-Typen 3.42.1 verifiziert. Quellen: Sprachaktivitätserkennung · Realtime-Gespräche.

Unterbrechungen und Sprechwechsel-Management

In natürlichen Gesprächen unterbrechen sich Menschen, sprechen übereinander und unterbrechen sich gegenseitig. Eine Sprach-Agentur, die diese Situationen nicht bewältigen kann, wirkt roboterhaft und frustrierend. Die Realtime API bietet zwei Mechanismen zur Verwaltung des Sprechwechsels: automatische Sprachaktivitätserkennung (VAD) und manuelle Steuerung.

Sprachaktivitätserkennung (VAD)

VAD ist in einer Sprach-Session standardmäßig aktiviert und arbeitet im Modus server_vad: Der Server analysiert eingehende Audioinhalte kontinuierlich, segmentiert basierend auf Stille und signalisiert den Beginn und das Ende der Benutzerrede. Sie konfigurieren dies in session.audio.input.turn_detection:

await ws.send(json.dumps({
    "type": "session.update",
    "session": {
        "type": "realtime",
        "audio": {
            "input": {
                "turn_detection": {
                    "type": "server_vad",
                    "threshold": 0.5,
                    "prefix_padding_ms": 300,
                    "silence_duration_ms": 500,
                    "create_response": True,      # sofort antworten, wenn der Sprechwechsel endet
                    "interrupt_response": True,   # Agent unterbrechen, wenn der Benutzer spricht
                }
            }
        },
    },
}))

VAD-Parameter

Parameter Beschreibung Auswirkung
threshold Erkennungsschwelle (0,0 bis 1,0) Hoch = weniger empfindlich, Niedrig = empfindlicher
prefix_padding_ms Vor dem Erkennungspunkt beibehaltene Audioinhalte Verhindert das Abschneiden von Wortanfängen
silence_duration_ms Benötigte Stillezeit zum Beenden des Sprechwechsels Kurz = reaktionsschnell, Lang = geduldig

Eine zu kurze silence_duration_ms löst eine Antwort während natürlicher Pausen in der Rede des Benutzers aus; zu lang wirkt die Agentur unreaktiv. OpenAI veröffentlicht keine sprachspezifischen Standards: Beginnen Sie mit dem Dokumentationsbeispiel (500 ms) und passen Sie es basierend auf Aufnahmen Ihrer Benutzer an. Ein höherer threshold erfordert lauterer Ton zur Auslösung, was in lauten Umgebungen hilft.

Semantische VAD

Der zweite Modus, semantic_vad, stützt sich nicht auf Stille, sondern auf Wörter: Ein Klassifizierer schätzt, ob der Benutzer seinen Satz beendet hat. Ein unvollständiger Satz gewinnt mehr Zeit als eine klare Aussage, und das Modell unterbricht seltener. Die Einstellung eagerness kann low (lassen Sie den Benutzer seine Zeit), medium, high (sofort antworten) oder auto, der Standardwert, der äquivalent zu medium ist:

await ws.send(json.dumps({
    "type": "session.update",
    "session": {
        "type": "realtime",
        "audio": {"input": {"turn_detection": {"type": "semantic_vad", "eagerness": "low"}}},
    },
}))

Behandlung von Unterbrechungen

Wenn der Benutzer spricht, während die Agentur antwortet, sendet der Server input_audio_buffer.speech_started. Mit VAD und interrupt_response aktiviert storniert der Server die aktuelle Antwort: Er sendet dann response.done mit dem Status cancelled. Sie müssen dennoch zwei Dinge auf Ihrer Seite tun, auf einer WebSocket-Verbindung, auf der Sie das Audio abspielen:

  1. Spielen Sie sofort ab und werfen Sie jedes gepufferte Audio weg, wobei Sie notieren, wie viele Millisekunden der Benutzer tatsächlich gehört hat
  2. Kürzen Sie den Agenten-Item auf diese Dauer unter Verwendung von conversation.item.truncate

Warten Sie nicht auf response.done, um eines der beiden zu tun.

async def handle_interruption(ws, event: dict, player, item_id: str | None, ms_played: int) -> None:
    """Behandelt Benutzerrede, während die Agentur spricht (WebSocket)."""
    if event["type"] != "input_audio_buffer.speech_started":
        return

    # 1. Abspielung stoppen und gepuffertes Audio löschen
    player.stop_stream()

    # 2. Den Teil aus der Historie entfernen, den der Benutzer nicht gehört hat
    if item_id:
        await ws.send(json.dumps({
            "type": "conversation.item.truncate",
            "item_id": item_id,
            "content_index": 0,
            "audio_end_ms": ms_played,
        }))

    # 3. Abspielung für die nächste Antwort neu öffnen
    player.start_stream()

Berechnen Sie ms_played basierend darauf, was Sie tatsächlich an den Lautsprecher gesendet haben: Bei 16-Bit Mono PCM mit 24 kHz entsprechen 48.000 Bytes einer Sekunde. Bei WebRTC oder SIP verwaltet der Server selbst den Ausgabepuffer, weiß, was abgespielt wurde, und kürzt automatisch: Sie müssen nichts senden.

Warum die Antwort kürzen?

Ohne Kürzung würde die Gesprächshistorie die vollständige Antwort des Modells enthalten, obwohl der Benutzer nur einen Teil gehört hat. Wenn der Benutzer fragt: „Was hast du zuletzt gesagt?“, würde das Modell denken, es hätte alles gesagt. Durch Kürzen wird die Historie mit dem abgehörten Inhalt des Benutzers abgeglichen. Die Dokumentation weist auf eine Einschränkung hin: Die Kürzung schneidet das Audio und entfernt die Transkription des nicht abgespielten Teils, bietet aber keine wortgenaue gekürzte Transkription.

Manueller Steuerungsmodus

Für bestimmte Anwendungsfälle (IVR-Menüs, Diktiergeräte, Quiz) ist automatische VAD nicht geeignet. Der manuelle Modus gibt Ihnen volle Kontrolle:

# VAD deaktivieren
await ws.send(json.dumps({
    "type": "session.update",
    "session": {"type": "realtime", "audio": {"input": {"turn_detection": None}}},
}))

# Taste gedrückt: Wenn die Agentur noch spricht, stornieren Sie ihre Antwort und kürzen Sie das nicht abgespielte Audio
await ws.send(json.dumps({"type": "response.cancel"}))

# Taste losgelassen: Audio wurde über input_audio_buffer.append gesendet, commit den Sprechwechsel...
await ws.send(json.dumps({"type": "input_audio_buffer.commit"}))

# ...dann die Antwort auslösen
await ws.send(json.dumps({"type": "response.create"}))

Ohne VAD ist nichts automatisch: Hier kommt response.cancel ins Spiel, wenn eine Antwort im Gange ist, während der Benutzer die Kontrolle wieder übernimmt. Zwischen den Sprechwechseln leert input_audio_buffer.clear den Eingabepuffer.

Es gibt einen Mittelweg: Lassen Sie VAD aktiviert, damit es weiterhin Sprechwechsel segmentiert und Ereignisse sendet, aber setzen Sie create_response und interrupt_response auf False. Ohne Ihre explizite response.create wird keine Antwort gesendet, was Ihnen Zeit gibt, den Input zu überprüfen oder zu bereichern (Moderation, Dokumentenabruf), zum Preis einer gewissen Latenz.

Anwendungsfälle für den manuellen Modus

  • IVR-Menü: Warten Sie auf einen DTMF-Ton oder ein bestimmtes Schlüsselwort, bevor Sie antworten
  • Diktat: Akkumulieren Sie lange Audiosegmente ohne Unterbrechung
  • Bestätigung: Warten Sie auf eine explizite „Ja” oder „Nein”
  • Push-to-talk: Der Benutzer drückt eine Taste, um zu sprechen

Architektur des Zustandsmanagements

Für ein robustes Sprechwechsel-Management pflegen Sie einen Zustandsautomaten:

from enum import Enum

class ConversationState(Enum):
    IDLE = "idle"                    # Warten
    USER_SPEAKING = "user_speaking"  # Benutzer spricht
    PROCESSING = "processing"        # Modell verarbeitet
    AGENT_SPEAKING = "agent_speaking" # Agentur antwortet
    INTERRUPTED = "interrupted"       # Unterbrechung im Gange

class TurnManager:
    def __init__(self):
        self.state = ConversationState.IDLE
        self.current_response_item_id = None
        self.played_audio_ms = 0

    def on_event(self, event_type: str):
        if event_type == "input_audio_buffer.speech_started":
            if self.state == ConversationState.AGENT_SPEAKING:
                self.state = ConversationState.INTERRUPTED
            else:
                self.state = ConversationState.USER_SPEAKING

        elif event_type == "input_audio_buffer.speech_stopped":
            self.state = ConversationState.PROCESSING

        elif event_type == "response.output_audio.delta":
            self.state = ConversationState.AGENT_SPEAKING

        elif event_type == "response.done":
            self.state = ConversationState.IDLE

Kernaussagen

  • VAD (server_vad standardmäßig) wird in session.audio.input.turn_detection konfiguriert
  • semantic_vad segmentiert basierend auf Bedeutung; eagerness steuert seine Geduld
  • Mit VAD storniert der Server die unterbrochene Antwort; auf WebSocket stoppen Sie die Abspielung und kürzen mit conversation.item.truncate (automatisch bei WebRTC und SIP)
  • Der manuelle Modus (turn_detection auf None gesetzt) eignet sich für Push-to-talk, IVR-Menüs und Diktat
  • Ein expliziter Zustandsautomat verhindert inkonsistentes Verhalten in Grenzfällen