
Jak vytvořit hlasového agenta na OpenAI Realtime API: Produkční návod v 7 krocích (2026)
Náš testovací agent zvedl hovor Twilio a vyslovil první slovo 1,1 sekundy poté, co volající přestal mluvit. To je p50 round-trip, měřeno na 40 hovorech na gpt-realtime-2 se semantic_vad. Žádná magie. OpenAI Realtime API dělá speech-to-speech uvnitř jednoho socketu, takže přeskočíte relay STT → LLM → TTS, která přidává zhruba 600 ms lepidla. Ale výchozí nastavení vás pod sekundu nedostane. Tohle je ten 7krokový build, který jsme nasadili, včetně kódu a tabulky latencí.
Toto je návod na stavbu, ne vysvětlení konceptu. Pokud chcete nejprve vrstvený rozbor, přečtěte si co je vlastně AI hlasový agent, a pak se vraťte. Vše níže předpokládá, že máte OpenAI API klíč a Node runtime.
Klíčové poznatky:
- gpt-realtime-2 dělá speech-to-speech v jednom socketu — žádné relay STT/LLM/TTS, ušetřeno ~600 ms.
- Dočasné klíče generujte na straně serveru; nikdy neposílejte svůj standardní API klíč do prohlížeče.
- Mediální stream Twilio je 8kHz μ-law; pro Realtime API převzorkujte na 24kHz PCM16.
- Naměřili jsme p50 1,1 s / p95 1,9 s round-trip. Přerušení (barge-in) se spouští přes
response.cancel.
Co postavíte v 7 krocích
Tento návod staví hlasového agenta na OpenAI Realtime API, který zvedá telefon, odpovídá do 1,5 sekundy, uprostřed konverzace volá skutečnou funkci a umožňuje volajícímu ho přerušit. Tok je krátký: volající vytočí telefonní číslo, zvuk se streamuje na váš server, váš server ho přemostí na gpt-realtime-2 přes jediný socket, model mluví a může spouštět volání nástrojů a zvuk se streamuje zpět.
Tady je cesta a můžete se zastavit na jakémkoli kroku, který odpovídá vašemu případu užití:
- Vygenerujte dočasný klíč (serverová ruta)
- Otevřete a nakonfigurujte session
- Přidejte volání funkcí
- Přemostění na telefonní číslo přes Twilio
- Zpracujte barge-in a přerušení
- Vylaďte latenci pod sekundu
- Nasaďte a zabezpečte
Zvuk přenášejí tři transporty a vaše volba závisí na tom, odkud zvuk přichází. Prohlížeč ho zachytává přímo (WebRTC), váš server už má surový stream (WebSocket), nebo ho doručuje telefonní síť (SIP). Pro most Twilio použijeme WebSocket a ostatní zmíníme tam, kam se hodí.
Krok 1: Vygenerujte dočasný klíč (ruta, kterou nemůžete přeskočit)
Nikdy nevystavujte svůj standardní OpenAI API klíč prohlížeči ani klientskému zařízení. Realtime API pro přesně tento účel vydává krátkodobé dočasné klíče. Váš server zavolá POST /v1/realtime/client_secrets se svým skutečným klíčem, předá klientovi token, který vyprší zhruba za minutu, a klient se místo toho připojí s ním.
Tady je minimální Express ruta, která jeden vygeneruje:
// server.js
import express from "express";
const app = express();
app.get("/session", async (req, res) => {
const r = await fetch("https://api.openai.com/v1/realtime/client_secrets", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.OPENAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
session: { type: "realtime", model: "gpt-realtime-2" },
}),
});
const data = await r.json();
res.json({ client_secret: data.value, expires_at: data.expires_at });
});
app.listen(3000);Prohlížeč načte /session, přečte krátkodobý secret a otevře s ním Realtime spojení. Pokud je váš agent pouze serverový (případ Twilio v kroku 4), můžete předání klientovi přeskočit a otevřít socket přímo z backendu se standardním klíčem. Tok s dočasnými klíči existuje kvůli ochraně nedůvěryhodných klientů.
Krok 2: Otevřete session a nakonfigurujte gpt-realtime-2
Otevřete spojení a poté pošlete session.update, který nastaví model, formát zvuku, hlas a detekci střídání. Dokumentace OpenAI doporučuje začít s reasoning.effort nastaveným na low a zvyšovat ho jen tehdy, pokud vaše logika nástrojů potřebuje větší přesnost, protože vyšší effort vás stojí latenci. Zvuk běží jako 24kHz PCM16 v obou směrech.
ws.send(JSON.stringify({
type: "session.update",
session: {
type: "realtime",
model: "gpt-realtime-2",
output_modalities: ["audio"],
audio: {
input: { format: "pcm16", sample_rate: 24000 },
output: { format: "pcm16", sample_rate: 24000, voice: "marin" },
},
instructions: "You are a reservations agent for a restaurant. Be brief.",
reasoning: { effort: "low" },
turn_detection: { type: "semantic_vad" },
},
}));Do jakého transportu tento socket zabalíte, závisí na zdroji zvuku:
| Transport | Kdy použít | Zdroj zvuku |
|---|---|---|
| WebRTC | Prohlížeč nebo mobilní aplikace zachytává mikrofon přímo | Klientské zařízení |
| WebSocket | Váš server už drží surový audio stream | Serverová pipeline |
| SIP | Chcete, aby OpenAI vyřídilo telefonní část | PSTN / telefonie |
Úplný seznam polí session a sadu funkcí GA najdete v dokumentaci OpenAI Realtime API, která je zdrojem pravdy. Použijeme WebSocket, protože Twilio nám v kroku 4 předává surový zvuk.
Krok 3: Přidejte volání funkcí (aby agent skutečně něco dělal)
Hlasový agent, který neumí jednat, je pouhý voice-over. Volání funkcí umožňuje gpt-realtime-2 uprostřed konverzace pozastavit, požádat váš kód o spuštění něčeho a pokračovat v mluvení s výsledkem. V session deklarujete nástroj, model vyšle událost function_call_arguments.done, když ho chce, vy provedete práci a pošlete výstup zpět.
Deklarujte nástroj a poté zpracujte událost:
// in session.update -> session.tools:
tools: [{
type: "function",
name: "book_reservation",
description: "Book a table for a given party size and time.",
parameters: {
type: "object",
properties: {
party_size: { type: "integer" },
time: { type: "string", description: "ISO 8601 datetime" },
},
required: ["party_size", "time"],
},
}]
// handling the call:
if (event.type === "response.function_call_arguments.done") {
const args = JSON.parse(event.arguments);
const result = await bookTable(args); // your real logic
ws.send(JSON.stringify({
type: "conversation.item.create",
item: {
type: "function_call_output",
call_id: event.call_id,
output: JSON.stringify(result),
},
}));
ws.send(JSON.stringify({ type: "response.create" })); // let it speak the result
}Nejčastější důvod, proč se nástroje tiše nikdy nespustí: neposloucháte function_call_arguments.done a poté nepošlete response.create. Model volání vygeneroval, vy ho ignorujete a volající slyší jen ticho.
Pokud váš agent žongluje s mnoha nástroji, OpenAI Agents SDK tady změnilo pravidla. Jeho přepracování z 15. dubna 2026 udělalo z Model Context Protocol (MCP) prvotřídního občana a přeměnilo předávání mezi sub-agent na runtime primitivum. Takže místo nacpání všech nástrojů do jednoho promptu může routerovací agent předat rezervaci sub-agentovi pro rezervace a fakturační dotaz jinému. Agents SDK voice quickstart balí stejnou Realtime session do RealtimeAgent a dává vám předávání bez psaní vlastní orchestrační smyčky.
Krok 4: Přemostěte ho na telefonní číslo (Twilio)
Pro příjem skutečných hovorů přemostíte do socketu poskytovatele telefonie. U Twilio nasměrujete příchozí hovor na TwiML <Connect><Stream>, který otevře WebSocket na váš server, a přenášíte audio rámce mezi Twilio a Realtime API. Alternativou je SIP — OpenAI Realtime přijímá SIP přímo, což zcela odstraní váš mediální relay, pokud nepotřebujete se zvukem manipulovat.
TwiML, který spustí stream:
<Response>
<Connect>
<Stream url="wss://your-server.com/twilio-stream" />
</Connect>
</Response>Tady je zádrhel, který vás připraví o den, pokud ho přehlédnete: mediální stream Twilio je 8kHz μ-law a Realtime API chce 24kHz PCM16. Musíte převzorkovat v obou směrech, jinak dostanete zkreslený, pisklavý zvuk.
// inbound: Twilio (8kHz μ-law base64) -> Realtime (24kHz PCM16)
const pcm16 = upsample(muLawDecode(Buffer.from(msg.media.payload, "base64")), 8000, 24000);
realtime.send(JSON.stringify({
type: "input_audio_buffer.append",
audio: pcm16.toString("base64"),
}));
// outbound: Realtime (24kHz PCM16) -> Twilio (8kHz μ-law)
const ulaw = muLawEncode(downsample(modelPcm16, 24000, 8000));
twilioWs.send(JSON.stringify({
event: "media",
media: { payload: ulaw.toString("base64") },
}));Úplný formát rámců najdete v dokumentaci Twilio Media Streams. Držte převzorkování levné, protože těžká knihovna tady přidá latenci, kterou zaplatíte na každém rámci.
Krok 5: Zpracujte barge-in a přerušení
Produkční agent umožňuje volajícímu mluvit přes něj. Barge-in znamená detekovat, že volající začal mluvit, zatímco je agent uprostřed věty, a poté agenta čistě přerušit. Realtime API to řeší pomocí response.cancel: když detekce střídání nahlásí, že během přehrávání začal hovor, zrušíte aktivní odpověď a vyprázdníte veškerý zvuk, který jste už nashromáždili směrem k volajícímu.
if (event.type === "input_audio_buffer.speech_started") {
realtime.send(JSON.stringify({ type: "response.cancel" }));
twilioWs.send(JSON.stringify({ event: "clear" })); // drop queued playback
}Detekce střídání má dva režimy a na volbě záleží. server_vad se spouští na surových prazích ticha a má tendenci přerušovat volajícího při přirozených pauzách. semantic_vad čeká, dokud si model nemyslí, že volající skutečně dokončil myšlenku, takže vytváří mnohem méně falešných přerušení při pauze na přemýšlení. Pro telefonní hovory je sémantické VAD to, co působí lidsky.
Krok 6: Vylaďte latenci pod sekundu
Tady se demo stává produktem, takže tady jsou čísla z naší vlastní implementace, ne teoretický rozpočet. Spustili jsme stejného restauračního agenta na 40 testovacích hovorech v květnu 2026, na jednom malém serveru colocovaném blízko regionu OpenAI, a měnili jsme pouze nastavení detekce střídání a reasoning.
| Konfigurace | p50 round-trip | p95 | Poznámky |
|---|---|---|---|
| server_vad, reasoning low | ~1,4 s | ~2,3 s | více falešných barge-in při pauzách |
| semantic_vad, reasoning low | ~1,1 s | ~1,9 s | naše produkční výchozí |
| semantic_vad, reasoning medium | ~1,8 s | ~3,1 s | lepší přesnost nástrojů, pomalejší |
Páky, které skutečně něco změnily, v pořadí podle dopadu:
- Držte
reasoning.effortnízko, pokud konkrétní nástroj přesnost skutečně nepotřebuje. Medium téměř zdvojnásobilo naši p50. - Netlačte zvuk rychleji než v reálném čase. Zahlcení
input_audio_buffer.appendpřeteče buffer a způsobí drift; dávkujte rámce podle reálného času. - Držte socket teplý. Chladné otevírání spojení pro každý hovor přidá handshake k latenci prvního slova. Tam, kde to objem hovorů umožňuje, sdružujte spojení do poolu.
- Převzorkovávejte efektivně. Naivní resampler v horké cestě nám přidal ~80 ms na každé střídání.
Kolik stojí provoz za minutu, jakmile je to nasazené? Výpočet pro bring-your-own-key jsme zpracovali zvlášť — viz kolik stojí BYOK hlasový agent za minutu, místo abychom to odvozovali znovu tady.
Krok 7: Nasaďte a zabezpečte pro produkci
Mezera mezi „fungovalo to na mém notebooku" a „přežije to 500 hovorů denně" je hrstka dobře známých selhání. Tady je kontrolní seznam zabezpečení, sestavený z chyb, které Realtime agenty skutečně rozbíjejí:
| Past | Symptom | Náprava |
|---|---|---|
| Špatná vzorkovací frekvence | zkreslený / pisklavý zvuk | 24kHz PCM16 oběma směry |
Ignorování function_call_arguments.done | nástroje se nikdy nespustí | poslouchat a poslat response.create |
| Tlačení zvuku rychleji než v reálném čase | přetečení bufferu, drift | dávkovat rámce podle reálného času |
| Žádná logika opětovného připojení | hovory se přeruší při výpadku socketu | automatické připojení + obnovení session |
Žádné zpracování response.done | překrývající se střídání | další střídání podmínit response.done |
Dvě další věci pro skutečný provoz. U dlouhých hovorů každých několik střídání session zrotujte nebo znovu inicializujte, aby kontext nedriftoval, protože 20minutový hovor nashromáždí stav, o který se model začne zakopávat. A logujte každé volání nástroje s jeho argumenty a výsledkem; když volající řekne „agent rezervoval špatný čas", samotný přepis vám neřekne, jestli se spletl model, nebo váš kód.
Pokud zvolíte cestu Agents SDK z kroku 3, jeho nový kontejnerový sandbox spouští kód nástrojů v izolaci, což je důležité, jakmile se vaše nástroje dotýkají souborového systému nebo shellu, a ne jen API.
Kdy byste si místo toho měli koupit spravovanou platformu
Stavba přímo na Realtime API vám dává největší kontrolu a nejnižší náklady za minutu, ale vlastníte logiku opětovného připojení, telefonní most, compliance a observabilitu — všechny nelákavé části kroků 4 až 7. Pokud potřebujete telefonního agenta nasadit tento týden a nechcete udržovat mediální relay, spravovaná platforma je rychlejší volba.
Postavili jsme stejného agenta na třech velkých a poctivě je porovnali: Retell, Vapi, nebo Bland. Pokud se stále rozhodujete, na které straně jste, projděte si kompletní rozhodovací rámec stavět vs. koupit, než investujete inženýrský čas.
Když týmy chtějí kontrolu vlastní Realtime implementace bez nutnosti ji personálně zajišťovat, to je práce, kterou děláme: vývoj produkčních hlasových agentů, od telefonního mostu po výše uvedené ladění latence. Rádi se podíváme na váš případ užití, pokud ho zvažujete.
O autorovi — Mert Batur Gurbuz je spoluzakladatelem Techsy.io, kde tým dodává AI agenty, automatizační systémy a hlasové/SDR pipeline pro B2B klienty. Studuje na University of Birmingham a píše o stacku nástrojů pro LLM, který tým Techsy skutečně používá v produkci. LinkedIn
Často kladené otázky
Jaká je latence hlasového agenta na OpenAI Realtime API?
V naší implementaci na gpt-realtime-2 se semantic_vad a nízkým reasoning effort jsme naměřili round-trip latenci p50 1,1 s a p95 1,9 s na 40 testovacích hovorech. Speech-to-speech v jednom socketu se vyhýbá relay STT/LLM/TTS, což je to, co vůbec umožňuje odezvy pod sekundu.
Potřebuji pro svého hlasového agenta WebRTC, WebSocket, nebo SIP?
Použijte WebRTC, když prohlížeč nebo mobilní aplikace zachytává mikrofon přímo, WebSocket, když váš server už drží surový audio stream (případ mostu Twilio), a SIP, když chcete, aby OpenAI vyřídilo telefonní část bez vašeho vlastního mediálního relay. Většina telefonních agentů používá WebSocket nebo SIP.
Jak připojím OpenAI Realtime API k Twilio?
Nasměrujte příchozí hovor Twilio na TwiML <Connect><Stream>, který otevře WebSocket na váš server, a poté přenášejte zvuk mezi Twilio a Realtime socketem. Převzorkujte 8kHz μ-law Twilio na 24kHz PCM16 API v obou směrech, jinak bude zvuk zkreslený.
Jak funguje volání funkcí v Realtime API?
Nástroje deklarujete v konfiguraci session. Když model nějaký chce, vyšle událost function_call_arguments.done. Provedete práci, pošlete výsledek zpět jako konverzační položku function_call_output a poté pošlete response.create, aby agent výsledek vyslovil. Zapomenutí na tento poslední krok je důvod, proč nástroje často „tiše" selžou.
Jak zpracujete přerušení (barge-in) v Realtime API?
Když detekce střídání během přehrávání nahlásí input_audio_buffer.speech_started, pošlete response.cancel pro zastavení aktivní odpovědi a vymazání veškerého zvuku výstupu ve frontě směrem k volajícímu. Zkombinujte to se semantic_vad, aby přirozené pauzy nespouštěly falešná přerušení uprostřed věty.
Jakou vzorkovací frekvenci zvuku OpenAI Realtime API používá?
Realtime API používá 24kHz PCM16 zvuk v obou směrech. Poskytovatelé telefonie jako Twilio doručují 8kHz μ-law, takže telefonní most musí převzorkovat nahoru na cestě dovnitř a dolů na cestě ven. Nesprávné vzorkovací frekvence jsou zdaleka nejčastější příčinou zkresleného zvuku.
Kolik stojí provoz hlasového agenta na Realtime API?
Náklady jsou řízeny minutami audio vstupu a výstupu na gpt-realtime-2 a ekonomika bring-your-own-key se výrazně liší od spravované platformy s cenou za minutu. Kompletní výpočet jsme zpracovali v našem rozboru cen hlasových agentů, místo abychom ho odhadovali tady.
Mám stavět na Realtime API, nebo použít Retell, Vapi, nebo Bland?
Stavte přímo, když chcete maximální kontrolu a nejnižší náklady za minutu a můžete si dovolit vlastnit opětovná připojení, telefonii a compliance. Kupte spravovanou platformu, když je důležitější rychlost uvedení na trh. Naše srovnání Retell vs Vapi vs Bland a rámec stavět vs. koupit pokrývají kompromisy.
Co změnila aktualizace OpenAI Agents SDK z dubna 2026 pro hlasové agenty?
Přepracování z 15. dubna 2026 udělalo z Model Context Protocol prvotřídního občana, přidalo kontejnerový sandbox pro kód nástrojů a přeměnilo předávání mezi sub-agent na runtime primitivum. Pro hlasové agenty to znamená, že routerovací agent může předávat specializovaným sub-agentům, místo aby cpal každý nástroj do jednoho promptu.