五个 TTS 后端怎么选:默认那个不一定适合你
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 TTS | pocket extra | --pocket_tts_device cpu | README 未单列语言行 | Kyutai Labs 出品,README 描述为「带声音克隆的流式 TTS」 |
| ChatTTS | chattts 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 里列出的支持取值是 BF16、Q8_0、Q4_K_M、F32。
没有 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 既可以填八个预设之一(alba、marius、javert、jean、fantine、cosette、eponine、azelma,默认 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 服务和实时服务,暴露 8080 与 8765 两个端口。这条路把 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 原文为准,本文不构成法律意见。安全相关做法请结合自身环境评估,本文不构成安全方案建议。