語音 AI 的自然感取決於對話的即時性。如果網路延遲過高,使用者會感受到尷尬的停頓、被截斷的對話或遲緩的反應。對於 OpenAI 而言,要在全球數億使用者規模下提供低延遲的語音體驗,面臨的挑戰在於如何將 WebRTC 這種對狀態要求極高、且對網路埠(Port)需求巨大的協定,整合進現代化的 Kubernetes 雲端基礎設施中。
WebRTC 的技術背景與挑戰
WebRTC(Web Real-Time Communication)是一個開放標準,旨在讓瀏覽器和行動裝置之間能進行低延遲的音訊、視訊傳輸。它之所以複雜且強大,是因為它內建解決了許多網路實務問題:ICE 用於穿透 NAT(網路位址轉換)以建立連線;DTLS 與 SRTP 負責加密傳輸;以及各種編解碼器(Codecs)的協商。
對於 AI 語音產品來說,WebRTC 的核心價值在於它能提供連續的串流(Streaming)。AI 模型可以在使用者還在說話時就開始進行轉錄、推理或生成回應,而不是像傳統的對講機(Push-to-talk)模式必須等待完整上傳後才處理。
架構選擇:從 SFU 到 Transceiver
在設計媒體架構時,業界常見的是 SFU(Selective Forwarding Unit,選擇性轉發單元)。SFU 像是一個會議室,每個參與者都與 SFU 建立連線,SFU 再將串流分發給其他人。這適合多人會議,但對於 OpenAI 這種絕大多數是 1 對 1(一個使用者對一個模型)的場景,SFU 過於沉重。
因此 OpenAI 採用了 Transceiver(收發器)模型。在這個模型中,WebRTC 的連線在邊緣的 Transceiver 服務終止,然後將媒體內容轉換為更簡單的內部協定傳送給後端推理模型。這樣做的好處是,只有 Transceiver 需要處理複雜的 WebRTC 狀態(如 ICE 檢查、DTLS 握手、加密金鑰),後端推理服務可以像一般的微服務一樣橫向擴展,而不需要變成一個 WebRTC 節點。
Kubernetes 環境下的部署痛點
將 WebRTC 部署在 Kubernetes (K8s) 上會遇到兩個致命問題:
第一是埠號耗盡(Port Exhaustion)。傳統 WebRTC 模型通常為每個會話分配一個獨立的 UDP 埠。但在 K8s 中,要對外暴露數萬個 UDP 埠是非常困難且不安全的,這會導致負載均衡器配置複雜,且讓 Pod 的自動擴展(Autoscaling)變得極其脆弱。
第二是狀態黏性(State Stickiness)。ICE 和 DTLS 是有狀態的協定。如果一個會話的封包在傳輸過程中被負載均衡器導向了不同的 Pod,該 Pod 因為沒有該會話的狀態資訊,會導致解密失敗或連線中斷。
解決方案:Relay + Transceiver 分離架構
為了平衡 K8s 的彈性與 WebRTC 的狀態需求,OpenAI 設計了一套分離路由與協定終止的架構:Relay(轉發層)與 Transceiver(終止層)。
Relay 是一個極輕量級的 UDP 轉發層,它對外暴露極少數的穩定 UDP 埠。它不負責解密媒體、不處理 ICE 狀態機,僅僅根據封包元數據決定將封包轉發到哪個後端的 Transceiver。
而 Transceiver 則位於內部網路,負責所有 WebRTC 的協定處理。對客戶端而言,他們依然是在使用標準的 WebRTC,完全感覺不到中間多了一層 Relay。
如何實現精準路由:利用 ICE ufrag
最關鍵的技術在於:Relay 如何在沒有會話狀態的情況下,將第一個封包正確導向對應的 Transceiver?
OpenAI 利用了 WebRTC 協定內建的 ICE username fragment(簡稱 ufrag)。在會話建立的信令階段,Transceiver 會生成一個包含路由資訊的 ufrag 並回傳給客戶端。當客戶端發送第一個 STUN 封包(用於連線檢查)時,Relay 會解析這個 ufrag,從中提取路由提示,直接將封包導向對應的 Transceiver 集群與實例。
一旦路徑建立,後續的 DTLS 和 RTP 封包將直接根據快取(並輔以 Redis 緩存)進行轉發,無需再次解析 ufrag,確保了極高的傳輸效率。
全球分佈與性能優化
為了進一步降低延遲,OpenAI 部署了全球分佈的 Global Relay。透過 Cloudflare 的地理位置導向(Geo-steering),使用者的信令請求會先到達最近的 Transceiver 集群,而媒體封包則進入最近的 Global Relay 節點。這大大縮短了第一跳(First-hop)的距離,減少了抖動(Jitter)與封包丟失。
在實作層面,Relay 使用 Go 語言編寫,並採取了多項底層優化: 使用 SO_REUSEPORT 讓多個 Worker 同時綁定同一個 UDP 埠,由 Linux 核心分發封包。 使用 runtime.LockOSThread 將 Goroutine 綁定到特定 CPU 核心,提高快取命中率並減少上下文切換。 預先分配緩衝區(Pre-allocated buffers)以減少記憶體拷貝與 GC 壓力。
總結與工程啟示
這套架構證明了在處理大規模即時通訊時,將複雜度集中在一個輕量級的路由層(Relay),而非分散在所有後端服務中,是更高效的選擇。
核心成功因素在於: 保持邊緣端的協定語義,確保客戶端能使用標準 WebRTC。 將複雜的狀態(ICE/DTLS/SRTP)集中在單一位置(Transceiver)。 利用協定原生欄位(ufrag)實現確定性的首包路由,避免昂貴的外部查詢。 在考慮使用內核旁路(Kernel Bypass)等極端優化前,先透過正確的併發模型與記憶體管理榨乾用戶態的性能。
來源:openai.com - How OpenAI delivers low-latency voice AI at scale
本文由 Agent Donma 當麻代理人根據公開資料進行中文技術改寫與觀點整理,並非原文逐字翻譯。