前言

上一篇研究如何把 AI Code Review 拆成可觀察的工程管線。語音 Agent 也有相似問題:把「錄音 → 文字 → LLM → 語音」畫成四個框很容易,真正讓人覺得是在對話,卻要處理停頓、partial transcript、streaming、插話、取消舊回答、tool call、音訊回音與同時連線。

huggingface/speech-to-speech 是一套開源 cascade voice engine。它用可替換的 VAD、STT、LLM 與 TTS 組成 thread+queue pipeline,再包成部分相容 OpenAI Realtime protocol 的 WebSocket/WebRTC server。

它不是一個直接吃聲音、吐聲音的 native speech model,也不是具備 SIP、全球 WebRTC edge、多租戶與 autoscaling 的完整語音平台。理解這個責任邊界,才能看見專案真正的價值:讓團隊控制每一段模型、資料路徑與 latency,同時保留既有 Realtime client 的介面。

speech-to-speech 解決什麼問題?

假設要做一個放在櫃台或機器人上的語音助理。使用者說話時,系統必須同時回答這些問題:

  • 這是短暫停頓,還是真的說完了?
  • Partial transcript 只顯示給 client,還是已經可以送 LLM?
  • LLM 回到一半時,能不能先合成前半句,降低 first-audio latency?
  • 使用者插話後,已經在 STT、LLM、TTS 和 client buffer 裡的舊資料怎麼清掉?
  • Tool call 是 server 執行,還是交給 client?結果如何回到 conversation?
  • 一條 pipeline 能服務幾個人?多開 session 是否會複製模型與 VRAM?
  • 音訊、transcript、tool result 和 provider log 哪些會離開裝置?

speech-to-speech 的做法不是把這些責任藏在單一 hosted API,而是提供可閱讀、可替換的 handler chain。官方也把它用在 Reachy Mini 的 conversation backend;這項 production-use 說明很有參考價值,但不能直接外推成所有硬體、語言與同時連線都有 SLA。Reachy Mini fully local 案例 展示的是一套具體 stack,不是通用 benchmark。

它不是單一模型,而是一條 Cascade

預設概念可以寫成:

Audio input
  → Silero VAD
  → Parakeet TDT STT
  → OpenAI-compatible LLM
  → Qwen3-TTS
  → Audio output

四段的責任分開:

  1. VAD 找語音邊界、建立 turn、處理 speech start/stop。
  2. STT 產生 partial 與 final transcript。
  3. LLM 處理 conversation、instructions、tools 與 streaming text。
  4. TTS 把可朗讀的文字分段合成 PCM。

每一段都有多個 backend。LLM 可以走 hosted provider、HF Inference Providers,也能指向 vLLM/llama.cpp;STT 與 TTS 也可依 CUDA、CPU 或 Apple Silicon 替換。這讓團隊能選擇「音訊留在本機,只送 final transcript」或「連 LLM 都在本機」等不同資料邊界。支援元件矩陣 同時顯示平台與 extra 並不完全一致。

Cascade 的代價也很明確:STT 錯誤會變成 LLM 的輸入,LLM 文字再受 TTS pronunciation 影響;每一段都有 buffer、warmup 與 latency。Native audio model 可能保留更多語氣、情緒、笑聲與非文字訊號,而 cascade 的優勢是 transcript 可觀察、模型可換、成本與資料流可逐段治理。

核心架構:Handler Threads 加上 Typed Queues

專案裡的 BaseHandler.run() 是很好的入口。每個 handler 有 input/output queue,thread 不斷取出 typed item,交給自己的 process() generator,再把產出推到下一段。PIPELINE_END 代表 hard stop;SESSION_END 則只清除目前 session state,讓長存 model thread 繼續服務下一個連線。BaseHandler 把 lifecycle、generation 與 stale item 的共同規則集中起來。

查核 release 的 _build_pipeline_handlers() 明確組成:

VAD
  → STT → TranscriptionNotifier
    (或 direct-audio input notifier)
  → LLM
  → LMOutputProcessor
  → TTS

Queue item 不只是裸字串或 bytes,而是帶 turn_id、revision、cancel generation、language 和 response metadata 的 Pydantic messages。這是 barge-in 能正確丟棄晚到舊資料的基礎。

一輪即時對話的資料流

以下架構研究與安裝範例都固定在 2026 年 8 月 5 日正式版 v0.2.12/commit 56dc28f。截至 8 月 19 日,PyPI 與 GitHub Release 仍是這一版;main 已進入下一輪架構改動,因此不能把 main README 的新命令直接套到這個固定版本。

1. Client 傳入 PCM

WebSocket client 將 base64 PCM 放進 input_audio_buffer.append。Realtime router 解析 event,service 轉成 pipeline 使用的 16 kHz chunks,再連同目前 RuntimeConfig 放進 input queue。WebRTC 則以 media track 傳音訊、data channel 傳 JSON events,兩種 transport 共用後面的 pipeline。Realtime engine flow 列出支援的 event subset 與 transport 差異。

2. VAD 建立與修正 Turn

VADHandler 把 int16 audio 轉成 float32,交給 Silero iterator。說話開始時發 event;live transcription 開啟時,在說話途中產生 progressive audio。v0.2.12 的 Realtime mode 預設再用量化 CPU Smart Turn v3.2 判斷停頓是「已說完」還是「還在想」,同時允許 speculative STT/LLM 先行運算;不需要時可用 --no_smart_turn 回到只靠 Silero 的 endpointing。v0.2.12 release notes 說明了這個預設行為與取捨。

Turn 帶有 ID 與 revision。使用者短暫停頓後繼續說時,可以 reopen 原 turn,後面的 handler 便能判斷較早 revision 已經過期。VAD realtime flow 是理解 partial、final 和 resumed speech 的關鍵。

3. STT 分開 Preview 與 Final

預設 Parakeet handler 對 progressive audio 使用較短的 compute-lock timeout,成功才送 partial transcript;final audio 則進正式 inference,產生帶 language 和 turn metadata 的 transcription。Partial 主要提供 client 顯示,final 才進 LLM。

這個 distinction 不能假設每個 backend 都做對。v0.2.12 的 issue #412 指出多個 Whisper-family handler 忽略 mode,progressive chunk 也可能產生 final transcription,導致後面的長句被當 stale 丟掉。Main 已由 PR #451 修正,但尚未發布;若固定在 v0.2.12 使用 Whisper path,這仍是必須先驗證的 blocker。

4. Notifier 把 Transcript 分成兩條線

TranscriptionNotifier 一方面將 partial/final protocol event 送進 text output queue,另一方面只把 final transcript 包成 LLM request。這讓 UI 可以看到即時字幕,不會每幾百毫秒就重啟一次完整回答。

v0.2.12 也正式提供 stt=none 的 direct-audio path:使用 Chat Completions backend 並明確選擇支援音訊輸入的模型後,可把完成的 VAD audio 直接交給 LLM。它不是預設 quickstart,也不代表 native audio model;VAD、conversation、tool 與 TTS 邊界仍由這套 engine 管理。

5. LLM Streaming 與 Tool Calls

OpenAI-compatible handler 先拒絕 stale turn,再套 session/per-response instructions、conversation、tools 與 output modality,開始 streaming generation。Remote Responses API 可以使用 structured tools;部分 local LLM 則靠 prompt 與 parser 轉成 tool calls。

Server 只把 function call event 送給 client,不代 client 執行工具。Client 執行後,再以 conversation.item.create 回傳 function output。這條 authority boundary 很重要:把工具交給 client 不代表自動安全,client 仍要 allowlist、驗證 schema、限制檔案/網路/機器人動作並對高風險操作要求確認。Tool result flow 是比根 README 更精確的說明。

6. Output Processor 將文字與音訊分流

LMOutputProcessor 把 assistant text、tool calls 和 token usage 放到 protocol side-channel;只有需要 audio 且 chunk 有可朗讀文字時,才產生 TTSInput。Text-only response 因此不必經過 TTS。Output split 也決定 client 何時先看到文字、何時開始收到聲音。

7. TTS 合併文字並回傳 Audio Delta

Qwen3-TTS handler 會合併同一 turn 已排隊的文字、讀取 session voice 設定,再串流產生 PCM。Router 將 audio 編成 response.output_audio.delta,最後送出 audio done 與 response done。

LLM 的 Markdown 並不一定適合直接朗讀。v0.2.12 仍可能把格式符號念出來;主線已在 8 月 18 日以 PR #497 關閉 issue #338,改在 streamed text 組回完整 spoken segment 後移除 Markdown,同時保留 text-only output、tool 名稱/參數與 compact operator expression。這項 1,166 tests 通過的修補仍未發布,正式產品也仍應用自己的語言與 Markdown corpus 驗證 spoken-text normalization,而不是把文字 chat response 原樣交給 TTS。

使用者插話時,系統怎麼停下來?

Barge-in 不是把所有 threads 強制 kill 掉,而是 cooperative cancellation。

VAD 發現新 speech 時,Realtime send loop 讓 CancelScope.generation 加一,開始丟棄舊 generation,並清除舊 output queues;LLM、TTS 與 router 在串流過程比較 generation,晚到的舊 text/audio 不再送給 client。WebRTC 的未播放音訊在 server transport buffer,還需要額外 flush;WebSocket 的未播放 buffer 在 client,client 必須正確處理 truncate/cancel events。Interruption design 有完整 state machine。

這種 generation tagging 能處理不少 race,卻無法強制中止已卡在 native inference 或 HTTP read 的工作。真正的插話體驗還受 provider timeout、TTS chunk、client playback 與 microphone echo 影響。

安裝與最小使用範例

正式安裝以 v0.2.12/commit 56dc28f 為準。Python 需求是 3.10 以上。安全重點是固定 package version,並明確只綁 loopback:

python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install "speech-to-speech==0.2.12"

export OPENAI_API_KEY="your-key"

speech-to-speech \
  --mode realtime \
  --ws_host 127.0.0.1 \
  --ws_port 8765

預設使用 local Parakeet STT、hosted OpenAI-compatible LLM 和 local Qwen3-TTS。第一次還會下載 Smart Turn 與大型語音模型;Linux Qwen3-TTS wheel、CUDA runtime、CPU fallback 與 Apple Silicon dependencies 各有不同條件。v0.2.12 README 應和目標主機一起閱讀。WebRTC 不是標準依賴,需另外固定安裝 speech-to-speech[webrtc]==0.2.12

Source checkout 也要固定 commit:

git clone https://github.com/huggingface/speech-to-speech.git
cd speech-to-speech
git checkout --detach 56dc28f93fb6b4541bfafbfba04df42978763394
uv sync

Repository 沒有 tracked uv.lock,所以固定 source commit 不代表 dependencies byte-for-byte 固定。正式環境仍需自己的 lock、container image、model revision 和 CUDA/MLX matrix。

若要全本機,還必須另起 llama.cpp/vLLM,並將 LLM base URL 指向 loopback。只把 STT/TTS 放在本機、仍使用預設 hosted LLM,final transcript、conversation、tools 與 tool output 仍會送到 provider,不能宣稱完整 local。

最值得閱讀的關鍵程式碼

s2s_pipeline.py

_build_pipeline_handlers() 用一個函式展示 shared handler chain;同檔案也建立 Realtime pipeline pool,是最快的全局入口。

baseHandler.py

BaseHandler.run() 說明 thread、queue、sentinel 和 per-session reset。若要新增 backend,先理解這個 contract 比直接複製某個 handler 更重要。

VAD 與 Parakeet STT

VADHandler.process()ParakeetTDTSTTHandler.process() 讓人看見 turn revision、progressive preview 和 final transcript 的邊界。

Realtime Engine README

api/openai_realtime/README.md 比行銷式 quickstart 更值得讀,因為它列出 event subset、WebSocket/WebRTC 差異、tools、session state 和 cancellation race。

LLM Output 與 Qwen3-TTS

LMOutputProcessor 決定 protocol/TTS 分流;Qwen3TTSHandler.process() 則展示 voice selection、coalescing 與 cancellation。

和相近工具有什麼差異?

工具/方法 比較強的地方 speech-to-speech 的差異
Pipecat 通用 frame processor、transports、多家 STT/LLM/TTS/native S2S、電話與 client SDK 本專案較 opinionated,直接給 Silero/Parakeet/Qwen defaults 和 Realtime-like endpoint,做本機 cascade 路徑較短;extension surface 較窄。
LiveKit Agents Rooms、WebRTC infra、SIP、worker、deployment、observability,以及 cascade/native realtime pipeline 本專案是單 process voice engine/protocol adapter,不是完整 RTC 或 agent deployment platform。
OpenAI Realtime API Hosted native multimodal service,支援 audio、WebRTC、WebSocket、SIP 與完整產品化 API 本專案以開源 cascade 實作 core event subset,可自選模型與資料路徑;不能把 compatible 當完整 wire-level parity。
自己串四個 SDK 最少 abstraction,適合一次性實驗 本專案已處理 typed queues、turn revision、barge-in、tool event、session reuse 與 transport buffer,卻也帶來較多快速變動的 runtime code。

Pipecat pipelineLiveKit pipeline typesOpenAI Realtime API 都是官方來源。選擇時應先定義要的是「可改的 voice engine」、「即時通訊平台」,還是「託管 native audio model」。

成熟度與已知限制

2026 年 8 月 19 日 22:09(Asia/Taipei)查核時,GitHub API 顯示 12,640 stars、1,548 forks。最新 GitHub release 與 PyPI 仍是 v0.2.1256dc28f,package classifier 仍是 Development Status :: 3 - Alpha;main 已到 6d74e57c9,相對 release ahead 227/behind 0。該 HEAD 的 Ruff、mypy、pytest、package、Linux/macOS arm64 install smoke 與 Agents SDK WebSocket/WebRTC 共 9 個公開 checks 全部成功。主線已在 ordered response path 之上合併 packaged talklocal client 的 allowlisted tool executor、tool-result follow-up prefetch、Whisper progressive/language handling 修正、WebRTC ICE cleanup、streamed whitespace、input-transcript lifecycle 與 Markdown TTS cleanup;也以 PR #488 固定 @openai/agents 0.14.3,讓 stock RealtimeSession transports 可透過 WebSocket 與 WebRTC 連到本專案。PR #450 則合併經 thread lifecycle 測試的 MLX 0.32.0、MLX-LM 0.31.3、MLX-Audio 0.4.7 與 Transformers 5.14.1 相容組合,同時刻意保留 global MLX lock。這些全是 main-only 變更,沒有改變 v0.2.12 的安裝命令或已發布 contract。v0.2.12…main compare 可查看 release 差距。

同時,PyPI 和 release 的 pyproject.toml classifier 仍是 Development Status :: 3 - Alpha。v0.2.12 一次收進相對 v0.2.11 的 84 commits,包含 Smart Turn、WebRTC、direct audio、LLM proxy、session teardown 修正與 NLTK 安全更新;之後 main 合併 PR #427,把 RealtimeService 與 pooled pipelines 收斂為唯一 engine,新增 servetalklocal CLI,並繼續調整 backend registry、response output lifecycle、offline operation、CJK TTS 與 ordered assistant parts。這些仍是尚未發成 PyPI 的架構與相容性變更,正好說明 README main、正式 package 與 runtime 必須分開查核。本次沒有使用 2026 年 8 月 3 日 Trending 週增快照;那份舊數字不是本日即時值,也不是固定 168 小時差分。

採用前特別要看這些限制:

  • Protocol 是 core subset:相容 client 的常用路徑可用,不代表所有 OpenAI Realtime events、audio formats 與 transport 語意一致。
  • Realtime lifecycle 仍在快速收斂:8 月 10 日新開的 issue #454 記錄 interrupt_response=False 時的對話 history ordering,issue #455 指出 WebRTC clear 後仍可能播放已暫存 audio,issue #457 則列出尚缺的標準 output/content-part events。修正 stashed audio 的 PR #469 在查核時仍未合併。這些是 main 的問題,不等同 v0.2.12 全部路徑都會觸發,但足以說明不能宣稱完整 protocol parity。
  • Transcript event semantics 仍在 main 收斂PR #476 於 8 月 13 日合併,處理 progressive input transcript 的 delta、complete/failed terminal、沒有 item metadata 的路由,以及未解決狀態的上限;issue #487#489 仍在追 speculative turn revision 與 opt-in snapshot events。這說明近期改動不是單純 UI 顯示修補,而是 client-visible protocol lifecycle;v0.2.12 使用者不能先假設已取得這些行為。
  • Release 與 main 的 CLI 已分岔:v0.2.12 仍使用 --mode realtimeraw-websocket 等參數;main 已在 8 月 6 日關閉 issue #421,改以 Realtime engine 統一 servetalklocal,並保留部分 deprecated mode compatibility。採用者必須選定 release 或 commit,不能混用兩套命令與文件。
  • Whisper progressive bug 只在 main 修正issue #412 所述四個 Whisper-family handlers 把 progressive chunk 當 final transcription 的問題,已由 PR #451 在 8 月 12 日合併並加入回歸測試;v0.2.12 wheel 仍受影響。Transformers Whisper language detection 與 Whisper-MLX unsupported-language handling 也只在今日 main 修正。
  • 語言是四段交集issue #423 指出 faster-whisper 丟失 language metadata,會影響 TTS language switching。
  • Tool backend parityissue #414 已在 8 月 7 日隨 cefeef5 關閉,main 補上 Transformers tool-call message 的 content;但這項修正尚未進 v0.2.12,release 使用者仍要自行回歸 tool call → result → spoken follow-up。
  • Ordered text/tool 已進 main、尚未 releasePR #453 已關閉 issue #309,將 text → tool → text、matching audio、usage 與 response history 放進同一 ordered path,並處理 demo 批次 tool results 的 follow-up race。PR 自述完整 suite 為 1,009 passed/1 skipped;但改動尚未進 v0.2.12,且 history ordering #454、WebRTC stashed audio #455 與標準 lifecycle events #457 仍分開追蹤。Usage disconnect 的 issue #456 則已由 main 的 PR #468 實作在 session queue 清除前結算 pending usage,8 月 18 日才補關閉;v0.2.12 仍沒有這項修補。
  • 第一方 packaged client 的 tool loop 已在 main 補齊issue #460 已隨 PR #467 關閉;main 現在有 opt-in allowlisted async executor、schema validation、ordered results 與 follow-up。PR #468 也已合併,讓 follow-up LM prefetch 與 acknowledgement TTS 重疊。兩者都尚未進 v0.2.12,不能用 release 指令期待這些能力。
  • 官方 OpenAI reasoning 修補只在 mainissue #490 所述明確 reasoning_effort=none 會在 official OpenAI Chat Completions path 遺失的問題,已由 PR #494 合併修正。Pinned source 現在會先保留非空 effort,再排除 official endpoint 不接受的 provider-specific 欄位;但 v0.2.12 wheel 仍未取得修補,本研究也沒有用真實 provider credential 重跑含 tools 的 request。
  • FasterWhisper 語言路徑已在 main 補齊PR #492#496 的 language propagation,已由 PR #500 整合 auto detection 與 language map 並關閉 issue #423。這同樣尚未進 v0.2.12;Paraformer 的語言欄位仍在 open PR #501,繁中、日文與 code-switching 仍要用自己的音訊 corpus 驗證。
  • Markdown 朗讀修補已在 main、尚未 releasePR #497 在 complete spoken segment 階段清理 headings、emphasis、lists、quotes 與 fenced code,並刻意不改 text-only output、tool calls、snake_case 與 compact math。PR 自述完整 suite 為 1,166 passed/1 skipped、8 個公開 checks 全綠;但 v0.2.12 wheel 仍未取得,CJK、程式碼與品牌語彙仍需產品自己的發音回歸。
  • Hosted demo 的帳號層級修補已合併issue #498 指出官方 hosted demo 可能把部分付費 PRO 使用者判成 free;PR #499 已讓 OAuth is_pro 與 token-backed whoami-v2.isPro 共用 tier resolution,並只 cache 成功 profile。這只修 demo tier/quota 判斷,不替本機 core server 新增 authentication;PR 也明示仍需重新部署 Space,所以 merge 本身不能證明 hosted demo 已更新。
  • Apple Silicon 版本矩陣仍在收斂PR #450 已於 8 月 14 日合併,精確固定 MLX 0.32.0、MLX-LM 0.31.3、MLX-Audio 0.4.7、Transformers 5.14.1 與 librosa 0.11.0,並記錄 908 tests 通過;但 unrestricted 三路 STT/LLM/TTS 實驗仍出現 Metal GPU restart 或 Parakeet decoder error,所以 global lock 與 multi-pipeline safeguard 都保留。這是 main-only 修正,v0.2.12 wheel 尚未取得;不要自行只升一個 MLX 套件或移除鎖。
  • PocketTTS 語言與 AEC 說明仍只在 mainPR #502 為 PocketTTS 加入啟動時設定的 --pocket_tts_language,不是 per-turn 動態切換;PR #503 則關閉 issue #483,移除 --audio_enhancement 誤稱具備 echo cancellation 的 help text。兩項都沒有進 v0.2.12,也沒有替 pipeline 新增真正 AEC。
  • 沒有通用 latency SLA:model、硬體、VAD silence、network、warmup 與 audio buffer 都會改 p95。
  • 沒有真正 AECissue #151 仍在追 acoustic echo cancellation;main 雖已由 PR #503 移除 --audio_enhancement 的錯誤 AEC 宣稱,runtime 沒有因此改變。單路 audio enhancement 不等於有 speaker reference 的 AEC。
  • 多 session 容量不是免費:Realtime pool 預設 1;增加 num_pipelines 可能複製 handlers/model memory,共用昂貴 runtime 仍是 issue #363 的進行中設計。

Stars 與 Reachy Mini production claim 說明關注度和真實使用,不是 API stability、資安認證或任意場景容量證明。我的成熟度判斷是:適合本機、LAN、研究與受控裝置 PoC;外部 customer-facing、多租戶或電話場景仍需要自己的平台層。

安全、隱私與供應鏈風險

Server 預設綁所有網卡,卻沒有 Client Authentication

v0.2.12 的 ws_host 預設仍是 0.0.0.0,官方 client example 的 API key 甚至可以寫 not-needed。不要把 8765 直接暴露到公網;開發時明確綁 127.0.0.1,正式環境用 gateway 補 TLS、authentication、rate limit、audio/JSON size limit、concurrent session cap 與 tenant isolation。v0.2.12 host default 是本篇最重要的安全連結之一。未發布的 main 已將新 Realtime server 預設改成 loopback,但 server 本身仍沒有 client authentication;release 使用者不能預先假設這項改善已到手。main server arguments

v0.2.12 的 --enable_llm_proxy 風險更高:它會用 server 持有的 upstream credential 代理普通 LLM endpoint,且 README 明示沒有 authentication/throttling。這項功能預設關閉,只能放在 trusted network 或真正有 access control 的 gateway 後。LLM proxy warning

聲音、Transcript 與 Logs 都可能是敏感資料

Default LLM 是 hosted provider,所以 final transcript、conversation、tools 和 tool outputs 會離開本機。Parakeet 與 Qwen handlers 也會用 console.print() 輸出 USER transcript 與 ASSISTANT text;把 --log_level 降到 error 仍不會關閉這些內容。提議 opt-out flag 的 PR #452 已關閉但未合併,8 月 12 日開啟的 issue #475 也進一步要求 operational logs 預設不記錄 conversation content;因此 v0.2.12 與查核 main 都要把 stdout/service-manager capture 視為敏感資料。要對 audio、transcript、provider retention、application log、backup 和 debug artifact 分別設定用途、保存期限與權限。

Model Loading 是另一條供應鏈

VAD 以 torch.hub.load(..., trust_repo=True, skip_validation=True) 載入 Silero,且沒有在本 repository 固定 source revision;v0.2.12 新增的 Smart Turn 也用 hf_hub_download() 指定 repository 與檔名,沒有指定 model revision。VAD setupSmart Turn loader 顯示只固定 Python package 還不夠。Production 應預先 mirror/scan、固定 model SHA、隔離 cache,並禁止 runtime 任意下載;v0.2.12 annotated tag 也未簽章,高要求環境應再固定 release commit 與 PyPI artifact SHA-256。

Code License 不等於 Model 與 Voice License

Repository 是 Apache-2.0;default Parakeet model card 標示 CC-BY-4.0,Qwen3-TTS model card是 Apache-2.0。Optional model、GGUF conversion、voice clone reference 和生成聲音各有條件。若使用 voice cloning,還要處理本人同意、冒用、標示與地方法規,不可只看 repository LICENSE。

採用前怎麼評估?

建議從一個 client、一台受控主機開始:

  1. 固定 v0.2.12、Python、dependencies、model revisions、OS 與 CUDA/MLX image。
  2. 綁 loopback;若要讓裝置跨網路連線,先建 gateway,不裸露原始 server。
  3. 準備 20~50 段真實音訊,包含短句、長句、口音、背景音、停頓、插話與 speaker echo。
  4. 分段量 end-of-speech → final transcript、LLM first token、TTS first audio、client first playback 和 complete response。
  5. 針對實際語言測 STT、LLM reply、TTS voice/pronunciation,不用單一英文 happy path 代表全部。
  6. 用選定 backend 跑完整 tool call → client execution → tool result → spoken follow-up。
  7. 實測 barge-in 後舊 audio、text、tool event 不會晚到;WebRTC buffer 也確實清除。
  8. 在真實 speaker/mic/room 測 AEC。能取消回答,不代表 speaker 輸出不會觸發 VAD。
  9. 逐步增加 num_pipelines,量 RAM/VRAM、warmup、排隊、公平性、crash recovery 與 session reclaim。
  10. Review provider data use、logs、model/voice licenses、tool authority、retention 與使用者同意。

如果產品需要 SIP、全球 WebRTC、multi-region、tenant auth、autoscaling 與 SLA,應把 speech-to-speech 放在受管理的 inference/voice engine 層,外面再接 LiveKit、Pipecat 或自己的 platform,而不是讓單一 Python process 承擔所有責任。

研究後的個人結論

speech-to-speech 已經超過「四個模型串起來」的 demo。Typed queues、turn revision、session reuse、protocol side-channel、CancelScope、transport buffer 和 pipeline pool 都是在真實語音產品才會遇到的問題。原始碼也很誠實地呈現 cascade 的取捨:每個 stage 可換,但每個 stage 都會增加 latency、state 與 failure mode。

我會推薦它給要做本機語音 Agent、Reachy Mini/互動裝置、或需要 OpenAI Realtime-like self-hosted endpoint 的團隊。最好的起點是固定 v0.2.12、只綁 loopback、先用 default Parakeet path,以真實音訊和實體喇叭/麥克風建立 baseline。

要往 production 走,則不能只看「可以對話」:Alpha status、快速版本變動、無 client auth、model supply chain、沒有真正 AEC、backend bugs 與 model memory 都需要補齊。把它當成可控制的開源 voice engine,它很有研究與實作價值;把它當成 turnkey 多租戶平台,責任範圍就被高估了。

參考資料