Jäta vahele ja mine põhisisu juurde
OpenAI

4. mai 2026

Inseneriteadus

Kuidas OpenAI pakub väikese latentsusega hääl-AI-d suures mastaabis

Autorid Yi Zhang ja William McDonald, tehnilise personali liikmed

Hääl-AI tundub loomulik ainult siis, kui vestlus liigub kõne tempos. Kui võrk jääb ette, kuulevad inimesed seda kohe kohmakate pauside, katkendlike vahelesegamiste või hilinenud sekkumisena. See on oluline ChatGPT Voice’i jaoks, arendajatele, kes loovad Realtime API-ga, agentidele, kes töötavad interaktiivsetes töövoogudes, ja mudelitele, mis peavad heli töötlema samal ajal, kui kasutaja veel räägib.

OpenAI mastaabis tähendab see kolme konkreetset nõuet:

  • Globaalne ulatus enam kui 900 miljonile iganädalasele aktiivsele kasutajale
  • Kiire ühenduse loomine, et kasutaja saaks rääkima hakata kohe seansi alguses
  • Madal ja stabiilne meedia edasi-tagasi viiteaeg ning väike värin ja paketikadu, et vooruvahetus tunduks sujuv

OpenAI meeskond, kes vastutab reaalaja AI-suhtluste eest, kujundas hiljuti meie WebRTC pinu ümber, et lahendada kolm piirangut, mis hakkasid mastaabis kokku põrkama: üks port seansi kohta meedia lõpetamiseks ei sobi hästi OpenAI taristuga, olekuga ICE (Interactive Connectivity Establishment) ja DTLS (Datagram Transport Layer Security) seansid vajavad stabiilset omanikku ning globaalne marsruutimine peab hoidma esimese hüppe latentsuse madalana. Selles postituses selgitame loodud jaotatud relay plus transceiver arhitektuuri, mis säilitab klientidele standardse WebRTC käitumise, muutes samal ajal seda, kuidas paketid OpenAI taristus liiguvad.

WebRTC võimaldab meil luua reaalaja AI-tooteid

WebRTC on avatud standard väikese latentsusega heli, video ja andmete edastamiseks brauserite, mobiilirakenduste ja serverite vahel. Seda seostatakse sageli võrdõigusvõrgu kõnedega, kuid see on ka praktiline alus kliendi ja serveri vahelistes reaalajas süsteemides, sest standardiseerib interaktiivse meedia keerulised osad: ICE ühenduvuse loomiseks ja NAT-i (Network Address Translation) läbimiseks, DTLS ja SRTP (Secure Real-time Transport Protocol) krüptitud transpordiks, koodekite läbirääkimine heli pakkimiseks ja dekodeerimiseks, RTCP (Real-time Transport Control Protocol) kvaliteedikontrolliks ning kliendipoolsed funktsioonid nagu kajaeemaldus ja värinapuhver.

See standardiseerimine on AI-toodete jaoks oluline. Ilma WebRTC-ta vajaks iga klient erinevat lahendust selleks, kuidas luua ühenduvus üle NAT-ide, krüptida meediat, pidada läbirääkimisi koodekite üle (edastuseks ja lahtipakkimiseks valitud koodrid-dekoodrid) ning kohaneda muutuvate võrguoludega. WebRTC-ga saame toetuda protokollipinule, mis on juba brauserites ja mobiiliplatvormidel rakendatud, keskendudes oma töös taristule, mis ühendab reaalajas meedia mudelitega.

Samuti toetume WebRTC ökosüsteemile endale, sealhulgas küpsetele avatud lähtekoodiga teostustele ja standardimistööle, mis hoiab brauserid, mobiilirakendused ja serverid koostalitlusvõimelistena. Justin Uberti (üks WebRTC algsetest arhitektidest) ja Sean DuBois’ (Pioni looja ja hooldaja) rajav töö võimaldas meiesugustel meeskondadel ehitada lahingutes proovile pandud meediataristule, selle asemel et leiutada uuesti madala taseme transporti, krüptimist ja ülekoormuse juhtimise käitumist. Meil on hea meel, et nii Justin kui Sean on nüüd siin OpenAI-s meie kolleegid ja aitavad suunata, kuidas WebRTC ja reaalaja AI üksteisele lähemale tuua.

AI jaoks on kõige olulisem omadus see, et heli saabub pideva voona. Kõnelev agent saab alustada transkribeerimist, arutlust, tööriistade kutsumist või kõne genereerimist samal ajal, kui kasutaja veel räägib, selle asemel et oodata täielikku üleslaadimist. See eristab süsteemi, mis tundub vestluslik, süsteemist, mis tundub nagu vajuta-ja-räägi.

Meediaarhitektuuri valimine

Kui olime WebRTC kasuks otsustanud, oli järgmine küsimus, kus see lõpetada (kus me WebRTC ühenduse vastu võtaksime ja omaksime — näiteks servas) ning kuidas ühendada need seansid järeldustehte taustsüsteemiga. Lõpetamine on oluline, sest see määrab, kuidas käsitleme reaalajas seansi olekut, meedia transporti, marsruutimist, latentsust ja rikete isoleerimist.

1. variant: SFU-lähenemine kaasab AI WebRTC osalejana

SFU ehk selective forwarding unit on meediaserver, mis võtab igalt osalejalt vastu ühe WebRTC voo ja edastab valikuliselt vood teistele. Selles mudelis lõpetab SFU iga osaleja jaoks eraldi WebRTC ühenduse ning AI liitub seansiga teise osalejana. See võib sobida toodetele, mis on olemuselt mitme osapoolega, näiteks grupikõnedele, klassiruumidele või koostöökoosolekutele. See hoiab heli koodekid, RTCP sõnumid, andmekanalid, salvestamise ja voo-põhise poliitika ühes kohas.1

Isegi kliendi-AI toodetes on SFU sageli vaikimisi lähtekoht, sest see võimaldab meeskondadel taaskasutada üht tõestatud süsteemi signaalimiseks, meedia marsruutimiseks, salvestamiseks, vaadeldavuseks ja tulevasteks laiendusteks, nagu inimesele ümbersuunamine või rohkemate osalejate lisamine.

2. variant: transiiveri lähenemine lõpetab WebRTC servas ja teisendab selle taustsüsteemi protokolliks

Meie töökoormus on teistsugune. Enamik seansse on 1:1 — üks kasutaja räägib ühe mudeliga või üks rakendus ühe reaalaja agendiga — ning iga voor on latentsuse suhtes tundlik. Sellise liiklusmustri jaoks valisime transiiveri mudeli: WebRTC servateenus lõpetab kliendiühenduse ja teisendab seejärel meedia ja sündmused lihtsamateks sisemisteks protokollideks mudeli järelduseks, transkriptsiooniks, kõne genereerimiseks, tööriistade kasutamiseks ja orkestreerimiseks.

Selles ülesehituses on transiiver ainus teenus, mis omab WebRTC seansi olekut, sealhulgas ICE ühenduvuskontrolle, DTLS käepigistust, SRTP krüptovõtmeid ja seansi elutsüklit. „Lõpetamine” tähendab siin, et transiiver on lõpp-punkt, mis need käepigistused lõpetab ning meedia krüptib või dekrüptib. Selle oleku hoidmine ühes kohas tegi seansi omanduse arutamise lihtsamaks ning võimaldas taustteenustel skaleeruda nagu tavalistel teenustel, selle asemel et käituda ise WebRTC partneritena.

Põhiline juurutusprobleem: WebRTC kohtub Kubernetesega

Pärast transiiveri mudeli valimist oli meie esimene teostus üks Go teenus, mis oli ehitatud Pionile ja käsitles nii signaalimist kui ka meedia lõpetamist. See käitab ChatGPT Voice’i, Realtime API WebRTC lõpp-punkti ja mitut uurimisprojekti.

Operatiivselt teeb transiiveri teenus kahte tööd:

  • Signaalimine: SDP läbirääkimised, koodeki valik, ICE mandaadid ja seansi seadistamine
  • Meedia: allavoolu WebRTC ühenduste lõpetamine ja ülesvoolu ühenduste hoidmine taustteenustega järelduse ja orkestreerimise jaoks

Tahtsime, et teenus töötaks nagu ülejäänud meie taristu: Kuberneteses, kus töökoormused saavad vastavalt nõudlusele üles ja alla skaleeruda ning liikuda hostide vahel. Kuid tavapärane üks-port-seansi-kohta WebRTC mudel sobib sellesse keskkonda halvasti, sest sõltub suurtest avalikest UDP pordivahemikest, mida on keeruline eksponeerida, turvata ja säilitada siis, kui pod’e lisatakse, eemaldatakse või ajastatakse ümber.2

Portide ammendumine

Esimene probleem oli üks-port-seansi-kohta mudel ise. Suure samaaegsuse juures tähendab see väga suurte UDP pordivahemike eksponeerimist ja haldamist.

  • Pilve koormusjaoturid ja Kubernetese teenused ei ole mõeldud kümnete tuhandete avalike UDP portide jaoks ühe teenuse kohta. Iga lisavahemik suurendab operatiivset keerukust koormusjaoturi konfiguratsioonis, tervisekontrollides, tulemüüripoliitikas ja juurutuse ohutuses.3
  • Suuri UDP pordivahemikke on raske turvata, sest need laiendavad väljastpoolt ligipääsetavat pinda ja muudavad võrgupoliitika auditeerimise keerulisemaks.
  • Need sobivad halvasti ka automaatseks skaleerimiseks. Kuberneteses lisatakse, eemaldatakse ja ajastatakse pod’e pidevalt ümber. Nõue, et iga pod reserveeriks ja reklaamiks suurt stabiilset pordivahemikku, muudab selle elastsuse hapraks.4

Seetõttu liiguvad paljud WebRTC süsteemid ühe UDP pordi suunas serveri kohta, kasutades selle pordi taga rakendustaseme demultipleksimist.5

Olekukleepuvus

Üks-port-serveri-kohta disainid lahendavad portide arvu probleemi, kuid toovad kaasa teise probleemi: iga seansi omanduse säilitamise üle kogu serveripargi.

ICE ja DTLS on olekuga protokollid. Protsess, mis seansi lõi, peab jätkama selle seansi pakettide vastuvõtmist, et valideerida ühenduvuskontrolle, lõpetada DTLS käepigistus, dekrüptida SRTP ning töödelda hilisemaid seansimuudatusi, näiteks ICE taaskäivitusi. Kui sama seansi paketid jõuavad mõne teise protsessini, võib seadistus ebaõnnestuda või meedia katkeda.

See andis meile konkreetse eesmärgi: eksponeerida avalikule internetile väike, fikseeritud UDP pind, kuid siiski marsruutida iga pakett transiiverile, kellele vastav WebRTC seanss kuulub.

WebRTC meediaarhitektuuride võrdlus

Hindasime selle saavutamiseks mitut võimalust, sealhulgas TURN-i (Traversal Using Relays around NAT), kus servarelee lõpetab kliendiallokatsioonid ja edastab liiklust nende nimel.2

Lähenemine

Eelised

Puudused

Unikaalne IP:port iga seansi kohta (tuntud ka kui natiivne otsene UDP)

Otsene kliendi-serveri meediatee

Andmete teel puudub edastamiskiht

Vajab ühte avalikku UDP porti iga seansi kohta

Suuri pordivahemikke on keeruline eksponeerida ja turvata

Sobib halvasti Kubernetese ja pilve koormusjaoturitega

Unikaalne IP:port serveri kohta

Palju väiksem avalik UDP jalajälg kui seansipõhisel eksponeerimisel

Üks jagatud sokkel serveri kohta saab demultipleksida palju seansse

Töötab puhtalt ühel hostil, kuid mitte iseseisvalt jagatud koormusjaotusega serveripargis

Seansi demultipleksimine ühel hostil aitab alles pärast seda, kui pakett sellesse hosti jõuab; koormusjaotusega serveripargis võib esimene pakett siiski maanduda vales instantsis, seega on endiselt vaja deterministlikku viisi iga seansi suunamiseks seda omavasse protsessi


TURN relee (protokolli lõpetav)

Kliendid peavad jõudma ainult TURN relee aadressi ja pordini

Võimaldab poliitika servas tsentraliseerida

TURN-i allokatsioonid lisavad seadistusele edasi-tagasi pöördeid

Allokatsioonide liigutamine või taastamine TURN-serverite vahel on endiselt keeruline

Olekuta edastaja + olekuga lõpetaja (OpenAI relay + transceiver)

Väike avalik UDP jalajälg

Transiiver omab endiselt täielikku WebRTC seanssi

Lisab ühe edastushüppe enne, kui meedia jõuab omava transiiverini

Nõuab kohandatud koordineerimist relee ja transiiveri vahel

Arhitektuuri ülevaade: relay + transceiver

Juurutatud arhitektuur eraldab pakettide marsruutimise protokolli lõpetamisest. Signaalimine jõuab seansi seadistamiseks endiselt transiiverini, samal ajal kui meedia siseneb kõigepealt relee kaudu. Relee on kerge UDP edastamiskiht väikese avaliku jalajäljega ning transiiver on selle taga olev olekuga WebRTC lõpp-punkt.

Relee edastab paketid olekuta transiiverile

Relee ei dekrüpti meediat, ei käivita ICE olekumasinaid ega osale koodekite läbirääkimistes. See loeb piisavalt paketimetadatat, et valida sihtkoht, ja seejärel edastab paketi transiiverile, kellele seanss kuulub. Transiiver näeb endiselt tavalist WebRTC voogu ja omab endiselt kogu protokolli olekut. Kliendi vaatenurgast ei muutu WebRTC seansis midagi.

Marsruutimine ICE mandaadi alusel

Esimese paketi marsruutimine on selles ülesehituses võtmeetapp. Relee peab marsruutima kliendi esimese paketi enne seda, kui paketiteel endal on seanssi olemas, mitte peatudes välise otsinguteenuse taga.

Iga WebRTC seanss sisaldab juba protokollipärast marsruutimiskonksu: ICE kasutajanimefragmenti ehk ufrag, lühikest identifikaatorit, mida vahetatakse seansi seadistamisel ja korratakse STUN-i ühenduvuskontrollides. Genereerime serveripoolse ufrag’i nii, et see sisaldaks just piisavalt marsruutimismetadatat, et relee saaks järeldada sihtklastri ja omava transiiveri.

Jadadiagramm näitab, kuidas ühendus luuakse

Signaalimise ajal eraldab transiiver seansi oleku ja tagastab SDP vastuses jagatud relee VIP-i ja UDP pordi. VIP on virtuaalne IP-aadress releepargi ees; koos pordiga annab see kliendile ühe stabiilse sihtkoha, näiteks 203.0.113.10:3478, kuigi selle taga on palju releeinstantsse. Kliendi esimene meediatee pakett on tavaliselt STUN-i (Session Traversal Utilities for NAT) sidumispäring, mida ICE kasutab kontrollimiseks, kas paketid jõuavad reklaamitud aadressile.

Relee parsib sellest esimesest STUN-paketist vaid nii palju, et lugeda serveri ufrag, dekodeerida marsruutimisvihje ja edastada pakett omavale transiiverile. Iga transiiver kuulab jagatud UDP soklil, mis tähendab üht operatsioonisüsteemi lõpp-punkti, mis on seotud sisemise IP:pordiga, mitte üht soklit seansi kohta. Pärast seda, kui relee loob seansi kliendi lähte-IP:pordist selle transiiveri sihtkohta, voolavad järgnevad DTLS-, RTP- ja RTCP-paketid seansi sees ilma ufrag’i uuesti dekodeerimata.

Relee seanss on teadlikult minimaalne, koosnedes ainult mälus hoitavast seansist pakettide edastamise suunamiseks ning vajalikest loenduritest seireks ja taimeritest seansi aegumiseks ning koristuseks. See disainivalik hoiab pakettide marsruutimise otse paketiteel. Kui relee taaskäivitub ja kaotab seansi, ehitab järgmine STUN-pakett seansi ufrag’i marsruutimisvihje põhjal uuesti üles. Et muuta see veel töökindlamaks, kasutatakse Redis’e vahemälu, mis hoiab pärast marsruudi loomist vastendust <kliendi IP + port, transiiveri IP + port>, et seda saaks taastada palju varem, enne järgmise STUN-paketi saabumist.

Global Relay ja geograafiliselt suunatud signaalimine

Kui olime vähendanud avaliku UDP pinna väikesele arvule stabiilsetele aadressidele ja portidele, saime sama releemustrit juurutada üle maailma. Global Relay on meie geograafiliselt hajutatud releesisendpunktide park, mis kõik rakendavad sama pakettide edastamise käitumist.

Lai geograafiline sisend lühendab esimest kliendi ja OpenAI vahelist hüpet, sest pakett saab siseneda meie võrku kasutaja lähedal asuva relee kaudu nii geograafia kui võrgu topoloogia mõttes, selle asemel et ületada avalik internet kõigepealt kaugesse piirkonda. Praktikas tähendab see väiksemat latentsust, vähem värinat ja vähem välditavaid kaopurskeid enne, kui liiklus jõuab meie põhivõrku.6

Global Relay kiht võtab kliendilt paketid vastu ja edastab need transiiveriklastrile

Kasutame signaalimisel Cloudflare’i geo- ja lähedusepõhist suunamist, et esialgne HTTP- või WebSocketi päring jõuaks lähedal asuvasse transiiveriklastrisse. Päringu kontekst määrab seansi asukoha ja selle, millist Global Relay sisendpunkti kliendile reklaamitakse. SDP vastus annab Global Relay aadressi, samas kui ufrag sisaldab piisavalt teavet, et Global Relay saaks marsruutida meedia määratud klastrisse ja relee sihttransiiverini.

Koos paigutavad geograafiliselt suunatud signaalimine ja Global Relay nii seadistuse kui meedia lähedasele sisenemisteele, hoides samal ajal seansi ankurdatuna ühe transiiveri külge. See vähendab edasi-tagasi viiteaega signaalimisel ja esimese ICE ühenduvuskontrolli puhul, mis lühendab otseselt aega, mida kasutaja ootab enne, kui kõne saab alata.

Relee teostus ja jõudlus

Kirjutasime releeteenuse Go-s ja hoidsime teostuse meelega kitsana. Linuxis võtab kerneli võrgupinu masina võrguliideselt vastu UDP-pakette ja toimetab need soklisse, operatsioonisüsteemi lõpp-punkti, mida protsess loeb pärast IP:pordiga sidumist. Relee töötab kasutajaruumis, nii et tavaline Go protsess loeb sellest soklist paketipäiseid, uuendab väikest hulka vooolekut ja edastab paketid ilma WebRTC-d lõpetamata. Me ei vajanud ühtegi kernelist möödahiilimise raamistikku, mis lubaks kasutajaruumiprotsessil kõrgemate paketisageduste jaoks võrgukärusid otse küsitleda, kuid lisaks ka operatiivset keerukust.

Peamised disainivalikud:

  • Protokolli mitte lõpetamine: relee parsib ainult STUN-i päiseid/ufrag’i; järgnevate DTLS-, RTP- ja RTCP-pakettide jaoks kasutab see vahemällu salvestatud olekut, hoides paketid läbipaistmatuna.
  • Ajutine olek: see hoiab väikest, lühikese aegumistähtajaga mälukaarti kliendi aadressist transiiveri sihtkohta voooleku ja vaadeldavuse jaoks.
  • Horisontaalne skaleeritavus: mitu releeinstantsi töötab paralleelselt koormusjaoturi taga. Olek ei ole raske WebRTC olek, seega põhjustavad taaskäivitused minimaalseid liikluskatkestusi ja kiire voo taastumise.

Tõhususmeetmed:

  • SO_REUSEPORT on Linuxi soklivalik, mis lubab mitmel releetöötajal samal masinal siduda sama UDP pordi. Kernel jagab seejärel sissetulevad paketid nende töötajate vahel, mis väldib ühe lugemistsükli pudelikaela.
  • runtime.LockOSThread kinnitab iga UDP-d lugeva goroutine’i kindla OS-i lõime külge. Koos SO_REUSEPORT-iga aitab see hoida sama voo paketid (lähte- ja siht-IP:port pluss protokoll) samal CPU tuumal, parandades vahemälu lokaalsust ja vähendades kontekstivahetusi.
  • Eelallokeeritud puhvrite ja minimaalse kopeerimisega hoitakse parsingu- ja allokeerimiskulu madalal, et vältida Go prügikoristust.

See teostus käsitles meie globaalset reaalaja meedialiiklust suhteliselt väikese releejalajäljega, seega jäime lihtsama disaini juurde, selle asemel et võtta kasutusele kernelist möödahiiliv lähenemine.

Tulemused ja õppetunnid

See arhitektuur võimaldab meil käitada WebRTC meediat Kuberneteses ilma tuhandeid UDP porte eksponeerimata. See on oluline, sest väiksemat ja fikseeritud UDP pinda on lihtsam turvata ja koormusjaotada ning see võimaldab taristul skaleeruda ilma suurte avalike pordivahemike reserveerimiseta. Tänu Kubernetese paremale taristutoele ja väiksema ründepinna tõttu suuremale turvalisusele säilitab see disain klientidele ka standardse WebRTC käitumise ning kinnitab, et SFU-vaba disain oli meie töökoormuse jaoks õige vaikimisi valik. Enamik meie seansse on punktist punkti, latentsustundlikud ja neid on lihtsam skaleerida, kui järeldusteenused ei pea käituma WebRTC partneritena.

Laiem õppetund on see, et parim koht keerukuse lisamiseks on õhuke marsruutimiskiht, mitte iga taustteenus ega kohandatud kliendikäitumine. Marsruutimismetadate kodeerimine protokollipärasesse välja andis meile deterministliku esimese paketi marsruutimise, väikese avaliku UDP jalajälje ja piisava paindlikkuse, et paigutada sisend kasutajatele üle maailma lähedale.

Mõned valikud olid eriti olulised:

  • Säilita protokolli semantika servas. Kliendid kasutavad endiselt standardset WebRTC-d, mis hoiab brauseri- ja mobiiliplatvormide koostalitlusvõime alles.
  • Hoia keeruline seansi olek ühes kohas. Transiiver omab ICE-d, DTLS-i, SRTP-d ja seansi elutsüklit; relee ainult edastab pakette.
  • Marsruudi teabel, mis on seadistuses juba olemas. ICE ufrag andis meile esimese paketi marsruutimiskonksu ilma kuuma tee otsingusõltuvust lisamata.
  • Optimeeri tavapärase juhtumi jaoks enne kernelist möödahiilimise poole pöördumist. Kitsas Go teostus koos hoolika SO_REUSEPORT-i kasutuse, lõimede kinnitamise ja vähese allokeerimisega parsingu abil oli meie töökoormuse jaoks piisav.

Reaalajas hääl-AI töötab ainult siis, kui taristu muudab latentsuse nähtamatuks. Meie jaoks tähendas see WebRTC juurutuse kuju muutmist, muutmata seda, mida kliendid WebRTC-lt ootavad.