選自latent.space作者:Kwindla Hultman Kramer等機(jī)器之心編譯機(jī)器之心編輯部OpenAI Realtime API 的「說明書」。
很多研究 ChatGPT 的人,在使用后不久就會開始搗鼓 ChatGPT API。它是 OpenAI 提供的開放程序接口,讓開發(fā)者可以把業(yè)界最先進(jìn)的大模型引入到自己的產(chǎn)品中,構(gòu)建聊天機(jī)器人、虛擬助手等等。近一年來,依靠這套工具打造的熱門 App 已有不少。Realme API 是 OpenAI 最新發(fā)布的 API 能力,它在今年 10 月 1 日推出,可幫助開發(fā)人員構(gòu)建快速語音轉(zhuǎn)語音的智能化體驗。近日,在 OpenAI DevDay 新加坡站,來自 Daily.co 的工程師受邀演講,介紹了基于 OpenAI 的能力構(gòu)建語音 AI 智能體的方法。一直以來,該公司的工程師們一直在使用實時 API 搭建產(chǎn)品。在活動之后,演講人發(fā)布了本篇博客,談了談構(gòu)建 Pipecat 時的經(jīng)驗教訓(xùn)。
博客地址:https://www.latent.space/p/realtime-api本篇博客的內(nèi)容已通過 OpenAI 員工審核。Pipecat 是由 Daily 發(fā)起的開源項目,現(xiàn)在是一個實時 API 框架。
鏈接:https://pipecat.ai對于想要構(gòu)建大模型語音產(chǎn)品的人們來說,這篇內(nèi)容可能包含你所需要的一切,從 24khz/G.711 音頻、RTMP、HLS、WebRTC 的技術(shù)細(xì)節(jié)到中斷 / VAD,再到成本、延遲、工具調(diào)用和上下文管理。讓我們看看他們是怎么說的。(以下為博客原文,機(jī)器之心做了不改變原意的編譯、整理。)首先,我們愿意分享一些在使用原始實時 API(無框架、無外部依賴)時積累的心得,特別是在準(zhǔn)備新加坡 DevDay 演講的過程中。標(biāo)準(zhǔn)的 OpenAI 參考應(yīng)用包含了許多內(nèi)置功能,我們盡量精簡這些功能,專注于語音活動檢測(VAD)和函數(shù)調(diào)用,從而打造了一個「簡易實時控制臺」演示。
實際上,語音活動檢測(VAD)并不總是完美無缺,而且演示語音應(yīng)用時很少能在完全安靜的環(huán)境下進(jìn)行。因此,我們建議在演示中始終配備「靜音」和「強(qiáng)制回復(fù)」按鈕,正如我們的演示所示。此外,該演示還展示了如何簡單添加和插入記憶,以及如何展示對話雙方的記錄。從 Pipeline到端到端模型在我的大部分職業(yè)生涯中,我都在研究人與人之間對話的網(wǎng)絡(luò)基礎(chǔ)設(shè)施 用于構(gòu)建低延遲媒體流、視頻通話和大數(shù)據(jù)協(xié)作環(huán)境等的工具。2023 年 3 月,GPT-4 還是一個純文本模型。但為 GPT-4 開發(fā)語音模式相對容易。我整合了一個語音轉(zhuǎn)文本系統(tǒng),將語音輸入轉(zhuǎn)換成文本提示,然后將 GPT-4 的文本輸出送入一個文本轉(zhuǎn)語音的音頻生成器中。
[語音輸入] [ ASR ] [ GPT4 ] [ TTS ] [語音輸出] 內(nèi)容來自 DevDay Realtime API Talk:https://www.youtube.com/watch?v=mVR90WmA34U這種多模型 pipeline 方法并不新鮮。我們撥打電話客戶支持熱線時使用的「自然語言處理」系統(tǒng)就是這樣工作的。新方法是 pipeline 核心的 GPT-4 大型語言模型。你可以用 GPT-4 進(jìn)行真正的對話。很明顯,那些較舊的 NLP 系統(tǒng)已經(jīng)過時了。但顯然,新的挑戰(zhàn)也已出現(xiàn)。這個系統(tǒng)的延遲很長。GPT-4 需要一秒鐘左右才能開始生成響應(yīng)。STT 和 TTS 模型又增加了一兩秒鐘。有時 GPT-4 會偏離軌道。弄清楚如何檢測這個問題,并把問題出現(xiàn)的幾率降到最低,似乎是一件相當(dāng)困難的事情。一些經(jīng)典的 NLP 問題仍然存在,例如句尾端點(弄清楚 LLM 應(yīng)該何時響應(yīng))和中斷處理。GPT-4 擅長對話,但沒有很好的方法與現(xiàn)有的后端系統(tǒng)集成。現(xiàn)有 TTS 模型的語音輸出質(zhì)量,一聽就知道是機(jī)器人聲。自 GPT-4 發(fā)布以來的 20 個月里,人工智能提升的速度令人驚嘆。當(dāng)前版本的 GPT-4 擅長遵循提示、專注于任務(wù)并減少了幻覺。函數(shù)調(diào)用和結(jié)構(gòu)化數(shù)據(jù)輸出是可靠的。模型響應(yīng)迅速,我們擁有快速、價格合理且質(zhì)量相當(dāng)高的 TTS 模型。最新的 GPT-4 功能是原生音頻輸入和輸出。GPT-4升級版的 GPT-4o現(xiàn)在有了自己的聲音和耳朵!實時 API10 月 1 日,OpenAI 發(fā)布了一款低延遲、多模態(tài) API,該 AP 利用了 GPT-4o 出色的「語音到語音」功能。這個新的「實時 API」能夠管理對話狀態(tài)、實現(xiàn)短語端點(輪流檢測)、提供雙向音頻流,并支持用戶中斷 LLM 的輸出。使用此 API,最簡單的處理 pipeline 如下所示:
[ 語音輸入 ] [ GPT-4o ] [ 語音輸出 ]我一直在幫助客戶、朋友和與我一起在開源項目上工作的人們使用 OpenAI Realtime API。使用這個新 API 與使用 OpenAI HTTP 推理 API 完全不同。新的 Realtime API 是有狀態(tài)的。它在 WebSocket 連接之上定義了一個雙向事件協(xié)議。最近,我寫了關(guān)于 Realtime API 的優(yōu)點、我認(rèn)為還需要一篇博客來講如何有效使用 Realtime API 。無論你是工程師還是開發(fā)者,都希望能從這篇博客找到一些有用的背景信息、代碼片段,和可以節(jié)省你時間的具體細(xì)節(jié)。在適當(dāng)?shù)牡胤剑視峁╂溄拥?Pipecat 的源代碼和示例。Pipecat 是一個開源的、供應(yīng)商中立的 Python 框架,專為實時、多模式 AI 代理和應(yīng)用程序設(shè)計。它支持 GPT-4o 及其實時版本,以及超過 40 種其他 AI API 和服務(wù),還涵蓋了多種網(wǎng)絡(luò)傳輸選項,包括 WebSockets、WebRTC、HTTP、SIP 以及 PSTN / 撥入 / 撥出等。Pipecat 還附帶一個大型核心功能庫,用于上下文管理、內(nèi)容審核、用戶狀態(tài)管理、事件處理、腳本跟蹤以及語音(和視頻)代理的其他重要構(gòu)建塊。
完整的 Pipecat OpenAI Realtime API 集成在這里:https://github.com/pipecat-ai/pipecat/tree/main/src/pipecat/services/openai_realtime_beta
這是一個使用 Realtime API 的單文件示例語音機(jī)器人:https://github.com/pipecat-ai/pipecat/blob/main/examples/foundational/19-openai-realtime-beta.py
OpenAI 實時 API 的架構(gòu)對話語音是 OpenAI 實時 API 支持的核心用例。對話語音 API 需要:
管理多個用戶和 LLM 輪次的對話狀態(tài);
確定用戶何時結(jié)束對話(并期待 LLM 的響應(yīng));
處理用戶中斷 LLM 輸出;
用戶語音的文本轉(zhuǎn)錄、函數(shù)調(diào)用和 LLM 上下文的操作對于許多用例也很重要。
OpenAI 的實時 API 通過定義一系列通過 WebSocket 連接發(fā)送和接收的事件來實現(xiàn)這些功能。該 API 包括 9 種客戶端事件(從客戶端發(fā)送到服務(wù)器的事件)和 28 種服務(wù)器事件(從服務(wù)器發(fā)送到客戶端的事件)。以下是所有 37 個事件的 Pydantic 事件定義:
https://github.com/pipecat-ai/pipecat/blob/main/src/pipecat/services/openai_realtime_beta/events.py這個事件結(jié)構(gòu)有很多優(yōu)點。Python 中包括所有導(dǎo)入和 asyncio 樣板的最小命令行客戶端大約只有 75 行代碼。
https://x.com/kwindla/status/1843118281911308355音頻以 base64 編碼塊的形式發(fā)送和接收,嵌入在 input_audio_buffer.append 和 audio.delta 事件中。API 當(dāng)前支持未壓縮的 16 位、24khz 音頻和壓縮的 G.711 音頻。
G.711 僅用于電話用例;與其他更現(xiàn)代的編解碼器選項相比,音頻質(zhì)量相對較差。
未壓縮的 16 位、24khz 音頻的比特率為 384 千比特 / 秒。base64 編碼開銷將標(biāo)稱比特率推高至約 500 kbs。但 permessage-deflate 標(biāo)準(zhǔn)壓縮將使比特率降至 300-400 kbs。
如果你關(guān)心的是實現(xiàn)實時延遲,那么 300kbs 的媒體流比人們通常希望通過 WebSocket 連接發(fā)送的媒體流要大。我們在后文也會談?wù)勓舆t和 WebSockets。
延遲人類希望在正常對話中得到快速響應(yīng),對話的響應(yīng)時間為 500 毫秒是正常的,AI 長時間的停頓會讓人感覺不自然。所以如果你正在構(gòu)建對話式 AI 應(yīng)用程序,語音到語音的延遲大概是 800 毫秒。盡管當(dāng)今的 LLM 很難始終如一地實現(xiàn)這一點。OpenAI Realtime API 提供了非常好的推理延遲效果。對于位于美國的客戶,API 的第一個字節(jié)時間約為 500 毫秒。如果我們的目標(biāo)是總語音到語音延遲為 800 毫秒,那么音頻處理和短語端點大約需要 300 毫秒。在理想條件下,這幾乎是一項不可能完成的任務(wù)。測量語音到語音延遲的過程十分簡單。你只需錄制對話,將錄音導(dǎo)入音頻編輯軟件,觀察音頻波形,并測量從用戶語音結(jié)束到 LLM 語音輸出開始之間的時間。如果你正在開發(fā)打算實際投產(chǎn)的對話式語音應(yīng)用,定期監(jiān)控延遲數(shù)據(jù)是非常重要的。在這些測試中加入模擬網(wǎng)絡(luò)數(shù)據(jù)包丟失和抖動的功能,將會加分。以編程方式測量真正的語音到語音延遲具有挑戰(zhàn)性,因為部分延遲發(fā)生在操作系統(tǒng)內(nèi)部深處。因此,大多數(shù)可觀察性工具僅測量推理到第一個字節(jié)的時間。這是總語音到語音延遲的合理代理,但請注意,此測量不包括短語端點時間(請參閱下一節(jié))。許多「小」事情可能會引發(fā)延遲的「蝴蝶效應(yīng)」。例如,藍(lán)牙音頻設(shè)備可能會增加幾百毫秒的延遲。有關(guān)導(dǎo)致在 Web 瀏覽器中運行的語音到語音應(yīng)用程序中延遲的所有因素的更多詳細(xì)信息,請參閱此推文、博客以及 AI.Engineer 的演講:推文鏈接:https://x.com/kwindla/status/1806129490411900940
博客鏈接:https://www.daily.co/blog/the-worlds-fastest-voice-bot/
句尾檢測與打斷在對話中,人們會輪流說話。在語音 AI 應(yīng)用中,對話雙方絲滑地切換回合需要做到兩部分:
應(yīng)用判斷人類是否已經(jīng)說完,開始期待系統(tǒng)的響應(yīng)。這被稱為短語終點檢測或回合檢測(turn detection)。大多數(shù)應(yīng)用都會嘗試自動檢測一個回合結(jié)束了,但有些應(yīng)用會在界面上設(shè)置按鈕,用戶按住按鈕才能說話,松開按鈕表示說話結(jié)束。
如果用戶在 LLM 說話時打斷了它,一般來說,系統(tǒng)應(yīng)該立即停止播放 LLM 的語音輸出。然而,對于一些應(yīng)用場景,這種行為需要是可配置的:有時候,即使用戶打斷了 LLM,也希望 LLM 能把話說完。
OpenAI 實時 API 內(nèi)置了自動句尾檢測和處理打斷的功能。這些功能由 VAD(Voice Activity Detection)實現(xiàn)。自動輪次檢測默認(rèn)是開啟的,但可以隨時關(guān)閉。以下是 OpenAI 關(guān)于自動輪次檢測的文檔鏈接:
https://platform.openai.com/docs/guides/realtime/realtime-api-beta#input-audio-buffer有多種 VAD 參數(shù)可配置,其中最重要的是 silence_duration_ms,即用戶停止說話后,VAD 等待的時間長度(以毫秒為單位)。在這段時間后,會觸發(fā) input_audio_buffer.speech_stopped 事件并開始推理。OpenAI 在服務(wù)器端維護(hù)了一個音頻緩沖區(qū),應(yīng)用程序可以通過發(fā)送 input_audio_buffer.append 事件持續(xù)地添加音頻幀。在自動輪次檢測模式下,應(yīng)用程序只需持續(xù)發(fā)送音頻數(shù)據(jù),依靠 OpenAI 服務(wù)器端的 VAD 來識別用戶何時開始和停止說話。當(dāng)用戶停止說話時,會觸發(fā)多個 API 事件,LLM 隨即開始生成響應(yīng)。若用戶再次開始說話,任何正在進(jìn)行的響應(yīng)將被中斷,音頻輸出也會被清除。這種方法非常簡單高效(無需編寫任何客戶端代碼),并且效果顯著。然而,在以下三種情況下,應(yīng)用可能會選擇關(guān)閉 OpenAI 的自動輪次檢測功能:
不希望允許應(yīng)用被打斷時
像微信一樣「按鍵說話」樣式的用戶界面
開發(fā)者使用其他句尾檢測方法
禁用 OpenAI 的自動輪次檢測功能后,客戶端需在用戶語音回合結(jié)束時發(fā)送兩個 Realtime API 事件:input_audio_buffer.commit 和 response.create。以下是在用戶開始說話時,如何調(diào)用這兩個事件的 Pipecat 代碼示例:
https://github.com/pipecat-ai/pipecat/blob/main/src/pipecat/services/openai_realtime_beta/openai.py#L145OpenAI VAD 似乎比 Pipecat 中的默認(rèn)短語端點實現(xiàn)對背景噪音更敏感。Pipecat 使用輸入音頻能量的平滑運行平均值來相對于背景噪音自動調(diào)平。它還會忽略音頻中的短尖峰,即使它們具有相當(dāng)高的語音置信度,并支持高級音頻處理。OpenAI 的 silence_duration_ms 參數(shù)默認(rèn)為 500ms,Pipecat 將這個參數(shù)稱為 stop_secs。這是一個很好的折衷方案,介于 LLM 響應(yīng)時間過長和 LLM 響應(yīng)過快之間。對于某些用例,最好選擇較長的靜音持續(xù)時間。例如,在工作面試環(huán)境中,讓人們在談話時有更多時間思考他們的答案通常會提供更好的體驗。在這種情況下,800ms 甚至 1s 都是理想的。使用標(biāo)準(zhǔn) VAD 時,除了語音 AI 演示之外,我們通常不建議將設(shè)置設(shè)置為低于 500 毫秒!有一些技術(shù)可以通過使用上下文感知短語端點來補(bǔ)充標(biāo)準(zhǔn) VAD,或進(jìn)行推測(貪婪)推理,或兩者兼而有之,從而獲得更快的響應(yīng)時間。這些技術(shù)超出了本文的范圍,但如果您對它們感興趣,Pipecat Discord 是一個閑逛的好地方。Pipecat 的基本 VAD 實現(xiàn)在這里:
https://github.com/pipecat-ai/pipecat/blob/1d4be0139aeff2ee8cc214c81ae00e5948e35977/src/pipecat/audio/vad/vad_analyzer.py#L86管理上下文多輪對話是一系列用戶輸入和 LLM 響應(yīng)。LLM 本身是無狀態(tài)的,因此每次有用戶輸入時,都需要將所有相關(guān)對話歷史記錄發(fā)送到 LLM。如果你之前構(gòu)建過對話式 LLM 應(yīng)用程序(文本或語音),你會熟悉跟蹤對話歷史記錄并使用該歷史記錄創(chuàng)建不斷增加的「上下文」。OpenAI Realtime API 為你進(jìn)行對話管理,有兩個巨大的好處:更簡單的代碼和更低的延遲。代碼更簡單,因為你不必跟蹤應(yīng)用程序中的對話歷史記錄。延遲較低有幾個原因。每次你希望 LLM 生成響應(yīng)時,不必重新發(fā)送大型上下文。這節(jié)省了一些網(wǎng)絡(luò)開銷。此外,當(dāng)前的音頻輸入可以流式傳輸?shù)?OpenAI 服務(wù)器,以便在請求推理時立即使用。最后,OpenAI 可以實現(xiàn)上下文緩存等內(nèi)部優(yōu)化。這一切帶來一次巨大的勝利!有兩個限制需要注意:最大上下文長度為 128000 tokens,單個對話的最大時間為 15 分鐘。在音頻對話中,你不太可能遇到 token 限制。音頻每分鐘使用大約 800 tokens。然而,15 分鐘時長對于某些應(yīng)用程序可能是一個限制。目前無法通過 OpenAI Realtime API 檢索對話上下文、將「助手」音頻消息加載到上下文中或可靠地加載多消息歷史記錄。參閱此存儲庫以獲取測試用例:https://github.com/kwindla/openai-realtime-test-cases
不過,實現(xiàn)持久對話和長時間對話是可能的。你需要將對話歷史記錄保存為文本。然后,在重新啟動對話時,發(fā)送完整的對話歷史記錄(和適當(dāng)?shù)奶崾荆┳鳛樾聦υ捴械牡谝粭l消息。以下是 Pipecat 代碼,它使用 OpenAI HTTP API 支持的相同消息列表格式來初始化對話:
https://github.com/pipecat-ai/pipecat/blob/main/src/pipecat/services/openai_realtime_beta/context.py#L76關(guān)于上下文管理的其他一些事情也值得討論。LLM 的音頻生成速度比語音輸出速度更快。OpenAI 將服務(wù)器端 LLM 響應(yīng)添加到對話上下文中,速度與生成的速度一樣快。但講話的播放速度較慢。如果用戶中斷 LLM,則用戶將只能聽到 LLM 響應(yīng)的一部分。在大多數(shù)情況下,您希望對話歷史記錄僅包含用戶實際聽到的 LLM 響應(yīng)部分。您需要發(fā)送對話.item.truncate 事件以強(qiáng)制服務(wù)器端上下文匹配用戶聽到的音頻范圍。請注意,無論您是否使用自動轉(zhuǎn)彎檢測 (server_vad),您都需要執(zhí)行此操作。以下是 Pipecat 代碼,用于計算用戶聽到的音頻的持續(xù)時間并調(diào)用對話.item.truncate:
https://github.com/pipecat-ai/pipecat/blob/main/src/pipecat/services/openai_realtime_beta/context.py#L49對于許多用例來說,用戶輸入和 LLM 輸出的轉(zhuǎn)錄都很重要。保存對話以便用戶稍后可以返回就是一個例子。許多企業(yè)用例需要對話記錄來滿足內(nèi)容審核、后處理需求或合規(guī)性原因。OpenAI Realtime API 始終提供 LLM 輸出的轉(zhuǎn)錄。輸入轉(zhuǎn)錄默認(rèn)關(guān)閉,但可以通過在配置會話時設(shè)置 input_audio_transcription 字段來啟用。輸出轉(zhuǎn)錄由 LLM 本地生成,與音頻輸出緊密匹配。輸入轉(zhuǎn)錄由單獨的模型生成,并不總是與模型 “聽到” 的內(nèi)容匹配。對于某些用例來說,這可能是一個問題。如果轉(zhuǎn)錄數(shù)據(jù)包含語言字段,這也會很有用。(許多語音人工智能用例都是多語言的。)目前還沒有辦法將輸出轉(zhuǎn)錄與語音定時對齊。這使得當(dāng)用戶中斷時很難截斷文本輸出,并且很難構(gòu)建諸如單詞精確的流文本字幕之類的東西。輸入音頻轉(zhuǎn)錄也可能落后于模型輸出幾秒鐘。如果您需要使用轉(zhuǎn)錄進(jìn)行內(nèi)容審核,您可能需要使用您自己的轉(zhuǎn)錄模型和門短語終結(jié)于轉(zhuǎn)錄完成或內(nèi)容審核檢查本身之后。最后,請注意 Realtime API 消息的內(nèi)容格式與 OpenAI HTTP API 的格式不同。以下是從 HTTP API 格式轉(zhuǎn)換為 Realtime API 格式的 Pipecat 代碼:
函數(shù)調(diào)用函數(shù)調(diào)用在 OpenAI Realtime API 中運行得非常好(所有 GPT-4 系列模型都是如此)。
與對話消息的格式一樣,工具格式與 OpenAI HTTP API 略有不同。
此 HTTP API 工具列表(只有一個條目):
tools = [ { "type": "function", "function": { "name": "get_current_weather", "description": "Get the current weather in a given location", "parameters": { "type": "object", "properties": { "location": { "type": "string", "description": "The city and state, e.g. San Francisco, CA", }, }, "required": ["location"], } } }]成為實時 API 中的工具列表:
tools = [ { "type": "function", "name": "get_current_weather", "description": "Get the current weather", "parameters": { "type": "object", "properties": { "location": { "type": "string", "description": "The city and state, e.g. San Francisco, CA", }, "format": { "type": "string", "enum": ["celsius", "fahrenheit"], "description": "The temperature unit to use. Infer this from the users location.", }, }, "required": ["location", "format"], }, }]可以通過兩種方式從 API 獲取函數(shù)調(diào)用事件:
通過流事件 response.function_call_arguments.delta 和 function_call_arguments.done
作為 response.done 事件的一部分
如果您從 HTTP API 進(jìn)行移植并希望保留盡可能多的現(xiàn)有代碼結(jié)構(gòu),則流事件可能會很有用。但令人高興的是,Realtime API 使得從 response.done 事件中提取函數(shù)調(diào)用結(jié)構(gòu)變得非常簡單。流對于函數(shù)調(diào)用來說并不是很有用 在調(diào)用函數(shù)之前,您需要完整的函數(shù)調(diào)用結(jié)構(gòu) 并且在使用 HTTP API 時,從流式響應(yīng)塊中組裝函數(shù)調(diào)用數(shù)據(jù)一直是一個小麻煩。下面是從 response.done 事件的輸出字段中提取函數(shù)調(diào)用信息的 Pipecat 代碼:https://github.com/pipecat-ai/pipecat/blob/main/src/pipecat/services/openai_realtime_beta/openai.py#L469成本對話式 AI 的使用場景,成本通常會隨著會話長度呈指數(shù)增長。大多數(shù)對話式 AI 應(yīng)用和 API 都會在每次推理請求中使用完整的會話歷史,OpenAI 實時 API 也不例外。不過,OpenAI 實時 API 能夠自動緩存并重復(fù)利用已發(fā)送的輸入 tokens。緩存的音頻 tokens 成本比非緩存的低 80%,在長對話中這可以大幅降低成本。一般的對話成本:
- 1 minute $0.11 - 2 minutes - $0.26 - 5 minutes - $0.92 - 10 minutes - $2.68 - 15 minutes - $5.28OpenAI 不會為接近靜音的音頻輸入生成 tokens。成本估算基于假設(shè)對話中 70% 的時間是用戶實際說話的時間。如果實際說話時間比例更低,成本會相應(yīng)降低。預(yù)計 OpenAI 會持續(xù)降低實時 API 的成本。但如果你的預(yù)算緊張,可以考慮每隔幾輪對話重置上下文,用文本替換音頻消息,也可以使用摘要功能進(jìn)一步減少輸入 tokens 的數(shù)量。以下是一個成本計算器表格,你可以調(diào)整其中的參數(shù)算一算輸入 token 的成本:https://docs.google.com/spreadsheets/d/1EL-mjqlmj4ehug8BjmgmAFm9uFZtZXY9N9EvqLm8Ebc/edit?usp=sharingWebSockets 還是 WebRTC?OpenAI 實時 API 使用 WebSockets 進(jìn)行網(wǎng)絡(luò)傳輸。WebSockets 非常適合用于服務(wù)器之間的通信,尤其是在對延遲要求不高的場景中,以及在原型開發(fā)和一般性開發(fā)測試中。如果你正在開發(fā)一個基于 OpenAI 實時 API 的瀏覽器或原生移動應(yīng)用,并且對會話延遲有嚴(yán)格要求,建議使用 WebRTC 連接。具體來說,用 WebRTC 將音頻從你的應(yīng)用發(fā)送到服務(wù)器,接收音頻,然后在服務(wù)器端直接調(diào)用 OpenAI 實時 API。Pipecat 支持 WebRTC、WebSockets 和 HTTP 傳輸,可以輕松構(gòu)建「客戶端」「服務(wù)器」 [推理服務(wù)器] 的架構(gòu)。但對于生產(chǎn)環(huán)境中的客戶端 服務(wù)器實時媒體連接,不推薦使用 WebSockets。理由如下:WebSockets 基于 TCP 協(xié)議,因此音頻流會遇到「首阻塞問題」。如果某個數(shù)據(jù)包延遲,后續(xù)的數(shù)據(jù)包也會被阻塞。此外,TCP 協(xié)議會嘗試重新發(fā)送丟失的數(shù)據(jù)包,但在實時場景中,如果這些數(shù)據(jù)包到達(dá)時已經(jīng)過期,就毫無意義,還可能進(jìn)一步增加延遲。用 WebRTC 就可以解決這些問題。首先,WebRTC 使用的 Opus 音頻編解碼器與 WebRTC 的帶寬估算和數(shù)據(jù)包調(diào)度(擁塞控制)邏輯緊密結(jié)合。這使得 WebRTC 音頻流能夠很好地適應(yīng)各種現(xiàn)實網(wǎng)絡(luò)環(huán)境。Opus 音頻編解碼器具有非常優(yōu)秀的前向糾錯能力,能有效處理音頻流中的丟包問題,保持音頻穩(wěn)定,(不過,這需要網(wǎng)絡(luò)能及時丟棄延遲的數(shù)據(jù)包且沒有首阻塞問題才行)。WebRTC 發(fā)送和接收的音頻會自動添加時間戳,因此播放和中斷邏輯的實現(xiàn)都變得非常簡單。而在 WebSockets 中,處理起來則要困難得多。此外, WebRTC 自帶出色的回聲消除、噪聲消減和自動增益控制功能。如果使用 WebSockets,則需要自己想辦法將這些音頻處理功能集成到應(yīng)用中。最后,在長距離網(wǎng)絡(luò)傳輸中,延遲和不穩(wěn)定性是不可避免的。為了減少這些問題,可以通過「靠近用戶的中轉(zhuǎn)節(jié)點」(路由器)優(yōu)化連接,從而提升實時媒體的性能,而 WebRTC 平臺會自動幫你完成這部分優(yōu)化。
如果你對媒體傳輸網(wǎng)絡(luò)協(xié)議的設(shè)計感興趣,可以參考這篇關(guān)于 RTMP、HLS 和 WebRTC 的技術(shù)概覽:https://www.daily.co/blog/video-live-streaming/
如果想深入了解 WebRTC 的路由機(jī)制,可以參考 Daily 詳解其全球 WebRTC 基礎(chǔ)設(shè)施的文章:
回聲消除和音頻處理幾乎所有支持對話的語音應(yīng)用都需要處理音頻的功能,特別是回聲消除。Media Capture and Streams API 為 Chrome、Safari 和 Edge 瀏覽器提供了相對成熟可靠的回聲消除功能,開發(fā)者可以放心使用。我們強(qiáng)烈建議不要將 Firefox 作為開發(fā)和測試的瀏覽器。Firefox 的回聲消除和音頻流管理功能較差且不穩(wěn)定。你可能得花費大量時間修復(fù) Firefox 的特有 bug,而這些問題在其他瀏覽器中完全不存在。因此,建議優(yōu)先針對 Chrome 和 Safari 開發(fā)功能,后續(xù)再考慮是否要適配 Firefox。瀏覽器的 WebRTC 和原生 SDK 通常會默認(rèn)開啟高質(zhì)量的回聲消除、消減底噪和自動增益控制功能。需要注意的是,回聲消除必須在客戶端設(shè)備上完成,而其他類型的音頻處理可以在服務(wù)器端實現(xiàn)。例如,Pipecat 集成了 Krisp 的降噪和分離說話人模型,可以在服務(wù)器端處理音頻。API 設(shè)計的題外話每個 API 都是工程的產(chǎn)物,要權(quán)衡軟件設(shè)計和開發(fā)中的各種限制。優(yōu)秀的 API 力求需求明確,找到功能細(xì)分的「黃金點」,可以讓簡單的事情更簡單,也能讓復(fù)雜的事情成為可能。把 OpenAI 實時 API 集成到 Pipecat 中是一件很有趣的事情。這兩種支持對話式語音 AI 的方法有很多相同之處。OpenAI 的事件(event)可以接映射成 Pipecat 的幀類型。OpenAI 實時 API 解決的問題類型或關(guān)注的領(lǐng)域,與 Pipecat 用戶已經(jīng)習(xí)慣的問題非常相似,對 OpenAI 的設(shè)計會很熟悉,不需要花太多時間去適應(yīng)。但它們在設(shè)計的底層架構(gòu)上有很大的差異,這種差異可能是因為兩者的定位和使用場景不同。OpenAI 實時 API 的事件架構(gòu)可以輕松集成到任何編程語言或框架中。發(fā)送事件時,只需傳輸一些 JSON(或類似格式)數(shù)據(jù);接收事件時,通過讀取循環(huán)將數(shù)據(jù)分發(fā)到相應(yīng)函數(shù)即可。相比之下,Pipecat 是一種數(shù)據(jù)流架構(gòu),受多年來多媒體數(shù)據(jù)處理框架(如 GStreamer)的影響較大,在設(shè)計上強(qiáng)調(diào)模塊化和流水線化。在 OpenAI 實時 API 中,核心構(gòu)建塊是「事件(event)」;在 Pipecat 中,核心構(gòu)建塊是「幀處理器(frame processor)」。一個 Pipecat 中的語音到語音循環(huán)可能看起來是這樣的:
pipeline = Pipeline( [ transport.input(), context_aggregator.user(), openai_realtime_llm, context_aggregator.assistant(), transport.output() ])在此基礎(chǔ)上添加語音轉(zhuǎn)文本和文本轉(zhuǎn)語音的處理器,這種架構(gòu)可以兼容任何大型語言模型(LLM)。
pipeline = Pipeline( [ transport.input(), context_aggregator.user(), stt, llm, tts, context_aggregator.assistant(), transport.output() ])
以下是一個更復(fù)雜的 Pipecat 流程,整合了多種功能模塊,能夠高效地處理客戶端命令和事件。通過 Webhook 實現(xiàn)函數(shù)調(diào)用, 內(nèi)置了處理計費、監(jiān)控流程,錯誤管理功能。
pipeline = Pipeline( [ el, transport.input(), rtvi, user_aggregator, openai_realtime_llm, rtvi_speaking, rtvi_user_transcription, rtvi_bot_llm, rtvi_bot_transcription, webhooks_processor, ml, rtvi_metrics, transport.output(), rtvi_bot_tts, assistant_aggregator, ])實時語音 API 需要判斷你的話在哪里結(jié)束,好接上對話。以下一個是減少延遲的實驗性方案。其中,語音活動檢測(VAD)負(fù)責(zé)聽聲音有沒有停下來,LLM 來判斷剛才說的是不是完整的一句話,是不是有話沒說完。這兩個判斷將放在并行的子流程中同時運行。
pipeline = Pipeline( [ transport.input(), stt, context_aggregator.user(), ParallelPipeline( [ # Pass everything except UserStoppedSpeaking to the elements after # this ParallelPipeline FunctionFilter(filter=block_user_stopped_speaking), ], [ # Ignore everything except an OpenAILLMContextFrame. Pass a specially constructed # LLMMessagesFrame to the statement classifier LLM. The only frame this # sub-pipeline will output is a UserStoppedSpeakingFrame. statement_judge_context_filter, statement_llm, completeness_check, ], [ # Block everything except OpenAILLMContextFrame and LLMMessagesFrame FunctionFilter(filter=pass_only_llm_trigger_frames), llm, bot_output_gate, # Buffer all llm output until notified. ], ), tts, user_idle, transport.output(), context_aggregator.assistant(), ])
更多資源
OpenAI 的實時 API 文檔:API 參考文檔:優(yōu)秀的實時 API 控制臺應(yīng)用:Pipecat 代碼,可以通過 Pipecat 來調(diào)用 OpenAI 的實時功能,尤其是其中的 Pydantic 模版可能對其他項目特別有用:THE END轉(zhuǎn)載請聯(lián)系本公眾號獲得授權(quán)