3.1 流式ASR与流式TTS管线 本节摘要:实时语音交互的两块基础组件是流式 ASR(语音转文字)和流式 TTS(文字转语音)。流式 ASR 的核心是用语音活动检测(VAD)切分语音段,再对每个段做增量识别,边说边出文字,而不是等用户说完才处理。流式 TTS 的核心是把待合成的文本切成短句并行合成,让第一个音节尽快出来,而不是等整段合成完。两者各有延迟来源和优化手段,本节拆解它们的内部管线,重点讲 VAD 触发、分块识别、分句并行合成这些降低可感知延迟的工程技巧。
本节摘要:实时语音交互的两块基础组件是流式 ASR(语音转文字)和流式 TTS(文字转语音)。流式 ASR 的核心是用语音活动检测(VAD)切分语音段,再对每个段做增量识别,边说边出文字,而不是等用户说完才处理。流式 TTS 的核心是把待合成的文本切成短句并行合成,让第一个音节尽快出来,而不是等整段合成完。两者各有延迟来源和优化手段,本节拆解它们的内部管线,重点讲 VAD 触发、分块识别、分句并行合成这些降低可感知延迟的工程技巧。
阅读完本节,你应当能够:
设想一个最朴素的语音助手:用户按住说话,说完松开,系统把整段录音送 ASR 一次转完,文字送 LLM 生成完整回复,回复整段送 TTS 合成完,再播放。这个流程的延迟有多长?假设用户说了 5 秒,ASR 处理 1 秒,LLM 生成 3 秒,TTS 合成 2 秒,播放本身又 5 秒——用户从说完到听完总共要等 6 秒(ASR+LLM+TTS),加上播放的 5 秒,体验极差。
问题出在"等整段"上。用户说到第 2 秒时,其实前 2 秒的语音已经可以转出文字了,没必要等说完。LLM 拿到前几句文字也能开始生成,没必要等全部转完。TTS 拿到 LLM 的前几个字也能开始合成,没必要等回复全部生成。如果每个环节都流式并提前启动下一环节,总延迟能从 6 秒压到 1–2 秒,这就是流式语音交互的核心思路。
但流式带来一堆工程难题:怎么知道用户"说完一句"了(VAD 的职责)?ASR 边出边改,中间结果和最终结果怎么区分?LLM 还在生成时 TTS 就开始合成,万一后面内容变了怎么办?这些就是本节和下一节要拆解的。
VAD(Voice Activity Detection)判断音频流里"哪段是人在说话、哪段是静音或噪声"。它是流式 ASR 的起点——只有知道用户开始说话了,才启动识别;只有判断用户停顿够了(比如静音超 500ms),才认为一句话结束,把这段提交识别。
VAD 的实现从简单的能量阈值(音量超多少算说话)到基于神经网络(Silero VAD、WeNet)的分类器都有。神经网络 VAD 在噪声环境下(咖啡馆、车里)明显更准,因为能区分人声和背景噪声。它的延迟主要来自"句末判断"——要等静音持续够久才能确认用户说完了,这个等待时间(通常 300–800ms)是 ASR 不可避免的固定开销。
| VAD 类型 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 能量阈值 | 音量超阈值算说话 | 极快、零成本 | 噪声环境误判严重 |
| 频谱特征 | 结合频率分布判断 | 比纯能量准 | 中等噪声仍不稳 |
| 神经网络 | 训练分类器区分语音/非语音 | 噪声鲁棒、最准 | 有计算开销 |
💡 关键直觉:VAD 的句末等待时间是个两难。设短了(比如 200ms),用户正常停顿就被误判为说完,一句话被切成几段,识别和对话都乱;设长了(比如 1.5 秒),响应明显迟钝。实践中 500–800ms 是多数场景的甜点,但要根据业务调——快节奏指令场景设短些,长篇叙述场景设长些。
VAD 切出一段语音后,ASR 模型对它做识别。如果等整段录完再一次性识别,延迟就是整段时长。流式 ASR 的做法是把音频流切成小块(比如每 100–300ms 一块),每来一块就送模型做一次增量识别,输出当前累积的转写结果。
这里要区分两类输出:中间结果(partial) 和 最终结果(final)。中间结果是模型"目前认为"的转写,会随着更多音频输入而修正——比如前 200ms 它听到"你好",再来 200ms 听到"世界",它会把整段修正为"你好世界"。最终结果是句末确认后的稳定转写。下游(比如 UI 显示)可以用中间结果做实时字幕,但送 LLM 必须用最终结果,否则 LLM 会基于不断变化的输入混乱。
流式 ASR 的延迟来源主要有三块:分块积累(每块 100–300ms)、模型推理(每块几十到几百 ms)、句末等待(VAD 判断 500–800ms)。加起来一句短语的"说完到出最终文字"通常 600ms–1.2s。
TTS 把文字转成语音。朴素做法是等 LLM 生成完整回复,整段送 TTS 合成完再播放,延迟等于 LLM 总时长加 TTS 总时长。流式 TTS 的优化是分句并行:LLM 每生成完一个短句(按标点或字数切分),立刻送 TTS 合成这句,合成完就播放这句,同时下一句在生成和合成。
关键优化是首音优先——让用户听到的第一个音节尽快出现。这要求 TTS 不等 LLM 生成很多,拿到第一个短句(哪怕只有几个字)就开始合成并播放。代价是后续句子可能需要更细的缓冲管理,避免播放到某句时下一句还没合成好导致卡顿。
| 策略 | 首音延迟 | 整体流畅度 | 实现复杂度 |
|---|---|---|---|
| 等完整回复再合成 | 最高(几秒) | 最好(无卡顿) | 最低 |
| 按完整句切分 | 中(1–2句后) | 好 | 中 |
| 按短语/标点切分 | 低(首句即播) | 较好(要管理缓冲) | 高 |
| 逐 token 合成 | 极低 | 易卡顿/不自然 | 极高 |
⚠️ 常见坑:切分粒度不是越细越好。按单字或极短短语切分,TTS 合成出来的语音会很不自然——因为语调、重音是基于上下文的,孤立合成一个字和合成完整句的效果差很多。实践中按完整句或至少一个短语(带标点的片段)切分,自然度和延迟的平衡最好。
选 ASR 引擎要考虑几方面:
流式能力:是不是原生支持流式输入和中间结果输出。有些引擎只能离线处理整段音频,不适合实时。
多语言支持:你的用户说什么语言。主流的 Whisper Streaming、各云厂商的 ASR 都支持多语言,但小语种准确率差异大。
部署形态:云端 API(省事但延迟受网络影响、数据要出境)还是本地部署(延迟低、数据不出,但要自己运维)。实时语音交互对延迟敏感,本地或专线部署往往更稳。
定制化:能不能加领域词表(专业术语、产品名)、能不能微调适应口音。垂直领域(医疗、法律)通用 ASR 经常识别错专业词,定制化能力很重要。
TTS 引擎这几年进步很大,从机械的拼接合成到神经网络合成(VITS、FastSpeech2、以及最新的大模型 TTS),自然度已经接近真人。但越自然的模型通常越大、越慢,延迟和质量的权衡要做。
一个常见的工程做法是用两个 TTS:快速 TTS 合成首句(优先低延迟,质量可略低),高质量 TTS 合成后续句(延迟要求宽松,质量优先)。这样首音延迟低,整体质量也好。
# 概念性双 TTS 管线 class DualTTS: def __init__(self): self.fast_tts = FastLightweightTTS() # 小而快 self.quality_tts = NeuralHiFiTTS() # 大而好 async def synthesize_stream(self, text_stream): first = True async for sentence in text_stream: if first: # 首句用快速TTS,抢首音延迟 audio = await self.fast_tts.synth(sentence) first = False else: audio = await self.quality_tts.synth(sentence) yield audio
把端到端延迟预算拆到各环节,能帮你判断哪里值得优化。一个典型配置:
| 环节 | 典型延迟 | 优化空间 |
|---|---|---|
| VAD 句末等待 | 500–800ms | 有限(两难) |
| ASR 增量推理 | 100–300ms | 中(换更快模型/硬件) |
| LLM 首字 | 300–800ms | 大(第2章的优化) |
| TTS 首音合成 | 200–500ms | 中(分句、快速TTS) |
| 网络往返 | 50–200ms | 中(就近部署) |
| 总计 | 1.2–2.6s | — |
总延迟控制在 1.5 秒内能让对话感觉自然,超过 2.5 秒用户会觉得卡。看上面表,LLM 首字和 VAD 句末是最大头,优化重点应放这俩。
💡 关键直觉:别只盯一个环节优化。我曾经见过团队把 TTS 从 500ms 优化到 200ms,但 VAD 句末等了 800ms,总延迟没降多少。要算总账,找到占比最大的环节下手。一个简单的做法是在每个环节加埋点统计,看实际占比再决策。
下一节把 ASR、LLM、TTS 串成完整的端到端语音交互系统,重点讲三者的流式咬合、打断处理,以及端到端语音模型带来的新范式。
两个组件的历史厚度容易被低估。ASR 从上世纪的 HMM-GMM 时代走到端到端神经网络(CTC、RNN-T、注意力编解码),每一次范式切换都在改写"流式"的实现方式:CTC 天然支持流式但输出无语言模型约束、同音字错误多;RNN-T 专为端侧流式设计,成为手机离线输入法的主流;注意力编解码准确率最高但需要整段音频,工程上靠"块级注意力 + 有限左上文"改造出流式版本。理解这个背景,你就能看懂各家云厂商 ASR 产品文档里"实时率""字准率""中英混说"这些指标背后的取舍。
Whisper 的流行给流式管线带来了一个有趣的工程课题:它是为离线整段转写设计的,社区把它改造成流式的方案有两类。一类是滑动窗口重解码——保留几秒历史音频,新块到达后连同历史一起重转,靠热词缓存和结果 diff 降低成本,实现简单但计算有冗余;另一类是局部一致策略——只信任最新窗口的输出,历史部分冻结,避免窗口滑动时同一句话被反复改写。Voice Activity Dashboard 类工具的经验表明,200–300 ms 的音频块长是延迟和识别稳定性的甜点,再短则每块的声学上下文不足,误触发和断句错误明显上升。
TTS 这十年的变化更剧烈。拼接合成和参数合成(STS、WaveNet 时代之前)让位给神经声学模型 + 声码器两段式架构,再到近年的单模型端到端 TTS 和零样本音色克隆。对流式管线来说,关键工程点从"合成质量"转移到了"合成延迟的结构":现代方案普遍把文本前端(正则化、多音字、韵律预测)做轻量化,把声学模型和声码器蒸馏到能单 A10 实时率 0.1 以下的规模,同时支持流式输出——输入端吃音素序列,输出端逐帧吐 mel 频谱,播放器边收边播。落地时的常见坑是文本前端的多音字错误("重庆"读错、"行"的读音),这类错误在评测集里测不出来,要用业务真实语料做发音抽检。

问:ASR 中间结果要不要展示给用户?答:展示能强化"它在听"的感知,但要处理中间结果改写带来的界面跳动(用户已瞥到"进京证"又变成"京城证"会动摇信任),常用做法是低置信度词淡显、最终结果落定后加粗。问:自建 TTS 还是调云服务?答:首版用云服务快速验证体验,日调用量上到千万级、或对音色资产有独占要求时再自建,自建的真实成本在发音抽检和韵律调优的人力,不在 GPU。问:VAD 参数怎么定?答:留白阈值和业务语速强相关——老人客服场景要放宽到 900 ms,游戏语音指挥要收紧到 300 ms,用真实录音标一遍静音分布比拍脑袋可靠。