默认 STT 只覆盖 25 种欧洲语言:想说中文得先换它

2026-08-09

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 给的语言口径
STTParakeet TDT(默认)25 种欧洲语言
STTWhisper / Whisper MLX / Faster Whisper广泛多语言,取决于所选 Whisper 检查点
STTParaformer取决于所选 FunASR 检查点,默认那个偏中文
TTSQwen3-TTS(默认)多语言,默认 --qwen3_tts_language auto
TTSChatTTS英文与中文
TTSMMS TTS通过 MMS 检查点提供广泛多语言

看完这张表能得到一个对定位很有用的结论:默认配置里出问题的是 STT 一环,不是两环。 默认 TTS 是 Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice,README 把它归在「多语言」,而且默认就带 --qwen3_tts_language auto。也就是说,你大概率只需要动 --stt(以及它对应的语言参数),而不必连 TTS 一起换。

还有一个更隐蔽的默认值要一起改:--language 的默认值是 en。这个参数在 whisper_stt_arguments.pymlx_audio_whisper_arguments.py 里都有定义,help 里列出的可选值包括 enfreszhkojahi,以及 auto。换了 STT 却忘了改它,等于让识别环节仍然按英文的预期在跑。

决策路径:四个问题问完就有答案了

罗列后端没有意义,直接从你的处境往下走。

问题一:你在什么平台上跑?

这一步筛掉的候选最多,因为安装矩阵本身就是按平台分的。

  • Apple Silicon(macOS):可选 Lightning Whisper MLX(whisper-mlx extra)与 MLX Audio Whisper(README 标注 macOS 上内置)。后者的默认检查点是 mlx-community/whisper-large-v3-turbo
  • CUDA / CPU(含 Windows、Linux):可选 Whisper(通过 Transformers,内置)、Faster Whisper(faster-whisper extra)、Paraformer(paraformer extra,走 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_namewhisper_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 服务和实时服务,暴露端口 80808765

真要断网跑,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)是两个不同的参数,名字只差一个词,别抄混。

换完之后检查这几处

  1. --stt 换了,且对应的检查点参数(--stt_model_name / --paraformer_stt_model_name / --faster_whisper_stt_model_name)显式指定了,没有沿用默认值。
  2. --language 从默认的 en 改成 zhauto;用小模型时考虑加 --enable_lang_prompt
  3. 跑一次 speech-to-speech serve --stt <你选的> -h,确认所有参数都在这个组合的输出里,没有被静默忽略的。
  4. 数据不出网的话,--llm_backend--responses_api_base_url 一起改掉,别让 LLM 还在打云端。
  5. 要多人用,改 --num_pipelines;要对外暴露,先想清楚 --host 0.0.0.0 之后谁来做认证和限流。
  6. 密钥用环境变量传($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 原文为准,本文不构成法律意见。安全相关做法请结合自身环境评估,本文不构成安全方案建议。

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