Real-time Voice (MLLM)
Voice-to-voice with a realtime multimodal model.
Use with Agora CLI
Clone the recipe and configure it with an Agora project.
agora init my-realtime-voice --recipe realtime-voiceRecipe prompt
Paste into Cursor, Claude Code, v0, or your coding agentYou are implementing the "Real-time Voice (MLLM)" recipe in this project.
Read the recipe markdown first:
https://raw.githubusercontent.com/AgoraIO-Conversational-AI/recipe-agent-realtime/main/README.md
Use the source repository for cross-reference:
https://github.com/AgoraIO-Conversational-AI/recipe-agent-realtime
Build this recipe into the user's app using the markdown as the implementation guide. Inspect related source files through the repository links when the recipe points to them. Ask before installing new dependencies.Recipe
Rendered from the configured recipe markdown.
Agora Conversational AI — Realtime Recipe (Python)
  
The realtime recipe in the Agora Conversational AI recipes family. Voice-to-voice conversation using a single OpenAI Realtime MLLM — no separate STT, LLM, or TTS. Speak, and hear the model respond directly.
Not zero-key — OPENAI_API_KEY with Realtime API access is required.
Pipeline: OpenAIRealtime MLLM via .with_mllm() (server_vad turn detection)
Prerequisites
- Python 3.10+
- Bun
- Agora CLI — makes generating an App ID + App Certificate easy
- OpenAI API key with Realtime API access — set as
OPENAI_API_KEYinserver/.env.local
The same commands work on macOS, Linux, and Windows. On macOS/Linux, setup uses python3; on Windows, it uses the Python launcher (py) or python. WSL and virtualenv activation are not required.
Run It
# 1. Install web deps + create the Python venv
bun run setup
# 2. Add Agora credentials (CLI), or edit server/.env.local by hand
agora login
agora project use <your-project> # select which project to use
agora project env write server/.env.local # writes App ID + Certificate
# 3. Add your OpenAI Realtime API key to server/.env.local
# OPENAI_API_KEY=sk-... (required — OpenAI Realtime access)
# OPENAI_MODEL=gpt-4o-realtime-preview (optional, this is the default)
# 4. Run backend + web
bun run devOpen http://localhost:3000 → Start Conversation → speak.
Working from a clone
If you cloned this repo (rather than scaffolding via the Agora CLI), the steps above are complete as written: bun run setup creates the Python venv and installs web dependencies, then bun run dev brings up both services. You still need Agora credentials and OPENAI_API_KEY in server/.env.local before a conversation can connect.
Services:
- Frontend — http://localhost:3000
- Backend — http://localhost:8000
- Mock LLM — N/A (the realtime MLLM handles voice end-to-end)
- API docs — http://localhost:8000/docs
Deploy
Deploy web (Next.js) and server (a reachable FastAPI backend). Set AGENT_BACKEND_URL in the web deployment so the Next rewrites reach the backend.
A backend-only Docker image is published to ghcr.io/AgoraIO-Conversational-AI/recipe-agent-realtime on v* tags. It exposes BACKEND-ONLY (:8000). No separate service is needed.
Environment variables
Backend env file: `server/.env.example`.
| Variable | Required | Default | Notes |
|---|---|---|---|
AGORA_APP_ID | ✅ | — | Agora Console → Project → App ID |
AGORA_APP_CERTIFICATE | ✅ | — | Agora Console → Project → App Certificate |
OPENAI_API_KEY | ✅ | — | BYO OpenAI key with Realtime API access. Validated at agent start. |
OPENAI_MODEL | gpt-4o-realtime-preview | OpenAI Realtime model name | |
AGENT_GREETING | built-in | Optional opening line override |
Commands
bun run setup # install web deps + create server/ venv
bun run dev # run backend (:8000) + web (:3000)
bun run doctor # prerequisite check (no creds needed)
bun run doctor:local # + .env.local + credentials checks
bun run verify # web-only gate (no Agora creds needed)
bun run verify:local # full local gate: backend compile + smoke tests + web build
bun run clean # remove venvs and build artifactsTests run standalone (no Agora cloud needed): pytest in server/, plus bun run verify in web/. CI runs them on Linux/macOS/Windows × Python 3.10 & 3.13.
Architecture
Browser (localhost:3000)
│ fetch /api/*
▼
Next.js ──rewrite──▶ Agent backend (server/, localhost:8000)
│ starts agent session (OpenAIRealtime MLLM)
▼
Agora ConvoAI Cloud
│ OpenAI Realtime (voice-to-voice, server_vad)
▼
User hears realtime voice responseNo cascading STT/LLM/TTS vendors. No llm/ service. See ARCHITECTURE.md.
What You Get
- A Next.js web client (:3000) that drives the RTC/RTM lifecycle and only ever calls
/api/*. - A FastAPI agent backend (:8000) that owns Agora token generation and the agent session lifecycle.
- The
/api/get_config·/api/startAgent·/api/stopAgentcontract between the web client and the backend (Next rewrites, no Route Handlers). - OpenAI Realtime MLLM attached via
.with_mllm()— replaces the cascading STT→LLM→TTS with a single voice-to-voice model. - Server-side VAD (
server_vad) turn detection — owned by the MLLM, no top-level cascading VAD config needed. - BYO key —
OPENAI_API_KEYis required; validated at agent start.
How It Works
- The browser calls
/api/get_config, which Next rewrites to the backend; the
backend mints an Agora token from AGORA_APP_ID + AGORA_APP_CERTIFICATE.
- The browser joins the RTC channel, then calls
/api/startAgent; the backend
validates OPENAI_API_KEY and starts an agent session using OpenAIRealtime.
- The user speaks. Agora routes audio to the OpenAI Realtime endpoint.
- OpenAI Realtime processes voice-to-voice and streams the response audio back.
- The agent's voice plays in the channel. RTM transcript + metrics arrive in the web UI.
/api/stopAgentends the session.
Repo Map
web/— Next.js frontend (:3000); RTC/RTM lifecycle and UI.server/— FastAPI agent backend (:8000); Agora tokens + agent lifecycle, OpenAI Realtime MLLM.ARCHITECTURE.md— system shape and component boundaries.AGENTS.md— guide for coding agents working in this repo.
Troubleshooting
| Problem | Fix |
|---|---|
/startAgent returns 400 | Check OPENAI_API_KEY is set and has OpenAI Realtime API access. |
| Agent starts but no audio | Ensure the model (OPENAI_MODEL) supports realtime voice. |
| Local calls fail under a global proxy (Clash, etc.) | Configure your proxy to send 127.0.0.1, localhost, and RFC-1918 ranges DIRECT. |
More Docs
License
Released under the MIT License.