這篇解決什麼問題:解決兩個 AI 虛擬主播共用一條虛擬音訊線導致兩張臉同時對嘴,以及 AI 之間接話有數秒尷尬空白的問題。 適合誰讀:已經有單個 AI 角色能說話,想擴展為雙角色同框直播的開發者。需要 Windows 系統、一張入門獨立顯示卡,且懂得安裝虛擬音訊驅動與 VTube Studio 的基礎操作。 讀完能做到什麼:實作兩個 AI 角色各自獨立對嘴、接話等待時間壓到 0.0 秒,且語調能隨情緒起伏而不會電子破音。

接續先前在 [[雙AI雜談台 架構與執行]] 的實驗,我記錄了 2026-06-12 到 06-13 期間打通雙 AI 上臉的技術實踐。關於延遲優化的理論背景,可以參考 [[直播延遲優化方案]]


0. 進度快照

  • 完成 階段 A 驗收:我實地運行 duo_talk.py,雙 AI 話題討論架構成立,後續僅需微調選題與人設。
  • 完成 雙 VTS 與雙音訊線:兩個角色各自獨立對嘴,測試通過。
  • 完成 接話空隙歸零:預生成機制升級為文字與整段語音同時預備,實測接話等待時間降至 0.0 秒。
  • 完成 情緒通道 v1:LLM 句首情緒標籤成功對應到 edge-tts 的語調微調。
  • 完成 負載實測:雙 VTS 運行 10 分鐘,GPU 平均使用率 29%、峰值 41%,VRAM 峰值 2799/6144 MiB。
  • 待辦 後續計畫:設定 VTS 內建動作(自動眨眼、呼吸、物理效果、空閒動作)與 OBS 同框推流長期測試。

1. 雙臉雙線:解決共用虛擬音訊線的對嘴衝突

VTube Studio(以下簡稱 VTS,一款 Live2D 角色控制軟體)的唇形同步機制是偵測輸入麥克風的音量大小來讓模型開合嘴巴。如果兩個 AI 角色共用同一個虛擬音訊裝置,兩張嘴就會同時開合,徹底失去雙人對話的真實感。 為了解決這個問題,我採用「一角色配置一條音訊線」的物理路由。

我將兩個角色的音訊路由進行並排對比:

角色Python 播放端送音位置VTS 實例的麥克風錄音端
星野CABLE Input(VB-CABLE,原有虛擬音訊裝置)CABLE Output
Hi-Fi Cable Input(新裝虛擬音訊裝置)Hi-Fi Cable Output

在選擇虛擬音訊線時,官方推薦的 VB-CABLE A+B 需要捐款至少 15 美元才能取得安裝包。因此我改用同公司免費提供的 Hi-Fi Cable 驅動。它的限制是不提供自動重採樣功能,也就是播放端與錄音端的音訊採樣率必須手動對齊。

在程式碼實作上,我在角色的 JSON 設定檔中新增了 audio_device 欄位。主程式 main.pyplay_routed() 函數改為可接受指定播放裝置,若未指定則使用全域設定 VTS_AUDIO_DEVICE。這讓多角色音訊路由簡化為一角色一行設定。


2. 接話延遲歸零:將 TTS 語音生成藏進對手說話時間

在先前的階段 A 中,我雖然已經把 LLM 文字預生成藏在對方播放音訊的時間內,但實測發現接話時仍有 1 至 3 秒的尷尬空白。 經過追查,發現問題出在文字轉語音(TTS)的延遲。原流程是聽完對方說話後,才開始將下一句的文字合成為語音。雖然 LLM 生成文字的時間被藏掉了,但 TTS 的網路請求與音訊轉檔時間卻沒被避開。

這就像是在舞台劇中,演員不能等對手講完最後一個字,才去後台拿大喇叭;而是要在對手還在說話時,就已經把大喇叭拿在手上,輪到自己時才能直接開口。這個提前準備並把語音檔案暫存在硬碟中的機制,就是「預生成」。

我將 main.pyspeak() 拆解成負責語音合成的 synth_to_wav48() 與負責播放的 play_routed()。在雙人對話控制腳本 duo_talk.py 中,當前一位角色正在發言時,背景執行緒會同時啟動 LLM 與 TTS 合成,將下一句的音訊直接轉成 WAV 檔備用。輪到該角色發言時,系統可以直接調用播放,等待時間直接壓到 0.0 秒。


3. 情緒通道:透過標籤同步驅動語調與動作

免費版的 edge-tts 並不支援微軟 Azure 的 SSML 情緒風格標籤,它只接受基本的語速(rate)與音高(pitch)調整。為了讓角色說話有起伏,我建立了一個「情緒通道」架構。

首先在系統提示詞中新增規則,要求 LLM 在生成每句話的句首輸出情緒標籤。程式在取得文本後會先拆下這些標籤,並將其轉換成對應的語速與音高增量。 這些增量是疊加在角色基礎音色上的,例如興奮會使語速增加 12%、音高增加 25Hz。 這些標籤在合成語音前會被過濾掉,不會被角色唸出來。

情緒通道的架構設計如下:

graph TD
    LLM[LLM 輸出句首帶標籤文本] --> Split[程式拆分標籤與純文本]
    Split --> Emotion[提取情緒標籤]
    Split --> Text[過濾後的純文本]
    Emotion --> Calc[計算語速與音高增量]
    Text --> TTS[TTS 語音合成]
    Calc --> TTS
    Emotion --> VTS[VTS WebSocket 動作觸發]
    TTS --> Play[虛擬音訊線播放對嘴]

這種設計的優點在於,情緒標籤是一個獨立的訊號源。目前 v1 版本它用來微調語音參數;未來 v2 版本則可以直接透過 pyvts 庫連接 VTS WebSocket API,將同一個標籤對應到 Live2D 模型的表情或動作快捷鍵上。當角色說到興奮時,聲音會高亢,模型也會同時做出揮手動作,完成音畫同步。

語調的極限備案,則是改用 Azure Speech 官方 API,或是在雲端 GPU 跑 [[GPT-SoVITS 與 Live2D 接線安裝指南|GPT-SoVITS]]


4. 技術踩坑:情緒參數疊加導致的破音與限流問題

情緒通道實際上線後,立刻遇到嚴重的語音失真與技術限制。 星野的基礎音色原本就偏高,當疊加了【驚訝】的情緒增量後,合成出來的音訊超出了該聲線的物理極限,導致長句子變成尖銳且兩倍速的怪異聲音;而男聲角色在疊加極端音高時,也因為播放緩衝不足而出現電子破音。 為此,我進行了參數修正與穩定性調整。


5. 免寫程式讓 Live2D 模型動起來的兩層做法

要讓虛擬主播顯得自然,除了對嘴之外,身體的自然擺動與眨眼也是關鍵。這部分可以分為免寫程式的內建設定,以及後續透過程式驅動兩種途徑。

在免寫程式的階段,我完全利用 VTube Studio 內建的功能來達成基本動態。


6. 硬體負載與未來展望

在單主機上多開兩個 VTube Studio 實例並運行雙 Python 控制腳本,對於系統硬體是一大考驗。 以下是在 GeForce GTX 1660 6GB 顯示卡上實測 10 分鐘的硬體消耗數據:

效能指標平均值峰值硬體上限
GPU 使用率29%41%100%
VRAM 顯示記憶體2632 MiB2799 MiB6144 MiB

測試結果顯示,顯示記憶體與繪圖晶片使用率連上限的一半都不到,硬體運算效能並非目前的瓶頸。

目前,雙臉雙音訊線的架構已在 2026-06-13 測試完畢。VTS 的內建動作配置完成,且 OBS 雙視窗同框推流長期測試表現穩定。

尚未驗證且仍待開發的部分,是中央音訊調度器。這套調度器預期要能支援逐句串流與播放中斷機制。完成後,AI 之間的插話行為將能從目前的「回合結束後插話」細緻化到「句子與句子之間中斷插話」。這項功能我先記錄在待辦事項中,後續再進行實作。