五个 TTS 后端怎么选:默认那个不一定适合你

2026-08-09

speech-to-speech 是 Hugging Face 的一条语音代理流水线,README 里的自我定位是「Build local voice agents with open-source models」,架构是 VAD → STT → LLM → TTS 四段级联,每段都能换后端(GitHub 元数据 2026-08-09 快照:star 11893,license 标注 Apache-2.0)。TTS 是最后一段,src/speech_to_speech/TTS/ 下摆着五个 handler:chatTTS、facebookmms、kokoro、pocket_tts、qwen3_tts。

pip install speech-to-speech 装完,--tts 的默认值是 "qwen3"。很多人就这么用下去了。但这个默认背后有一串隐含前提——你有一块能跑 CUDA 的卡、你的 CUDA 运行时版本对得上、你说的是它默认那套语言、你只服务一个人。这五个前提有一个不成立,默认就不是最优解。

这篇不打算把五张参数表并排贴出来,那样读者看完还是不知道该选谁。我们按处境倒推。

先说清楚:哪些维度我们不比

这一点必须放在最前面,否则后面的结论会被误读。

我们没有 pip install 过这个包,没有启动过服务,没有对着麦克风说过一句话,也没有下载过任何一份模型权重。所以下面这些维度,这篇一个字都不会写

  • 音质、听感、哪个音色更自然
  • 首包延迟、实时率、每秒能合成多少音频
  • 显存占用多少 GB、8 GB 的卡能不能跑

官方 README 也没有给这些数据。谁要是拿一篇没跑过服务的文章告诉你「A 比 B 快 30%」,那是编的。

能比的只有源码与文档明写的东西:安装方式、默认设备、模型标识里自带的参数量、量化取值、语言覆盖、是否支持声音克隆、参数多少个。够不够做决策?够,而且这些恰好是最容易在装机第一天就把你卡住的东西。

五个后端的硬事实

后端安装默认设备参数语言覆盖(README 表)备注
Qwen3-TTS(默认)内置--qwen3_tts_device cuda多语言,--qwen3_tts_language 默认 auto非 macOS 走 GGML,Apple Silicon 自动走 mlx-audio;23 个参数
Kokoro-82M非 macOS 需 kokoro extra,macOS 内置--kokoro_device auto多种语言/音色映射,取决于后端可用性--kokoro_voice 默认 bm_fable--kokoro_lang_code 默认 b
Pocket TTSpocket extra--pocket_tts_device cpuREADME 未单列语言行Kyutai Labs 出品,README 描述为「带声音克隆的流式 TTS」
ChatTTSchattts extra--chat_tts_device cuda英文与中文只有 3 个参数
MMS TTS内置--facebook_mms_device cuda通过 MMS 检查点提供广泛多语言--tts_language 默认 en,模型按该语言自动选

模型标识里自带的参数量:默认 TTS 是 Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice(1.7B),Kokoro 是 hexgrad/Kokoro-82M(82M)。注意这只是名字里写的参数量,不是显存占用——权重体积的算术下限还要再加激活值、KV cache、音频缓冲和框架开销,不同后端(GGML / torch / MLX)差异很大,这条口径我们不越界。

安装方式那一列比看上去重要。内置的三个(Qwen3-TTS、MMS TTS、以及 macOS 上的 Kokoro)意味着装完包就能选;带 extra 的意味着你要多跑一条 pip install "speech-to-speech[...]",而多跑这一条在某些环境里就是一整个下午。

决策路径

第一问:你的机器上有什么

Apple Silicon 的 Mac。 Qwen3-TTS 在这里会自动走 mlx-audio,--qwen3_tts_backend 那个 ggml/torch 的选择会被忽略;量化走的是 --qwen3_tts_mlx_quantization,默认 6bit。Kokoro 在 macOS 上是内置的,不用装 extra。这一档默认值基本是顺的,可以先用默认跑通再说。

Linux/Windows + 一块 NVIDIA 卡。 默认路径能走,但要过 GGML wheel 那一关(下一节讲)。量化参数换成 --qwen3_tts_ggml_quantization,默认 BF16,这个参数的 help 里列出的支持取值是 BF16Q8_0Q4_K_MF32

没有 GPU,只有 CPU。 这是默认最不适配的一档。看上面那张表的默认设备列:Qwen3-TTS、ChatTTS、MMS TTS 三个的默认设备参数都写死 cuda,只有 Pocket TTS 默认就是 cpu,Kokoro 是 auto。这不代表另外三个跑不了 CPU(--qwen3_tts_device 的可选值里就有 cpu),但代表你必须显式改设备参数,而且 CUDA-wheel 那条坑你还得绕。纯 CPU 的机器,从 Pocket TTS 或 Kokoro 开始试是阻力最小的路径。

第二问:要不要中文

这里有个必须先泼的冷水:TTS 选对中文没用,STT 也得换。 默认 STT 是 Parakeet TDT(nvidia/parakeet-tdt-0.6b-v3),README 的多语言表里写得很清楚——25 种欧洲语言。也就是说你说中文,第一级就转不出来,后面 TTS 再怎么选都是空的。做中文得换成 Whisper 系或 Paraformer(paraformer extra,README 说默认那个检查点偏中文)。

TTS 这一级,README 语言表里明确写了中文的只有 ChatTTS(英文与中文)。Qwen3-TTS 标的是多语言、默认 --qwen3_tts_language auto,MMS TTS 标的是「通过 MMS 检查点提供广泛多语言」而 --tts_language 默认 en这三个之间谁的中文更好,README 没给任何评测数据,我们不比。

能给的判断是:如果中文是硬需求且你想少折腾,ChatTTS 是文档里唯一把中文单独列出来的那个,参数也只有三个(--chat_tts_stream 默认 True--chat_tts_device 默认 cuda--chat_tts_chunk_size 默认 512),配置面小意味着出错面也小。要用多语言/自动切换那套,走 Qwen3-TTS 的 auto,另外流水线级还有 --language(默认 en,可设 auto)和 --enable_lang_prompt(默认 False,会追加一句 “Please reply to my message in …” 的指令;README 给的判断依据是大模型通常能从上下文推断语言,这条显式指令对小模型可能有帮助)。

第三问:装得动吗

这一问经常决定最终结果,尤其在公司内网机器上。

坑一,Qwen3-TTS 的 CUDA 版本错配。 README 单独开了一节讲:Linux 上 Qwen3-TTS 的 GGML 后端来自 faster-qwen3-tts[ggml],它在 PyPI 上的默认 qwentts-cpp-python wheel 面向 CUDA 12.8。你机器上要是没有这个 wheel 期望的 CUDA 12 运行时,得先按自己的 CUDA 版本装匹配 wheel 再装主包:

# CUDA 13.x
pip install "qwentts-cpp-python==0.3.1+cu130" \
  -f https://huggingface.co/datasets/andito/qwentts-cpp-python-wheels/tree/main/whl/cu130

# CUDA 12.4
pip install "qwentts-cpp-python==0.3.1+cu124" \
  -f https://huggingface.co/datasets/andito/qwentts-cpp-python-wheels/tree/main/whl/cu124

# 仅 CPU 兜底
pip install "qwentts-cpp-python==0.3.1+cpu" \
  -f https://huggingface.co/datasets/andito/qwentts-cpp-python-wheels/tree/main/whl/cpu

pip install speech-to-speech

想绕开 GGML 这条线,README 给的另一条路是传 --qwen3_tts_backend torch,改用之前那套 CUDA-graphs 实现。

坑二,numpy 版本互斥。 README 原文说得很直白:DeepFilterNet(VAD 那一级可选的音频增强)要 numpy<2,Pocket TTS 要 numpy>=2,两者冲突,只在不用 Pocket TTS 的环境里手动装 DeepFilterNet。所以「我想开音频增强」和「我想用 Pocket TTS」在同一个环境里是二选一的。对应的开关是 --audio_enhancement,默认 False

这两条合起来给出一个很现实的排序:只想快速跑通、又不想碰 CUDA wheel 和 numpy 冲突的,Kokoro 是摩擦最小的那个——非 macOS 一条 extra,macOS 连 extra 都不用,参数只有六个。

第四问:要不要克隆音色

要,就只看两个。

Pocket TTS 的定位 README 直接写了是「带声音克隆的流式 TTS」,--pocket_tts_voice 既可以填八个预设之一(albamariusjavertjeanfantinecosetteeponineazelma,默认 jean),也可以填本地音频文件路径或 Hugging Face 路径。README 给的示例是:

speech-to-speech serve \
    --tts pocket \
    --pocket_tts_voice jean \
    --pocket_tts_device cpu

Qwen3-TTS 走的是另一套:--qwen3_tts_ref_audio 给参考音频,或者用预计算的 --qwen3_tts_ref_spk(speaker embedding,与 ref_audio 互斥)配 --qwen3_tts_ref_rvq(声学码,需要同时给 ref_spk 和 ref_text)。--qwen3_tts_ref_text 自带一段挺长的英文默认文稿——这一点值得单独记一下:如果你换了参考音频却忘了改 ref_text,参考文稿和音频就对不上了。另外 --qwen3_tts_speaker 默认是 Aiden

不需要克隆音色的话,这一问跳过,别为一个用不上的能力去承担额外的安装复杂度。

第五问:是不是要进生产

三件事,和 TTS 选谁无关但会一起翻车:

一是 --num_pipelines 默认 1。参数 help 写得很明确:一个 uvicorn 服务监听 --port,把每个进来的客户端路由到下一个空闲流水线,每条流水线有自己的 VAD/STT/LM/TTS handler 和会话状态;最大并发 WebSocket 会话数就等于 num_pipelines,再多的连接会被拒绝。默认 1 意味着默认只服务一个人。多用户部署时这是第一个要动的参数——但同时也意味着每加一条流水线就多一整套 TTS 实例,选谁在这里被乘以 N 倍放大。

二是 --host 默认 127.0.0.1--port 默认 8765。要让别的机器连上就得改 host,而 README 关于 --enable_llm_proxy(默认 False)和 --host 0.0.0.0 的声明必须原样带出来:服务端自己不做认证、不做限流,只应在受信网络或网关之后启用。 这不是「配个反向代理就安全了」,是官方在提醒边界在哪儿;具体怎么防护要结合你自己的环境评估。

三是 Docker 那条路。README 说装好 NVIDIA Container Toolkit 后 docker compose up,compose 会起一个跑 Gemma 4 的 llama.cpp 服务和实时服务,暴露 80808765 两个端口。这条路把 CUDA wheel 的麻烦包进了镜像,但也意味着你接受了它预设的那套组合。

三个选完之后最容易栽的地方

第一,参数写错不会报错。 README 明说:CLI 只为选中的后端构造配置,未激活后端的已知选项仍然被接受,只是带警告地忽略;JSON 配置里多余的非激活后端键同理。翻译成人话——你选了 Kokoro 却在命令行里写了一串 --qwen3_tts_*,程序不会停下来告诉你写错了,它会警告一句然后照跑,你还以为参数生效了。改完参数发现行为没变,先回头看是不是给了另一个后端的参数。

第二,两个量化参数不是一个开关。 --qwen3_tts_ggml_quantization(默认 BF16)管的是非 macOS 的 GGML 后端,--qwen3_tts_mlx_quantization(默认 6bit)管的是 Apple Silicon 上的 mlx-audio。跨平台抄命令的时候这两个最容易抄错,抄错了正好撞上第一条——不报错。

第三,怎么确认你看的是对的默认值。 README 给的方法是 speech-to-speech serve -h,而且要看另一种组合的参数,得把选择器放在 -h 前面,比如 speech-to-speech serve --stt mlx-audio-whisper -h。这条很反直觉,但它是你在本机核对默认值的唯一可靠手段——本文所有默认值都以你自己那份 -h 输出为准,版本一变就可能不同。

顺带说一句选择器取值本身:事实层面我们能确认的只有 --tts 默认 "qwen3",以及 README 示例里出现过的 --tts pocket。其余三个后端的选择器字面量请照 -h 的实际输出写,别照猜。

一句话版本的结论

  • Apple Silicon:先用默认(Qwen3-TTS 走 mlx-audio),跑通再谈换。
  • 有 NVIDIA 卡:默认可用,但先把 CUDA wheel 那一关过了;不想过就 --qwen3_tts_backend torch 或改用 Kokoro。
  • 纯 CPU:从 Pocket TTS(默认设备就是 cpu)或 Kokoro(auto)起步,别硬扛默认那三个写死 cuda 的。
  • 要中文:先换 STT,再在 TTS 侧考虑 ChatTTS 或 Qwen3-TTS 的 auto;谁的中文更好没有官方数据。
  • 要克隆音色:Pocket TTS 或 Qwen3-TTS 的 ref 系参数,二选一。
  • 要多人用:先改 --num_pipelines,再谈 TTS 选谁。

什么情况下这套路径不适用:你有明确的音质或延迟指标要达标——那这篇帮不了你,因为这些维度我们没有任何数据,只能你自己在目标机器上按同一段文本、同一套硬件横向跑一遍再定。另外各模型权重(Qwen3-TTS、Kokoro、ChatTTS、Pocket TTS、MMS)的许可各不相同,我们一份都没读过,商用前请自行核对各自模型页面的许可原文。

延伸阅读


本文依据 speech-to-speech 官方仓库(github.com/huggingface/speech-to-speech)的 README、 src/speech_to_speech/arguments_classes/ 下的参数定义与 Realtime Engine 架构文档整理,核对日 2026-08-09。 本文内容为仓库源码与文档口径,我们没有安装、部署或调用过该服务,文中毫秒值均为参数默认值而非实测延迟。 参数与默认值随版本变动,请以 speech-to-speech serve -h 的实际输出为准。

许可条款请以官方 LICENSE 原文为准,本文不构成法律意见。安全相关做法请结合自身环境评估,本文不构成安全方案建议。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。