默认 STT 只覆盖 25 种欧洲语言:想说中文得先换它
speech-to-speech 是 Hugging Face 的开源语音代理流水线,仓库描述原文是 “Build local voice agents with open-source models”,GitHub 上 star 数 11893(2026-08-09 快照,仓库标注 Apache-2.0)。它的结构是四段级联:VAD → STT → LLM → TTS,每段都能换后端。
装完之后按 README 的 Quickstart 三条命令跑起来,speech-to-speech serve 的等价完整命令里,STT 那一环是 --stt parakeet-tdt。而在 parakeet_tdt_arguments.py 里,--parakeet_tdt_language 这个参数的 help 文本最后一句写得很直白:Supports 25 European languages。README 的多语言表格也是同一口径——STT 那一行,Parakeet TDT(默认)对应的语言列就是「25 种欧洲语言」。
所以这条链子对中文用户来说,第一环就是断的。这篇不打算把 131 个 CLI 参数抄一遍,只回答一件事:要让它听懂中文,你该换哪个 STT,怎么换。
先搞清楚语言能力挂在哪一层
一个很常见的误解是「这个项目支不支持中文」。按 README 的写法,这个问题问错了层级:语言覆盖取决于你选的 STT 与 TTS,而不是流水线本身。
把 README 的多语言表按「跟中文有没有关系」重排一下,只留下这篇要用的行:
| 环节 | 后端 | README 给的语言口径 |
|---|---|---|
| STT | Parakeet TDT(默认) | 25 种欧洲语言 |
| STT | Whisper / Whisper MLX / Faster Whisper | 广泛多语言,取决于所选 Whisper 检查点 |
| STT | Paraformer | 取决于所选 FunASR 检查点,默认那个偏中文 |
| TTS | Qwen3-TTS(默认) | 多语言,默认 --qwen3_tts_language auto |
| TTS | ChatTTS | 英文与中文 |
| TTS | MMS TTS | 通过 MMS 检查点提供广泛多语言 |
看完这张表能得到一个对定位很有用的结论:默认配置里出问题的是 STT 一环,不是两环。 默认 TTS 是 Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice,README 把它归在「多语言」,而且默认就带 --qwen3_tts_language auto。也就是说,你大概率只需要动 --stt(以及它对应的语言参数),而不必连 TTS 一起换。
还有一个更隐蔽的默认值要一起改:--language 的默认值是 en。这个参数在 whisper_stt_arguments.py 与 mlx_audio_whisper_arguments.py 里都有定义,help 里列出的可选值包括 en、fr、es、zh、ko、ja、hi,以及 auto。换了 STT 却忘了改它,等于让识别环节仍然按英文的预期在跑。
决策路径:四个问题问完就有答案了
罗列后端没有意义,直接从你的处境往下走。
问题一:你在什么平台上跑?
这一步筛掉的候选最多,因为安装矩阵本身就是按平台分的。
- Apple Silicon(macOS):可选 Lightning Whisper MLX(
whisper-mlxextra)与 MLX Audio Whisper(README 标注 macOS 上内置)。后者的默认检查点是mlx-community/whisper-large-v3-turbo。 - CUDA / CPU(含 Windows、Linux):可选 Whisper(通过 Transformers,内置)、Faster Whisper(
faster-whisperextra)、Paraformer(paraformerextra,走 FunASR)。
extra 的安装写法 README 都给了,照抄即可:
pip install "speech-to-speech[faster-whisper]" # Faster Whisper STT
pip install "speech-to-speech[whisper-mlx]" # macOS 上的 Lightning Whisper MLX STT
pip install "speech-to-speech[paraformer]" # 通过 FunASR 的 Paraformer STT
问题二:只说中文,还是中英混说?
这两种情况 README 明确分成了两种使用模式。
单语言模式:把 --language 设成目标语言代码。README 给出的中文示例是这条(原样抄,注意它是 macOS 的 MLX 路径):
speech-to-speech serve \
--stt whisper-mlx \
--stt_model_name large-v3 \
--language zh \
--llm_backend mlx-lm \
--model_name mlx-community/Qwen3-4B-Instruct-2507-bf16
这条命令里有个细节值得注意:--stt_model_name 在 whisper_stt_arguments.py 中的默认值是 distil-whisper/distil-large-v3,而 README 的中文示例显式把它换成了 large-v3。README 没解释为什么换,我们也不替它解释;按它给的「语言覆盖取决于所选 Whisper 检查点」的口径,检查点必须由你显式挑,这一项不能沿用默认值。
语言切换模式:--language auto,由 STT 逐句检测语言再转给 LLM。可选再加 --enable_lang_prompt,它会追加一句 “Please reply to my message in …” 的指令。这个开关在 language_model_base_arguments.py 里默认是 False,README 给的判断依据是:大模型通常能从上下文推断该用什么语言回,但对小模型来说这条显式指令可能有帮助。
翻译成决策语言就是:你用的 LLM 越小,越值得把 --enable_lang_prompt 打开。 用大模型时它是多余的一轮指令。
问题三:中文这一环,Whisper 系和 Paraformer 选哪个?
这是唯一需要横向比的一步,而能比的维度其实很少。
Paraformer 的参数只有两个:--paraformer_stt_model_name 默认 paraformer-zh,help 里指向 FunASR 的模型列表;--paraformer_stt_device 默认 cuda。README 对它的语言描述是「取决于所选 FunASR 检查点,默认那个偏中文」——从默认检查点标识就能看出来它是奔着中文去的,这是这条路径唯一的、也是最实在的选型依据:默认值就对准了中文,你少改一处。
Faster Whisper 那边默认值则完全反过来:--faster_whisper_stt_model_name 默认 tiny.en,--faster_whisper_stt_gen_language 默认 en。要做中文,这两项都得显式改,且改成什么检查点得你自己定。
至于「哪个识别中文更准」「哪个更快」——README 没给任何准确率、延迟或吞吐数据,我们也没有下载过任何模型权重、没有跑过一次推理,这个维度我们不比。 这里能给的只是配置层面的成本差异:Paraformer 默认值离中文更近,Whisper 系的可选检查点更多、跨平台路径更全(CUDA/CPU 与 Apple Silicon 都有对应实现)。
问题四:这套要不要进生产?
到这一步就跟中文没什么关系了,但换 STT 的人常常紧接着就撞上它们。
默认只承载一个并发会话。 --num_pipelines 默认是 1,它的 help 写得很清楚:一个 uvicorn 服务监听 --port,把每个进来的客户端路由到下一个空闲流水线,每条流水线有自己的 VAD/STT/LM/TTS 处理器与会话状态,最大并发 WebSocket 会话数等于 num_pipelines,超出的连接会被拒绝。多用户部署要动的第一个参数就是它。
默认只绑定本机。 --host 默认 127.0.0.1,--port 默认 8765。help 原文说的是:显式传 0.0.0.0 才会把这个未认证的(unauthenticated) API 暴露到网络上。同样地,--enable_llm_proxy 默认 False,官方对它的声明是服务端自己不认证、不限流,只应在受信网络或网关后启用。这里必须把话说死:本文不给「这样配就安全了」的结论,暴露方式请结合你自己的网络环境评估。
中文场景下 LLM 那一环的连带问题
换完 STT 你会发现另一个反直觉的默认值:项目叫 “Build local voice agents”,但 --llm_backend 默认是 responses-api,--model_name 默认是 gpt-5.4-mini——开箱即用的配置里,LLM 那一环打的是云端。
如果你换 STT 的动机之一是数据不出网,那 LLM 必须一起换。README 给的最省事的全本地做法是把 LLM 放到独立的 llama.cpp 进程:
# 终端 1:llama.cpp 提供 Gemma 4
llama-server -hf ggml-org/gemma-4-E4B-it-GGUF -np 2 -c 65536 -fa on --swa-full
# 终端 2:speech-to-speech 指向这个本地服务
speech-to-speech serve \
--stt parakeet-tdt \
--llm_backend responses-api \
--tts qwen3 \
--model_name "ggml-org/gemma-4-E4B-it-GGUF" \
--responses_api_base_url "http://127.0.0.1:8080/v1" \
--responses_api_api_key "" \
--responses_api_stream \
--enable_live_transcription
要做中文,把上面第二条里的 --stt parakeet-tdt 换成你在问题三里选定的那个后端,并补上对应的检查点与 --language zh。以上为按官方参数语义组合的示例,未逐项实测,以官方文档与 --help 的实际输出为准。
另外,Docker 那条路 README 也给了:装好 NVIDIA Container Toolkit 后 docker compose up,compose 会起一个跑 Gemma 4 的 llama.cpp 服务和实时服务,暴露端口 8080 与 8765。
真要断网跑,README 的 Offline Operation 一节有一条容易漏的前置动作:断网前先在联网状态下用完全相同的配置启动一次,让它把 STT、LLM、TTS、Silero VAD、NLTK 和 Smart Turn 需要的资源缓存下来,然后才是 HF_HUB_OFFLINE=1。换过 STT 就等于换了配置,这一次预热得重做。
一个会让你白找半天的静默行为
选型阶段最该记住的一条 README 原文:CLI 只为选中的后端构造配置;未激活后端的已知选项仍然被接受,但会带警告地忽略。 JSON 配置同理。
这句话的实际后果是:你写 --stt whisper 却顺手加了 --faster_whisper_stt_gen_language zh,程序不会报错停下,只会警告一句然后照跑——而你以为自己已经把语言设成中文了。
怎么确认自己写的参数属于当前选中的后端?README 给了判定动作:看某个组合的默认值与专属参数用 speech-to-speech serve -h;要看另一种组合的参数,把选择器放在 -h 前面:
speech-to-speech serve --stt paraformer -h
换 STT 之后,先跑一次这条命令,确认你打算加的每个参数都出现在输出里,再去改启动脚本。
顺便澄清两件不该混的事
第一,VAD 侧那堆毫秒值跟你换不换 STT 没关系,也不能当成延迟指标。 --thresh 默认 0.6、--min_silence_ms 默认 64、--min_speech_ms 默认 384、--speech_pad_ms 默认 500,Smart Turn 侧 --smart_turn_threshold 默认 0.5、--smart_turn_incomplete_delay_ms 默认 600、--smart_turn_max_wait_ms 默认 2000、--speculative_reopen_ms 默认 800、--unanswered_reopen_ms 默认 7000。这些是流水线自己引入的、可配置的等待,不含 STT/LLM/TTS 的推理耗时,把它们加起来得出「端到端多少毫秒」是错的,那三段真正吃算力的时间取决于你的模型与硬件。
第二,--enable_live_transcription(模块级,默认 True)与 --enable_realtime_transcription(VAD 侧,默认 False)是两个不同的参数,名字只差一个词,别抄混。
换完之后检查这几处
--stt换了,且对应的检查点参数(--stt_model_name/--paraformer_stt_model_name/--faster_whisper_stt_model_name)显式指定了,没有沿用默认值。--language从默认的en改成zh或auto;用小模型时考虑加--enable_lang_prompt。- 跑一次
speech-to-speech serve --stt <你选的> -h,确认所有参数都在这个组合的输出里,没有被静默忽略的。 - 数据不出网的话,
--llm_backend与--responses_api_base_url一起改掉,别让 LLM 还在打云端。 - 要多人用,改
--num_pipelines;要对外暴露,先想清楚--host 0.0.0.0之后谁来做认证和限流。 - 密钥用环境变量传(
$OPENAI_API_KEY/$HF_TOKEN),别写进脚本。
各模型权重的许可各不相同,我们一份都没读过,以各模型页面的许可为准。
延伸阅读
本文依据 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 原文为准,本文不构成法律意见。安全相关做法请结合自身环境评估,本文不构成安全方案建议。