
OpenAI 如何在大規模環境下實現低延遲語音 AI
OpenAI 介紹了他們如何重新建構 WebRTC 堆疊,透過拆分中繼與收發器架構,在 Kubernetes 基礎設施中實現低延遲、全球規模且無縫對話輪替的即時語音 AI。
2026 年 5 月 4 日
OpenAI 如何在大規模環境下實現低延遲語音 AI
作者:Yi Zhang 與 William McDonald,技術人員
語音 AI 只有在對話速度與說話速度同步時,才會讓人感到自然。當網路成為阻礙,人們會立即察覺到尷尬的停頓、被切斷的插話或延遲的介入。這對於 ChatGPT 語音、使用 Realtime API 構建的開發者、在互動式工作流中運作的代理(Agents),以及需要在用戶說話時同步處理音訊的模型來說都至關重要。
在 OpenAI 的規模下,這轉化為三個具體要求:
OpenAI 負責即時 AI 互動的團隊最近重新架構了我們的 WebRTC 堆疊,以解決在大規模環境下出現的三個衝突限制:每個會話佔用一個連接埠的媒體終止方式不適合 OpenAI 的基礎設施、狀態化的 ICE(互動式連接建立)和 DTLS(資料報傳輸層安全)會話需要穩定的歸屬權,以及全球路由必須保持低首跳延遲。在本文中,我們將介紹我們構建的「拆分中繼(Split Relay)加收發器(Transceiver)」架構,該架構在改變 OpenAI 內部基礎設施數據包路由方式的同時,仍為客戶端保留了標準的 WebRTC 行為。
WebRTC 讓我們得以打造即時 AI 產品
WebRTC 是一個在瀏覽器、行動應用程式和伺服器之間傳送低延遲音訊、視訊和數據的開放標準。它通常與點對點通話聯繫在一起,但它也是客戶端到伺服器即時系統的實用基礎,因為它將互動式媒體中最困難的部分標準化了:用於連接建立和 NAT(網路位址轉換)穿透的 ICE、用於加密傳輸的 DTLS 和 SRTP(安全即時傳輸協定)、用於壓縮和解碼音訊的編解碼器協商、用於品質控制的 RTCP(即時傳輸控制協定),以及回音消除和抖動緩衝等客戶端功能。
這種標準化對 AI 產品至關重要。如果沒有 WebRTC,每個客戶端都需要針對如何跨 NAT 建立連接、加密媒體、協商編解碼器以及適應不斷變化的網路條件提供不同的解決方案。有了 WebRTC,我們可以在已於瀏覽器和行動平台實現的協定堆疊上進行構建,將精力集中在連接即時媒體與模型的基礎設施上。
我們也建立在 WebRTC 生態系統之上,包括成熟的開源實現和保持瀏覽器、行動應用程式與伺服器互操作性的標準工作。Justin Uberti(WebRTC 的原始架構師之一)和 Sean DuBois(Pion 的創建者兼維護者)的基礎性工作,使像我們這樣的團隊能夠在經過實戰測試的媒體基礎設施上進行構建,而不是重新發明底層傳輸、加密和擁塞控制行為。我們很幸運,Justin 和 Sean 現在都是 OpenAI 的同事,協助指導我們如何讓 WebRTC 與即時 AI 結合得更緊密。
對於 AI 來說,最重要的特性是音訊以連續流的形式到達。語音代理可以在用戶還在說話時就開始轉錄、推理、調用工具或生成語音,而不是等待完整的上傳。這就是「對話感系統」與「對講機式系統」之間的區別。
選擇媒體架構
一旦我們選擇了 WebRTC,下一個問題就是在哪裡終止它(即我們在哪裡接收並擁有 WebRTC 連接——例如在邊緣節點),以及如何將這些會話連接到推理後端。終止點很重要,因為它決定了我們如何處理即時會話狀態、媒體傳輸、路由、延遲和故障隔離。
SFU(選擇性轉發單元)是一種媒體伺服器,它從每個參與者接收一個 WebRTC 流,並選擇性地將流轉發給其他參與者。在這種模型中,SFU 為每個參與者終止一個獨立的 WebRTC 連接,而 AI 則作為會話中的另一個參與者加入。這非常適合本質上是多方的產品,如群組通話、教室或協作會議。它將音訊編解碼器、RTCP 訊息、數據通道、錄音和每流策略集中在一處。1
即使在客戶端到 AI 的產品中,SFU 通常也是預設的起點,因為它讓團隊可以重複使用一個成熟的系統來進行信令、媒體路由、錄音、可觀測性以及未來的擴展(如人工接管或增加更多參與者)。
我們的工作負載則不同。大多數會話是 1:1 的——一個用戶對一個模型,或一個應用程式對一個即時代理——且每一輪對話都對延遲極其敏感。針對這種流量型態,我們選擇了收發器(Transceiver)模型:一個 WebRTC 邊緣服務終止客戶端連接,然後將媒體和事件轉換為更簡單的內部協定,用於模型推理、轉錄、語音生成、工具使用和編排。
在這種設計中,收發器是唯一擁有 WebRTC 會話狀態的服務,包括 ICE 連接檢查、DTLS 握手、SRTP 加密金鑰和會話生命週期。「終止」在這裡意味著收發器是完成這些握手並加密或解密媒體的端點。將狀態保持在一個地方使會話歸屬權更容易理解,並讓後端服務可以像普通服務一樣擴展,而不是自己充當 WebRTC 對等端。
核心部署問題:WebRTC 遇上 Kubernetes
在選擇收發器模型後,我們的第一個實現是一個基於 Pion 構建的單一 Go 服務,同時處理信令和媒體終止。它支援了 ChatGPT 語音、Realtime API 的 WebRTC 端點以及許多研究專案。
在運作上,收發器服務承擔兩項工作:
我們希望該服務能像我們其他的基礎設施一樣運行:在 Kubernetes 上,工作負載可以根據需求增減規模,並隨著需求變化在主機之間移動。但傳統的「每個會話一個連接埠」的 WebRTC 模型與這種環境契合度很差,因為它依賴於大量的公共 UDP 連接埠範圍,這些範圍在 Pod 增加、刪除或重新調度時難以暴露、保護和保留。2
連接埠耗盡
第一個問題是「每個會話一個連接埠」模型本身。在高併發情況下,這意味著需要暴露和管理非常龐大的 UDP 連接埠範圍。
這就是為什麼許多 WebRTC 系統轉向「每台伺服器單一 UDP 連接埠」的原因,並在該連接埠後方進行應用層的多路分解(Demultiplexing)。5
狀態黏性
單連接埠設計解決了連接埠數量的問題,但引入了第二個問題:如何在集群中保留每個會話的歸屬權。
ICE 和 DTLS 是狀態化協定。創建會話的進程需要持續接收該會話的數據包,以便驗證連接檢查、完成 DTLS 握手、解密 SRTP 並處理後續的會話變更(如 ICE 重啟)。如果同一個會話的數據包落在不同的進程上,設置可能會失敗或媒體會中斷。
這給了我們一個具體目標:向公共網際網路暴露一個小型的、固定的 UDP 介面,同時仍能將每個數據包路由到擁有對應 WebRTC 會話的收發器。
WebRTC 媒體架構比較
我們評估了幾種實現方法,包括 TURN(使用中繼穿透 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 包含足夠的路由元數據,讓中繼能推斷出目標集群和所屬收發器。
在信令期間,收發器分配會話狀態並在 SDP 應答中返回一個共享的中繼 VIP 和 UDP 連接埠。VIP 是前端中繼集群的虛擬 IP 位址;結合連接埠,它為客戶端提供了一個單一穩定的目的地(例如 203.0.113.10:3478),即使背後有許多中繼實例。客戶端的第一個媒體路徑數據包通常是 STUN(NAT 會話遍歷公用程式)綁定請求,ICE 使用它來驗證數據包是否能到達廣告位址。
中繼僅解析該首個 STUN 數據包中足夠的部分以讀取伺服器 ufrag,解碼路由提示,並將數據包轉發給所屬收發器。每個收發器都在一個共享的 UDP 套接字上監聽,這意味著一個綁定到內部 IP:連接埠的作業系統端點,而不是每個會話一個套接字。在中繼創建了從客戶端來源 IP:連接埠到該收發器目的地的會話後,後續的 DTLS、RTP 和 RTCP 數據包將在該會話內流動,無需重新解碼 ufrag。
中繼的會話被刻意設計得極簡,僅包含一個用於通知數據包轉發的記憶體內會話,以及用於監控的必要計數器和用於會話過期與清理的定時器。這種設計選擇將數據包路由直接保持在數據包路徑上。如果中繼重啟並丟失會話,下一個 STUN 數據包會根據 ufrag 路由提示重建會話。為了使其更加可靠,我們使用了 Redis 快取來保存一旦路由建立後的 <客戶端 IP + 連接埠, 收發器 IP + 連接埠> 映射,以便在下一個 STUN 數據包到達之前更早地恢復路由。
全球中繼與地理引導信令
一旦我們將公共 UDP 介面減少到少數穩定的位址和連接埠,我們就可以在全球部署相同的中繼模式。全球中繼(Global Relay)是我們地理分佈的中繼入口點集群,它們都實現相同的數據包轉發行為。
廣泛的地理入口縮短了客戶端到 OpenAI 的第一跳,因為數據包可以在地理和網路拓撲上靠近用戶的中繼進入我們的網路,而不是先跨越公共網際網路到達遙遠的區域。在實際應用中,這意味著在流量到達我們的骨幹網之前,延遲更低、抖動更少,且可避免的丟包突發更少。6
我們使用 Cloudflare 的地理和鄰近引導來處理信令,使初始 HTTP 或 WebSocket 請求到達附近的收發器集群。請求上下文決定了會話的位置以及向客戶端廣告哪個全球中繼入口點。SDP 應答提供全球中繼位址,而 ufrag 包含足夠的資訊,讓全球中繼將媒體路由到指定的集群,並讓中繼路由到目標收發器。
地理引導信令與全球中繼相結合,將設置和媒體都放在附近的入口路徑上,同時將會話錨定在一個收發器上。這減少了信令和第一次 ICE 連接檢查的往返時間,直接縮短了用戶在語音開始前的等待時間。
中繼實現與效能
我們使用 Go 語言編寫中繼服務,並刻意保持實現的精簡。在 Linux 上,核心的網路堆疊從機器的網路介面接收 UDP 數據包,並將其傳送到套接字(進程在綁定 IP:連接埠後讀取的作業系統端點)。中繼運行在用戶空間,因此一個常規的 Go 進程從該套接字讀取數據包標頭,更新少量的流狀態,並在不終止 WebRTC 的情況下轉發數據包。我們不需要任何核心旁路(Kernel-bypass)框架,雖然這能讓用戶空間進程直接輪詢網路隊列以獲得更高的數據包速率,但也會增加運作複雜性。
關鍵設計選擇:
- 非阻塞 I/O:使用多個讀取循環從共享套接字消費數據包。
- 無鎖數據路徑:使用分片映射(Sharded maps)或原子操作來管理會話狀態,減少鎖競爭。
- 零分配轉發:重複使用緩衝區池,避免在轉發路徑上產生垃圾回收壓力。
效率措施:
- GOMAXPROCS 調優:使工作線程與 CPU 核心匹配,以最小化上下文切換。
- 批次 I/O:使用
recvmmsg和sendmmsg系統調用在單次核心轉換中處理多個數據包。
這種實現以相對較小的中繼佔用空間處理了我們的全球即時媒體流量,因此我們保留了較簡單的設計,而沒有採用核心旁路方案。
結果與啟示
這種架構讓我們能在 Kubernetes 中運行 WebRTC 媒體,而無需暴露數千個 UDP 連接埠。這很重要,因為較小且固定的 UDP 介面更容易保護和負載平衡,並讓基礎設施在不保留大量公共連接埠範圍的情況下進行擴展。憑藉 Kubernetes 更好的基礎設施支援以及由於介面較小而提高的安全性,這種設計還為客戶端保留了標準的 WebRTC 行為,並證實了「無 SFU 設計」是我們工作負載的正確預設選擇。我們的大多數會話是點對點的、對延遲敏感的,且當推理服務不需要表現得像 WebRTC 對等端時,更容易擴展。
更廣泛的教訓是,增加複雜性的最佳位置是在薄薄的路由層,而不是在每個後端服務中,也不是在自定義的客戶端行為中。將路由元數據編碼到協定原生欄位中,為我們提供了確定的首包路由、小的公共 UDP 佔用空間,以及足夠的靈活性將入口點放置在世界各地靠近用戶的地方。
有幾個選擇尤為重要:
- 保持中繼無狀態(或接近無狀態):中繼不擁有 WebRTC 協定狀態,這使其極易擴展且對重啟具有彈性。
- 利用現有協定欄位:使用
ufrag進行路由意味著我們不需要在 WebRTC 之外發明新的封裝或標記方式。 - 將信令與媒體解耦:這讓我們能獨立優化兩者的路徑,同時仍能將它們錨定在正確的處理節點上。
即時語音 AI 只有在基礎設施讓延遲變得「隱形」時才有效。對我們來說,這意味著在不改變客戶端對 WebRTC 預期的情況下,改變我們 WebRTC 部署的型態。
作者
Yi Zhang, William McDonald
參考資料
- Discord 如何使用 WebRTC 處理 250 萬同時在線語音用戶(在新視窗中開啟)
- GitHub - l7mp/stunner: 一個用於 WebRTC 的 Kubernetes 媒體閘道器(在新視窗中開啟)
- 簡而言之 WebRTC 連接埠 [範例] - BlogGeek.me(在新視窗中開啟)
- 部署到 Kubernetes - LiveKit 文件(在新視窗中開啟)
- 僅使用單一 UDP 連接埠而非大範圍連接埠進行媒體連接 - mediasoup(在新視窗中開啟)
- Cloudflare Calls:一路向下的數百萬棵級聯樹(在新視窗中開啟)
延伸閱讀

工程 2026 年 4 月 27 日

工程 2026 年 4 月 22 日

工程 2026 年 3 月 11 日
— OpenAI
相關文章