先把場景擺出來。你要讓「某一個特定的聲音」念一段文字——可能是公司品牌的旁白、一集有聲書、一段客服提示音、一支短影音的口白。這件事聽起來很日常,但直到不久之前,你能走的路只有兩條,而且兩條都不太好走。

第一條,請真人配音。找配音員、喬檔期、進錄音室。聲音是好聽,但貴、慢,最要命的是——腳本改一個字,就得把人再約回來重錄一段。第二條,用系統內建的 TTS。快、免費,但你一聽就知道那是機器在講話:斷句怪、重音錯、多音字亂念,中文更慘,方言根本不存在。

這篇要講的 CosyVoice,是阿里巴巴通義實驗室開源的中文語音合成模型。它有意思的地方,不在於「又一個 TTS」,而在於它把上面那件事的做法,整個換了一種姿勢。所以我不打算照功能表一條條念給你聽,我想沿著同一個動作——讓指定的聲音念指定的文字——把「以前怎麼做」和「現在怎麼做」擺在一起看。差別擺出來,你自己就會看到那條線移到哪去了。

舊做法:要一個聲音,先得餵飽它

過去要讓 AI 用「某個特定的人」的聲音講話,路徑大致是這樣:你得先蒐集這個人大量的錄音,幾十分鐘、甚至幾小時的乾淨語料,然後拿這批資料去訓練(或微調)一個專屬於這個聲音的模型。訓練要 GPU、要時間,跑個幾小時到幾天。跑完,你才得到一個「只會用這個聲音講話」的模型。

換一個聲音?從頭再來一次。

這個路徑的成本結構決定了它的用途:只有那種「聲音會被重複用很多次、值得一次性投資」的場景撐得起——大公司的固定品牌音、長期經營的虛擬主播。你臨時想用同事的聲音錄個生日祝福?別想了,光準備語料就把你勸退。

CosyVoice 做的第一件事,就是把這個前提拆掉。

新做法:給它 30 秒,不用訓練

CosyVoice 最常用的功能叫零樣本音色複製(zero-shot)。你給它一段 3 到 30 秒的參考音訊,再打上你想講的文字,它就用那段音訊裡的聲音,把你的文字念出來。不重新訓練、不微調,當場就出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import sys
sys.path.append('third_party/Matcha-TTS')
from cosyvoice.cli.cosyvoice import AutoModel
import torchaudio

cosyvoice = AutoModel(model_dir='pretrained_models/CosyVoice-300M')

# 給一段參考音訊,用那個聲音講新的文字
for i, j in enumerate(cosyvoice.inference_zero_shot(
'八百標兵奔北坡,北坡砲兵並排跑。', # 要合成的文字
'希望你以後能做得比我還好。', # 參考音訊裡「原本說的話」
'./asset/zero_shot_prompt.wav', # 參考音訊(3~30 秒)
stream=False
)):
torchaudio.save(f'output_{i}.wav', j['tts_speech'], cosyvoice.sample_rate)

看清楚這裡真正省掉的是什麼。舊做法裡最重、最貴的那一步——「為這個聲音準備語料 + 訓練一個模型」——整個消失了。準備成本從「幾小時語料加幾小時訓練」壓到「一段幾十秒的錄音」。

這不是把同一件事做快一點而已。它改變的是你會拿它來做什麼。當複製一個聲音的門檻低到只要 30 秒錄音,你會開始想那些以前根本不會考慮的用途:用旁白員的聲音把整本電子書念完、幫每個客戶用同一個品牌聲音生成專屬語音、把三年前錄壞的一句旁白單獨補錄——不對,是單獨「重新生成」,因為你根本不需要人再開口。

它憑什麼不用訓練就能學會一個聲音

到這裡你大概會想:不訓練,它是怎麼「知道」那個聲音長什麼樣的?這個問題值得停下來拆一下,因為想通它,你就會知道這東西的能力邊界在哪。

先給你一個粗略但夠用的心智圖。CosyVoice 內部其實是三段接力:

第一段是一個語言模型,做的事情跟你熟悉的那種「預測下一個字」的模型幾乎一樣,只是它預測的不是文字,是語音的 token——你可以想成把聲音也切成一顆顆「音的積木」,它負責決定下一顆積木是什麼。第二段叫 Flow Matching,把這串語音 token 還原成頻譜圖(聲音的「設計圖」)。第三段是 HiFi-GAN,把設計圖轉成你耳朵真正聽到的波形。

零樣本的祕密就藏在第一段。當它從你那段 30 秒錄音裡,抽出這個人的「聲音特徵」——音色、語調的慣性、那種只屬於他的腔——然後在預測每一顆語音積木的時候,都帶著這個特徵去預測。所以生出來的每一顆積木,都染上了那個人的味道。

打個比方會更清楚。這比較像你請一個很會模仿的朋友。你放一段某人講話給他聽三十秒,他抓到那個人的說話習慣之後,你給他任何一句新的台詞,他都能用那個腔調講出來——他不需要「重新學做人」,只是把抓到的特徵套到新句子上。CosyVoice 做的是同一件事,只是換成了機率模型在做。

想通這個,你也就懂了它的軟肋:它抓的是「特徵」,不是「這個人本身」。參考音訊品質差、背景吵、只有三秒,它抓到的特徵就模糊,出來的聲音就飄。餵得好,它學得像;餵得爛,它也只能瞎猜。

中文這一關,它是怎麼過的

多數語音模型是英文優先,中文永遠是二等公民。CosyVoice 反過來,它就是為中文而生的,而且把中文最麻煩的兩個坑都填了。

第一個坑是方言。CosyVoice 3.0 支援 9 種語言、18 種以上的中文方言——廣東話、閩南話、四川話、東北話都在裡面。用 Instruct 模式,你甚至可以直接下指令叫它換方言講:

1
2
3
4
5
6
7
8
# 用廣東話講
for i, j in enumerate(cosyvoice.inference_instruct2(
'好少咯,一般係放喺唔國慶啊。',
'You are a helpful assistant. 請用廣東話表達。<|endofprompt|>',
'./asset/zero_shot_prompt.wav',
stream=False
)):
torchaudio.save(f'cantonese_{i}.wav', j['tts_speech'], cosyvoice.sample_rate)

第二個坑是多音字。「重」念 chóng 還是 zhòng、「予」念 yǔ 還是 jǐ——這是中文 TTS 最常翻車的地方,一個字念錯,整句就出戲。CosyVoice 3.0 讓你用拼音或音標直接把發音釘死:

1
2
# [j][ǐ] 強制「予」讀作 jǐ
text = '高管也通過電話、簡訊等方式對報導[j][ǐ]予好評。'

而如果你的內容主要是給台灣人聽的,這裡有個更貼的選擇。聯發科研究院基於 CosyVoice 1.0 的架構,改造出一個叫 BreezyVoice 的版本,專門針對台灣口音和中英夾雜調過,Apache 2.0 授權可以商用。它最大的差別是原生支援注音——多音字直接用你從小學的 ㄅㄆㄇㄈ 標,不用去背拼音:

1
2
3
4
# 「好」要念第三聲,直接用注音標
python single_inference.py \
--content_to_synthesize "今天天氣真好[:ㄏㄠˇ]" \
--speaker_prompt_audio_path "./data/example.wav"

對台灣的內容創作者來說,這個細節很實在——你講的話裡本來就中英混雜,多音字又多,一個能吃注音的模型省下的校對力氣,比帳面上看起來多得多。

還有一個轉變:語音從「先做完」變成「邊做邊出」

CosyVoice 2.0 之後補上一個叫 bi-streaming 的能力,值得單獨拉出來講,因為它又動了一次做法的前提。

舊的 TTS 是「先把整段文字給我,我全部生成完,再一次給你」。這在你已經有完整稿子時沒問題。但如果文字本身是一邊生一邊來的——比方說前面接著一個 LLM,它的回答是一個 token 一個 token 吐出來的——那舊做法就卡住了:你得等 LLM 把整段話講完,才能開始合成語音,使用者就得多等一輪。

bi-streaming 讓文字可以用串流的方式餵進去,音訊同步串流出來。你可以直接把 LLM 的輸出接上:

1
2
3
4
5
6
7
8
9
10
11
12
def text_generator():
# 模擬 LLM 逐步吐字
yield '收到好友從遠方寄來的生日禮物,'
yield '那份意外的驚喜與深深的祝福,'
yield '讓我心中充滿了甜蜜的快樂。'

for i, j in enumerate(cosyvoice.inference_zero_shot(
text_generator(), # 文字串流進
prompt_text, prompt_wav,
stream=True # 音訊串流出
)):
play_audio(j['tts_speech']) # 每個片段即時播放

3.0 版把首個音訊片段的延遲壓到 150ms。在有 GPU 的環境下,這已經接近「你講完它就答」的即時語音對話體感——也就是類似 GPT 那種你講一句它馬上用聲音回你的東西,現在你可以自己用開源模型拼出來。

誠實講一下它的坑

到這你可能已經想 clone 一份下來玩。先把兩件事講在前面,免得你踩到才回來罵我。

macOS 上會很慢。 官方不支援 Apple 的 MPS(也就是不吃 M 系列晶片的 GPU),預設就跑 CPU。CPU 能跑,但生成 5~10 秒的語音大概要等 30 秒到好幾分鐘。這代表它在 Mac 上適合「批次生成、生完再聽」,不適合拿來做即時對話。真的要即時,你需要一台有 NVIDIA GPU 的 Linux 機器。安裝時 Mac 使用者還得手動改 requirements.txt——把 deepspeedtensorrt 那幾行拿掉,onnxruntime-gpu 換成 onnxruntime;另外 ttsfrd 這個文字正規化套件在 Mac 裝不起來是正常的,系統會自動退回 wetext,功能不缺,只是正規化品質稍微差一點。

還有一件不是技術的事。 零樣本音色複製只要 30 秒錄音,這個門檻低到令人舒服,也低到令人不安——同一個能力,可以拿來幫視障朋友用他熟悉的家人聲音讀文件,也可以拿來偽造某人根本沒講過的話。授權(Apache 2.0)給了你商用的自由,但沒給你複製別人聲音的權利。這條線在法律和倫理上都還很新,用之前先想清楚:這個聲音,你有沒有資格用。

那條線,到底移到哪去了

把前面對照的每一段收攏起來,你會看到移動的其實是同一條線。

以前,「一個聲音」是一種資產:你得預先蒐集、訓練、把它存成一個模型,用的時候調出來。它是名詞,是你擁有的一個東西。CosyVoice 之後,「一個聲音」變成了一種函式:你把一段參考音訊和一段文字當參數丟進去,它當場算給你。你不再「擁有」某個聲音,你只是在需要的那一刻「呼叫」它。

功能列表上,CosyVoice 就是個很強的中文 TTS。但真正變掉的不是它能做幾件事,而是「聲音」這個東西在你腦子裡的位置——從一個要花成本先備好、存起來的資產,變成一個給參數就即時生成的呼叫。門檻一旦掉到這個高度,能長出來的用法,會比今天任何一份功能表寫得都多。

想試的話,從最小的 CosyVoice-300M(約 2 GB)開始,先確認在你的機器上跑得動,再決定要不要換上最強的 3.0。台灣的內容就直接看 BreezyVoice。挑一段你自己的錄音丟進去,聽聽看它學得像不像——這件事你以前得花一整天,現在花的時間,大概就跟你讀完這篇差不多。

參考來源:CosyVoice GitHub(20K+ Stars)、BreezyVoice GitHubHuggingFace FunAudioLLM。授權:Apache 2.0。