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