ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

实时音频感知模型如何改变语音转写:从ASR到SOTA的工程实践

实时音频感知模型如何改变语音转写:从ASR到SOTA的工程实践 过去转写一段对话录音正确流程是先录完整段音频再上传服务器等待离线识别短则几十秒长则几分钟。开会、访谈、直播字幕这些场景根本等不了这么久。大家真正需要的是说话的同时文字就能跟上甚至能在说话人停顿的几百毫秒内就给出修正后的结果。这就是实时音频感知模型要解决的问题。Muse Voice Transcribe 的出现把这个问题重新拉回讨论中心它是 MSL 旗下首个实时音频感知模型发布口径直接对标当前最优水平SOTA,State-of-the-Art。很多人第一反应是“又一个 ASR 模型”但只看表面会错过重点。它真正值得关注的不是“转写更准”这种老话题而是“实时音频感知”这个能力边界的变化模型不仅要听清你说什么还要在极低延迟下持续理解音频流里的语音、语义和说话人变化。这篇文章不打算只做新闻复述。我会从实时音频感知模型的实际落地出发讲清楚几个问题这类模型和传统语音转写到底差在哪为什么 SOTA 指标不能直接等于业务好用如果要在自己的项目里接入类似能力完整链路应该怎么设计有哪些坑是文档里常常不会写但线上一定会遇到的。无论你是做语音笔记工具、会议纪要、直播字幕还是客服质检这篇文章都值得收藏后慢慢看。1. 实时音频感知模型到底解决了什么痛点很多开发者在做语音功能时踩过的第一道坎是“离线录音再转写”的架构限制。完整的离线识别流程通常是客户端录音、生成音频文件、上传服务端、服务端跑完整 ASR、返回文本。这条链路在录音时长可控、结果不要求即时返回的场景下没有太大问题但一旦叠加了“用户正在说话就想看到文字跟着出现”的需求延迟和交互体验就成了致命伤。实时音频感知模型解决的是另一层问题它不等你的音频变成完整文件而是在音频流还在产生的时候就对已经到达的片段做感知与识别。这里的关键词是“感知”而不仅仅“识别”。传统 ASR 是一个单任务模型输入语音输出文本过程是单向的。实时音频感知模型更像一个持续运转的听觉系统一边接收新的音频片段一边结合前面已经说过的内容推理当前这一段最可能对应的文字、语气和语义边界。从工程架构看这改变了三个环节输入侧从文件上传变成了流式传输。音频按 20ms、40ms、100ms 等切片持续发送而不是一次性传完。推理侧从“等待完整话语”变成了“边听边猜”。模型会先给出临时结果partial result随着音频增多再不断修正成最终结果final result。交互侧从“一次性响应”变成了“实时回调”。前端或业务系统通过事件订阅文字更新而不是发一次请求收一次响应。这些变化带来的直接收益是转写延迟从“录完再等几秒”压缩到“说完后几百毫秒内”。会议纪要工具可以边开边生成记录直播平台可以实时显示字幕语音输入法在按下结束键之前就已经能看到接近正确的文字。但也要说清楚边界。实时音频感知不是万能的。它适合对延迟敏感、对结果连续性要求高的场景但不适合对绝对准确率要求极高、允许等待的离线音频转写。两类场景的技术选型逻辑完全不同后面我会专门对比。2. 核心概念从 ASR 到实时音频感知模型2.1 什么是 ASRASR 是 Automatic Speech Recognition 的缩写中文通常叫自动语音识别。它的任务很朴素给定一段语音输出对应的文字。传统 ASR 系统包含声学模型、语言模型、解码器等模块现在则更多被端到端模型取代输入音频特征直接输出 Token 序列。ASR 的核心评估指标是词错率 WERWord Error Rate。WER 通过计算识别文本与参考文本之间的编辑距离得到数值越低越好。一个 WER 为 5% 的系统意味着平均每 100 个词里有 5 个词被错误替换、删除或插入。2.2 什么是实时音频感知模型实时音频感知模型不是某一个特定算法而是一类模型能力集合。它要求模型能够处理持续输入的音频流并在极短时间窗口内输出对音频内容的理解结果。以 Muse Voice Transcribe 为代表的新一代模型通常同时包含以下几个能力点流式语音识别边接收音频边产生文字而不是等待整段结束。增量结果修正前期输出的临时结果会随着后续上下文出现而被修正模型需要有能力基于新音频更新旧假设。音频事件感知不仅理解语音内容还能感知说话人切换、停顿、语气变化等音频层面的信息。低延迟推理为了保证实时性模型必须能在计算资源有限的情况下在几十到几百毫秒内完成一个片段的分析。注意这里的“实时”在不同产品里定义不同。有的产品把“500 毫秒内返回最终结果”称为实时有的则要求“100 毫秒内返回临时结果”。接入前一定要先搞清楚对方说的是哪一种实时。2.3 MSL 是什么在标题里MSL 指的是推出 Muse Voice Transcribe 的团队或实验室品牌属于研究侧的品牌缩写。从公开发布口径来看Muse Voice Transcribe 是 MSL 在实时音频感知方向上的第一款模型因此它的产品定位和评测结果对后续系列迭代有很强的参考意义。具体代表哪些词的全称官方没有统一说明对外统一使用 MSL 作为品牌代号即可。理解这一点对接入决策有什么用有用。如果 MSL 过去没有实时音频模型积累那么第一版模型更可能的策略是“先跑通能力再打磨细节”如果它背后有成熟的语音研究积累那么第一个实时模型的技术成熟度会高很多。但无论哪种情况都不要因为“SOTA”三个字就跳过自己的评测流程。2.4 SOTA 不等于全场景可用SOTA 是 State-of-the-Art 的缩写表示在某个指定任务、指定数据集上达到当前最优水平。这个表述看似简单实际隐藏了大量限定条件。评测数据集是什么语言是否包含噪声说话人范围有多大领域是通用对话还是专业术语延迟约束是多少这些都是 SOTA 指标成立的前提。换一个场景SOTA 模型的表现可能还不如一个针对该场景微调过的小模型。在实际项目选型里应该把 SOTA 当作“参考起点”而不是“选择终点”。真正要回答的问题是在你的目标场景、目标语言、目标音频条件下这个模型的准确率和延迟是否仍然领先。3. 传统离线转写与实时感知模型的方案对比很多团队在选择语音方案时会把离线转写和实时转写放在一起比较但这两者的架构差异决定了它们很难互相替代。我整理了一个对比表方便你快速把握区别。对比维度离线转写方案实时音频感知方案音频输入完整音频文件实时音频流转写时机录音结束后异步处理说话过程中同步产出单次延迟秒级到分钟级百毫秒级结果特性一次性最终结果临时结果 最终结果上下文利用可依赖整段音频只能用当前及历史音频适合场景录音归档、质检、离线字幕直播字幕、实时会议、语音交互架构复杂度相对简单需要流式处理和重连机制成本特征按音频时长付费或自建GPU批处理常按并发路数或时长计费需要关注空闲时长表格里最容易忽略的差异是“结果特性”。离线转写只给你一个最终结果实时感知模型会先给临时结果再不断修正。如果你在业务层不做处理直接把临时结果渲染给用户会看到文字跳来跳去。这不一定代表模型质量差而是流式识别的正常状态。一个经验法则是如果业务允许用户等 5 秒以上再看到完整结果优先选离线转写它更稳定、成本更低如果用户体验要求“说话时文字就不能停”才需要引入实时音频感知模型。两类系统不是互斥的很多产品会同时用离线模型做归档精转写用实时模型做现场字幕。4. Muse Voice Transcribe 值得关注的技术看点4.1 实时音频感知而不是单纯的流式 ASR“流式 ASR”和“实时音频感知模型”之间不是同一个概念。流式 ASR 只是把解码过程切碎按时间片推进实时音频感知模型则把音频流当作一个持续变化的感知对象不仅要处理语音到文本的映射还要对音频中的人声活动、语音边界、说话人变化做出实时判断。这种设计差异会导致模型接收的输入组织方式不同、输出格式不同、延迟预算策略也不同。从模型发布口径看Muse Voice Transcribe 强调的正是“real-time audio perception”这个定位而不是传统的 speech-to-text。这意味着它要为开发者提供的不只是一段文字而是一种“持续理解音频中发生了什么”的能力。比如会议场景下谁正在发言、哪句话被中断、哪个片段的语速异常都可能成为模型输出的一部分。4.2 第一版就做到 SOTA意味着什么MSL 把 Muse Voice Transcribe 的第一版就直接对标 SOTA这是需要底气的动作。通常一个团队发布新模型时会选择比较保守的表述避免预期过高。敢在第一版就用 SOTA说明它在内部评测集上已经跑赢了当前一批主流方案。但作为行内人看到这种表述会多问一句对比的基线是什么测的是 WER 还是别的指标是在通用数据上还是专用数据上如果一个模型在英文通用语音评测集上 SOTA而你的业务是中文电话客服质检这个 SOTA 对你的参考价值就有限。4.3 低延迟设计决定产品体验上限语音转写类产品最影响体验的不是绝对准确率而是“感受到的延迟”。如果用户说了一句话两秒后文字才出现哪怕文字完全正确体验评价也可能远低于“边说边出、偶尔有几个错字”的方案。实时音频感知模型的工程设计里延迟不是一个参数而是一整套约束。模型需要决定什么时候输出临时结果缓存多少音频再开始推理一个片段处理不完时是丢帧还是排队。这些策略都会影响最终体验。接入 Muse Voice Transcribe 时建议特别关注它提供的延迟档位配置和临时结果回调频率。5. 实时语音转写系统的通用架构与接入思路5.1 总体链路设计无论你接入的是 Muse Voice Transcribe还是其他同类模型一套标准实时转写系统的链路大致如下麦克风 - 音频采集 - VAD/端点检测 - 音频编码 - 流式传输 - 实时推理 - 临时结果回调 - 后处理 - 业务消费字幕/纪要/命令其中几个环节容易出错下面分别说明。音频采集是最基础的一环。浏览器端用 MediaRecorder 采集 WebM/Opus 格式移动端用原生 AudioRecord 采集 PCM桌面端则可能通过声卡驱动采集系统声音。这里的核心要求是采样率稳定、声道信息一致、格式统一。很多实时识别效果差不是模型问题而是采集端音频参数没有对齐模型要求。VADVoice Activity Detection语音活动检测负责判断当前是否有有效人声。它有两个作用一是省流量没人说话时不发送音频数据降低服务端压力和成本二是切分句子VAD 判断一段连续语音结束后客户端可以请求服务端返回最终结果。Muse Voice Transcribe 这类实时感知模型一般自带有一定的话音检测能力但客户端仍然建议保留一层 VAD减少音频流中大量静音片段对结果稳定性的干扰。流式传输是实时识别的核心环节。最常见的实现是基于 WebSocket 的长连接让音频数据以二进制帧持续发送模型结果以 JSON 文本帧返回。也有部分服务基于 gRPC 双向流实现适合高并发和高吞吐场景。对大多数中小团队WebSocket 足够开发成本低且浏览器兼容性好。后处理环节容易被忽略。模型返回的临时结果会出现“同一句话被输出多次但每次略有不同”的情况为了让 UI 显示更稳定通常需要做去重和结果合并。常见做法是客户端维护一个 sessionId 和 resultId当一条最终结果到来后用它替换掉之前所有的临时结果缓存。5.2 接入前需要明确的四个参数在接 Muse Voice Transcribe 或开发自己的实时语音引擎之前建议先确认四个参数音频采样率通常是 16kHz 单声道但也有服务支持 8kHz 电话音频和 48kHz 高保真音频确认模型训练时的采样率很重要。如果模型在 16kHz 上训练你传 48kHz 音频服务端通常会自动降采样但降采样算法可能导致一定精度损失。音频编码格式PCM、Opus、WebM 等格式各有优劣。PCM 保真但体积大Opus 压缩率高但需要服务端支持解码。流式场景推荐 Opus实时性和带宽占用平衡得最好。结果回调格式不同服务返回的 JSON 结构差异很大有的返回一个字符串有的返回带有时间戳的 words 列表。接入前一定要拿到完整示例避免“看起来识别成功但字段解读错误”。连接并发限制部分服务按并发连接数计费有些按音频时长计费。实时转写通常是长连接一个连接可能保持数小时需要评估并发上限和超时策略。我见过不少项目接入语音服务时把 90% 精力放在调 “模型选型”最后发现瓶颈其实在音频采集格式、网络抖动和回调处理上。模型只是整条链路的一个环节链路稳定才是实时体验的根基。6. 实时音频感知模型的接入示例Python 客户端实现下面用一个最小可运行的 Python 客户端演示如何接入一个 WebSocket 协议为主的实时转写服务。这里以 Muse Voice Transcribe 的通用接入思路为例如果你的服务商提供的协议字段不同替换对应的 URL、参数和消息体即可整体流程完全一致。6.1 环境准备建议使用 Python 3.9 以上版本并安装以下依赖。pip install sounddevice websocket-client numpy三个库的分工是sounddevice负责读取麦克风音频底层依赖 PortAudioWindows、macOS、Linux 均可用。websocket-client负责与服务端建立 WebSocket 长连接发送二进制音频帧接收 JSON 结果。numpy负责音频数据的类型转换和切片处理。如果你在服务器上进行联调没有物理麦克风可以用 soundfile 读取一个测试音频文件按帧模拟采集逻辑相同。6.2 音频采集与发送import sounddevice as sd import numpy as np import json import websocket SAMPLE_RATE 16000 CHANNELS 1 BLOCK_SIZE 1600 # 100ms audio per block def audio_callback(indata, frames, time_info, status): # indata shape: (frames, channels) pcm (indata[:, 0] * 32767).astype(np.int16) ws.send(pcm.tobytes(), opcodewebsocket.ABNF.OPCODE_BINARY) def on_message(ws, message): payload json.loads(message) if payload.get(type) final_result: print([final], payload.get(text, )) elif payload.get(type) partial_result: # 临时结果一般用于 UI 实时刷新这里可以打印但不作为最终输出 print([partial], payload.get(text, )) ws websocket.WebSocketApp( wss://your-endpoint.example.com/v1/audio/transcribe, header{Authorization: Bearer YOUR_TOKEN}, on_messageon_message, ) ws.on_open lambda ws: print(connection opened) stream sd.InputStream( samplerateSAMPLE_RATE, channelsCHANNELS, dtypefloat32, blocksizeBLOCK_SIZE, callbackaudio_callback, ) with stream: ws.run_forever()这段代码里有几个细节值得展开解释。BLOCK_SIZE 1600意味着每次采集 100ms 音频。这个值不是随便设的。如果设置太小比如 10ms会导致网络请求过密服务端压力大且容易造成音频碎片如果太大比如 1 秒临时结果的更新频率就跟不上实时体验需求。100ms 是比较通用的起步值后续可以根据服务端的推荐调整。websocket.ABNF.OPCODE_BINARY表示以二进制帧发送音频。为什么不发 JSON因为二进制帧省去了 base64 编码的开销对实时传输更友好。服务端只需要按固定格式解析原始 PCM 字节即可。on_message中区分了partial_result和final_result这对应前面提到的“临时结果”和“最终结果”。实际业务场景里UI 收到partial_result就实时刷新用户看到的文字收到final_result则覆盖掉之前的临时结果并作为稳定记录保存。6.3 处理断线重连与静音检测真实生产环境中WebSocket 连接随时可能因为网络波动而断开。一个健壮的实时转写客户端必须具备重连机制。下面这段代码在原始示例基础上增加了简单的断线重连和结束标志。import time def run_realtime(session_id, max_retry5): retry 0 while retry max_retry: try: ws websocket.WebSocketApp( url, header{Authorization: Bearer YOUR_TOKEN}, on_messageon_message, ) ws.on_open lambda ws: start_audio_stream(ws) ws.on_error lambda ws, err: print(websocket error:, err) ws.on_close lambda ws, code, msg: print(connection closed) ws.run_forever() break except Exception as exc: retry 1 print(fretry {retry} after exception: {exc}) time.sleep(2 * retry)这里引入session_id的概念每条完整的转写会话最好有一个唯一 ID。当断线重连时携带相同的 session_id可以让服务端知道当前音频流是上一次的延续而不是一条全新会话。否则用户一句话说到一半突然断网重连语句会从零开始识别影响体验。静音检测常用在录音结束判断上。如果 2 到 3 秒没有检测到人声客户端就知道当前说话告一段落。但注意不能只依赖模型端语音活动检测来判断“用户说完了”因为你可能需要在用户停顿时就让部分结果落盘。合理的逻辑是VAD 检测到 800ms 停顿向服务端请求一次“当前最终结果”VAD 检测到 3 秒停顿客户端自动停止发送音频并关闭连接。6.4 文件模拟流式输入服务器上没有麦克风时可以用音频文件模拟流式输入。核心思路是每次从文件中读固定长度的音频块然后 sleep 相应的时间让发送速率接近真实录音速度。import soundfile as sf import time def send_file_as_stream(file_path, websocket_conn, block_ms100): data, sr sf.read(file_path, dtypefloat32, always_2dTrue) if sr ! SAMPLE_RATE: # 实际使用中应该接入重采样逻辑 raise ValueError(fsample rate mismatch: {sr} ! {SAMPLE_RATE}) block_size int(sr * block_ms / 1000) for start in range(0, len(data), block_size): chunk data[start:start block_size] pcm (chunk[:, 0] * 32767).astype(np.int16) websocket_conn.send(pcm.tobytes(), opcodewebsocket.ABNF.OPCODE_BINARY) time.sleep(block_ms / 1000)这个函数不需要麦克风也不需要真实时间等待非常适合做自动化测试。它还可以配合本地音频文件做模型效果回归把一批测试音频输入模型保存输出结果比较不同版本之间的 WER 变化。7. 运行结果与验证方法单纯“跑通”不算完成还需要设计一套验证方案确认你接入的实时转写链路真的可用。针对 Muse Voice Transcribe 或其他实时感知模型建议从延迟、准确率、稳定性三个维度验证。7.1 延迟验证延迟是实时转写最重要的指标。测量方式是在客户端记录每段音频发送的时间戳t_send收到最终结果时记录t_recv两者的差就是端到端延迟。send_time time.time() def on_message(ws, message): payload json.loads(message) if payload.get(type) final_result: latency_ms (time.time() - send_time) * 1000 print(flatency{latency_ms:.1f}ms text{payload.get(text,)})但要注意这个延迟包含了网络传输、服务端排队、推理、结果回传的全链路时间不是模型单次推理时间。判断结果时要分清楚“网络延迟正常但服务端慢”和“服务端快但网络抖动大”两种不同情况。建议多次测试取 P90 和 P95 延迟而不是看平均值。平均值容易被极端值掩盖P95 才能反映普通用户的真实感受。7.2 准确率验证建议准备 20 到 50 条与你业务场景相符的测试音频覆盖不同说话人、不同背景噪声、不同专业术语。用 Muse Voice Transcribe 识别后和人工转写文本对比计算 WER。以下是 WER 计算需要的最小代码逻辑完整实现需要编辑距离算法。def compute_wer(reference, hypothesis): # 这里需要实现字符或词级别的编辑距离 # 简化思路按空格分词后计算 Levenshtein 距离 ref_words reference.split() hyp_words hypothesis.split() distance levenshtein_distance(ref_words, hyp_words) return distance / max(len(ref_words), 1)不要拿官方英文示例音频测试中文场景也不要用纯净无噪声的合成音频测试真实会议场景。评测音频越接近生产环境选型结论越可靠。7.3 稳定性验证稳定性测试通常要连续跑 30 分钟以上观察连接是否意外断开、内存是否持续增长、临时结果是否长时间不更新、间歇性静音后是否仍然能正常识别。稳定性差的项目往往通过 1 分钟 Demo 测试发现不了但放到线上就会频繁出问题。8. 常见问题与排查思路实时音频转写链路比较长一旦出问题排查时需要从采集、传输、服务端、回调四个环节逐一排除。下表是我整理的常见问题和排查方向。问题现象可能原因排查方式解决方案没有任何识别结果音频未发送或格式不被服务端接受抓包或打印发送字节长度确认服务端是否收到数据检查采样率、声道数、编码格式是否与服务端要求一致识别文本延迟越来越高音频发送速度快于服务端消费速度造成消息积压观察发送队列积压数量和服务端负载降低发送帧率增大单帧音频块必要时更换更高性能服务文字频繁跳动最终结果和临时结果差异大临时结果更新策略过于激进检查临时结果返回频率对比同一句话的临时和最终结果调低临时结果刷新频率或等最终结果再更新稳定显示网络断开后无法恢复缺少断线重连与会话恢复机制查看是否捕获了 websocket close 事件加入带 session_id 的重连逻辑识别内容出现大量吞字VAD 切分节奏过短把句子拦腰截断检查服务端返回的句子边界时间戳调长 VAD 静音阈值让句子完整输出后再出最终结果多人说话时结果杂乱并发说话场景没有做说话人分离查看模型是否支持 diarization 能力改用或叠加支持说话人分离的模型麦克风权限或驱动问题导致采集不到数据操作系统权限未开启或音频设备异常打印采集回调中数据长度修复权限设置更换默认录音设备用 sounddevice 自带列表查设备排查实时音频问题时第一原则是“分层定位”。先确认音频采集数据有效再用本地文件模拟测试排除设备问题最后才考虑模型识别效果。很多团队一上来就怀疑模型准确率不行结果发现是采样率设错所有音频都被服务端以错误方式解码试多少次都不可能准。9. Muse Voice Transcribe 接入与生产落地的工程建议无论是接 Muse Voice Transcribe还是在自己的系统里跑实时音频感知模型有几条工程建议值得提前落实。9.1 用 session 管理上下文实时转写最好把一次完整对话作为一个 session而不是每次 WebSocket 连接独立处理。这样有几个好处一方面方便做上下文累积模型能根据前文语义修正后文同音字另一方面方便连接断开后恢复。音频会话启动时生成 sessionId连接断开重连时带上同一个 sessionId服务端就能把前后音频拼接起来。9.2 不要直接展示临时结果很多人看到 partial_result 就直接刷到 UI 上导致用户看到文字不停跳动。正确做法是界面上有两层文本一层是稳定的最终结果一层是不断更新的临时结果。最终结果落地临时结果只做预览。当新 final 结果到达时用它替换临时结果并追加到最终文本区。9.3 注意敏感信息的边界语音转写天然会经过服务端处理如果你的产品涉及用户隐私、敏感对话或合规要求一定要在接入前明确数据流向。建议做到三点传输全程加密使用 wss 而不是 ws。服务端返回的音频和文本日志设置自动清理周期。在隐私政策中明确告知用户“语音内容可能被传输到云端处理”。涉及内部工具时更稳妥的做法是私有化部署或者使用本地推理模型彻底避免音频出网。Muse Voice Transcribe 如果提供私有化版本语料安全要求高的企业应优先评估。9.4 设计结果回退方案任何模型都可能有识别错误。实时场景给用户的体验必须是“可修正的”。产品设计上应允许用户手动点击文字修改修改结果要作为训练反馈回流持续优化效果。工程上要避免把模型输出直接当作不可变数据写入数据库后续想修正会很麻烦。9.5 成本与并发规划实时转写的成本模型通常由时长、并发、功能项决定。相比离线转写实时连接空闲时也会产生没必要的开销因此客户端应实现“空闲自动关闭”逻辑用户停止说话超过 5 秒自动关闭音频流需要再次说话时再打开连接。不要为了省事让 WebSocket 一直挂着一个多小时那是成本账单爆炸最常见的原因。9.6 建立灰度评测机制模型版本升级是常态。每次升级前用固定的测试集跑一份基线结果对比新旧版本的 WER、延迟和稳定性。建议把评测脚本做成 CI 流程的一部分。做到这一步你就不怕官方发布新模型了因为你能用数据判断该不该升级。10. 总结实时音频感知模型会给开发带来什么变化Muse Voice Transcribe 作为 MSL 在实时音频感知方向的第一款模型它的意义不只是又多了一个可调用的语音识别接口。更深层的变化在于“实时音频感知”正在成为语音类产品的基础能力它把语音从“需要事后处理的文件”变成了“可以实时消费的事件流”。这种变化会影响会议、直播、语音笔记、客服质检、无障碍字幕等一大片应用的交互范式。如果你正在做或准备做语音类产品我的建议是先想清楚三层问题第一你的用户真的需要实时结果还是能接受离线转写第二如果做实时你的业务指标是延迟优先、准确率优先还是成本优先第三接完模型后你打算如何评测和迭代。把这三层问题想透接 Muse Voice Transcribe 还是其他模型并不重要因为选型逻辑已经清楚了。最后提醒一句任何大模型发布时都会有“SOTA”光环但光环属于评测集业务效果只属于你的真实场景。拿到一个实时音频感知模型后第一件事不是急着写业务代码而是先搭一套评测脚本用你自己的数据跑出 WER、延迟和稳定性基线。有了基线后面的技术决策都会从容很多。
返回列表