Salta al contingut principal
OpenAI

4 de maig del 2026

Enginyeria

Com OpenAI ofereix IA de veu de baixa latència a gran escala

Per Yi Zhang i William McDonald, membres del personal tècnic

La IA de veu només se sent natural si la conversa avança a la velocitat de la parla. Quan la xarxa interfereix, les persones ho perceben immediatament com a pauses incòmodes, interrupcions truncades o interrupcions amb retard. Això és important per a la veu de ChatGPT, per als desenvolupadors que creen amb l'API Realtime, per als agents que treballen en fluxos de treball interactius i per als models que han de processar àudio mentre un usuari encara parla.

A nivell d'OpenAI, això es tradueix en tres requisits concrets:

  • Abast global per a més de 900 milions d'usuaris actius setmanals
  • Establiment ràpid de la connexió perquè un usuari pugui començar a parlar tan bon punt comenci una sessió
  • Temps d'anada i tornada del flux multimèdia baix i estable, amb jitter baix i poca pèrdua de paquets, perquè l'alternança de torns sigui àgil

L’equip d’OpenAI responsable de les interaccions d’IA en temps real ha reestructurat recentment l’arquitectura de la nostra pila WebRTC per abordar tres restriccions que van començar a col·lidir a escala: la terminació del flux multimèdia amb un port per sessió no s’adapta bé a la infraestructura d’OpenAI, les sessions ICE (Interactive Connectivity Establishment) i DTLS (Datagram Transport Layer Security) amb estat necessiten una assignació estable de propietari, i l’encaminament global ha de mantenir baixa la latència del primer salt. En aquesta entrada, expliquem pas a pas l'arquitectura dividida de relé més transceptor que vam crear per preservar el comportament estàndard de WebRTC per als clients, alhora que canviàvem com s'encaminen els paquets dins de la infraestructura d'OpenAI.

WebRTC ens permet crear productes d’IA en temps real

WebRTC és un estàndard obert per enviar àudio, vídeo i dades amb baixa latència entre navegadors, aplicacions mòbils i servidors. Sovint s’associa amb les trucades d’igual a igual, però també és una base pràctica per als sistemes en temps real de client a servidor, perquè estandarditza les parts complexes del flux multimèdia interactiu: ICE per a l’establiment de la connectivitat i la travessia de NAT (traducció d’adreces de xarxa), DTLS i SRTP (Protocol segur de transport en temps real) per al transport xifrat, la negociació de còdecs per comprimir i descodificar àudio, RTCP (Protocol de control de transport en temps real) per al control de qualitat, i funcions del costat del client com ara la cancel·lació de l’eco i la memòria intermèdia de jitter.

Aquesta estandardització és important per als productes d’IA. Sense WebRTC, cada client necessitaria una solució diferent per saber com establir la connectivitat a través de NATs, xifrar els fluxos multimèdia, negociar còdecs (els codificadors-descodificadors seleccionats per a la transmissió i la descompressió) i adaptar-se a les condicions canviants de la xarxa. Amb WebRTC, podem basar-nos en una pila de protocols que ja està implementada en navegadors i plataformes mòbils, i centrar la nostra feina en la infraestructura que connecta els fluxos multimèdia en temps real amb els models.

També ens basem en el mateix ecosistema WebRTC, incloses les implementacions madures de codi obert i la tasca d’estandardització que manté interoperables els navegadors, les aplicacions mòbils i els servidors. La feina fundacional de Justin Uberti (un dels arquitectes originals de WebRTC) i Sean DuBois (creador i mantenidor de Pion) va fer possible que equips com el nostre poguessin basar-se en una infraestructura multimèdia provada en entorns exigents, en lloc de reinventar el transport de baix nivell, el xifratge i el comportament de control de congestió. Tenim la sort que tant Justin com Sean siguin ara companys nostres aquí a OpenAI, ajudant a orientar la manera com apropem WebRTC i la IA en temps real.

Per a la IA, la propietat més important és que l’àudio arribi com un flux continu. Un agent de veu pot començar a transcriure, raonar, cridar eines o generar veu mentre l’usuari encara parla, en lloc d’esperar que s’hagi pujat tot. Aquesta és la diferència entre un sistema que sembla conversacional i un que sembla de "prémer per parlar".

Triar una arquitectura de flux multimèdia

Un cop vam triar WebRTC, la següent pregunta era on finalitzar la connexió WebRTC (on acceptaríem i gestionaríem la connexió WebRTC; per exemple, a la perifèria de la xarxa) i com connectar aquestes sessions al backend d’inferència. La terminació és important perquè determina com gestionem l’estat de les sessions en temps real, el transport de flux multimèdia, l’encaminament, la latència i l’aïllament de fallades.

Opció 1: L'enfocament SFU inclou la IA com a participant de WebRTC

Una SFU, o unitat de reenviament selectiu, és un servidor multimèdia que rep un flux WebRTC de cada participant i reenvia selectivament els fluxos als altres. En aquest model, l'SFU termina una connexió WebRTC independent per a cada participant, i la IA s'uneix com un participant més a la sessió. Això pot ser una bona opció per a productes que tenen inherentment diversos participants, com ara trucades de grup, aules o reunions col·laboratives. Manté els còdecs d’àudio, els missatges RTCP, els canals de dades, l’enregistrament i la política per flux en un sol lloc.1

Fins i tot en productes de client a IA, una SFU sol ser el punt de partida predeterminat perquè permet als equips reutilitzar un únic sistema provat per a la senyalització, l’encaminament de fluxos multimèdia, l’enregistrament, l’observabilitat i futures extensions, com ara la transferència a un humà o l’addició de més participants.

Opció 2: L’enfocament de transceptor termina WebRTC al perímetre i el converteix en un protocol de backend

La nostra càrrega de treball és diferent. La majoria de les sessions són 1:1 —un usuari que parla amb un model, o una aplicació que parla amb un agent en temps real— i són sensibles a la latència en cada torn. Per a aquest perfil de trànsit, vam triar un model de transceptor: un servei perimetral WebRTC termina la connexió del client i després converteix el contingut multimèdia i els esdeveniments en protocols interns més senzills per a la inferència del model, la transcripció, la generació de veu, l’ús d’eines i l’orquestració.

En aquest disseny, el transceptor és l’únic servei que controla l’estat de la sessió WebRTC, incloses les comprovacions de connectivitat ICE, l’establiment de connexió DTLS, les claus de xifratge SRTP i el cicle de vida de la sessió. “Termination” aquí vol dir que el transceptor és el punt final que completa aquestes negociacions i xifra o desxifra el contingut multimèdia. Mantenir aquest estat en un sol lloc va facilitar el raonament sobre la propietat de la sessió i va permetre que els serveis de backend escalessin com ho fan els serveis convencionals en lloc d’actuar ells mateixos com a socis de WebRTC.

El problema clau del desplegament: WebRTC es troba amb Kubernetes

Després de triar el model de transceptor, la nostra primera implementació va ser un únic servei a Go basat en Pion que gestionava tant la senyalització com la terminació dels fluxos multimèdia. Fa funcionar la veu de ChatGPT, el punt final WebRTC de l’API en temps real i diversos projectes de recerca.

Des del punt de vista operatiu, el servei transceptor fa dues tasques:

  • Senyalització: negociació SDP, selecció de còdecs, credencials ICE i establiment de la sessió
  • Fluxos multimèdia: finalització de connexions WebRTC descendents i manteniment de connexions ascendents amb serveis de backend per a inferència i orquestració

Volíem que el servei s’executés com la resta de la nostra infraestructura: a Kubernetes, on les càrregues de treball poden augmentar o reduir l’escala i moure’s entre hosts a mesura que canvia la demanda. Però el model WebRTC convencional d’un port per sessió s’adapta malament a aquest entorn, perquè depèn d’intervals amplis de ports UDP públics que són difícils d’exposar, protegir i mantenir a mesura que s’afegeixen, s’eliminen o es reprogramen pods.2

Esgotament de ports

El primer problema era el mateix model d’un port per sessió. Amb una concurrència elevada, això implica exposar i gestionar rangs molt grans de ports UDP.

  • Els equilibradors de càrrega al núvol i els serveis de Kubernetes no estan dissenyats per a desenes de milers de ports UDP públics per servei. Cada rang addicional afegeix complexitat operativa en la configuració del balancejador de càrrega, les comprovacions de salut, la política del tallafoc i la seguretat del desplegament.3
  • Els intervals amplis de ports UDP són difícils de protegir perquè amplien la superfície accessible des de l’exterior i fan que la política de xarxa sigui més difícil d’auditar.
  • També són poc adequats per a l'escalat automàtic. Els pods s'afegeixen, se suprimeixen i es replanifiquen constantment a Kubernetes. Exigir que cada pod reservi i anunciï un interval ampli i estable de ports fa que aquesta elasticitat sigui fràgil.4

Per això molts sistemes WebRTC opten per un únic port UDP per servidor, amb demultiplexació a nivell d’aplicació darrere d’aquest port.5

Adhesió de l’estat

Els dissenys d’un sol port per servidor resolen el nombre de ports, però introdueixen un segon problema: mantenir la propietat de cada sessió en tota una flota.

ICE i DTLS són protocols amb estat. El procés que ha creat una sessió ha de continuar rebent els paquets d’aquella sessió perquè pugui validar les comprovacions de connectivitat, completar la negociació DTLS, desxifrar l’SRTP i processar canvis posteriors de la sessió, com ara reinicis d’ICE. Si els paquets de la mateixa sessió arriben a un procés diferent, la configuració pot fallar o els fluxos multimèdia es poden trencar.

Això ens va donar un objectiu concret: exposar una superfície UDP petita i fixa a la Internet pública, sense deixar d’encaminar cada paquet al transceptor que posseeix la sessió WebRTC corresponent.

Comparació de les arquitectures multimèdia de WebRTC

Vam avaluar diverses maneres d’arribar-hi, incloent-hi TURN (Traversal Using Relays around NAT), en què un relé perimetral finalitza les assignacions dels clients i reenvia el trànsit per compte seu.2

Mètode

Avantatges

Contres

IP:port únic per sessió (també conegut com a UDP directe natiu)

Camí multimèdia directe de client a servidor

Sense cap capa de reenviament en el camí de dades

Requereix un port UDP públic per sessió

Els intervals amplis de ports són difícils d'exposar i de protegir

Poc adequat per a Kubernetes i equilibradors de càrrega al núvol

IP:port únic per servidor

Empremta UDP pública molt més reduïda que l’exposició per sessió

Un únic socket compartit per servidor pot desmultiplexar moltes sessions

Funciona sense problemes en un sol host, però no en una flota compartida amb equilibratge de càrrega sol

La demultiplexació de sessions en un sol host només ajuda després que un paquet arribi a aquest host; en una flota amb equilibri de càrrega, el primer paquet encara pot acabar a la instància incorrecta, de manera que continues necessitant una manera determinista d’encaminar cada sessió cap al procés que n’és propietari


Relé TURN (amb terminació de protocol)

Els clients només han d'accedir a l'adreça i el port del relé TURN

Poder centralitzar les polítiques al perímetre

Les assignacions TURN afegeixen anades i tornades durant la configuració

Moure o recuperar assignacions entre servidors TURN continua sent difícil

Reenviador sense estat + terminador amb estat (relé + transceptor d'OpenAI)

Petjada UDP pública reduïda

El transceptor encara és el propietari de tota la sessió WebRTC

Afegeix un salt de reenviament abans que el contingut multimèdia arribi al transceptor propietari

Requereix una coordinació específica entre el relé i el transceptor.

Visió general de l’arquitectura: relé + transceptor

L'arquitectura que vam llançar separa l'encaminament de paquets de la terminació de protocols. La senyalització encara arriba al transceptor per configurar la sessió, mentre que els fluxos multimèdia entren primer a través del relé. El relé és una capa lleugera de reenviament UDP amb una exposició pública reduïda, i el transceptor és el punt final WebRTC amb estat que té al darrere.

Relay reenvia paquets al transceptor sense mantenir l'estat

El retransmissor no desxifra els fluxos multimèdia, no executa màquines d’estat ICE ni participa en la negociació de còdecs. Llegeix prou metadades del paquet per triar una destinació i, a continuació, reenvia el paquet al transceptor que és propietari de la sessió. El transceptor continua veient un flux de WebRTC normal i continua mantenint la propietat de tot l’estat del protocol. Des de la perspectiva del client, no canvia res de la sessió WebRTC.

Encaminament segons les credencials ICE

L’encaminament del primer paquet és el pas clau en aquesta configuració. Un relé ha d’encaminar el primer paquet d’un client abans que existeixi cap sessió en el mateix camí del paquet, en lloc d’aturar-se per recórrer a un servei extern de consulta.

Cada sessió WebRTC ja incorpora un ganxo d’encaminament natiu del protocol: el fragment de nom d’usuari ICE, o ufrag, un identificador breu que s’intercanvia durant l’establiment de la sessió i es repeteix en les comprovacions de connectivitat STUN. Generem l’ufrag del costat del servidor perquè contingui just les metadades d’encaminament necessàries perquè el relé pugui inferir el clúster de destinació i el transceptor associat.

El diagrama de seqüència mostra com s’estableix la connexió

Durant la senyalització, el transceptor assigna l’estat de la sessió i retorna una VIP de relé compartida i un port UDP a la resposta SDP. Una VIP és una adreça IP virtual que fa de frontal per a la flota de relés; combinada amb el port, proporciona al client una única destinació estable, com ara "203.0.113.10:3478", tot i que hi hagi moltes instàncies de relé al darrere. El primer paquet de la ruta de fluxos multimèdia del client sol ser una sol·licitud de vinculació STUN (Session Traversal Utilities for NAT), que ICE utilitza per verificar que els paquets poden arribar a l’adreça anunciada.

Relay analitza només la part necessària d’aquest primer paquet STUN per llegir l’ufrag del servidor, descodificar la indicació d’encaminament i reenviar el paquet al transceptor que n’és el propietari. Cada transceptor escolta en un sòcol UDP compartit, és a dir, un únic punt final del sistema operatiu vinculat a una IP:port interna, i no pas un sòcol per sessió. Després que el relé creï una sessió des de la IP:port d’origen del client fins a aquella destinació del transceptor, els paquets DTLS, RTP i RTCP posteriors flueixen dins de la sessió sense tornar a descodificar l’ufrag.

La sessió del retransmissor és deliberadament mínima i consta només d’una sessió en memòria per informar el reenviament de paquets, juntament amb els comptadors necessaris per a la supervisió i els temporitzadors per a l’expiració i la neteja de la sessió. Aquesta decisió de disseny manté l'encaminament de paquets directament a la ruta dels paquets. Si un relé es reinicia i perd la sessió, el paquet STUN següent reconstrueix la sessió a partir de la indicació d’encaminament ufrag. Per fer-ho encara més fiable, s’utilitza una memòria cau de Redis per conservar la correspondència de <IP del client + port, IP del transceptor + port> un cop establerta la ruta, de manera que es pugui recuperar molt abans, abans que arribi el paquet STUN següent.

Retransmissió global i senyalització geodirigida.

Un cop vam reduir la superfície UDP pública a un nombre reduït d’adreces i ports estables, vam poder desplegar el mateix patró de retransmissió a escala global. Global Relay és la nostra flota de punts d’entrada de retransmissió distribuïts geogràficament, tots els quals implementen el mateix comportament de reenviament de paquets.

Una entrada geogràfica àmplia escurça el primer salt del client a OpenAI perquè un paquet pot entrar a la nostra xarxa en un relé proper a l'usuari, tant geogràficament com pel que fa a la topologia de xarxa, en lloc de travessar primer la Internet pública fins a una regió distant. En termes pràctics, això es tradueix en una latència més baixa, menys jitter i menys ràfegues de pèrdua evitables abans que el trànsit arribi a la nostra xarxa troncal.6

La capa Global Relay rep paquets del client i els reenvia al clúster de transceptors

Fem servir l'encaminament geogràfic i per proximitat de Cloudflare per a la senyalització, de manera que la sol·licitud HTTP o WebSocket inicial arribi a un clúster de transceptors proper. El context de la sol·licitud determina la ubicació de la sessió i quin punt d’entrada de Global Relay s’anuncia al client. La resposta SDP proporciona l’adreça de Global Relay, mentre que l’ufrag conté informació suficient perquè Global Relay encamini el trànsit multimèdia cap al clúster designat i perquè el relé l’encamini cap al transceptor de destinació.

Conjuntament, la senyalització geodirigida i Global Relay situen tant l’establiment com els fluxos multimèdia en una ruta d’entrada propera, alhora que mantenen la sessió ancorada a un únic transceptor. Això redueix el temps d’anada i tornada de la senyalització i de la primera comprovació de connectivitat ICE, la qual cosa escurça directament el temps que un usuari espera abans de començar a parlar.

Implementació i rendiment de Relay

Vam escriure el servei de retransmissió a Go i vam mantenir la implementació acotada deliberadament. A Linux, la pila de xarxa del nucli rep paquets UDP de la interfície de xarxa de la màquina i els lliura a un sòcol, el punt final del sistema operatiu des del qual llegeix un procés després de vincular-se a una IP:Port. Relay s'executa en l'espai d'usuari, de manera que un procés Go normal llegeix les capçaleres dels paquets d'aquest socket, actualitza una petita quantitat d'estat del flux i reenvia els paquets sense finalitzar WebRTC. No vam necessitar cap marc de bypass del nucli, que permetria que un procés en espai d’usuari consultés directament les cues de xarxa per obtenir taxes de paquets més altes, però que també afegiria complexitat operativa.

Decisions de disseny clau:

  • Sense terminació de protocol: Relay només analitza les capçaleres STUN/ufrag; utilitza l’estat en memòria cau per als DTLS, RTP i RTCP posteriors, mantenint els paquets opacs.
  • Estat efímer: Manté un petit mapa en memòria, amb un temps d’espera curt, que associa l’adreça del client amb la destinació del transceptor per a l’estat del flux i l’observabilitat.
  • Escalabilitat horitzontal: Diverses instàncies de relé s’executen en paral·lel darrere d’un equilibrador de càrrega. L’estat no és un estat persistent de WebRTC, de manera que els reinicis causen interrupcions mínimes del trànsit i una recuperació ràpida del flux.

Mesures d'eficiència:

  • SO_REUSEPORT és una opció de sòcol de Linux que permet que diversos treballadors de retransmissió de la mateixa màquina es vinculin al mateix port UDP. Aleshores, el nucli distribueix els paquets entrants entre aquests treballadors, cosa que evita un coll d’ampolla en un únic bucle de lectura.
  • runtime.LockOSThread fixa cada gorutina que llegeix UDP a un fil específic del sistema operatiu. Combinat amb SO_REUSEPORT, això tendeix a mantenir els paquets del mateix flux (la IP:port d’origen i de destinació més el protocol) al mateix nucli de CPU, millorant la localitat de la memòria cau i reduint els canvis de context.
  • Els búfers preassignats i el mínim de còpies mantenen baixa la sobrecàrrega d’anàlisi i d’assignació per evitar la recollida de residus a Go.

Aquesta implementació gestionava el nostre trànsit multimèdia global en temps real amb una infraestructura de relés relativament petita, de manera que vàrem mantenir el disseny més senzill en lloc d’optar per una via de bypass del nucli.

Resultats i aprenentatges

Aquesta arquitectura ens permet executar contingut multimèdia de WebRTC a Kubernetes sense exposar milers de ports UDP. Això és important perquè una superfície UDP més petita i fixa és més fàcil de protegir i d'equilibrar-ne la càrrega, i permet que la infraestructura escali sense reservar grans intervals de ports públics. Amb un millor suport d’infraestructura de Kubernetes i més seguretat gràcies a una superfície d’atac més reduïda, aquest disseny també preserva el comportament estàndard de WebRTC per als clients i confirma que un disseny sense SFU era l’opció predeterminada adequada per a la nostra càrrega de treball. La majoria de les nostres sessions són punt a punt, sensibles a la latència i més fàcils d’escalar quan els serveis d’inferència no han de comportar-se com a parells WebRTC.

La lliçó més general és que el millor lloc per afegir complexitat és en una capa d’encaminament lleugera, no en cada servei backend, i no en un comportament personalitzat del client. Codificar les metadades d’encaminament en un camp natiu del protocol ens va proporcionar un encaminament determinista del primer paquet, una petjada UDP pública reduïda i prou flexibilitat per situar els punts d’ingrés a prop dels usuaris arreu del món.

Algunes opcions van ser especialment importants:

  • Preservar la semàntica del protocol a la perifèria. Els clients continuen utilitzant el WebRTC estàndard, cosa que manté intacta la interoperabilitat amb navegadors i dispositius mòbils.
  • Mantenir els estats de sessió complexos en un sol lloc. El transceptor és responsable de l'ICE, el DTLS, l'SRTP i el cicle de vida de la sessió; el relé només reenvia paquets.
  • Encaminar segons la informació que ja és present a la configuració. L'ufrag d'ICE ens va proporcionar un punt d'enganxament d'encaminament del primer paquet sense afegir cap dependència de consulta al camí crític.
  • Optimitzar per al cas habitual abans de recórrer al bypass del nucli. Una implementació acotada a Go amb un ús curós de SO_REUSEPORT, fixació de fils i anàlisi amb poques assignacions de memòria va ser suficient per a la nostra càrrega de treball.

La IA de veu en temps real només funciona quan la infraestructura fa que la latència sigui imperceptible. Per a nosaltres, això va significar canviar el nostre desplegament de WebRTC sense canviar el que els clients esperen de WebRTC en si.