> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aihubmix.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Echtzeit-Konversation

> Stellen Sie eine dauerhafte WebSocket-Verbindung für bidirektionale Sprach- und Textinteraktion mit niedriger Latenz zu einem Konversationsmodell her

## Einführung

Die Echtzeit-Konversation stellt über WebSocket (ein Protokoll, das eine langlebige, bidirektionale Verbindung zwischen Client und Server hält) eine dauerhafte Verbindung her, überträgt Ihre Audio- oder Texteingabe in Echtzeit an das Konversationsmodell, und das Modell schiebt Text- und Sprachantworten inkrementell zurück. Sie eignet sich für Sprachassistenten, Echtzeit-Fragen und Antworten, Sprechübungen und andere Szenarien mit wechselseitiger Interaktion.

Wie die [Echtzeit-Transkription](/de/api/realtime-transcription) läuft sie über WebSocket, die beiden haben jedoch unterschiedliche Zwecke:

| Dimension                       | Echtzeit-Transkription               | Echtzeit-Konversation (diese Seite)                                       |
| ------------------------------- | ------------------------------------ | ------------------------------------------------------------------------- |
| Ziel                            | Sprache in Text umwandeln            | Eine mehrstufige Konversation führen, in der das Modell Antworten erzeugt |
| Richtung                        | Einseitig: Audio hinein, Text hinaus | Beidseitig: Audio oder Text hinein, Text und Sprache hinaus               |
| Verbindungsparameter            | `?intent=transcription&model=...`    | Nur `?model=...` (ohne `intent`)                                          |
| Sprachaktivitätserkennung (VAD) | Nicht unterstützt, muss `null` sein  | Unterstützt, automatische Turn-Erkennung verfügbar                        |
| Typische Szenarien              | Meeting-Untertitel, Live-Diktat      | Sprachassistenten, Echtzeit-Sprachinteraktion                             |

**Verfügbares Modell:**

* **gpt-realtime-2.1**: Konversations-Sprachmodell, unterstützt Audio- und Texteingabe und gibt Text- und Sprachantworten in Echtzeit aus.

<Warning>
  **Diese API ist für die serverseitige Integration gedacht; Browser können sich nicht direkt verbinden.** Aus Sicherheitsgründen prüft und lehnt das Gateway Verbindungen mit einem `Origin`-Header ab, lehnt das `openai-insecure-api-key`-Subprotokoll ab und akzeptiert den Schlüssel nur über den Standard-Header `Authorization`. Ein vom Browser initiierter WebSocket fügt automatisch einen `Origin`-Header hinzu und wird daher abgelehnt. Wenn Sie Echtzeit-Konversation im Frontend benötigen, stellen Sie die Verbindung zum Gateway von Ihrem eigenen Server aus her und leiten Sie Audio und Ergebnisse zwischen Frontend und Server weiter.
</Warning>

## Schnellstart

### Verbindungsendpunkt

```text theme={null}
wss://aihubmix.com/v1/realtime?model=gpt-realtime-2.1
```

* `model=gpt-realtime-2.1`: **erforderlich**, das Modell wird beim Verbindungsaufbau durch den URL-Parameter festgelegt und kann während der Sitzung nicht mehr geändert werden (siehe die Einschränkungen unten).
* **Beachten Sie den Unterschied zur Transkription**: Der Konversationsendpunkt übernimmt **kein** `intent=transcription`.

### Authentifizierung

Übergeben Sie den Schlüssel beim Handshake in einem Standard-HTTP-Header:

```text theme={null}
Authorization: Bearer $AIHUBMIX_API_KEY
```

### Anforderungen an das Audioformat

Audioeingabe und -ausgabe unterstützen derzeit nur ein Format. Konvertieren Sie Ihr Audio vor dem Senden:

* **Kodierung**: PCM16 (16-Bit-Ganzzahl mit Vorzeichen, Little-Endian)
* **Abtastrate**: 24000 Hz
* **Kanäle**: Mono

Also `audio/pcm@24000`. Wird für Eingabe oder Ausgabe ein anderes Format (etwa G.711/µ-law) deklariert, wird dies abgelehnt und die Sitzung geschlossen.

<Note>
  Anders als bei der Transkription **unterstützen** Konversationssitzungen die Sprachaktivitätserkennung (turn\_detection / VAD). Ist sie aktiviert, erkennt das Modell automatisch das Ende eines Redebeitrags und löst eine Antwort aus; ist sie deaktiviert (auf `null` gesetzt), steuern Sie selbst, wann Audio übergeben und wann eine Antwort angefordert wird. Wählen Sie je nach Bedarf.
</Note>

## Sitzungskonfiguration (session.update)

Nach dem Verbindungsaufbau kann der Client einen `session.update`-Frame senden, um Konversationsparameter zu konfigurieren (etwa Stimme, Systemanweisungen, ob VAD aktiv ist). Das Modell der Konversationssitzung ist bereits durch die Verbindungs-URL verankert, daher **können Sie ohne `session.update` direkt sprechen**; senden Sie ihn, wenn Sie eine eigene Stimme oder Anweisungen benötigen.

```json theme={null}
{
  "type": "session.update",
  "session": {
    "type": "realtime",
    "instructions": "You are a helpful voice assistant. Keep answers concise.",
    "audio": {
      "input": {
        "format": { "type": "audio/pcm", "rate": 24000 },
        "turn_detection": { "type": "server_vad" }
      },
      "output": {
        "format": { "type": "audio/pcm", "rate": 24000 },
        "voice": "alloy"
      }
    }
  }
}
```

### Konfigurationsparameter

<ParamField body="session.type" type="string" required>
  Sitzungstyp, für Konversation `realtime`.
</ParamField>

<ParamField body="session.instructions" type="string">
  Systemanweisungen, die Rolle, Ton und Antwortvorgaben des Modells festlegen.
</ParamField>

<ParamField body="session.output_modalities" type="string[]">
  Ausgabemodalitäten, entweder `["audio"]` oder `["text"]`: Mit `["audio"]` (Standard) gibt das Modell Sprache aus, und der Antworttext kommt über das Ereignis `response.output_audio_transcript.delta`. Mit `["text"]` gibt es nur Text aus, der über `response.output_text.delta` geliefert wird. Jede andere Kombination (zum Beispiel `["audio", "text"]`) wird abgelehnt und liefert ein `error`-Ereignis.
</ParamField>

<ParamField body="session.audio.input.format" type="object" required>
  Audioformat der Eingabe, festgelegt auf `{ "type": "audio/pcm", "rate": 24000 }`.
</ParamField>

<ParamField body="session.audio.input.turn_detection" type="object | null">
  Sprachaktivitätserkennung. Übergeben Sie `{ "type": "server_vad" }`, um die automatische Turn-Erkennung zu aktivieren; übergeben Sie `null`, um sie zu deaktivieren und Audio sowie Antwortanforderungen manuell vom Client zu steuern.
</ParamField>

<ParamField body="session.audio.output.format" type="object" required>
  Audioformat der Ausgabe, festgelegt auf `{ "type": "audio/pcm", "rate": 24000 }`.
</ParamField>

<ParamField body="session.audio.output.voice" type="string">
  Stimme der Antwortausgabe. **Sie kann nach Beginn der ersten Antwort nicht mehr geändert werden**: Sobald die Sitzung in den Generierungszustand wechselt, wird ein erneut gesendetes `voice` ignoriert (die übrigen Einstellungen gelten weiterhin). Legen Sie die Stimme daher vor der ersten Antwortanforderung fest.
</ParamField>

<Note>
  Die folgenden Funktionen werden **in dieser Version nicht unterstützt** und schließen die Sitzung bei Konfiguration (Schließcode `1008`): das Aktivieren der Inline-Transkription innerhalb einer Konversationssitzung (`audio.input.transcription`, Grund `input_transcription_not_supported`), das Einbringen von Audio (Grund `item_audio_not_supported`) oder Bildern (Grund `image_input_not_supported`) über Konversationselemente sowie jeder andere Inhaltselementtyp als Text (Grund `unsupported_content_part`). Senden Sie Audio ausschließlich über den Kanal `input_audio_buffer.append`.
</Note>

## Eingabe senden

### Audio senden

Zerlegen Sie PCM16-Audio in kleine Stücke (etwa ein Stück pro 100 ms), kodieren Sie sie mit base64 und senden Sie sie fortlaufend über das Ereignis `input_audio_buffer.append`:

```json theme={null}
{
  "type": "input_audio_buffer.append",
  "audio": "<base64-kodiertes PCM16-Audiostück>"
}
```

Bei aktiviertem VAD erkennt das Modell das Ende eines Redebeitrags und löst automatisch eine Antwort aus. Bei deaktiviertem VAD müssen Sie nach dem Senden eines Abschnitts manuell übergeben und eine Antwort anfordern:

```json theme={null}
{ "type": "input_audio_buffer.commit" }
{ "type": "response.create" }
```

### Text senden

Sie können auch direkt eine Textnachricht einbringen und dann eine Antwort anfordern:

```json theme={null}
{
  "type": "conversation.item.create",
  "item": {
    "type": "message",
    "role": "user",
    "content": [{ "type": "input_text", "text": "Introduce yourself in one sentence." }]
  }
}
{ "type": "response.create" }
```

## Antworten empfangen

Der Server schiebt fortlaufend Ereignisse. Wichtige Ereignistypen:

<ParamField body="session.created / session.updated" type="event">
  Bestätigung, dass die Sitzung erstellt oder ihre Konfiguration aktualisiert wurde. Nach `session.created` können Sie Audio und Text senden.
</ParamField>

<ParamField body="conversation.item.added / conversation.item.done" type="event">
  Ein Konversationselement wurde geschrieben: jede Nutzereingabe und jede Modellantwort erzeugt ein Element.
</ParamField>

<ParamField body="input_audio_buffer.speech_started / input_audio_buffer.speech_stopped" type="event">
  Bei aktivierter VAD hat der Server erkannt, dass der Nutzer zu sprechen beginnt oder aufhört. Ein `speech_started`-Ereignis bedeutet meist, dass der Nutzer das Modell unterbricht; siehe [Unterbrechung und Kürzung](#interruption).
</ParamField>

<ParamField body="response.created" type="event">
  Eine Antwort wurde zu generieren begonnen.
</ParamField>

<ParamField body="response.output_item.added / response.output_item.done" type="event">
  Das Ausgabeelement der Antwort hat begonnen und ist abgeschlossen. Das Feld `item.id` im `added`-Ereignis ist die ID des Konversationselements, die Sie beim späteren Kürzen von Audio referenzieren.
</ParamField>

<ParamField body="response.output_audio.delta / response.output_audio.done" type="event">
  Ein **inkrementeller** Ausschnitt des Antwort-Audios (base64-kodiertes PCM16) und seine Abschlussmarkierung; Sie können ihn beim Eintreffen abspielen.
</ParamField>

<ParamField body="response.output_audio_transcript.delta / response.output_audio_transcript.done" type="event">
  Das **inkrementelle** Transkript passend zum Antwort-Audio, Satz für Satz, und seine Abschlussmarkierung; das Feld `delta` enthält den neu hinzugefügten Text. **Bei aktivierter Audioausgabe nehmen Sie den Antworttext aus diesem Ereignis**, etwa um während der Wiedergabe Untertitel anzuzeigen.
</ParamField>

<ParamField body="response.output_text.delta / response.output_text.done" type="event">
  Ein **inkrementeller** Ausschnitt einer reinen Textantwort und ihre Abschlussmarkierung, nur bei der Ausgabemodalität Text (`output_modalities: ["text"]`).
</ParamField>

<ParamField body="response.done" type="event">
  Eine Antwort ist abgeschlossen. Dieses Ereignis trägt den Token-Verbrauch des Turns (`usage`), auf dem die Abrechnung basiert.
</ParamField>

<ParamField body="conversation.item.truncated" type="event">
  Bestätigung, dass die Kürzungsanforderung wirksam wurde; siehe [Unterbrechung und Kürzung](#interruption).
</ParamField>

<ParamField body="error" type="event">
  Fehlereignis mit Fehlercode und Beschreibung. Ein Problem der Anfrage selbst (etwa ein ungültiger Wert für `output_modalities`) liefert ein einzelnes `error`-Ereignis, und die Sitzung bleibt nutzbar; Richtlinienfragen (Modellwechsel, aufgebrauchtes Guthaben) schließen die Sitzung.
</ParamField>

<Note>
  **Wählen Sie das richtige Ereignis für den Antworttext.** Standardmäßig (Ausgabe enthält Audio) schiebt das Modell nur `response.output_audio_transcript.delta` und **nicht** `response.output_text.delta`; setzen Sie die Ausgabemodalität auf reinen Text, wandert der Text zu `response.output_text.delta`. Überwachen Sie in beiden Modi beide Ereignisse, damit kein Text verloren geht (siehe [Ausgabe aus dem Messlauf](#run-output) unten).
</Note>

<h2 id="interruption">
  Unterbrechung und Kürzung
</h2>

Wenn der Nutzer zu sprechen beginnt, während das Modell spricht, steht bereits generierter, aber noch nicht abgespielter Inhalt dem nächsten Satz des Nutzers entgegen. Bei einer WebSocket-Verbindung übernimmt der Client die Wiedergabe, also schließt der Client auch die Aufräumarbeit nach einer Unterbrechung ab.

Bei aktivierter VAD sendet der Server `input_audio_buffer.speech_started`, sobald er erkennt, dass der Nutzer zu sprechen begonnen hat. Nach Erhalt dieses Ereignisses sollte der Client:

1. **Die lokale Wiedergabe sofort stoppen** und festhalten, wie weit die Antwort bereits abgespielt wurde (in Millisekunden).
2. `conversation.item.truncate` senden, um das nicht abgespielte Audio aus der Konversation zu entfernen, damit das Modell es im nächsten Turn nicht als gesprochen behandelt.

```json theme={null}
{
  "type": "conversation.item.truncate",
  "item_id": "item_ABC123",
  "content_index": 0,
  "audio_end_ms": 1500
}
```

* `item_id`: die ID des Konversationselements dieser Antwort, entnommen aus `item.id` im Ereignis `response.output_item.added`.
* `content_index`: der Index des Audio-Inhaltsteils, immer `0`.
* `audio_end_ms`: die beizubehaltende Audiolänge in Millisekunden, nach der tatsächlich abgespielten Position des Clients.

Der Server antwortet mit `conversation.item.truncated`, sobald die Anforderung verarbeitet ist. Die Kürzung betrifft nur das Audio dieser Antwort und das zugehörige Transkript; die Sitzung selbst bleibt unverändert, und Sie können mit dem nächsten Turn fortfahren. Im OpenAI SDK entspricht das `conn.conversation.item.truncate(item_id=..., content_index=0, audio_end_ms=...)`.

Bei deaktivierter VAD (etwa Push-to-Talk) ist der Tastendruck die Unterbrechung: Senden Sie beim Drücken `response.cancel`, um die laufende Antwort abzubrechen, und kürzen Sie dann wie oben beschrieben. Beim Loslassen senden Sie `input_audio_buffer.append`, `input_audio_buffer.commit` und `response.create` in dieser Reihenfolge.

## Vollständige Beispiele

Unten stehen drei Vorgehensweisen; wählen Sie eine:

* **Offizielles OpenAI SDK (empfohlen)**: Sie müssen keine WebSocket-Frames von Hand schreiben; richten Sie `websocket_base_url` (der WebSocket-Basis-URL-Parameter des SDK) auf das Gateway und nutzen Sie die offizielle Bibliothek weiter.
* **Offizielles OpenAI Agents SDK**: die Echtzeit-Sprachform des offiziellen Agent-Frameworks; ersetzen Sie die `url` in `model_config` durch die Gateway-Adresse.
* **Rohes websockets**: ohne SDK Frames direkt nach Protokoll austauschen. Wenigste Abhängigkeiten und am einfachsten zu diagnostizieren.

<Note>
  **Warum den Modellnamen beim Verbindungsaufbau übergeben?** Das AiHubMix-Gateway benötigt das `model` im Moment des WebSocket-Handshakes, um den Modellanbieter zu wählen, zu authentifizieren und Kontingent zu reservieren, während `session.update` erst nach Abschluss des Handshakes eintrifft. Mit einem SDK müssen Sie daher `model` explizit an `connect()` übergeben (das SDK setzt es in die URL-Abfrage); ohne es **lehnt das Gateway bereits beim Handshake ab** und es kommt keine Verbindung zustande. Anders als bei der Transkription benötigt der Konversationsendpunkt **kein** `intent=transcription`.
</Note>

<CodeGroup>
  ```python Python (OpenAI SDK) theme={null}
  # Abhängigkeit: pip install "openai[realtime]"
  import asyncio
  import base64
  from openai import AsyncOpenAI

  # Die Wiederverwendung des offiziellen SDK erfordert nur zwei Anpassungen:
  #   1) websocket_base_url auf das AiHubMix-Gateway richten (statt der OpenAI-Standardadresse)
  #   2) model explizit an connect() übergeben, erforderlich für den Gateway-Handshake (kein intent für Konversation)
  client = AsyncOpenAI(
      api_key="sk-***",  # Ersetzen Sie dies durch Ihren AiHubMix-API-Schlüssel
      websocket_base_url="wss://aihubmix.com/v1",
  )

  async def main():
      async with client.realtime.connect(model="gpt-realtime-2.1") as conn:
          # 1) Sitzung konfigurieren: Systemanweisungen + Stimme + VAD aktivieren (automatische Turn-Erkennung)
          await conn.session.update(session={
              "type": "realtime",
              "instructions": "You are a helpful voice assistant. Keep answers concise.",
              "audio": {
                  "input": {
                      "format": {"type": "audio/pcm", "rate": 24000},
                      "turn_detection": {"type": "server_vad"},
                  },
                  "output": {
                      "format": {"type": "audio/pcm", "rate": 24000},
                      "voice": "alloy",
                  },
              },
          })

          # 2) Eine Textnachricht senden und eine Antwort anfordern (Audioeingabe siehe append/commit im rohen Beispiel)
          await conn.conversation.item.create(item={
              "type": "message",
              "role": "user",
              "content": [{"type": "input_text", "text": "What is the capital of France?"}],
          })
          await conn.response.create()

          # 3) Antwort dieses Turns empfangen: Text kommt als Transkript-Deltas, Sprache als Audio-Deltas
          async for event in conn:
              if event.type == "response.output_audio_transcript.delta":
                  print(event.delta, end="", flush=True)  # Antworttext (Ausgabe enthält Audio)
              elif event.type == "response.output_audio_transcript.done":
                  print()  # Transkript dieses Turns abgeschlossen
              elif event.type == "response.output_text.delta":
                  print(event.delta, end="", flush=True)  # reine Textausgabe
              elif event.type == "response.output_text.done":
                  print()
              elif event.type == "response.output_audio.delta":
                  pass  # base64-kodiertes PCM16-Audiostück, zum Abspielen dekodieren
              elif event.type == "input_audio_buffer.speech_started":
                  pass  # Nutzerunterbrechung: Wiedergabe stoppen, dann conn.conversation.item.truncate(...) aufrufen
              elif event.type == "response.done":
                  print("\n[Turn abgeschlossen]", event.response.usage)
                  break
              elif event.type == "error":
                  print("\n[Fehler]", event.to_dict())
                  break

  asyncio.run(main())
  ```

  ```python Python (websockets) theme={null}
  import asyncio
  import base64
  import json
  import websockets

  API_KEY = "sk-***"  # Ersetzen Sie dies durch Ihren AiHubMix-API-Schlüssel
  URL = "wss://aihubmix.com/v1/realtime?model=gpt-realtime-2.1"

  async def main():
      # websockets >= 13 nutzt additional_headers; ältere Versionen nutzen extra_headers
      async with websockets.connect(
          URL, additional_headers={"Authorization": f"Bearer {API_KEY}"}
      ) as ws:
          # 1) Sitzung konfigurieren (VAD aus, Zeitpunkt der Antwort manuell steuern)
          await ws.send(json.dumps({
              "type": "session.update",
              "session": {
                  "type": "realtime",
                  "instructions": "You are a helpful voice assistant.",
                  "audio": {
                      "input": {
                          "format": {"type": "audio/pcm", "rate": 24000},
                          "turn_detection": None,
                      },
                      "output": {
                          "format": {"type": "audio/pcm", "rate": 24000},
                          "voice": "alloy",
                      },
                  },
              },
          }))

          # 2) Lokale rohe PCM16- / 24-kHz- / Mono-Datei lesen, in Stücken senden, dann commit + Antwort anfordern
          async def send_audio():
              with open("audio_pcm16_24k.raw", "rb") as f:
                  pcm = f.read()
              chunk = 24000 * 2 // 10  # 100 ms = Abtastrate x 2 Byte / 10
              for i in range(0, len(pcm), chunk):
                  await ws.send(json.dumps({
                      "type": "input_audio_buffer.append",
                      "audio": base64.b64encode(pcm[i:i + chunk]).decode(),
                  }))
                  await asyncio.sleep(0.1)  # Echtzeit-Takt simulieren
              # Bei deaktiviertem VAD manuell übergeben und eine Antwort anfordern
              await ws.send(json.dumps({"type": "input_audio_buffer.commit"}))
              await ws.send(json.dumps({"type": "response.create"}))

          asyncio.create_task(send_audio())

          # 3) Antwort empfangen
          async for msg in ws:
              evt = json.loads(msg)
              etype = evt.get("type", "")
              if etype == "response.output_audio_transcript.delta":
                  print(evt.get("delta", ""), end="", flush=True)  # Antworttext (Ausgabe enthält Audio)
              elif etype == "response.output_audio_transcript.done":
                  print()  # Transkript dieses Turns abgeschlossen
              elif etype == "response.output_text.delta":
                  print(evt.get("delta", ""), end="", flush=True)  # reine Textausgabe
              elif etype == "input_audio_buffer.speech_started":
                  pass  # Nutzerunterbrechung: Wiedergabe stoppen, dann conversation.item.truncate senden
              elif etype == "response.output_audio.delta":
                  pass  # base64-kodiertes PCM16-Audiostück, zum Abspielen dekodieren
              elif etype == "response.done":
                  print("\n[Turn abgeschlossen]", evt.get("response", {}).get("usage"))
                  break
              elif etype == "error":
                  print("\n[Fehler]", evt.get("error"))
                  break

  asyncio.run(main())
  ```

  ```python Python (Agents SDK) theme={null}
  # Abhängigkeit: pip install openai-agents
  import asyncio
  from agents.realtime import (
      OpenAIRealtimeWebSocketModel,
      RealtimeAgent,
      RealtimeSession,
  )

  agent = RealtimeAgent(
      name="Assistant",
      instructions="You are a helpful voice assistant. Keep answers concise.",
  )

  async def main():
      session = RealtimeSession(
          OpenAIRealtimeWebSocketModel(),
          agent,
          None,
          model_config={
              "api_key": "sk-***",  # Ersetzen Sie dies durch Ihren AiHubMix-API-Schlüssel
              "url": "wss://aihubmix.com/v1/realtime?model=gpt-realtime-2.1",
          },
          run_config={
              "model_settings": {
                  "modalities": ["audio"],
                  "output_audio_format": "pcm16",
                  # Zwingend deaktivieren: Die standardmäßig aktive Audio-Transkription der Eingabe
                  # wird von dieser API nicht unterstützt, sonst wird die Sitzung mit 1008 geschlossen
                  "input_audio_transcription": None,
              },
          },
      )
      async with session:
          await session.send_message("What is the capital of France?")
          async for event in session:
              if getattr(event, "type", "") == "raw_model_event":
                  data = getattr(event, "data", None)
                  if getattr(data, "type", "") == "transcript_delta":
                      print(getattr(data, "delta", ""), end="", flush=True)
                  elif getattr(data, "type", "") == "turn_ended":
                      print("\n[Turn abgeschlossen]")
                      return

  asyncio.run(main())
  ```

  ```bash Verbindungstest (wscat) theme={null}
  # Mit wscat schnell Konnektivität und Authentifizierung prüfen (erfordert npm i -g wscat)
  wscat -c "wss://aihubmix.com/v1/realtime?model=gpt-realtime-2.1" \
    -H "Authorization: Bearer $AIHUBMIX_API_KEY"

  # Nach dem Verbinden einen session.update-Frame einfügen, dann eine Textnachricht + response.create senden
  ```
</CodeGroup>

<Tip>
  Um beliebiges Audio in das von dieser API geforderte rohe PCM-Format zu bringen, nutzen Sie ffmpeg:

  ```bash theme={null}
  ffmpeg -i input.mp3 -f s16le -acodec pcm_s16le -ac 1 -ar 24000 audio_pcm16_24k.raw
  ```
</Tip>

### Offizielle Beispiele wiederverwenden

Die meisten von OpenAI veröffentlichten Echtzeit-Konversationsbeispiele hängen nur vom Basis-URL-Parameter des SDK ab; richten Sie die Adresse auf den AiHubMix-Endpunkt und Sie können sie wiederverwenden:

| Offizielles Beispiel                                                                        | Wiederverwendbar nur durch Adressänderung | Was geändert werden muss                                                                                                                                                                                                                                  |
| ------------------------------------------------------------------------------------------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Offizielles Echtzeit-Konversationsbeispiel des Python-SDK                                   | Ja                                        | `websocket_base_url` auf `wss://aihubmix.com/v1` setzen und `model` an `connect()` übergeben                                                                                                                                                              |
| Offizielles Echtzeit-Konversationsbeispiel des Node- / JS-SDK                               | Ja                                        | `baseURL` auf `https://aihubmix.com/v1` setzen (das SDK wandelt es in `wss` um und baut `/realtime?model=...`)                                                                                                                                            |
| Offizielles Echtzeit-Sprachbeispiel des Agents SDK                                          | Ja                                        | `model_config.url` auf `wss://aihubmix.com/v1/realtime?model=gpt-realtime-2.1` setzen und die standardmäßig aktive Audio-Transkription der Eingabe deaktivieren                                                                                           |
| Offizielle Browser-Beispiele (etwa die Echtzeit-Konsole und das Multi-Agent-Sprachbeispiel) | Nein                                      | Diese Beispiele verbinden sich direkt aus dem Browser und werden von der `Origin`-Prüfung des Gateways abgelehnt; zudem hängen sie von serverseitig ausgestellten temporären Zugangsdaten ab, während diese API nur serverseitiges WebSocket bereitstellt |

<h2 id="run-output">
  Ausgabe aus dem Messlauf (in Produktion)
</h2>

Nachfolgend das reale Ergebnis des OpenAI-SDK-Beispiels in der Produktionsumgebung `aihubmix.com` mit dem Modell `gpt-realtime-2.1`. Die Sitzung aktiviert `server_vad`, und sowohl die Prompts als auch das Audio sind englisch.

**Texteingabe**

```text theme={null}
# Text "What is the capital of France?" senden
[Turn 1, Text] abgeschlossen in 2,33 s | 2,70 s PCM16-Audioausgabe
  Antwort: The capital of France is Paris.
  usage: input_tokens 29 (text 29) / output_tokens 81 (audio 54 + text 27, inklusive reasoning 8)
```

**Audioeingabe**

```text theme={null}
# 6,3 s englisches Audio in Stücken senden; das Modell erkennt das Turn-Ende und antwortet
[Turn 2, Audio] abgeschlossen in 9,59 s | 4,35 s PCM16-Audioausgabe
  Antwort: Everything sounds good on my side, and I'm ready to keep this conversation going.
  usage: input_tokens 117 (audio 67 + text 50) / output_tokens 129 (audio 87 + text 42, inklusive reasoning 11)
VAD-Ereignisse: input_audio_buffer.speech_started / input_audio_buffer.speech_stopped
```

**Gemessener Unterschied zweier Konfigurationen**

| Konfiguration                            | Gemessenes Ergebnis                                                                                                                                                                                           |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `turn_detection: {"type": "server_vad"}` | Nach dem Senden des Audios erhalten Sie `input_audio_buffer.speech_started` und `speech_stopped`, und das Modell erkennt das Turn-Ende und beginnt ohne manuelles `commit` und `response.create` zu antworten |
| `output_modalities: ["text"]`            | Der Antworttext wandert zu `response.output_text.delta`, für den Turn treten keine Audioausgabeereignisse auf, und `audio_tokens` ist in der usage 0                                                          |

<Note>
  Gemessene Bestätigung: Standardmäßig (Ausgabe enthält Audio) trifft der Antworttext zeichenweise nur über `response.output_audio_transcript.delta` ein, und `response.output_text.delta` erscheint nie; `response.done` trägt die `usage` des Turns; der Handshake dauert etwa 2 bis 4 Sekunden, die Kosten der Kontingentreservierung beim Aufbau der Sitzung.
</Note>

## Abrechnung

* **Abrechnung pro Token**: Eine Konversationssitzung gibt die Token-Nutzung jedes Turns (`usage`) mit dem Ereignis `response.done` zurück, und darauf basiert die Abrechnung. Die Nutzung wird getrennt nach Komponenten gemessen, darunter **Audioeingabe, Audioausgabe, Texteingabe und Textausgabe**. Der Stückpreis jeder Komponente folgt dem laufend ausgewiesenen Preis auf der [Modelldetailseite](https://aihubmix.com/model/gpt-realtime-2.1).
* **Laufende Abrechnung**: Dies ist eine langlebige Verbindung, und die Kosten werden während der Sitzung mit jedem Turn in Echtzeit abgezogen, ohne einmalige Abrechnung am Ende. Beim Aufbau einer Sitzung wird zunächst eine **Kontingentreservierung** von etwa einer Minute Nutzung vorgenommen (nur eine Zulassungsprüfung, keine tatsächliche Belastung), und die verbleibende Reservierung wird am Ende der Sitzung freigegeben. **Das verfügbare Guthaben Ihres Kontos muss daher mindestens etwa eine Minute Nutzung abdecken, damit eine Sitzung aufgebaut werden kann.**
* Jeder Abrechnungsdatensatz einer Echtzeit-Konversation ist in [Nutzung und Abrechnung](https://aihubmix.com) einzeln einsehbar.

## Grenzen und Einschränkungen

1. **Sitzungsdauer**: Eine WebSocket-Verbindung dauert höchstens **62 Minuten**, danach schließt der Server sie (Schließcode `1000`, Grund `session_duration_limit`). Teilen Sie sie auf, wenn Sie länger brauchen.
2. **Trennung bei Inaktivität**: Wenn weder der Client noch das Modell **5 Minuten** lang Aktivität zeigt, schließt der Server die Sitzung (Schließcode `1008`, Grund `idle_timeout`). Aktivität einer der beiden Seiten setzt den Timer zurück, eine lange weiter gestreamte Antwort wird also nicht unterbrochen.
3. **Unzureichendes Guthaben**: **Beim Aufbau der Sitzung** wird der Handshake direkt abgelehnt (HTTP 403) und keine Sitzung aufgebaut, wenn das verfügbare Guthaben die Reservierung von etwa einer Minute nicht abdeckt; **während der Sitzung** wird die aufgebaute Verbindung sofort geschlossen, wenn das Guthaben verbraucht ist.
4. **Nur serverseitig**: Direkte Browserverbindungen werden nicht unterstützt (der `Origin`-Header wird geprüft); integrieren Sie serverseitig.
5. **Modell fixiert**: Das Modell ist in der Verbindungs-URL festgelegt, und eine Änderung per `session.update` während der Sitzung wird abgelehnt und schließt die Sitzung.
6. **Format fixiert**: Audioeingabe und -ausgabe unterstützen nur `audio/pcm@24000` mono; andere Formate werden abgelehnt.
7. **Stimme fixiert**: `voice` kann nach Beginn der ersten Antwort nicht geändert werden; legen Sie sie vor der ersten Antwortanforderung fest.
8. **Nicht unterstützt**: Inline-Transkription innerhalb einer Konversationssitzung, das Einbringen von Audio- oder Bildinhalten über Konversationselemente sowie jeder andere Inhaltselementtyp als Text.
9. **Eine Antwort zugleich**: Eine Sitzung erlaubt nur eine laufende Antwort; ein weiteres `response.create` vor Abschluss des aktuellen Turns wird abgelehnt und schließt die Sitzung (Schließcode `1008`, Grund `response_already_active`).

## Häufige Fehler

| Szenario                                                     | Schließcode / Status                       | Beschreibung                                                                                               |
| ------------------------------------------------------------ | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------- |
| Dienst nicht aktiviert                                       | HTTP 403 `realtime_disabled`               | Die Echtzeit-Konversation ist für diese Umgebung nicht geöffnet                                            |
| `Origin`-Header vorhanden / direkte Browserverbindung        | Handshake abgelehnt                        | Verwenden Sie eine serverseitige Verbindung                                                                |
| Unzureichendes Guthaben beim Verbinden                       | HTTP 403 `insufficient_user_quota`         | Das Guthaben deckt die Reservierung von etwa einer Minute nicht; laden Sie auf und versuchen Sie es erneut |
| Modellwechsel während der Sitzung                            | `1008` `model_override_forbidden`          | Das Modell kann nur in der Verbindungs-URL angegeben werden                                                |
| Audioformat nicht PCM                                        | `1008` `audio_format_unsupported`          | In `audio/pcm@24000` konvertieren                                                                          |
| Stimmenwechsel nach der ersten Antwort                       | `voice`-Feld wird ignoriert                | Legen Sie `voice` vor der ersten Antwortanforderung fest                                                   |
| Inline-Transkription aktivieren                              | `1008` `input_transcription_not_supported` | In Konversationssitzungen in dieser Version nicht unterstützt                                              |
| Audio über Konversationselemente einbringen                  | `1008` `item_audio_not_supported`          | Senden Sie Audio über `input_audio_buffer.append`                                                          |
| Bilder über Konversationselemente einbringen                 | `1008` `image_input_not_supported`         | In dieser Version nicht unterstützt                                                                        |
| Konversationselement mit einem anderen Inhaltstyp als Text   | `1008` `unsupported_content_part`          | Konversationselemente unterstützen nur Textinhalt                                                          |
| Ungültiger Wert für `output_modalities`                      | `error`-Ereignis `invalid_value`           | Unterstützt werden nur `["audio"]` und `["text"]`; die Sitzung bleibt offen                                |
| Maximale Sitzungsdauer erreicht                              | `1000` `session_duration_limit`            | Die Grenze von 62 Minuten ist erreicht; verbinden Sie sich erneut                                          |
| Beide Seiten 5 Minuten inaktiv                               | `1008` `idle_timeout`                      | Aktivität einer der beiden Seiten setzt den Timer zurück                                                   |
| Weitere Anfrage während einer laufenden Antwort              | `1008` `response_already_active`           | Warten Sie auf `response.done`, bevor Sie `response.create` senden                                         |
| Doppelte `event_id`                                          | `1008` `duplicate_event_id`                | Die `event_id` jedes Client-Ereignisses muss innerhalb der Sitzung eindeutig sein                          |
| `response.conversation` auf einen Nicht-Standardwert gesetzt | `1008` `conversation_mode_not_supported`   | Nur der Standard-Konversationsmodus wird unterstützt                                                       |
| Client sendet ein serverseitiges Ereignis                    | `1008` `client_forged_lifecycle_event`     | Im Namensraum `response.*` darf der Client nur `response.create` und `response.cancel` senden              |
| Guthaben während der Sitzung erschöpft                       | Verbindung geschlossen                     | Laden Sie auf und verbinden Sie sich erneut                                                                |

***

Zuletzt aktualisiert: 2026-09-21
