Koe Lab
Research · 實測日期 2026-09-07

挑一個聲音,
比挑一個模型難得多。

這份研究把 ElevenLabs 當成雲端語音供應商從頭量過一遍:模型陣容怎麼選、額度實際怎麼扣、 哪些參數在文件上寫著能用但實際會被拒絕。然後我們做了一件文件不會幫你做的事—— 用同一份稿子、同一組參數,讓 88 個聲音各說一次,做成一個可以盲測、對決、排名的實驗室。

88
個聲音(日 38/英 22/中 28)
5,562
段音檔,全部同一組參數
200
句原創台詞,附讀音與註解
1 credit
每個字元(v2/v3),Flash 半價

五個結論

如果只讀一段,讀這裡。

  1. 真正的戰略功能是時間戳,不是音色。 with-timestamps 端點回傳字元級對齊, 讓「生成」與「字幕時間軸」在同一次請求裡完成。市面上的本地引擎多半只能事後靠強制對齊補回來。
  2. 共享語音庫可以直接合成,不必先加進帳號。 這是這次最大的意外—— 八百多個社群聲音全部立即可用,帳號內建的三十一個只是起點。整個實驗室就是建立在這個發現上。
  3. v3 也支援時間戳,而且它的日語音調明顯比 v2 準。 情緒標籤不影響字元對齊;更重要的是,同樣的聲音與句子,v3 分得開 88% 的最小對立對,v2 只有 62%—— 而兩者的音高幅度幾乎相同,所以那不是「比較誇張」。詳見音調一節
  4. 「多語言」不等於「每個語言的參數都一樣」。 語言正規化開關對日語有效、對中文直接被 API 拒絕, 中文的數字與日期必須自己先寫成漢字。
  5. 音色不是你在挑的東西,節奏才是。 這是做完 5,562 段音檔之後最強烈的感受, 也是實驗室要用兩兩比較而不是打星等的原因。

模型陣容:該用哪一個

三個真正需要記住的選項,其餘都是它們的變體或已被取代。

模型單次上限成本它擅長什麼什麼時候別用
Multilingual v2
eleven_multilingual_v2
10,000 字元1 credit/字元 長篇的一致性主力。完整參數支援、時間戳、請求接合(previous_textnext_text)、seed。 需要誇張演技時。它穩,但不會演。
Eleven v3
eleven_v3
5,000 字元1 credit/字元 情緒標籤([whispers][laughs][sarcastic])。角色台詞、動畫感演出。 長篇。上限只有一半,而且不支援 <break>,停頓只能靠標點。
Flash v2.5
eleven_flash_v2_5
40,000 字元0.5 credit/字元 草稿、迭代、即時互動(約 75 ms)。半價。 成品。省下來的錢,會在重錄的時候還回去。
我們的用法

比較用的核心語料一律走 Multilingual v2 並固定 seed——公平比較的前提是只有聲音這一個變數。 情緒台詞另外走 v3。Turbo 系列已被官方標為棄用,直接當它不存在。

時間戳:這才是差距所在

POST /v1/text-to-speech/{voice_id}/with-timestamps 回傳的不只是音檔,還有 alignmentnormalized_alignment:每個字元的起訖秒數。 這代表字幕、卡拉OK 高亮、逐字時間軸這些東西,不需要事後再跑一次對齊模型, 在生成的當下就已經拿到了。

實驗室裡的字元高亮就是直接吃這份資料。日文的難處在於一個漢字可能對應多個音拍, 而 API 給的是字元級而非音節級——但對於「唸到哪裡了」這個用途,字元級已經精準得驚人。

v3 的情緒標籤本身也會出現在對齊陣列裡。處理方式很單純:把方括號涵蓋的字元連同它們的時間一起刪掉, 剩下的序列剛好就是顯示文字,時間軸完全不用重算。我們在 5,562 段音檔上逐段驗證過這件事成立。

另一個沒被充分討論的端點

/v1/forced-alignment 接受最大 1 GB 的音檔加上逐字稿,回傳字元與詞層級的時間戳與信心值。 剪輯過的音檔要重新對回時間軸時,這是唯一的正解。

音調:合成日語真正的破綻

聽寫檢查看不到它,非母語者聽不出它,而母語者一秒就知道不對。

日語是高低重音語言。「雨」和「飴」的假名完全一樣,差別只在音高落在哪裡; 「橋」「箸」「端」三個字同樣如此。合成語音可以把每個音素都唸對、通過逐字比對, 然後在這一層錯得徹底——而這一層是這個實驗室裡所有其他檢查都看不見的。 所以我們自己量了。

怎麼量的

  • 八組最小對立對,寫成一般句子(雨が降ってきたね。飴が好きなんだ。), 由三十八個日語聲音各唸一次。
  • 用自相關法抽出基頻曲線,再靠生成時就存下來的字元級時間戳,把音高切到每一拍上。
  • 主要指標是「對比」而不是「符合字典」:一個聲音如果把「雨」和「飴」唸成同一個輪廓, 它就錯了——這個判斷不需要訴諸任何權威。次要指標才拿去和東京標準音比對。
  • 追蹤器本身用已知頻率的合成訊號驗證過(含倍頻陷阱與缺基頻的情形)。在真值最無爭議的題目上, 它的準確率是七成——所以單一片段的判定不可信,聚合比較才可信。這個誤差我們寫在這裡, 而不是藏起來。

量到了什麼

  • 八組裡典型只分得開五組。 在 Multilingual v2 上,對比率的中位數是 62%。 最難的是「神/紙」,三十八個聲音裡只有十七個分得開。
  • 聲音之間的差距比想像中大得多。 最好的做到八組全中,最差的只有三組, 而且差距中位數只有 1.02 半音——等於把最小對立對唸成同一個東西。 挑聲音這件事,在日語上不是喜好問題,是正確性問題。
  • 模型的影響更大,而且方向和直覺相反。 同樣的聲音、同樣的句子, eleven_v3 分得開 88%、符合標準音 56%;eleven_multilingual_v2 是 62% 與 38%; Flash 最差。
  • 而且那不是「v3 比較誇張」造成的假象。 兩者的整體音高幅度幾乎相同 (8.53 對 8.61 半音),但 v3 的最小對立對差距是 4.92 對 3.16 半音。 它不是動得比較多,是動在對的地方。
  • v3 的停頓也更短。 同一份文字,v3 有 11.1% 的時間是標點停頓,v2 是 23.3%。 (我們一度以為 v3 拖沓,那其實是我們自己在台詞裡寫滿了「……」。)
能控制的與不能控制的

音調本身沒有 API 可以控制:Multilingual v2 不支援 IPA 音素也不支援 SSML 的 <phoneme>,發音辭典只能替換「讀音」而不能指定音高。 所以真正的槓桿只有兩個——選模型選聲音。 這份研究把兩者都量化了,而實驗室的排行榜現在直接顯示每個日語聲音的音調分數。

我們據此改了什麼

日語語料改用 eleven_v3 重新生成。同時修掉一個我們自己的疏漏: v3 其實接受 language_code,而先前的生成器沒有送—— 六百多個日語片段是在模型只能從夾雜英文情緒標籤的文字裡自行猜測語言的情況下產出的。 (順帶一提,v3 會直接拒絕 apply_language_text_normalization。)

仍未解決的:句中位置與句調會蓋過詞彙聲調,所以這裡測的是句首的詞; 我們標註的東京標準音型也可能有錯,這正是把「對比」放在「符合」之前的原因。

額度:實際上怎麼扣

計價單位是送出去的字元數,不是產出的音檔長度。這件事有幾個不直覺的後果:

  • v3 的情緒標籤是要錢的。[cheerfully] 十二個字元就是十二個 credit,即使它不發出任何聲音。
  • 失敗的請求不扣額度,但被截斷的成功請求會。超過單次上限要自己切段。
  • character_count 是最終一致的:剛跑完一批之後查,數字會落後一段時間才追上。
  • 額度按月重置且不累積。剩下的到期就沒了。

查詢方式是 GET /v1/user/subscription,回傳 tiercharacter_countcharacter_limitnext_character_count_reset_unix 以及語音欄位配額。 任何會花錢的批次跑之前,先算好預估成本再送出——我們的生成器把這件事寫死成一道閘門。

2026-05-07 的定價重設

TTS 降價約 55%、STT 降 45%,同時引入 pay-as-you-go。但對既有訂閱者是選擇性加入的—— 要在後台按下切換,否則你還在舊價目表上。這是一個很容易錯過幾個月的按鈕。

實測踩到的坑

以下每一條都是打到線上 API 之後才知道的,文件上找不到或寫得不明顯。

  • 中文不接受語言正規化。 apply_language_text_normalizationlanguage_code: zh 會回 language_text_normalization_not_supported;日文可以。 所以中文稿裡的數字、日期、金額都得自己先寫成漢字,而且「兩點」不能寫成「二點」。
  • pcm_* 是裸資料。 沒有 WAV 標頭,直接存檔播不出來。要自己包一層—— wav_* 家族才是含標頭的那個。
  • seed 是盡力而為。 同樣的 seed 加同樣的參數只是「嘗試」重現,不保證位元相同。 當它是降低變異的工具,不是快取鍵。
  • 並行數有上限。 Creator 方案的 TTS 並行是 5(Flash 10)。我們用五條連線跑, 穩定在每秒三段左右;再往上推就會開始吃到 429。
  • Windows 會先於 API 倒下。 每次請求都開新 socket 的話,兩千段音檔就會把暫時連接埠耗盡 (WinError 10048)。每個工作執行緒維持一條 keep-alive 連線就解決了。
  • 偶發失敗是正常的。 幾千段裡有零星幾段會無故失敗;生成器設計成可續跑, 重跑一次就只補那幾段,不會重花錢。
  • API key 自己也有額度上限,而且它跟帳號的上限是兩件事。 我們在跑到第四百段時被擋下來,錯誤訊息是 This request exceeds your API key (<名稱>) quota of 30000—— 帳號還有十萬額度沒動,但那把 key 被設了三萬的天花板。 /v1/user/subscription 不會告訴你這件事。批次跑之前要檢查的是 key,不只是帳號。

共享語音庫:這次最大的發現

帳號的語音庫裡有三十一個聲音,看起來就是全部了。但 GET /v1/shared-voices 能列出社群共享的公開聲音——我們抓下日、英、中三種語言共八百多個。

真正關鍵的是下一件事:這些聲音可以直接拿 voice_id 去合成,不需要先「加入我的語音庫」。 我們用一個沒加進帳號的聲音打了一次 with-timestamps,回 200。 這把可用的聲音數量從三十一擴大到八百以上,而且完全不佔語音欄位配額。

於是選角本身變成一件有內容的工作。這個實驗室的 88 個聲音是手挑的, 每種語言都刻意覆蓋可愛/動畫、自然對話、旁白、男聲,並且至少放一個地方腔—— 日語有關西腔與九州腔,中文有台灣國語與北京普通話的直接對照。

授權的位置

所有付費方案(Starter 以上)都含商業授權,這一點比多數可以本地跑的開源引擎乾淨得多—— 它們的基礎權重經常是非商業授權。專業聲音複製只能複製自己的聲音並需要驗證; 即時複製對付費用戶開放,但那是另一個需要逐案判斷權利的題目。

方法:這個語料庫是怎麼做出來的

如果實驗設計是壞的,聽起來再厲害的結論都不算數。

  • 只留一個變數。 每一句台詞由所有聲音各說一次,模型相同、 voice_settings 相同(stability 0.5/similarity 0.75/speed 1.0)、seed 相同、 輸出格式相同(mp3 44.1 kHz/128 kbps)。你聽到的差別只可能來自聲音。
  • 台詞是自己寫的。 日語的「心動台詞集」帶有動畫的味道,但每一句都是原創, 不是任何作品的引用。每句附假名、羅馬字、繁體中文與英文對照,以及一條語法或語感筆記。
  • 刻意設計的難句。 每種語言都有一組專門用來逼出破綻的句子: 日語的長音/促音/拗音/量詞音變/日期讀法,中文的破音字(長・行・樂・還・覺・差)與號碼裡的「么」。 平順的句子人人都唸得好,差距要靠難句才看得出來。
  • 判斷用兩兩比較,不用打分。 絕對評分會漂移也會壓縮——大多數聲音都會落在三分或四分。 「比較想再聽哪一個」既省力又穩定,再用 Bradley–Terry 最大概似估計擬合成排名。 大約每個聲音累積八場比較,順序就會定下來。
  • 每一段音檔都有出處。 模型、聲音、參數、seed、字元數、預估額度、延遲、 位元組數與字元對齊全部隨檔記錄,所以任何一段都能被追溯,也能被單獨重生成。

生成器本身是可續跑的:已存在的音檔絕不重跑,所以中斷不用付代價,失敗的段落可以單獨補。 預算是一道硬閘門,跑之前先印出預估成本。

接下來

這個語料庫是一個起點而不是結論。接下來值得做的幾件事:把 Scribe 語音辨識接上來, 對每一段生成音檔做自動聽寫比對,用來抓出唸錯字的段落;把長篇朗讀擴大到真正的段落級測試, 驗證請求接合在跨段落時的韻律連續性;以及把排行的結果,變成影片管線裡真正的預設聲音。

但在那之前,先去聽。排名是聽出來的,不是讀出來的。

進入聲音實驗室 →