Text size
Dark mode
RecallRunGuides & benchmarks
Learn to build real systemsGuides•Benchmarks•Experiments•Community
Search the site/Free checklist

Guides/OpenAI SDK

OpenAI SDK: Realtime & voice

A voice assistant built from three calls (transcribe → think → speak, part 09) works, but each hop adds latency, and conversation feels stilted.

In this post

What this post covers
  1. 1. Chained versus realtime
  2. 2. The concepts
  3. 3. A server-side session (sketch)
  4. 4. When to choose which
  5. Recap

A voice assistant built from three calls (transcribe → think → speak, part 09) works, but each hop adds latency, and conversation feels stilted. The Realtime API keeps a persistent session (WebRTC in browsers, WebSocket on servers) with a speech-to-speech model. It hears audio as it streams, detects when the user stops speaking, can be interrupted, calls tools, and answers with audio in fractions of a second.

1. Chained versus realtime

Chained (lesson 09) transcribe audio text model text → speech latency adds up per hop; tone of voice is lost Realtime one session: audio streams both ways turn detection · interruptions · tool calls · transcripts on the side conversational latency; hears and produces tone

2. The concepts

ConceptMeaning
Sessiona long-lived connection with configuration: instructions, voice, tools, audio formats
Eventseverything is an event in both directions: audio chunks appended, responses created, deltas, tool calls
Turn detection (VAD)the server decides when the user has finished speaking, so the model can reply without a button
Interruptionif the user talks over the reply, the reply is cancelled, as in a real conversation
Ephemeral keysbrowsers get a short-lived token from your server, never your real API key

3. A server-side session (sketch)

text in, text out over a realtime connection (real API; not executed here)

import asyncio
from openai import AsyncOpenAI

async def main():
    client = AsyncOpenAI()
    async with client.realtime.connect(model="gpt-realtime-2.1") as conn:   # a current realtime model
        await conn.session.update(session={
            "type": "realtime",
            "instructions": "You are a friendly order-status assistant. Keep answers short.",
            "output_modalities": ["text"],        # use ["audio"] (and stream mic audio in) for voice
        })
        await conn.conversation.item.create(item={
            "type": "message", "role": "user",
            "content": [{"type": "input_text", "text": "Is order 1042 delivered?"}],
        })
        await conn.response.create()
        async for event in conn:
            if event.type == "response.output_text.delta":
                print(event.delta, end="", flush=True)
            elif event.type == "response.done":
                break

asyncio.run(main())
Check the current Realtime guide before building

Realtime is the fastest-moving part of the API. Session fields, event names and model IDs have changed across versions, and the models page currently lists several realtime and "live" models. Treat this code as the shape of the solution. Use the official Realtime guide and the Agents SDK's voice and realtime agents for production voice apps, and test on real devices and networks.

4. When to choose which

Realtime

Live voice conversation: phone agents, in-app voice assistants, interpreting, tutoring. Anything where a one-second pause feels broken.

Chained

Voice notes, transcription of recordings, podcasts from text, or when you need a specific text model in the middle and a few seconds of latency is fine.

Recap

  • Realtime = one persistent session streaming audio both ways, with turn detection and interruption.
  • Everything is an event; tools work as in the Responses API.
  • Browsers use ephemeral keys minted by your server.
  • Fast-moving API: follow the current guide; use chained calls when latency does not matter.

Get the free RAG production checklist

25 checks to run before real users see your RAG feature: exact-match misses, invented citations, prompt injection through documents, quality that slips after a prompt change. Confirm your email and the PDF comes with the welcome email, plus each new experiment.

One email to confirm. Unsubscribe any time. What's in it · Privacy

Want the production version of this? See ShipRAG: A production RAG + MCP starter kit for FastAPI: hybrid search, validated citations, evals in CI, Docker, 32 tests.

Written by

Alby Tomy

Python/FastAPI Engineer | Data Engineer | AI Engineer building RAG and MCP systems.

X · GitHub · Contact & enquiries