ai-machine-learning

Bygg en stemmeagent på OpenAI Realtime API: produksjonsveiledningen i 7 trinn (2026)

Skrevet av Mert Batur
Jun 6, 2026
10 lesing
Bygg en stemmeagent på OpenAI Realtime API: produksjonsveiledningen i 7 trinn (2026)

Bygg en stemmeagent på OpenAI Realtime API: produksjonsveiledningen i 7 trinn (2026)

Testagenten vår besvarte et Twilio-anrop og sa sitt første ord 1,1 sekund etter at oppringeren sluttet å snakke. Det er p50-rundturen, målt over 40 anrop med gpt-realtime-2 og semantic_vad. Ingen magi. OpenAI Realtime API gjør tale-til-tale i én enkelt socket, så du hopper over STT → LLM → TTS-stafetten som legger på rundt 600 ms limkode. Men standardverdiene tar deg ikke til ett sekund. Dette er byggingen i 7 trinn som vi lanserte, med koden og latenstabellen.

Dette er en byggeveiledning, ikke en konseptforklaring. Vil du ha den lagdelte oppdelingen først, les hva en KI-stemmeagent faktisk er og kom så tilbake. Alt nedenfor forutsetter at du har en OpenAI API-nøkkel og en Node-kjøretid.

Viktigste punkter:

  • gpt-realtime-2 gjør tale-til-tale i én socket, ingen STT/LLM/TTS-stafett, ~600 ms spart.
  • Lag midlertidige nøkler på serversiden; send aldri din standard-API-nøkkel til en nettleser.
  • Twilios mediestrøm er 8 kHz μ-law; resample til 24 kHz PCM16 for Realtime API.
  • Vi målte p50 1,1 s / p95 1,9 s rundtur. Avbrytelse skjer via response.cancel.

Hva du bygger i 7 trinn

Denne veiledningen bygger en telefonsvarende OpenAI Realtime API-stemmeagent som svarer innen 1,5 sekund, kaller en ekte funksjon midt i samtalen og lar oppringeren avbryte. Flyten er kort: en oppringer ringer et nummer, lyd strømmes til serveren din, serveren din broer det via én socket til gpt-realtime-2, modellen snakker og kan utløse verktøykall, og lyd strømmes tilbake.

Her er veien, og du kan stoppe ved ethvert trinn som passer ditt bruksområde:

  1. Lage en midlertidig nøkkel (serverrute)
  2. Åpne og konfigurere økten
  3. Legge til funksjonskall
  4. Bro til et telefonnummer med Twilio
  5. Håndtere avbrytelser
  6. Trimme latensen til under ett sekund
  7. Distribuere og herde for produksjon

Tre transporter bærer lyden, og valget ditt avhenger av hvor lyden kommer fra. En nettleser fanger den direkte (WebRTC), serveren din har allerede en rå strøm (WebSocket), eller et telefonnett leverer den (SIP). Vi bruker WebSocket for Twilio-broen og nevner de andre der de passer.

Trinn 1: Lage en midlertidig nøkkel (ruten du ikke kan hoppe over)

Eksponer aldri din standard-OpenAI-API-nøkkel for en nettleser eller klientenhet. Realtime API utsteder kortlevde midlertidige nøkler nettopp for dette. Serveren din kaller POST /v1/realtime/client_secrets med din ekte nøkkel, gir klienten et token som utløper på omtrent ett minutt, og klienten kobler til med det i stedet.

Her er en minimal Express-rute som lager én:

javascript
// 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);

Nettleseren henter /session, leser den kortlevde hemmeligheten og åpner Realtime-tilkoblingen med den. Hvis agenten din kun er på serversiden (Twilio-tilfellet i trinn 4), kan du hoppe over klientoverleveringen og åpne socketen fra backenden din direkte med standardnøkkelen. Den midlertidige flyten finnes for å beskytte ikke-betrodde klienter.

Trinn 2: Åpne økten og konfigurere gpt-realtime-2

Åpne en tilkobling, send så en session.update som setter modell, lydformat, stemme og turdeteksjon. OpenAI-dokumentasjonen anbefaler å starte med reasoning.effortlow og bare øke det hvis verktøylogikken din trenger mer nøyaktighet, fordi høyere innsats koster deg latens. Lyd kjører som 24 kHz PCM16 i begge retninger.

javascript
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: "Du er en bookingagent for en restaurant. Vær kortfattet.",
    reasoning: { effort: "low" },
    turn_detection: { type: "semantic_vad" },
  },
}));

Hvilken transport du pakker rundt den socketen avhenger av lydkilden:

TransportBruk nårLydkilde
WebRTCEn nettleser eller mobilapp fanger mikrofonen direkteKlientenhet
WebSocketServeren din har allerede en rå lydstrømServerrørledning
SIPDu vil at OpenAI håndterer telefondelenPSTN / telefoni

For den fullstendige feltlisten for økten og GA-funksjonssettet er OpenAI Realtime API-dokumentasjonen kilden til sannhet. Vi bruker WebSocket fordi Twilio gir oss rå lyd i trinn 4.

Trinn 3: Legge til funksjonskall (så agenten faktisk kan gjøre noe)

En stemmeagent som ikke kan handle, er en speakerstemme. Funksjonskall lar gpt-realtime-2 pause midt i samtalen, be koden din kjøre noe og fortsette å snakke med resultatet. Du erklærer et verktøy i økten, modellen sender en function_call_arguments.done-hendelse når den vil ha det, du kjører arbeidet og sender tilbake utdataen.

Erklær verktøyet, og håndter så hendelsen:

javascript
// i session.update -> session.tools:
tools: [{
  type: "function",
  name: "book_reservation",
  description: "Booker et bord for et antall gjester og et tidspunkt.",
  parameters: {
    type: "object",
    properties: {
      party_size: { type: "integer" },
      time: { type: "string", description: "ISO 8601 dato/tid" },
    },
    required: ["party_size", "time"],
  },
}]

// håndtering av kallet:
if (event.type === "response.function_call_arguments.done") {
  const args = JSON.parse(event.arguments);
  const result = await bookTable(args);            // din ekte logikk
  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" }));  // la den si resultatet
}

Den vanligste grunnen til at verktøy stille aldri utløses: ikke å lytte på function_call_arguments.done og ikke sende response.create etterpå. Modellen produserte kallet, du ignorerte det, oppringeren hører radiostillhet.

Hvis agenten din sjonglerer mange verktøy, endret OpenAI Agents SDK regnestykket her. Overhalingen 15. april 2026 gjorde Model Context Protocol (MCP) førsteklasses og forvandlet overleveringer mellom underagenter til en kjøretidsprimitiv. Så i stedet for å stappe hvert verktøy inn i én prompt kan en ruteragent overlevere en booking til en bookingunderagent og et faktureringsspørsmål til en annen. Agents SDK-hurtigstarten for stemme pakker den samme Realtime-økten inn i en RealtimeAgent og gir deg overleveringer uten å skrive din egen orkestreringssløyfe.

Trinn 4: Bro til et telefonnummer (Twilio)

For å besvare ekte anrop broer du en telefonileverandør inn i socketen. Med Twilio retter du et innkommende anrop mot en TwiML <Connect><Stream> som åpner en WebSocket til serveren din, og du videreformidler lydrammer mellom Twilio og Realtime API. SIP er alternativet. OpenAI Realtime aksepterer SIP direkte, noe som fjerner medierelaeet ditt helt hvis du ikke trenger å røre lyden.

TwiML-en som starter strømmen:

xml
<Response>
  <Connect>
    <Stream url="wss://your-server.com/twilio-stream" />
  </Connect>
</Response>

Her er fellen som spiser en dag hvis du overser den: Twilios mediestrøm er 8 kHz μ-law, og Realtime API vil ha 24 kHz PCM16. Du resampler i begge retninger, ellers får du forvrengt ekornlyd.

javascript
// innkommende: 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"),
}));

// utgående: Realtime (24kHz PCM16) -> Twilio (8kHz μ-law)
const ulaw = muLawEncode(downsample(modelPcm16, 24000, 8000));
twilioWs.send(JSON.stringify({
  event: "media",
  media: { payload: ulaw.toString("base64") },
}));

Det fullstendige rammeformatet finnes i Twilio Media Streams-dokumentasjonen. Hold resamplingen billig, fordi et tungt bibliotek her legger til latens du betaler for i hver ramme.

Trinn 5: Håndtere avbrytelser

En produksjonsagent lar oppringeren snakke over den. Avbrytelse (barge-in) betyr å oppdage at oppringeren begynte å snakke mens agenten er midt i en setning, og så kutte agenten rent. Realtime API håndterer dette med response.cancel: når turdeteksjonen rapporterer at tale begynte under avspilling, avbryter du det aktive svaret og tømmer den allerede bufrede lyden mot oppringeren.

javascript
if (event.type === "input_audio_buffer.speech_started") {
  realtime.send(JSON.stringify({ type: "response.cancel" }));
  twilioWs.send(JSON.stringify({ event: "clear" }));   // kast køet avspilling
}

Turdeteksjon har to moduser, og valget betyr noe. server_vad utløses på rå stillhetsterskler og har en tendens til å kutte oppringeren ved naturlige pauser. semantic_vad venter til modellen tror at oppringeren faktisk avsluttet en tanke, og produserer dermed langt færre falske avbrytelser ved en tenkepause. For telefonanrop er semantisk VAD den som føles menneskelig.

Trinn 6: Trimme latensen til under ett sekund

Her blir en demo et produkt, så her er tallene fra vår egen bygging, ikke et teoretisk budsjett. Vi kjørte den samme restaurantagenten over 40 testanrop i mai 2026, på én enkelt liten server samlokalisert nær OpenAI-regionen, og byttet bare turdeteksjons- og resonneringsinnstillingene.

Konfigurasjonp50 rundturp95Notater
server_vad, reasoning low~1,4 s~2,3 sflere falske avbrytelser ved pauser
semantic_vad, reasoning low~1,1 s~1,9 svår produksjonsstandard
semantic_vad, reasoning medium~1,8 s~3,1 sbedre verktøynøyaktighet, tregere

Spakene som virkelig flyttet nålen, i rekkefølge etter innvirkning:

  • Hold reasoning.effort på low med mindre et bestemt verktøy virkelig trenger nøyaktigheten. Medium nesten doblet vår p50.
  • Ikke skyv lyd raskere enn sanntid. Å oversvømme input_audio_buffer.append får bufferen til å renne over og forårsaker drift; takt rammer mot veggklokken.
  • Hold socketen varm. Å kaldåpne en tilkobling per anrop legger håndtrykket til latensen din for første ord. Pool tilkoblinger der anropsvolumet tillater.
  • Resample effektivt. En naiv resampler i den varme banen la til ~80 ms per tur for oss.

Hva koster det å kjøre per minutt når det først er live? Vi gjorde ta-med-din-egen-nøkkel-regnestykket separat, se hva en BYOK-stemmeagent koster per minutt i stedet for å utlede det på nytt her.

Trinn 7: Distribuere og herde for produksjon

Gapet mellom «det fungerte på laptopen min» og «det overlever 500 anrop om dagen» er en håndfull velkjente feil. Her er herdesjekklisten, hentet fra feilene som faktisk knekker Realtime-agenter:

FelleSymptomLøsning
Feil samplingsfrekvensforvrengt / ekornlyd24 kHz PCM16 begge veier
Ignorere function_call_arguments.doneverktøy utløses aldrilytt og send response.create
Skyve lyd raskere enn sanntidbufferoverløp, drifttakt rammer mot sanntid
Ingen gjentilkoblingslogikkanrop faller ved en socketforstyrrelseautogjentilkobling + gjenoppta økt
Ingen response.done-håndteringoverlappende turergrind neste tur på response.done

To ting til for ekte trafikk. Ved lange anrop, roter eller så om økten med noen turers mellomrom så konteksten ikke driver, fordi et 20-minutters anrop samler tilstand som modellen begynner å snuble over. Og logg hvert verktøykall med argumentene og resultatet; når en oppringer sier «agenten booket feil tid», forteller transkripsjonen alene deg ikke om det var modellen eller koden din som tok feil.

Hvis du tar Agents SDK-veien fra trinn 3, kjører dens nye container-sandkasse verktøykode isolert, noe som betyr noe så snart verktøyene dine berører et filsystem eller skall i stedet for bare et API.

Når du heller bør kjøpe en administrert plattform

Å bygge direkte på Realtime API gir deg mest kontroll og lavest kostnad per minutt, men du eier gjentilkoblingslogikken, telefonbroen, samsvar og observerbarhet, alle de uglamorøse delene av trinn 4 til 7. Hvis du trenger en telefonagent live denne uken og ikke vil vedlikeholde et medierelae, er en administrert plattform det raskere valget.

Vi bygde den samme agenten på de tre store og sammenlignet dem ærlig: Retell, Vapi eller Bland. Hvis du fortsatt bestemmer hvilken side av linjen du er på, gå gjennom det fullstendige beslutningsrammeverket bygge-eller-kjøpe før du binder ingeniørtid.

Når team vil ha kontrollen over en skreddersydd Realtime-bygging uten å bemanne den, er det jobben vi gjør: stemmeagentutvikling for produksjon, fra telefonbroen til latenstrimmingen over. Vi ser gjerne på bruksområdet ditt hvis du veier det.

Om forfatteren — Mert Batur er medgrunnlegger av Techsy.io, der teamet leverer KI-agenter, automatiseringssystemer og stemme-/SDR-pipelines for B2B-kunder. Han skriver om LLM-verktøystakken som Techsy-teamet faktisk bruker i produksjon. LinkedIn

Ofte stilte spørsmål

Hva er latensen til en OpenAI Realtime API-stemmeagent?

I vår bygging på gpt-realtime-2 med semantic_vad og lav resonneringsinnsats målte rundturlatensen p50 1,1 s og p95 1,9 s over 40 testanrop. Tale-til-tale i én socket unngår STT/LLM/TTS-stafetten, som er det som gjør svar under ett sekund mulig i det hele tatt.

Trenger jeg WebRTC, WebSocket eller SIP for stemmeagenten min?

Bruk WebRTC når en nettleser eller mobilapp fanger mikrofonen direkte, WebSocket når serveren din allerede har en rå lydstrøm (Twilio-brotilfellet), og SIP når du vil at OpenAI håndterer telefondelen uten ditt eget medierelae. De fleste telefonagenter bruker WebSocket eller SIP.

Hvordan kobler jeg OpenAI Realtime API til Twilio?

Rett et innkommende Twilio-anrop mot en TwiML <Connect><Stream> som åpner en WebSocket til serveren din, og videreformidle så lyd mellom Twilio og Realtime-socketen. Resample Twilios 8 kHz μ-law til API-ets 24 kHz PCM16 begge veier, ellers kommer lyden ut forvrengt.

Hvordan fungerer funksjonskall i Realtime API?

Du erklærer verktøy i øktkonfigurasjonen. Når modellen vil ha ett, sender den en function_call_arguments.done-hendelse. Du kjører arbeidet, sender tilbake resultatet som et function_call_output-samtaleelement, og sender så response.create så agenten sier resultatet. Å glemme det siste trinnet er grunnen til at verktøy ofte feiler «stille».

Hvordan håndterer man avbrytelser (barge-in) i Realtime API?

Når turdeteksjonen rapporterer input_audio_buffer.speech_started under avspilling, send response.cancel for å stoppe det aktive svaret og tøm all bufret utgående lyd mot oppringeren. Par det med semantic_vad så naturlige pauser ikke utløser falske avbrytelser midt i en setning.

Hvilken lydsamplingsfrekvens bruker OpenAI Realtime API?

Realtime API bruker 24 kHz PCM16-lyd i begge retninger. Telefonileverandører som Twilio leverer 8 kHz μ-law, så en telefonbro må resample oppover ved inngangen og nedover ved utgangen. Ikke-samsvarende samplingsfrekvenser er den vanligste årsaken til forvrengt lyd.

Hvor mye koster det å kjøre en stemmeagent på Realtime API?

Kostnaden drives av lyd-inn- og lyd-ut-minutter på gpt-realtime-2, og økonomien for ta-med-din-egen-nøkkel skiller seg kraftig fra en administrert per-minutt-plattform. Vi gjorde hele regnestykket i vår prisanalyse for stemmeagenter i stedet for å anslå det her.

Bør jeg bygge på Realtime API eller bruke Retell, Vapi eller Bland?

Bygg direkte når du vil ha maksimal kontroll og lavest kostnad per minutt og kan eie gjentilkoblinger, telefoni og samsvar. Kjøp en administrert plattform når hurtighet til lansering betyr mer. Vår Retell vs Vapi vs Bland-sammenligning og bygge-eller-kjøpe-rammeverket dekker avveiingene.

Hva endret OpenAI Agents SDK-oppdateringen i april 2026 for stemmeagenter?

Overhalingen 15. april 2026 gjorde Model Context Protocol førsteklasses, la til en container-sandkasse for verktøykode og forvandlet overleveringer mellom underagenter til en kjøretidsprimitiv. For stemmeagenter betyr det at en ruteragent kan overlevere til spesialiserte underagenter i stedet for å stappe hvert verktøy inn i én prompt.

Emneord

openai realtime api voice agentgpt-realtime-2function callingtwilio voice agentopenai agents sdkvoice ai tutorial

Del denne artikkelen

Kom i gang

Klar til å bygge noe ekstraordinært?

La oss gjøre visjonen din til virkelighet. Teamet vårt er klart til å hjelpe deg med å lage programvare som utgjør en forskjell.