
Rakenna ääniagentti OpenAI Realtime API:n päälle: Tuotanto-ohje 7 vaiheessa (2026)
Testiagenttimme vastasi Twilio-puheluun ja sanoi ensimmäisen sanansa 1,1 sekuntia sen jälkeen, kun soittaja lopetti puhumisen. Se on p50 round-trip, mitattuna 40 puhelun yli gpt-realtime-2:lla semantic_vad:illa. Ei taikuutta. OpenAI Realtime API tekee speech-to-speechin yhdessä socketissa, joten ohitat STT → LLM → TTS -viestiketjun, joka kasaa päälle suunnilleen 600 ms liimaa. Mutta oletukset eivät vie sinua sekuntiin. Tämä on se 7-vaiheinen toteutus, jonka julkaisimme, koodin ja latenssitaulukon kera.
Tämä on rakennusohje, ei konseptin selitys. Jos haluat ensin kerroksittaisen läpikäynnin, lue mikä tekoälyääniagentti oikeastaan on, ja tule sitten takaisin. Kaikki alla oleva olettaa, että sinulla on OpenAI API -avain ja Node-ajoympäristö.
Keskeiset opit:
- gpt-realtime-2 tekee speech-to-speechin yhdessä socketissa — ei STT/LLM/TTS-viestiketjua, ~600 ms säästyy.
- Luo väliaikaiset avaimet palvelinpuolella; älä koskaan lähetä vakio-API-avaintasi selaimeen.
- Twilion mediavirta on 8kHz μ-law; näytteistä uudelleen 24kHz PCM16:een Realtime API:lle.
- Mittasimme p50 1,1 s / p95 1,9 s round-tripin. Keskeytys (barge-in) laukeaa
response.cancel:in kautta.
Mitä rakennat 7 vaiheessa
Tämä ohje rakentaa puhelimeen vastaavan OpenAI Realtime API -ääniagentin, joka vastaa alle 1,5 sekunnissa, kutsuu oikeaa funktiota kesken keskustelun ja antaa soittajan keskeyttää. Kulku on lyhyt: soittaja soittaa puhelinnumeroon, ääni virtaa palvelimellesi, palvelimesi siltaa sen gpt-realtime-2:een yhden socketin yli, malli puhuu ja voi laukaista työkalukutsuja, ja ääni virtaa takaisin.
Tässä on polku, ja voit pysähtyä mihin tahansa vaiheeseen, joka vastaa käyttötapaustasi:
- Luo väliaikainen avain (palvelinreitti)
- Avaa ja määritä istunto
- Lisää funktiokutsut
- Siltaa puhelinnumeroon Twiliolla
- Käsittele keskeytykset ja barge-in
- Säädä latenssi alle sekunnin
- Ota käyttöön ja kovenna
Kolme kuljetusta kantaa äänen, ja valintasi riippuu siitä, mistä ääni tulee. Selain kaappaa sen suoraan (WebRTC), palvelimellasi on jo raakavirta (WebSocket) tai puhelinverkko toimittaa sen (SIP). Käytämme WebSocketia Twilio-sillalle ja mainitsemme muut siellä, missä ne sopivat.
Vaihe 1: Luo väliaikainen avain (reitti, jota et voi ohittaa)
Älä koskaan paljasta vakio-OpenAI API -avaintasi selaimelle tai asiakaslaitteelle. Realtime API myöntää lyhytikäisiä väliaikaisia avaimia juuri tätä varten. Palvelimesi kutsuu POST /v1/realtime/client_secrets:ia oikealla avaimellasi, antaa asiakkaalle tokenin, joka vanhenee noin minuutissa, ja asiakas yhdistää sillä sen sijaan.
Tässä on minimaalinen Express-reitti, joka luo sellaisen:
// 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);Selain hakee /session:in, lukee lyhytikäisen salaisuuden ja avaa Realtime-yhteyden sillä. Jos agenttisi on vain palvelimella (Twilio-tapaus vaiheessa 4), voit ohittaa asiakasluovutuksen ja avata socketin suoraan backendistasi vakioavaimella. Väliaikainen kulku on olemassa suojaamaan ei-luotettuja asiakkaita.
Vaihe 2: Avaa istunto ja määritä gpt-realtime-2
Avaa yhteys ja lähetä sitten session.update, joka asettaa mallin, äänimuodon, äänen ja vuorontunnistuksen. OpenAI-dokumentaatio suosittelee aloittamaan reasoning.effort asetettuna low:ksi ja nostamaan sitä vain, jos työkalulogiikkasi tarvitsee enemmän tarkkuutta, koska korkeampi effort maksaa sinulle latenssia. Ääni kulkee 24kHz PCM16:na molempiin suuntiin.
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" },
},
}));Mihin kuljetukseen paketoit sen socketin, riippuu äänilähteestä:
| Kuljetus | Käytä kun | Äänilähde |
|---|---|---|
| WebRTC | Selain tai mobiilisovellus kaappaa mikrofonin suoraan | Asiakaslaite |
| WebSocket | Palvelimellasi on jo raaka äänivirta | Palvelinputki |
| SIP | Haluat OpenAI:n hoitavan puhelinosuuden | PSTN / puhelinverkko |
Istuntokenttien täydellinen lista ja GA-ominaisuusjoukko löytyvät OpenAI Realtime API -dokumentaatiosta, joka on totuuden lähde. Käytämme WebSocketia, koska Twilio antaa meille raakaa ääntä vaiheessa 4.
Vaihe 3: Lisää funktiokutsut (jotta agentti voi oikeasti tehdä asioita)
Ääniagentti, joka ei voi toimia, on pelkkä selostusääni. Funktiokutsut antavat gpt-realtime-2:n pysähtyä kesken keskustelun, pyytää koodiasi suorittamaan jotain ja jatkaa puhumista tuloksen kanssa. Julistat työkalun istunnossa, malli lähettää function_call_arguments.done -tapahtuman, kun se haluaa sen, suoritat työn ja lähetät tuloksen takaisin.
Julista työkalu ja käsittele sitten tapahtuma:
// 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
}Yleisin syy siihen, miksi työkalut eivät koskaan laukea hiljaisesti: et kuuntele function_call_arguments.done:a etkä lähetä response.create:a sen jälkeen. Malli tuotti kutsun, sinä jätit sen huomiotta, ja soittaja kuulee vain hiljaisuutta.
Jos agenttisi pyörittää monia työkaluja, OpenAI Agents SDK muutti laskutoimituksen tässä. Sen 15. huhtikuuta 2026 uudistus teki Model Context Protocolista (MCP) ensiluokkaisen ja muutti sub-agenttien luovutukset ajonaikaiseksi primitiiviksi. Joten sen sijaan, että ahtaisit jokaisen työkalun yhteen promptiin, reitittäjäagentti voi luovuttaa varauksen varaus-sub-agentille ja laskutuskysymyksen toiselle. Agents SDK voice quickstart paketoi saman Realtime-istunnon RealtimeAgent:iin ja antaa sinulle luovutukset ilman oman orkestrointisilmukan kirjoittamista.
Vaihe 4: Siltaa se puhelinnumeroon (Twilio)
Vastataksesi oikeisiin puheluihin siltaat puheluntarjoajan sockettiin. Twiliolla osoitat saapuvan puhelun TwiML <Connect><Stream>:iin, joka avaa WebSocketin palvelimellesi, ja välität äänikehyksiä Twilion ja Realtime API:n välillä. SIP on vaihtoehto — OpenAI Realtime hyväksyy SIP:in suoraan, mikä poistaa mediavälityksesi kokonaan, jos sinun ei tarvitse koskea ääneen.
TwiML, joka käynnistää virran:
<Response>
<Connect>
<Stream url="wss://your-server.com/twilio-stream" />
</Connect>
</Response>Tässä on ansa, joka syö päivän, jos ohitat sen: Twilion mediavirta on 8kHz μ-law ja Realtime API haluaa 24kHz PCM16:n. Näytteistät uudelleen molempiin suuntiin, tai saat säröistä, oravaääntä.
// 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") },
}));Täydellinen kehysmuoto löytyy Twilio Media Streams -dokumentaatiosta. Pidä uudelleennäytteistys kevyenä, koska raskas kirjasto tässä lisää latenssia, jonka maksat jokaisessa kehyksessä.
Vaihe 5: Käsittele keskeytykset ja barge-in
Tuotantoagentti antaa soittajan puhua sen päälle. Barge-in tarkoittaa sitä, että havaitaan soittajan aloittaneen puhumisen, kun agentti on kesken lauseen, ja katkaistaan agentti siististi. Realtime API käsittelee tämän response.cancel:illa: kun vuorontunnistus raportoi puheen alkaneen toiston aikana, peruutat aktiivisen vastauksen ja tyhjennät kaiken äänen, jonka olet jo puskuroinut soittajaa kohti.
if (event.type === "input_audio_buffer.speech_started") {
realtime.send(JSON.stringify({ type: "response.cancel" }));
twilioWs.send(JSON.stringify({ event: "clear" })); // drop queued playback
}Vuorontunnistuksessa on kaksi tilaa, ja valinnalla on väliä. server_vad laukeaa raaoista hiljaisuuskynnyksistä ja taipuu katkaisemaan soittajan luonnollisissa tauoissa. semantic_vad odottaa, kunnes malli luulee soittajan oikeasti lopettaneen ajatuksen, joten se tuottaa paljon vähemmän vääriä keskeytyksiä miettimistauolla. Puheluita varten semanttinen VAD on se, joka tuntuu inhimilliseltä.
Vaihe 6: Säädä latenssi alle sekunnin
Tässä demosta tulee tuote, joten tässä ovat luvut omasta toteutuksestamme, ei teoreettinen budjetti. Ajoimme samaa ravintola-agenttia 40 testipuhelun yli toukokuussa 2026 yhdellä pienellä palvelimella, joka sijaitsi lähellä OpenAI-aluetta, ja vaihdoimme vain vuorontunnistus- ja reasoning-asetuksia.
| Asetus | p50 round-trip | p95 | Huomautukset |
|---|---|---|---|
| server_vad, reasoning low | ~1,4 s | ~2,3 s | enemmän vääriä barge-ineja tauoissa |
| semantic_vad, reasoning low | ~1,1 s | ~1,9 s | tuotanto-oletuksemme |
| semantic_vad, reasoning medium | ~1,8 s | ~3,1 s | parempi työkalutarkkuus, hitaampi |
Vivut, jotka oikeasti liikuttivat neulaa, vaikutusjärjestyksessä:
- Pidä
reasoning.effortmatalana, ellei tietty työkalu oikeasti tarvitse tarkkuutta. Medium melkein kaksinkertaisti p50:mme. - Älä työnnä ääntä nopeammin kuin reaaliajassa.
input_audio_buffer.append:in tulviminen ylivuotaa puskurin ja aiheuttaa ajautumista; tahdita kehykset seinäkelloaikaan. - Pidä socketti lämpimänä. Yhteyden kylmä avaaminen puhelua kohden lisää kättelyn ensimmäisen sanan latenssiisi. Poolaa yhteydet, missä puhelutilavuus sallii.
- Näytteistä uudelleen tehokkaasti. Naiivi uudelleennäytteistäjä kuumassa polussa lisäsi ~80 ms vuoroa kohden meille.
Mitä tämän pyörittäminen maksaa minuutilta, kun se on tuotannossa? Laskimme bring-your-own-key-matematiikan erikseen — katso mitä BYOK-ääniagentti maksaa minuutilta sen sijaan, että johtaisimme sen uudelleen tässä.
Vaihe 7: Ota käyttöön ja kovenna tuotantoa varten
Kuilu "se toimi kannettavallani" ja "se selviää 500 puhelusta päivässä" välillä on kourallinen tunnettuja vikoja. Tässä on kovennuksen tarkistuslista, joka on koottu virheistä, jotka oikeasti rikkovat Realtime-agentteja:
| Ansa | Oire | Korjaus |
|---|---|---|
| Väärä näytteenottotaajuus | säröinen / oravaääni | 24kHz PCM16 molempiin suuntiin |
function_call_arguments.done:n huomiotta jättäminen | työkalut eivät koskaan laukea | kuuntele ja lähetä response.create |
| Äänen työntäminen nopeammin kuin reaaliajassa | puskurin ylivuoto, ajautuminen | tahdita kehykset reaaliaikaan |
| Ei uudelleenyhdistyslogiikkaa | puhelut katkeavat socketin häiriöön | automaattinen uudelleenyhdistys + jatka istuntoa |
Ei response.done-käsittelyä | päällekkäiset vuorot | portita seuraava vuoro response.done:lla |
Kaksi asiaa lisää oikeaa liikennettä varten. Pitkillä puheluilla kierrätä tai alusta istunto uudelleen muutaman vuoron välein, jotta konteksti ei ajautuisi, koska 20 minuutin puhelu kerää tilaa, johon malli alkaa kompastua. Ja logita jokainen työkalukutsu argumentteineen ja tuloksineen; kun soittaja sanoo "agentti varasi väärän ajan", pelkkä litterointi ei kerro sinulle, oliko malli vai koodisi väärässä.
Jos omaksut Agents SDK -reitin vaiheesta 3, sen uusi konttihiekkalaatikko ajaa työkalukoodia eristyksissä, millä on väliä, kun työkalusi koskevat tiedostojärjestelmää tai shelliä eivätkä vain API:a.
Milloin sinun kannattaa ostaa hallinnoitu alusta sen sijaan
Suoraan Realtime API:n päälle rakentaminen antaa sinulle eniten hallintaa ja alhaisimman minuuttihinnan, mutta omistat uudelleenyhdistyslogiikan, puhelinsillan, vaatimustenmukaisuuden ja havainnoitavuuden — kaikki vaiheiden 4–7 epäkiiltävät osat. Jos tarvitset puhelinagentin tuotantoon tällä viikolla etkä halua ylläpitää mediavälitystä, hallinnoitu alusta on nopeampi valinta.
Rakensimme saman agentin kolmelle suurelle ja vertailimme niitä rehellisesti: Retell, Vapi vai Bland. Jos vielä päätät, kummalla puolella rajaa olet, käy läpi täydellinen rakenna-vs-osta-päätöskehys, ennen kuin sitoudut insinööriaikaa.
Kun tiimit haluavat räätälöidyn Realtime-toteutuksen hallinnan ilman henkilöstöä, se on työtä, jota teemme: tuotantoääniagenttien kehitys, puhelinsillasta yllä olevaan latenssin säätöön. Katsomme mielellämme käyttötapaustasi, jos harkitset sitä.
Kirjoittajasta — Mert Batur Gurbuz on Techsy.io:n perustajajäsen, jossa tiimi toimittaa tekoälyagentteja, automaatiojärjestelmiä ja ääni/SDR-putkia B2B-asiakkaille. Hän opiskelee Birminghamin yliopistossa ja kirjoittaa LLM-työkalupinosta, jota Techsy-tiimi oikeasti käyttää tuotannossa. LinkedIn
Usein kysytyt kysymykset
Mikä on OpenAI Realtime API -ääniagentin latenssi?
Toteutuksessamme gpt-realtime-2:lla semantic_vad:illa ja matalalla reasoning effortilla round-trip-latenssi mitattiin p50 1,1 s ja p95 1,9 s 40 testipuhelun yli. Speech-to-speech yhdessä socketissa välttää STT/LLM/TTS-viestiketjun, mikä on se, mikä tekee alle sekunnin vastaukset ylipäätään mahdollisiksi.
Tarvitsenko WebRTC:n, WebSocketin vai SIP:in ääniagentilleni?
Käytä WebRTC:tä, kun selain tai mobiilisovellus kaappaa mikrofonin suoraan, WebSocketia, kun palvelimellasi on jo raaka äänivirta (Twilio-siltatapaus), ja SIP:iä, kun haluat OpenAI:n hoitavan puhelinosuuden ilman omaa mediavälitystäsi. Useimmat puhelinagentit käyttävät WebSocketia tai SIP:iä.
Miten yhdistän OpenAI Realtime API:n Twilioon?
Osoita saapuva Twilio-puhelu TwiML <Connect><Stream>:iin, joka avaa WebSocketin palvelimellesi, ja välitä sitten ääntä Twilion ja Realtime-socketin välillä. Näytteistä Twilion 8kHz μ-law uudelleen API:n 24kHz PCM16:een molempiin suuntiin, tai ääni tulee ulos säröisenä.
Miten funktiokutsut toimivat Realtime API:ssa?
Julistat työkalut istunnon asetuksissa. Kun malli haluaa yhden, se lähettää function_call_arguments.done -tapahtuman. Suoritat työn, lähetät tuloksen takaisin function_call_output-keskustelukohteena ja lähetät sitten response.create:n, jotta agentti puhuu tuloksen. Viimeisen vaiheen unohtaminen on syy siihen, miksi työkalut usein epäonnistuvat "hiljaisesti".
Miten käsittelet keskeytykset (barge-in) Realtime API:ssa?
Kun vuorontunnistus raportoi input_audio_buffer.speech_started:in toiston aikana, lähetä response.cancel pysäyttääksesi aktiivisen vastauksen ja tyhjentääksesi kaiken jonossa olevan ulostuloäänen soittajaa kohti. Yhdistä se semantic_vad:iin, jotta luonnolliset tauot eivät laukaise vääriä keskeytyksiä kesken lauseen.
Mitä äänen näytteenottotaajuutta OpenAI Realtime API käyttää?
Realtime API käyttää 24kHz PCM16 -ääntä molempiin suuntiin. Puhelintarjoajat kuten Twilio toimittavat 8kHz μ-law:ta, joten puhelinsillan täytyy näytteistää uudelleen ylös sisään tullessa ja alas ulos mennessä. Yhteensopimattomat näytteenottotaajuudet ovat yksittäinen yleisin syy säröiseen ääneen.
Paljonko maksaa ääniagentin pyörittäminen Realtime API:lla?
Kustannuksia ajavat äänen sisään- ja ulostulominuutit gpt-realtime-2:lla, ja bring-your-own-key-talous eroaa jyrkästi hallinnoidusta minuuttihinnoitellusta alustasta. Laskimme täyden matematiikan ääniagenttien hintaerittelyssämme sen sijaan, että arvioisimme sitä tässä.
Pitäisikö minun rakentaa Realtime API:lle vai käyttää Retelliä, Vapia vai Blandia?
Rakenna suoraan, kun haluat maksimaalisen hallinnan ja alhaisimman minuuttihinnan ja voit omistaa uudelleenyhdistykset, puhelintekniikan ja vaatimustenmukaisuuden. Osta hallinnoitu alusta, kun nopeus markkinoille on tärkeämpää. Retell vs Vapi vs Bland -vertailumme ja rakenna-vs-osta-kehyksemme kattavat kompromissit.
Mitä huhtikuun 2026 OpenAI Agents SDK -päivitys muutti ääniagenteille?
- huhtikuuta 2026 uudistus teki Model Context Protocolista ensiluokkaisen, lisäsi konttihiekkalaatikon työkalukoodille ja muutti sub-agenttien luovutukset ajonaikaiseksi primitiiviksi. Ääniagenteille se tarkoittaa, että reitittäjäagentti voi luovuttaa erikoistuneille sub-agenteille sen sijaan, että ahtaisi jokaisen työkalun yhteen promptiin.