19. 语音与多模态推理
前面一直是打字提问。现在小林对麦克风说“年假怎么申请?”,希望直接听到回答。这一篇先沿着这段声音走一遍,看语音识别、语言模型和语音合成怎样接力;再用 sherpa-onnx 看语音框架怎样把模型接进应用;然后判断前面学过的缓存、批处理、量化,哪些能用在语音上、哪些不能;最后讨论怎样测量语音的等待。读完你应该能分清模型、语音框架和计算后端,也能区分首字、首 token 和首个可播放音频这几种“快”。
同一个问题,多了哪些接力
小林的声音先变成文字,资料助手生成回复,再把回复变成声音。可以把它想成“听写员 → 资料答疑员 → 播音员”的接力:中间的人写得再快,也不能消除听写员判断是否说完、播音员准备开口的等待。实际系统可让几段工作重叠,图中还画出了用户打断时的控制路径。
语音推理同样适用缓存、批处理、量化和调度这些思想,但不一定能直接用 vLLM 或 SGLang 执行整条链路。 要先看模型怎样计算,再看引擎是否实现了它的输入、状态、输出与流式协议。“能输入音频”“能流式转写”“能实时生成音频”是三种不同能力。
sherpa-onnx 把语音模型接进应用
小林希望断网时也能在设备上识别问题。只下载一个模型文件还不够:麦克风提供的是声音采样,模型可能需要声学特征;模型输出的是概率或编号,应用需要的是文字。支持流式的模型还要保留跨音频块的状态。
sherpa-onnx 是语音推理与部署框架,把这些步骤组织起来。它有 C++ 核心和多种语言接口,可以部署在手机、桌面、嵌入式设备,也可以在服务器上提供服务。它覆盖语音识别、语音合成、人声检测、关键词检测、说话人相关任务等;具体能力由模型、框架版本和设备后端共同决定。
下面拆开一次识别。ONNX 是模型的表示格式,ONNX Runtime 是执行模型计算的运行时;sherpa-onnx 在计算前后补上语音任务需要的处理。图中展示常见 ONNX Runtime 路线,部分设备使用专门后端。
沿箭头看:采样先变成模型所需的输入,神经网络执行计算,再由适配的解码器解释输出。不同架构的特征、状态和解码步骤会有所不同。能用 ONNX Runtime 加载文件,只验证了其中一层;模型的输入输出、词表和前后处理也要与框架适配。
现在把它接回资料助手。下面用固定教学样例推进“听 → 答 → 说”,每一步都会改变当前数据和接手的组件。
小林:年假怎么申请?固定样例 · 教学回放
- 1收音
- 2准备输入
- 3模型计算
- 4得到文字
- 5查资料并回答
- 6合成声音
- 7播放
1 / 7 · 应用 · 音频接入
- 输入
- 麦克风的声音采样
- 输出
- 采样率、声道明确的音频块
应用取得录音权限,检查音频格式,把音频块送给识别器。此时还没有文字,也没有调用语言模型。
模型与结果均为教学示例;不录音、不调用真实模型。实际服务可以重叠运行部分阶段,耗时需单独测量。
识别文字交回应用后,应用检查资料权限、检索年假制度,再把资料和问题交给语言模型服务。sherpa-onnx 可以负责两端的 ASR 和 TTS,vLLM 或 SGLang 可以承接中间已适配的语言模型。播放器与打断控制仍由应用协调。离线要求覆盖整条链路时,语言模型与资料也需要在本地或内网可用。
版本变化要单独回归:sherpa-onnx 2.0.0
sherpa-onnx 从 1.13.x 升到 v2.0.0(2026-10-23 20:49,上海时间)。这一版不再内置 espeak-ng 和 piper-phonemize:TTS 的文本前端只保留内置词典(lexicon)路线,依赖这两个库生成音素的模型要在外部先完成音素化,再把音素或 token 传入;原来指向 espeak 数据的 data_dir 配置会被忽略。识别侧则为流式 NeMo Transducer 补上了 modified_beam_search 热词,并修复了长流 VAD 崩溃、识别结果 JSON 转义等问题。
这些变化分别关系到 TTS 接口兼容、热词可用范围与长时间运行的稳定性,不能相加成一个通用加速倍数。评估升级时,固定模型与录音,先确认所用 TTS 模型是否依赖 espeak 音素化,再分别回归识别结果、热词和长流运行;是否受益取决于实际使用的识别器、合成模型和运行路径。
都在做推理,为什么不能直接替换
“模型”好比听写的方法,“计算后端”是执行数字运算的设备接口,“语音框架”把收音、计算和文字结果组织成可调用的任务;多人服务还会增加排队与调度。实际项目可以覆盖多个层次,先确定职责再比较工具。
| 对象 | 在这个例子里负责什么 | 比较时看什么 |
|---|---|---|
| ASR / TTS 模型 | 决定声音与文字之间怎样转换 | 语言、准确率、音质、架构与资源需求 |
| sherpa-onnx | 组织已适配语音模型的输入、执行、解码、流状态与语言接口 | 模型与设备组合、流式结果、内存、实时率 |
| ONNX Runtime | 执行受支持的计算图与算子 | 算子、精度、执行后端、硬件兼容性 |
| vLLM / SGLang | 组织已适配生成模型的缓存、批处理与服务调度 | 首 token、生成间隔、并发容量、显存与成本 |
FunASR 也有推理与部署能力;它与 sherpa-onnx 在部分语音场景存在交集,也可以在模型导出与部署环节配合。选择时应核对具体模型的适配和产品需求,而不是固定成“一个只训练、一个只推理”。
热词怎样影响识别
假设公司联系人叫“周望君”,模型却把相似发音写成“周望军”。热词增强会在搜索候选文字时,给指定词对应的路径增加分数;模型参数可以保持不变。训练或微调则会更新参数,两者处理问题的位置不同。
截至 2026-10-26,sherpa-onnx 的热词文档限定这套能力使用 Transducer 模型与 modified_beam_search 解码,流式和非流式均有支持。下面只演示配置条件,不计算真实声学概率。
联系人:周望君配置条件 · 教学实验
模型条件满足解码条件满足权重始终不变
具备热词增强条件
搜索时可给“周望君”对应的路径加分,模型权重保持不变。候选是否最终胜出仍取决于声音、原始分数和热词分数。
这里只判断文档规定的配置前提,不模拟识别准确率,也不预测错误配置会被具体接口如何处理。实际还要核对词表、热词文件和加载结果。
具备热词条件时,也要测“该出现时是否识别正确”和“不该出现时是否被误插入”。加分过高可能把普通词强行拉向热词。把热词写入文件后,还需要确认目标接口确实加载了文件;模型不匹配或仍使用贪心解码时,这条热词增强路线就用不上。
从哪里开始实际接入
先选一个官方已适配的模型包,在电脑上用文件识别例子跑通同一段录音,确认文字结果。接着换到目标设备,保持模型、词表和音频相同,比较结果与耗时。最后再接麦克风、验证流式或切段行为,以及业务需要的热词、时间戳等输出。
这里“支持 Android”“支持某个模型”“支持 NPU”是三项条件。落地时需要确认目标模型 × 框架版本 × 设备后端 × 所需功能的组合可用;导出格式相同也可能因算子、状态或接口适配而失败。
具体 API 与配置沿已有专题继续:sherpa-onnx 概览、识别运行模式、模型与部署选型。下面回到计算结构,看看为何不同语音模型能借用的优化各有边界。
进一步区分:不同 ASR / TTS 架构能迁移哪些优化?
| 语音路线 | 核心计算 | 可迁移的优化 | 需要专门处理的部分 |
|---|---|---|---|
| CTC ASR | 声学编码器输出帧级分布,再折叠或搜索 | 算子、量化、声学 batch、长度分桶 | 特征帧、流式状态、CTC 解码与热词 |
| Transducer ASR | encoder、prediction network、joint 协作 | 编码器优化、搜索批处理、状态池 | blank、对齐、beam、跨块状态 |
| Encoder-decoder ASR | 音频编码,再自回归生成文本 | decoder KV、批处理、attention 优化 | encoder 状态、cross-attention、长音频分段 |
| LLM 型 ASR | 音频编码与投影,语言模型生成文本 | 受支持路径上的 KV、连续 batch、量化 | 音频编码、模态位置、输入处理与端点 |
| 时长/声学模型加声码器 TTS | 文本到声学特征,再转波形 | batch、编译、算子与精度优化 | 时长、音素、声学帧、声码器分块 |
| 自回归音频 token TTS | 逐步生成语义或 codec token | 可能使用 KV、调度、投机 | 多码本、采样、codec 解码与音频拼接 |
| 扩散 / flow TTS | 多步去噪或积分生成声学表示 | 编译、融合、batch、减少求解步骤 | 质量与步数关系、条件编码和声码器 |
| 端到端语音模型 | 音频输入输出,可能交错文本与音频 | 引擎已适配部分的调度与缓存 | 全双工、音频时钟、打断、回声和多流状态 |
Whisper 类架构含自回归 decoder,但不等于普通纯文本 decoder-only 模型。Flow 或扩散模型的“步数”,也不是 LLM 的输出 token 数。每个路线都应使用与自身结构匹配的优化和质量指标。
语音为什么还有等待
一段离线音频可以一次送入模型;实时麦克风只能不断收到未来的声音。系统可能要攒够一个声学块,保留右侧上下文,等待人声检测(VAD,判断有没有人在说话)确认这句话已经结束,再修正和提交文本。
对话里“用户已经说完”与“系统确认说完”存在时间差。把断句等待从 500 ms 降到 200 ms,可能比语言模型快几个 token 更影响体验;但过短会在自然停顿处截断句子,损害识别与交互。
ASR 主体通常可以在用户说话时运行;用户停止后,关键路径更接近“端点等待 + ASR 收尾 + 首段回复文本 + TTS 首块 + 播放开销”,而不是把整段 ASR 运行时间再加一遍。
首音频时延预算从用户实际停止说话起算
断句等待
300 ms
累计排队
50 ms
ASR 收尾
150 ms
首段可合成文本
250 ms
TTS 首个可播放块
180 ms
首个可播放音频约 930 ms
串行关键路径估算,未计网络、播放缓冲、回声消除与设备开销;ASR 主体假设已在说话时运行,只计收尾。分块模式仍须攒够可合成文本,后续音频也须及时续上。这里不估计整段对话完成时间。
先降低 LLM 时间,再降低断句等待,观察总预算的变化。切换到等待完整文本和音频,会把两段额外等待带回首音频路径。真实系统可能重叠更多阶段,也可能因网络、语音质量或播放缓冲增加成本,因此要用 trace 校准每项。
从文本片段到连续声音
ASR 可以逐步返回临时文本,但最终结果可能修订;协议需要区分 partial 与 final。TTS 接口即使通过流传输,也可能先算完全部音频再切块返回;这种传输流式并不意味着模型首音频计算已经缩短。
真正的增量 TTS 还要考虑输入文本块是否足以确定发音和韵律。文本太短可能造成停顿、重音或语调不自然;等待整句又增加首音频。LLM 的 token 边界也不一定是适合合成的词句边界。
首块很快只是开始。后续块若不能赶上播放时钟,就会断音。需要同时观察音频 chunk 的到达间隔、可播放时长和缓冲水位。
语音的性能指标
| 指标 | 解释 | 需要防止的误读 |
|---|---|---|
| RTF | 处理墙钟时间 / 音频时长 | 30 秒音频耗时 3 秒,RTF=0.1;实时等待还需测端点、收尾与输出 |
| 首字/首个 partial | 从约定起点到首次文本 | 起点是音频首帧、用户停说还是请求发出,结论不同 |
| Final 时延 | 用户实际结束到稳定最终结果 | 含端点与收尾,不能只测模型 forward |
| 首音频时延 | 到首个可播放音频 | HTTP 首字节可能是头信息或不足以播放的数据 |
| 音频续流 | 块间隔、缓冲和欠载 | 平均生成速度快仍可能偶发长停顿 |
| 质量 | WER/CER、说话人、音质、自然度等 | 不同任务需要不同评估,不能只测吞吐 |
例如 10 路音频的批量离线 RTF 很低,可能来自充分聚批。在线只有一小块音频到达时,等待凑 batch 会损伤延迟;要把 batch 大小和最大等待时间一起调。
取消、打断和会话状态
用户说“停一下”时,需要终止或失效化旧 LLM 请求、TTS 合成、待播放音频,并清理会话引用。已经发出的音频不能靠取消 GPU 任务撤回,播放器也要有清空队列的协议。
底层原生推理未必能立即中断,超时后仍可能继续使用缓冲。应用应区分“用户不再等待”与“底层资源已释放”,避免重复提交同一任务或过早复用内存。具体实践见推理输入合同与资源生命周期。
什么时候选择哪条部署路线
如果模型是引擎明确适配的音频输入或输出生成模型,可以评估 vLLM、SGLang 及其相关多模态扩展,但要单测流式、采样、codec 和并发状态。仅支持文本部分,不能推断整条语音链路都受加速。
传统 ASR/TTS 或端侧 SDK,可以先看 sherpa-onnx、模型官方运行时或 FunASR 等任务框架,再确认它们实际支持的 ONNX Runtime、TensorRT、OpenVINO、Core ML、ExecuTorch 等设备执行路线;这些后端分别属于不同生态,并非每个框架都能任意切换。服务器上的声学模型也可以与 LLM 引擎并列运行,通过业务层连接。
图像与视频同理:视觉 encoder、预处理、多模态 token 展开和解码各有成本。图像数量、分辨率、视频帧数和音频长度可能让“相同文本 token 数”的请求完全不是同一种负载。
判断练习:ASR 的 final 慢 800 ms,换 vLLM 能直接解决吗?
先拆出 VAD 端点等待、声学收尾、decoder、搜索和队列。如果 600 ms 来自确认用户说完,替换 decoder 引擎未必有效。如果模型受支持且 decoder 是主要瓶颈,才有明确的评估方向。还要保持识别质量和切句完整度。
语音交互把听、答、说与播放串在一起。sherpa-onnx 组织语音任务,ONNX Runtime 等后端执行受支持的模型计算,应用连接资料、语言模型和播放控制。端点判断、首个可播放块、后续续流和打断共同决定体验;沿实际结构逐段测量,才能判断该优化解码、调度,还是音频链路。
不管是文字还是语音,优化做完以后都要回答同一个问题:怎样证明它真的有效?下一篇讲性能测试与分析。
