Пређите на главни садржај
OpenAI

4. мај 2026.

Инжењеринг

Како OpenAI испоручује гласовну AI са малим кашњењем у великом обиму

Аутори: Ји Џанг (Yi Zhang) и Вилијем МекДоналд (William McDonald), чланови техничког особља

Гласовни AI делује природно само ако се разговор одвија брзином говора. Када мрежа почне да смета, људи то одмах чују као непријатне паузе, одсечене прекиде или закаснело упадање у реч. То је важно за Говорни ChatGPT, за програмере који граде помоћу Realtime API, за агенте који раде у интерактивним токовима рада и за моделе који треба да обрађују звук док корисник још увек говори.

На нивоу обима пословања компаније OpenAI, то подразумева три конкретна захтева:

  • Глобални досег за више од 900 милиона недељно активних корисника
  • Брзо успостављање везе како би корисник могао да почне да говори чим сесија започне
  • Ниско и стабилно време повратног пута медија, уз ниско подрхтавање и губитак пакета, тако да смена у говору делује течно и без застоја

Тим у OpenAI, одговоран за AI интеракције у реалном времену, недавно је изнова осмислио архитектуру нашег WebRTC стека како би одговорио на три ограничења која су почела да се сударају при великом обиму: терминирање медијског саобраћаја по принципу један порт по сесији не уклапа се добро у инфраструктуру компаније OpenAI, сесије ICE (успостављање интерактивног повезивања) и DTLS (безбедност слоја датаграмског транспорта) са стањем захтевају стабилно власништво, а глобално рутирање мора да одржи ниско кашњење првог скока. У овом посту објашњавамо подељену архитектуру релеја плус примопредајника, коју смо изградили како бисмо очували стандардно WebRTC понашање за клијенте, док мењамо начин на који се пакети усмеравају унутар инфраструктуре компаније OpenAI.

WebRTC нам омогућава да правимо AI производе у реалном времену

WebRTC је отворени стандард за слање звука, видеа и података са малим кашњењем између прегледача, мобилних апликација и сервера. Често се повезује са peer-to-peer позивањем, али је такође и практична основа за клијент–сервер системе у реалном времену, јер стандардизује захтевне делове интерактивних медија: ICE за успостављање повезивости и пролазак кроз NAT (превођење мрежних адреса), DTLS и SRTP (безбедни протокол за пренос у реалном времену) за шифровани пренос, преговарање о кодецима за компримовање и декодирање звука, RTCP (протокол за контролу преноса у реалном времену) за контролу квалитета, као и функције на страни клијента, као што су поништавање еха и баферовање подрхтавања.

Та стандардизација је важна за производе засноване на AI. Без WebRTC, сваки клијент би морао да има другачије решење за то како да успостави повезивост преко NAT, шифрује медијске токове, преговара кодеке (кодери-декодери изабрани за пренос и декомпресију) и прилагођава се променљивим мрежним условима. Уз WebRTC, можемо да се ослонимо на протоколски стек који је већ имплементиран у прегледачима и на мобилним платформама, усмеравајући сопствени рад на инфраструктуру која повезује медије у реалном времену са моделима.

Такође се ослањамо на сам WebRTC екосистем, укључујући зреле имплементације отвореног кода и рад на стандардима који обезбеђују да прегледачи, мобилне апликације и сервери буду интероперабилни. Темељни рад Џастина Убертија (Justin Uberti) (једног од оригиналних архитеката WebRTC) и Шона Дибоа (Sean DuBois) (творца и одржаваоца Pion) омогућио је тимовима попут нашег да граде на медијској инфраструктури провереној у пракси, уместо да изнова осмишљавају транспорт на ниском нивоу, шифровање и контролу загушења. Имамо срећу што су и Џастин и Шон сада наше колеге овде у компанији OpenAI, где помажу да усмеримо начин на који приближавамо WebRTC и AI у реалном времену.

За AI, најважније својство је да звук пристиже као непрекидан ток. Говорни агент може да започне транскрибовање, резоновање, позивање алата или генерисање говора док корисник још увек говори, уместо да чека потпуно отпремање. То је разлика између система који се осећа разговорно и оног који се осећа као да се прича.

Избор медијске архитектуре

Када смо изабрали WebRTC, следеће питање било је где да га терминишемо (где бисмо прихватили и преузели WebRTC везу – на пример, на ивици) и како да те сесије повежемо са системом за инференцију. Терминација је важна јер одређује како управљамо стањем сесије у реалном времену, преносом медија, рутирањем, кашњењем и изолацијом кварова.

Опција 1: SFU приступ укључује AI као WebRTC учесника

SFU, или јединица за селективно прослеђивање, је медијски сервер који прима по један WebRTC ток од сваког учесника и селективно прослеђује токове осталима. У овом моделу, SFU прекида засебну WebRTC везу за сваког учесника, а AI се придружује сесији као још један учесник. То може да буде добар избор за производе који по својој природи укључују више учесника, као што су групни позиви, учионице или састанци за сарадњу. Аудио-кодеке, RTCP поруке, канале података, снимање и политику по стриму држи на једном месту.1

Чак и у производима типа клијент–AI, SFU је често подразумевана полазна тачка јер омогућава тимовима да поново користе један проверен систем за сигнализацију, усмеравање медија, снимање, посматрање и будућа проширења, као што су преусмеравање на човека или додавање више учесника.

Опција 2: Приступ са примопредајником терминира WebRTC на ивици мреже и конвертује га у протокол позадинског система

Наше радно оптерећење је другачије. Већина сесија се одвија 1:1 — један корисник разговара са једним моделом или једна апликација разговара са једним агентом у реалном времену — при чему је свака размена осетљива на кашњење. За такав профил саобраћаја изабрали смо модел примопредајника: WebRTC edge услуга терминира клијентску везу, а затим претвара медије и догађаје у једноставније интерне протоколе за инференцију модела, транскрипцију, генерисање говора, коришћење алата и оркестрацију.

У овом дизајну, примопредајник је једини сервис који поседује стање WebRTC сесије, укључујући ICE провере повезивости, DTLS руковање, SRTP кључеве за шифровање и животни циклус сесије. „Терминација” овде значи да је примопредајник крајња тачка која довршава та руковања и шифрује или дешифрује медије. Држање тог стања на једном месту учинило је власништво над сесијом лакшим за разумевање и омогућило бекенд сервисима да се скалирају као обични сервиси, уместо да сами делују као WebRTC партнери.

Основни проблем примене: WebRTC и Kubernetes

Након избора модела примопредајника, наша прва имплементација била је један Go сервис изграђен на Pion-у који је обрађивао и сигнализацију и завршетак медија. Покреће Говорни ChatGPT, WebRTC крајњу тачку API-ја у реалном времену и низ истраживачких пројеката.

Са оперативне стране, сервис примопредајника обавља два задатка:

  • Сигнализација: преговарање о SDP, избор кодека, ICE подаци за пријаву и успостављање сесије
  • Медији: Прекидање низводних WebRTC веза и одржавање узводних веза са позадинским сервисима за закључивање и оркестрацију

Желели смо да услуга ради као и остатак наше инфраструктуре: на Kubernetes, где радна оптерећења могу да се скалирају навише и наниже и да се премештају између хостова како се потражња мења. Али конвенционални WebRTC модел са једним портом по сесији лоше се уклапа у то окружење, јер зависи од великих опсега јавних UDP портова које је тешко изложити, обезбедити и очувати како се подови додају, уклањају или поново распоређују.2

Исцрпљивање портова

Први проблем био је сам модел са једним портом по сесији. При високој истовремености, то значи да је потребно изложити веома велике опсеге UDP портова и управљати њима.

  • Балансери оптерећења у облаку и Kubernetes услуге нису пројектовани за десетине хиљада јавних UDP портова по услузи. Сваки додатни опсег повећава оперативну сложеност у конфигурацији балансера оптерећења, провери здравља, политици заштитног зида и безбедности увођења.3
  • Велике опсеге UDP портова тешко је обезбедити јер проширују површину изложену спољном приступу и отежавају ревизију мрежних политика.
  • Такође нису погодни за аутоматско скалирање. Подови се у Kubernetes непрестано додају, уклањају и поново распоређују. Захтев да сваки pod резервише и оглашава велики стабилан опсег портова чини ту еластичност крхком.4

Због тога многи WebRTC системи прелазе на један UDP порт по серверу, уз демултиплексирање на нивоу апликације иза тог порта.5

Стање лепљивости

Решења са једним портом по серверу решавају проблем броја портова, али уводе други проблем: очување власништва над појединачним сесијама у читавој флоти сервера.

ICE и DTLS су протоколи са стањем. Процес који је креирао сесију мора да настави да прима пакете те сесије како би могао да валидира провере повезаности, доврши DTLS руковање, дешифрује SRTP и обради касније промене сесије, као што су поновна покретања ICE. Ако пакети за исту сесију стигну у други процес, успостављање може да не успе или медијски ток може да се прекине.

То нам је дало конкретан циљ: изложити малу, фиксну UDP површину јавном интернету, док се сваки пакет и даље усмерава ка примопредајнику који припада одговарајућој WebRTC сесији.

Поређење WebRTC медијских архитектура

Размотрили смо неколико начина да то постигнемо, укључујући TURN (Traversal Using Relays around NAT), где ивични релеј терминира клијентске алокације и прослеђује саобраћај у њихово име.2

Приступ

Предности

Мане

Јединствени IP:порт по сесији (познато и као нативни директни UDP)

Директан пут медија од клијента до сервера

Нема слоја за прослеђивање у путањи података

Захтева један јавни UDP порт по сесији

Велике опсеге портова је тешко изложити и обезбедити

Неприкладан за Kubernetes и балансере оптерећења у облаку

Јединствени IP:порт по послужитељу

Знатно мањи јавни UDP отисак у односу на изложеност по сесији

Један заједнички сокет по серверу може да демултиплексира више сесија

Функционише без проблема на једном серверу, али не и у дељеном скупу сервера са балансирањем оптерећења

Демултиплексирање сесија на једном хосту помаже тек након што пакет стигне до тог хоста; у кластеру са балансирањем оптерећења први пакет и даље може да заврши на погрешној инстанци, тако да је и даље потребан детерминистички начин да се свака сесија усмери ка процесу који управља том сесијом


TURN релеј (прекидање протокола)

Клијенти само треба да приступе адреси и порту TURN релеја

Може да централизује смернице на ивици мреже

TURN алокације додају повратне размене током успостављања

Премештање или обнављање додела између TURN сервера и даље је тешко

Прослеђивач без стања + терминатор са стањем (релеј и примопредајник компаније OpenAI)

Мали јавни UDP отисак

Примопредајник и даље управља целокупном WebRTC сесијом

Додаје један скок прослеђивања пре него што медији стигну до примопредајника власника

Захтева прилагођену координацију између релеја и примопредајника

Преглед архитектуре: релеј и примопредајник

Архитектура коју смо испоручили раздваја усмеравање пакета од завршетка протокола. Сигнализација и даље стиже до примопредајника ради успостављања сесије, док медијски саобраћај најпре улази преко релеја. Релеј је лагани слој за прослеђивање UDP саобраћаја са малим јавним отиском, а примопредајник је WebRTC крајња тачка са стањем иза њега.

Релеј без чувања стања прослеђује пакете примопредајнику

Релеј не дешифрује медијски садржај, не извршава ICE машине стања нити учествује у преговарању о кодецима. Чита довољно метаподатака пакета да изабере одредиште, а затим прослеђује пакет примопредајнику који поседује сесију. Примопредајник и даље види уобичајени WebRTC ток и и даље управља целокупним стањем протокола. Из перспективе клијента, ништа у вези са WebRTC сесијом се не мења.

Рутирање на основу ICE акредитива

Рутирање првог пакета је кључни корак у овом подешавању. Релеј мора да рутира први пакет од клијента пре него што на самој путањи пакета постоји било каква сесија, а не тако што ће застати ради екстерног сервиса за претрагу.

Свака WebRTC сесија већ садржи механизам за усмеравање уграђен у протокол: фрагмент корисничког имена ICE, или ufrag, кратак идентификатор који се размењује током успостављања сесије и понавља у STUN проверама повезивости. Генеришемо ufrag на страни сервера тако да садржи довољно метаподатака за усмеравање како би релеј могао да одреди одредишни кластер и припадајући примопредајник.

Дијаграм секвенце приказује како се успоставља веза

Током сигнализације, примопредајник алоцира стање сесије и враћа дељену релејну VIP адресу и UDP порт у SDP одговору. VIP је виртуелна IP адреса која стоји испред флоте релеја; у комбинацији са портом, клијенту даје једно стабилно одредиште, као што је `203.0.113.10:3478`, иако се иза њега налази више инстанци релеја. Први клијентов пакет на медијској путањи обично је STUN (Session Traversal Utilities for NAT) захтев за везивање, који ICE користи да провери да ли пакети могу да стигну до оглашене адресе.

Релеј парсира тек онолико првог STUN пакета колико је потребно да прочита ufrag сервера, декодира наговештај за рутирање и проследи пакет надлежном примопредајнику. Сваки примопредајник слуша на заједничком UDP сокету, што значи једну крајњу тачку оперативног система везану за интерни IP:порт, а не један сокет по сесији. Након што релеј креира сесију од изворног IP:порта клијента до тог одредишта примопредајника, наредни DTLS, RTP и RTCP пакети протичу у оквиру сесије без поновног ufrag декодирања.

Сесија релеја је намерно минимална, састоји се само од сесије у меморији за прослеђивање пакета, уз неопходне бројаче за надгледање и тајмере за истек и чишћење сесије. Ово пројектно решење омогућава рутирање пакета директно на путањи пакета. Ако се релеј поново покрене и изгуби сесију, следећи STUN пакет ће обновити сесију на основу ufrag наговештаја за рутирање. Да би се учинило још поузданијим, користи се Redis кеш за чување мапирања <IP клијента + порт, IP примопредајника + порт> када се рута успостави, како би се обновила много раније, пре него што стигне следећи STUN пакет.

Global Relay и гео-усмеравана сигнализација

Када смо јавно изложену UDP површину свели на мали број стабилних адреса и портова, могли смо глобално применити исти релејни образац. Global Relay је наша флота географски распоређених улазних тачака релеја које све примењују исто понашање прослеђивања пакета.

Широка географска покривеност улазних тачака скраћује први скок од клијента до OpenAI мреже, јер пакет може да уђе у нашу мрежу преко релеја који је близу корисника, како географски тако и у погледу топологије мреже, уместо да прво прелази преко јавног интернета до удаљеног региона. У практичном смислу, то значи мање кашњење, мање варијација кашњења и мање налета губитака који се могу избећи пре него што саобраћај стигне до наше окоснице.6

Слој Global Relay прима пакете од клијента и прослеђује их кластеру примопредајника

Користимо Cloudflare географско и близинско усмеравање за сигнализацију, тако да почетни HTTP или WebSocket захтев стигне до оближњег кластера примопредајника. Контекст захтева одређује локацију сесије и која се улазна Global Relay тачка објављује клијенту. SDP одговор пружа Global Relay адресу, док ufrag садржи довољно информација да Global Relay усмери медијски саобраћај ка назначеном кластеру, а релеј ка одредишном примопредајнику.

Географски усмеравана сигнализација и Global Relay заједно постављају и успостављање везе и медијске токове на оближњу улазну путању, уз задржавање сесије усидрене на једном примопредајнику. То смањује време повратног пута за сигнализацију и за прву ICE проверу повезивости, што директно скраћује време које корисник чека пре него што говор може да почне.

Имплементација и Relay перформансе

Написали смо сервис за прослеђивање у плану Go и намерно ограничили обим имплементације. На Linux систему, мрежни стек језгра прима UDP пакете са мрежног интерфејса машине и испоручује их сокету, крајњој тачки оперативног система коју процес чита након везивања за IP:порт. Relay ради у корисничком простору, тако да обичан Go процес чита заглавља пакета из тог сокета, ажурира малу количину стања тока и прослеђује пакете без WebRTC прекидања. Није нам био потребан никакав оквир за заобилажење кернела, који би омогућио процесу у корисничком простору да директно испитује мрежне редове ради већих стопа пакета, али би такође додао оперативну сложеност.

Кључни дизајнерски избори:

  • Без прекида протокола: Релеј анализира само STUN заглавља/ufrag; користи кеширано стање за накнадне DTLS, RTP и RTCP, остављајући пакете непрозирним.
  • Ефемерно стање: Одржава малу мапу у меморији са кратким временом истека, која повезује адресу клијента са одредиштем примопредајника ради праћења стања тока и видљивости.
  • Хоризонтална скалабилност: Више инстанци релеја ради паралелно иза балансера оптерећења. Стање није чврсто WebRTC стање, па поновна покретања узрокују минималне падове саобраћаја и брз опоравак тока.

Мере ефикасности:

  • SO_REUSEPORT је опција Linux сокета која омогућава да више радника за прослеђивање на истој машини веже исти UDP порт. Језгро затим распоређује долазне пакете међу тим радним процесима, чиме се избегава уско грло једне петље за читање.
  • runtime.LockOSThread везује сваку горутину која чита UDP за одређену нит оперативног система. У комбинацији са SO_REUSEPORT, то обично задржава пакете из истог тока (изворишни и одредишни IP:порт плус протокол) на истом процесорском језгру, побољшавајући локалност кеша и смањујући пребацивање контекста.
  • Унапред алоцирани бафери и минимално копирање одржавају ниско оптерећење парсирања и алокације како би се избегло сакупљање смећа у плану Go.

Ова имплементација је обрађивала наш глобални медијски саобраћај у реалном времену уз релативно мали број релеја, па смо задржали једноставнији дизајн уместо да кренемо путем заобилажења кернела.

Резултати и сазнања

Ова архитектура нам омогућава да покрећемо WebRTC медије у Kubernetes без излагања хиљада UDP портова. То је важно јер је мању и фиксну UDP површину лакше обезбедити и балансирати оптерећење, а инфраструктури омогућава да се скалира без резервисања великих опсега јавних портова. Уз бољу подршку инфраструктуре од стране Kubernetes и већу безбедност захваљујући мањој површини напада, овај дизајн такође чува стандардно WebRTC понашање за клијенте и потврђује да је дизајн без SFU био прави подразумевани избор за наше радно оптерећење. Већина наших сесија је од тачке до тачке, осетљива је на кашњење и лакше се скалира када сервиси за инференцију не морају да се понашају као WebRTC peer сарадници.

Шира лекција је да је најбоље место за додавање сложености у танком слоју за рутирање, а не у свакој услузи позадинског система, нити у прилагођеном понашању клијента. Кодирање метаподатака за усмеравање у поље својствено протоколу омогућило нам је детерминистичко усмеравање првог пакета, мали јавни UDP отисак и довољну флексибилност да поставимо улазне тачке близу корисника широм света.

Неколико одлука било је посебно важно:

  • Очувајте семантику протокола на ивици. Клијенти и даље комуницирају путем стандардног WebRTC, чиме се очувава интероперабилност прегледача и мобилних уређаја.
  • Чувајте фиксна стања сесије на једном месту. Примопредајник управља ICE, DTLS, SRTP и животним циклусом сесије, док релеј само прослеђује пакете.
  • Усмерите на основу информација које су већ присутне у подешавању. ICE ufrag нам је обезбедио тачку за рутирање првог пакета без додавања зависности од претраге на критичној путањи.
  • Оптимизујте за уобичајени случај пре него што посегнете за заобилажењем кернела. Уско специјализована Go имплементација, са пажљивом употребом SO_REUSEPORT, фиксирањем нити и парсирањем уз мало алокација, била је довољна за наше радно оптерећење.

Говорни AI у реалном времену функционише само када инфраструктура чини кашњење неприметним. За нас је то значило промену облика наше WebRTC примене без промене онога што клијенти очекују од WebRTC.