PRODUCT
Realtime API 是 OpenAI 的實(shí)時(shí)語(yǔ)音交互接口,在 24 年的 DevDay 首次亮相,當(dāng)時(shí)還是 beta,調(diào)用貴到離譜,音頻輸出 200 刀/百萬(wàn) token:
兩個(gè)月后新加坡 DevDay,我在現(xiàn)場(chǎng)看了多語(yǔ)言混合輸入輸出的演示,情緒和語(yǔ)氣都非常到位,比 Whisper 鏈路的效果好了一個(gè)量級(jí)
之后經(jīng)歷了 WebRTC 支持、SIP 電話(huà)接入、圖片輸入、多輪調(diào)價(jià),到 2025 年 8 月正式 GA。現(xiàn)在這套系統(tǒng)服務(wù)數(shù)億周活用戶(hù),語(yǔ)音 AI 這條線(xiàn)上,目前沒(méi)有第二家能打的
Realtime API 這個(gè)東西,最牛逼的是延遲:從你對(duì)著手機(jī)說(shuō)一句話(huà)開(kāi)始,到聽(tīng)到 AI 返回聲音為止,只需要不到 0.3 秒
在這個(gè)過(guò)程中,聲音變成數(shù)據(jù)包,穿過(guò) Wi-Fi、運(yùn)營(yíng)商的網(wǎng)絡(luò)、橫跨大半個(gè)互聯(lián)網(wǎng),到達(dá) OpenAI 的服務(wù)器。然后,服務(wù)器跑完推理、生成語(yǔ)音,再原路返回。整個(gè)過(guò)程必須快到讓你感覺(jué)不到延遲,就像跟一個(gè)真人在說(shuō)話(huà)
對(duì)于這玩意兒是怎么實(shí)現(xiàn)的,OpenAI 今天發(fā)了個(gè)技術(shù) Blog,來(lái)詳細(xì)介紹了下
![]()
https://openai.com/index/delivering-low-latency-voice-ai-at-scale/
然后...第二作者,是麥當(dāng)勞
核心信息包括:
→ OpenAI 沒(méi)有用行業(yè)默認(rèn)方案,自己設(shè)計(jì)了relay + transceiver兩層架構(gòu),前者只負(fù)責(zé)轉(zhuǎn)發(fā)數(shù)據(jù)包,后者負(fù)責(zé)所有通話(huà)狀態(tài)
→ relay 極其輕量,不解密、不解碼、不參與任何協(xié)商,只看數(shù)據(jù)包頭部的一小段標(biāo)記就知道往哪兒轉(zhuǎn)
→ 全球各地部署了相同的 relay 入口,用戶(hù)的數(shù)據(jù)包在離自己最近的地方進(jìn)入 OpenAI 的網(wǎng)絡(luò)
→ relay 用 Go 語(yǔ)言寫(xiě)的,沒(méi)有用更底層的高性能方案,因?yàn)閴蛴昧?/p>
→ 整套架構(gòu)跑在 Kubernetes 上,對(duì)外只暴露少量固定端口
技術(shù)方案選型
OpenAI 用的實(shí)時(shí)通信協(xié)議叫WebRTC,就是你平時(shí)微信視頻通話(huà)、Google Meet 開(kāi)會(huì)時(shí)底層跑的那套技術(shù)。它是一個(gè)開(kāi)放標(biāo)準(zhǔn),能在瀏覽器、手機(jī)和服務(wù)器之間傳輸?shù)脱舆t的音頻和視頻
做 WebRTC 服務(wù),行業(yè)里有一個(gè)默認(rèn)選擇叫SFU(選擇性轉(zhuǎn)發(fā)單元)。簡(jiǎn)單說(shuō)就是一個(gè)中轉(zhuǎn)站,每個(gè)參與者跟它建一條連接,它負(fù)責(zé)把聲音和畫(huà)面轉(zhuǎn)發(fā)給其他人。多人視頻會(huì)議用這個(gè)方案很合適,音視頻編解碼、錄制、策略控制都集中管理
![]()
SFU 方案:AI 作為 WebRTC 參與者加入,適合多方通話(huà)
OpenAI 的場(chǎng)景不一樣。絕大多數(shù)會(huì)話(huà)是 1:1,一個(gè)用戶(hù)對(duì)一個(gè)模型,每一輪對(duì)話(huà)都對(duì)延遲極度敏感。SFU 帶來(lái)的多方通話(huà)基礎(chǔ)設(shè)施,在這個(gè)場(chǎng)景里是多余的
他們還評(píng)估過(guò)另一個(gè)常規(guī)方案TURN,這是 WebRTC 穿透防火墻時(shí)常用的中繼方式。但 TURN 要求中繼節(jié)點(diǎn)持有客戶(hù)端的連接分配狀態(tài),不夠輕量
最后選的方案叫 transceiver 模型:在網(wǎng)絡(luò)邊緣部署一個(gè) WebRTC 服務(wù),負(fù)責(zé)跟客戶(hù)端完成連接建立、加密握手這些協(xié)議工作,然后把收到的音頻轉(zhuǎn)成更簡(jiǎn)單的內(nèi)部協(xié)議,分別送給后面的推理、轉(zhuǎn)錄、語(yǔ)音合成服務(wù)。所有通話(huà)狀態(tài)集中在 transceiver 一個(gè)地方,后端的 AI 服務(wù)可以當(dāng)普通服務(wù)來(lái)擴(kuò)展,完全不需要懂 WebRTC
![]()
transceiver 方案:在邊緣終止 WebRTC,轉(zhuǎn)換為后端協(xié)議
端口占用問(wèn)題
選定 transceiver 方案之后,還有一個(gè)工程問(wèn)題要解決:端口占用
傳統(tǒng) WebRTC 部署里,每個(gè)通話(huà)需要占用一個(gè)獨(dú)立的網(wǎng)絡(luò)端口。當(dāng)同時(shí)通話(huà)的用戶(hù)有幾百萬(wàn)個(gè)的時(shí)候,端口會(huì)不夠用。OpenAI 的基礎(chǔ)設(shè)施跑在容器化平臺(tái) Kubernetes 上,沒(méi)法給每個(gè)容器預(yù)留幾千個(gè)公網(wǎng)端口
他們的做法是把數(shù)據(jù)包的「轉(zhuǎn)發(fā)」和「處理」拆成兩層
relay是第一層,部署在面向公網(wǎng)的入口。它是一個(gè)極輕的 UDP 轉(zhuǎn)發(fā)服務(wù):不解密通話(huà)內(nèi)容,不跑任何協(xié)議狀態(tài)機(jī),不參與編解碼協(xié)商,不知道你在說(shuō)什么。它只做一件事,讀取數(shù)據(jù)包頭部的一小段標(biāo)記來(lái)判斷這個(gè)包屬于哪個(gè)會(huì)話(huà),然后轉(zhuǎn)發(fā)給對(duì)應(yīng)的 transceiver
transceiver是第二層,在 relay 后面。它擁有通話(huà)的全部協(xié)議狀態(tài),包括 ICE 連通性檢查、DTLS 加密握手、SRTP 媒體解密,以及會(huì)話(huà)的整個(gè)生命周期。從用戶(hù)的手機(jī)或?yàn)g覽器來(lái)看,通話(huà)行為沒(méi)有任何變化
![]()
relay 只做無(wú)狀態(tài)轉(zhuǎn)發(fā),transceiver 持有完整會(huì)話(huà)狀態(tài)
relay 持有的信息極其精簡(jiǎn):一條內(nèi)存中的轉(zhuǎn)發(fā)映射(這個(gè)客戶(hù)端的包往哪個(gè) transceiver 送),加幾個(gè)監(jiān)控計(jì)數(shù)器和過(guò)期定時(shí)器。沒(méi)有持久化,沒(méi)有協(xié)議參與。如果 relay 重啟了,下一個(gè)數(shù)據(jù)包到達(dá)時(shí)就能自動(dòng)重建路由
解決首響應(yīng)問(wèn)題
Realtime API 最牛逼的地方,是在 0.3 秒內(nèi)完成首響應(yīng),這就需要對(duì)首包進(jìn)行路由管理。用戶(hù)發(fā)出的第一個(gè)數(shù)據(jù)包到達(dá) relay 時(shí),relay 還沒(méi)有任何關(guān)于這個(gè)用戶(hù)的信息,但它必須立刻知道往哪里轉(zhuǎn)發(fā)。在這一步中,如果停下來(lái)查數(shù)據(jù)庫(kù)或者問(wèn)別的服務(wù)都會(huì)增加延遲,是不行的
OpenAI 利用了 WebRTC 協(xié)議自帶的一個(gè)機(jī)制:ICE ufrag(ICE 用戶(hù)名片段)。這是在通話(huà)建立階段雙方交換的一個(gè)短標(biāo)識(shí)符,之后客戶(hù)端發(fā)的每個(gè)連通性檢查包都會(huì)帶上它。OpenAI 在服務(wù)端生成 ufrag 時(shí),把路由需要的信息編碼在了里面
具體流程:通話(huà)建立時(shí),transceiver 分配好會(huì)話(huà)狀態(tài),在協(xié)商應(yīng)答(SDP answer)里返回一個(gè)共享的 relay 虛擬 IP 和 UDP 端口。客戶(hù)端看到的是一個(gè)固定的目標(biāo)地址,比如203.0.113.10:3478,背后其實(shí)是整個(gè) relay 集群
客戶(hù)端發(fā)出的第一個(gè)數(shù)據(jù)包通常是一個(gè) STUN binding request。relay 只解析這個(gè)包頭部的 ufrag 字段,解碼出路由提示,把包轉(zhuǎn)發(fā)給擁有該會(huì)話(huà)的 transceiver。之后這個(gè)客戶(hù)端的所有后續(xù)包都走同一條已建立的路
![]()
從連接建立到媒體傳輸?shù)耐暾麜r(shí)序:Client → LB → Relay → Transceiver
容災(zāi)方面,Redis 緩存了「客戶(hù)端 IP:Port → transceiver IP:Port」的映射。relay 重啟后可以在下一個(gè) STUN 包到來(lái)之前就從 Redis 恢復(fù)轉(zhuǎn)發(fā)路徑,進(jìn)一步縮短中斷窗口
進(jìn)行全球部署
如果用戶(hù)在北京說(shuō)一句話(huà),如果數(shù)據(jù)包要跑到美國(guó)西海岸才開(kāi)始處理,單程網(wǎng)絡(luò)延遲就可能超過(guò) 150 毫秒,一來(lái)一回 300 毫秒。對(duì)話(huà)體驗(yàn)會(huì)明顯卡頓。解決辦法是讓數(shù)據(jù)包盡早進(jìn)入 OpenAI 自己的高速網(wǎng)絡(luò)
relay 的公網(wǎng)暴露面縮到少量固定地址和端口之后,同一套轉(zhuǎn)發(fā)邏輯就能在全球各地復(fù)制部署。OpenAI 把這個(gè)叫Global Relay,一組地理分布式的 relay 入口點(diǎn),都運(yùn)行相同的包轉(zhuǎn)發(fā)行為
![]()
Global Relay 接收全球客戶(hù)端的數(shù)據(jù)包,轉(zhuǎn)發(fā)給 transceiver 集群
用戶(hù)的數(shù)據(jù)包在離自己最近的入口進(jìn)入 OpenAI 網(wǎng)絡(luò),然后通過(guò)內(nèi)部骨干網(wǎng)到達(dá) transceiver。跟直接穿越公網(wǎng)相比,延遲更低,抖動(dòng)更小,丟包更少
整套架構(gòu)跑在 Kubernetes 上不需要暴露成千上萬(wàn)個(gè) UDP 端口。更小且固定的暴露面更容易做安全策略和負(fù)載均衡,擴(kuò)展時(shí)也不需要預(yù)留大段公網(wǎng)端口范圍
底層是 Go 寫(xiě)的
做實(shí)時(shí)媒體轉(zhuǎn)發(fā),常規(guī)選擇是 C/C++ 或者 Rust,有些追求極致的團(tuán)隊(duì)甚至?xí)?kernel bypass,繞過(guò)操作系統(tǒng)內(nèi)核讓程序直接操作網(wǎng)卡。OpenAI 的 relay 用 Go 寫(xiě),這在行業(yè)里算非常規(guī)
他們?cè)?Go 運(yùn)行時(shí)層面做了幾個(gè)針對(duì)性?xún)?yōu)化:
→SO_REUSEPORT讓同一臺(tái)機(jī)器上多個(gè) relay 進(jìn)程共享同一個(gè) UDP 端口,操作系統(tǒng)內(nèi)核在它們之間分配數(shù)據(jù)包,避免單一進(jìn)程成為瓶頸
→runtime.LockOSThread把每個(gè)負(fù)責(zé)讀 UDP 數(shù)據(jù)的 goroutine 釘在一個(gè)固定線(xiàn)程上,配合 SO_REUSEPORT,同一個(gè)通話(huà)的包傾向于落在同一個(gè) CPU 核心,緩存命中率更高
→ 預(yù)分配內(nèi)存緩沖區(qū),最小化數(shù)據(jù)拷貝,避免在轉(zhuǎn)發(fā)熱路徑上觸發(fā) Go 的垃圾回收
這套實(shí)現(xiàn)撐住了全球的實(shí)時(shí)媒體流量,relay 集群規(guī)模相對(duì)不大。所以他們沒(méi)有進(jìn)一步走 kernel bypass 路線(xiàn)
補(bǔ)充一個(gè)細(xì)節(jié):OpenAI 使用了Pion,一個(gè) Go 語(yǔ)言的 WebRTC 開(kāi)源庫(kù)。Pion 的作者 Sean Der 在 Hacker News 上確認(rèn)了這一點(diǎn)
三條設(shè)計(jì)原則
對(duì)于這個(gè)項(xiàng)目,OpenAI 在總結(jié)了三條原則,對(duì)任何做實(shí)時(shí)系統(tǒng)的團(tuán)隊(duì)都有參考價(jià)值:
→硬性狀態(tài)集中在一個(gè)地方transceiver 擁有 ICE、DTLS、SRTP 和會(huì)話(huà)生命周期,relay 只轉(zhuǎn)發(fā)。狀態(tài)集中意味著出了問(wèn)題只查一個(gè)地方
→在已有信息上做路由ICE ufrag 是協(xié)議自帶的標(biāo)識(shí)符,把路由信息編碼在里面,首包到達(dá)時(shí)就能路由,不需要在熱路徑上加外部查詢(xún)
→夠用就不換Go 配合幾個(gè)內(nèi)核級(jí)優(yōu)化對(duì)當(dāng)前負(fù)載已經(jīng)夠用,就沒(méi)有上 kernel bypass。先跑起來(lái),再?zèng)Q定要不要換更重的方案
實(shí)時(shí)語(yǔ)音 AI 能跑起來(lái),靠的是基礎(chǔ)設(shè)施讓延遲變得感知不到
OpenAI 改變的是 WebRTC 部署的內(nèi)部形態(tài),但沒(méi)有改變客戶(hù)端對(duì) WebRTC 協(xié)議的預(yù)期
openai.com/index/delivering-low-latency-voice-ai-at-scale
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶(hù)上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.