
上个月帮一个做会议纪要的团队复盘转录质量他们那条链路的错字率常年在8%上下晃客户投诉集中在两类人名地名写成谐音以及说话人那些嗯、那个、就是说被原样保留进了正式文档。这几乎是所有ASR落地项目的通病——模型听得见但写不对。最近业内传得比较凶的一个数字是2.6%某头部科技公司放出的新一代语音识别模型在标准测试集上把词错误率压到了这个量级同时第一次把手动删改口误这件事做进了模型本身。对做转录产品的人来说这两个指标指向的是两个完全不同的问题WER 2.6%解决的是字对不对自动改口误解决的是句子能不能直接拿去用。前者是识别精度后者是可用性。这篇东西我打算把这两件事拆开讲清楚WER这个数字到底怎么读、新模型在架构上动了哪些地方、你怎么把它接进现有流水线、以及怎么科学地测出属于你自己场景的真实错误率。刚接触ASR的同学可以看前半部分建立概念已经在上生产的同行可以直接跳到第3节看参数配置和第4节看评测脚本。1. 先把WER这个数字读明白别被2.6%带偏1.1 WER的拆解公式以及三个子指标各自意味着什么词错误率Word Error RateWER不是错了百分之几的字这么朴素的理解它是一个基于编辑距离的比值。标准定义是把参考文本转换成识别文本所需的最少操作次数除以参考文本的总词数WER (S D I) / N其中S是替换substitution把A写成了BD是删除deletion漏掉了I是插入insertion凭空多出来N是参考文本的词数。中文场景更常用字错误率Character Error RateCER把词换成字计算逻辑完全一样。这三个子指标的意义完全不同却被一个总分掩盖了。举个例子某条音频的WER是6%拆开看可能S2%、D3%、I1%。删除率高通常意味着音频有丢帧、VAD把语音切掉了、或者说话人声音太小低于阈值插入率高多半是背景噪声、呼吸声、口头禅被当成了语音替换率高才是真正的听错可能来自口音、专业术语、同音字。你拿到一个总WER第一件事应该是把它拆成这三项否则根本不知道该往哪个方向修。我见过不少团队拿着总WER反复调模型参数结果发现30%的错误来自VAD切分边界——音频被切成两半前半句的尾字和后半句的首字都被削掉了全算成删除错误。这类问题调模型调一年也没用改切分策略当天就见效。1.2 2.6%这个数字的含金量取决于它跑在什么集上任何WER数字离开测试集都是耍流氓。同样是2.6%跑在朗读语料和跑在真实会议录音上含金量差着量级。你看到一个新模型报出低错误率至少要追问四件事追问项为什么关键常见的水分点测试集是什么类型朗读、播客、会议、电话客服的难度天差地别用干净朗读集报数落地到会议场景直接翻倍有没有开热词/上下文偏置开了偏置等于给了答案提示报数时开产品里默认关是离线整段还是流式分块整段识别能吃满上下文流式只能看历史宣传用离线产品要实时参考文本的归一化规则数字、标点、大小写怎么算归一化宽松错误被洗掉我个人判断一个数字可信度的土办法先看它有没有同时报出带噪远场带口音这几个子集的结果。只报一个总分的基本可以当作上限参考真实落地打个1.5到2倍的折扣是常态。1.3 为什么你自测的WER总比官方高出一截这个现象太普遍了我在三个不同团队都遇到过。原因通常不在模型而在你自己的评测口径。第一条是参考文本ground truth本身不干净人工转写时标点、数字写法、语气词保留策略和模型输出不一致每处不一致都算一个错误。第二条是归一化没做模型输出二零二四年三月参考文本写2024年3月逐字比对全错实际上语义完全正确。第三条是切分粒度不同参考文本按句切模型输出按段切边界处必然产生插入和删除。提示在跑任何WER对比之前先把参考文本和模型输出过一遍同一套归一化函数。这一步能让你看到的错误率下降2到4个百分点而且这个下降是真实的因为那些错误本来就不该算。2. 从听得清到写得对新模型动的是哪几刀2.1 端到端架构与上下文偏置解决的是专有名词灾难传统ASR流水线是声学模型、发音词典、语言模型三段式任何一段出问题都会传导到最终结果。新一批模型走的是端到端路线音频直接映射到文本序列中间不再有独立的发音词典。这个变化带来的最直接好处是**上下文偏置contextual biasing**变得极其自然你可以把一批专有名词、人名、项目代号作为提示喂进去模型在解码时会主动往这些词上靠。这件事的产品意义被严重低估了。真实业务里错误最集中的往往不是常用词而是那些一天出现几十次的项目名、产品型号、客户姓名。这些词在通用语料里的频率极低模型没有任何理由认识它们。我做过一个统计某次内部评测中专有名词只占参考文本总词数的4%却贡献了整体替换错误的37%。配置热词时有两个经验值值得记住。第一热词表不要贪多控制在100到300条超过这个量级偏置效果会被稀释而且容易引发误触发——把发音相近的普通词硬拽成热词。第二热词要带上权重参数业务上必须对的词给高权重锦上添花的给低权重。很多接口把这个参数叫boost或者weight取值区间通常是0到10我一般核心词给8普通词给3。2.2 自动改口误这不是简单的正则替换标题里自动帮你改口误这件事行话叫非流利性消除disfluency removal包含三类东西填充词嗯、啊、那个、就是说、重复我我我觉得、自我修正我们周三……不对周四开会。前两类靠正则能搞定大半第三类是真难点因为它需要理解语义。举个例子我们定在下周二呃不下周三碰一下。正则删掉呃不之后剩下我们定在下周二下周三碰一下语义直接矛盾了。正确的改写应该是整段重写为我们定在下周三碰一下。这就不是字符串操作能解决的需要模型具备重写能力。新模型把这一步做进了解码流程输出的时候直接给你一份顺滑版本。这里有个关键设计选择值得说它保留了原始文本和改写文本两路输出。这个设计非常务实因为改口误天然带有信息损失风险法律、医疗、审计类场景必须留底。你做产品设计时务必要把原始逐字稿和整理稿作为两个独立字段存下来别只存一份。我在实际使用中踩过最狠的一个坑某次给客户演示整理稿里把这个方案不行我觉得要重做改成了这个方案我觉得要重做一个否定词被顺滑掉了意思完全反了。后来我加了一条规则——改写前后如果出现否定词增减一律标记为待人工确认。2.3 长音频分块与说话人分离的联动会议录音动辄一小时模型不可能一次吞下。分块策略直接决定边界处的错误率。常见做法是固定30秒切一刀但语音不会刚好在你切的地方停顿硬切必然造成首尾丢字。更稳的做法是基于静音检测动态切分找到能量最低的谷点再切同时让相邻块重叠0.3到0.5秒解码后按时间戳去重。重叠去重这件事说起来简单做起来容易出错。我的做法是保留每个词的时间戳重叠区的词按时间戳排序后用最长公共子序列对齐重复的只保留置信度高的那份。如果接口不返回词级时间戳那就退回按句子粒度去重效果会差一些但可接受。说话人分离diarization和识别的顺序也有讲究。串行做先分离再识别实现简单但分离一旦出错识别整段跟着错并行做同时输出文本和说话人标签效果好但对接口有要求。中小团队我建议先做串行把分离质量单独评估——分离错误的排查成本比识别错误低得多。3. 落地实操把新模型接进你的转录流水线3.1 音频预处理这一步决定了错误率的下限我见过太多人跳过预处理直接调接口然后抱怨模型不行。真实录音里光是采样率和声道这两个基础项就能吃掉你几个百分点。采样率统一到16kHz。高于16k的信息对识别帮助有限反而增加传输和推理开销低于16k会损失高频辅音中文的s/sh、z/zh区分度直接崩掉。重采样用sox或者ffmpeg都行我习惯用ffmpeg一条命令解决ffmpeg -i input.m4a -ar 16000 -ac 1 -c:a pcm_s16le output.wav-ar 16000指定采样率-ac 1强制单声道-c:a pcm_s16le输出16位PCM。别小看单声道这一步双声道文件如果左右声道有相位差某些模型会把同一个声音识别两遍插入错误率飙升。增益归一化。手机录音和会议室录音的电平能差20dB。做一个简单的峰值归一化到-3dB或者用响度标准化到-16 LUFS能明显降低声音太小被判成静音的删除错误。我用的是ffmpeg-normalize两行搞定。VAD预切分。把长静音段切掉既省成本又减少插入错误。阈值别设太激进我一般用能量阈值配合最小语音段300ms、最小静音段500ms这两个参数。切太碎会让模型丢失上下文整句识别变成断句识别标点质量跟着下降。注意不要对音频做人声分离、强降噪之后再送识别。我实测过几款降噪工具处理后的音频听感变好了但WER反而上升——降噪引入的 artifacts 会让模型把辅音听错。除非噪声真的到了掩蔽语音的程度否则轻度降噪即可或者干脆不降。3.2 调用参数怎么配一份可直接抄的配置下面这段是伪代码风格字段名按常见接口习惯写的不同厂商命名会有差异但参数语义大同小异resp asr_client.transcribe( audio_pathmeeting_01_16k.wav, languagezh, # 明确指定语言别让它自动检测 enable_punctuationTrue, # 标点下游排版必需 enable_itnTrue, # 逆文本正则化把二零二四转成2024 enable_disfluency_removalTrue, # 口误顺滑关键开关 keep_raw_transcriptTrue, # 保留逐字稿务必打开 hotwords[ {text: 某某协同平台, weight: 8}, {text: 某某型号, weight: 8}, {text: 季度复盘, weight: 3}, ], diarizationTrue, # 说话人分离 chunk_seconds30, overlap_seconds0.4, timestamp_granularityword, # 词级时间戳做字幕必需 )几个参数的选择理由值得展开。language一定要显式指定自动语言检测在短句、中英混杂的场景下误判率高一旦判成英文中文段落会整段变成拼音或者空白。enable_itn这个开关很多人不开结果下游做数据分析时百分之三十和30%变成了两个值。keep_raw_transcript是我强烈建议打开的一项。顺滑后的文本好看但不可回溯。出了争议需要核对原话时只有逐字稿能救命。3.3 后处理时间戳校正与字幕生成拿到结果别急着落库还有三步。第一步是时间戳单调性检查重叠去重之后偶尔会出现后一个词的开始时间早于前一个词的结束时间需要做一次单调递增修正。第二步是句子重组模型按语义断句字幕需要按长度断句一般单行不超过20个中文字符超过就得按标点二次切分。第三步是数字与单位规范化回写把3到5个工作日统一成3-5个工作日这类固定格式。生成SRT的代码不长核心就是把词级时间戳按句子边界聚合def to_srt(segments): def fmt(t): h, rem divmod(t, 3600) m, s divmod(rem, 60) return f{int(h):02d}:{int(m):02d}:{s:06.3f}.replace(., ,) lines [] for i, seg in enumerate(segments, 1): lines.append(str(i)) lines.append(f{fmt(seg[start])} -- {fmt(seg[end])}) lines.append(seg[text].strip()) lines.append() return \n.join(lines)注意fmt里把小数点换成逗号SRT格式要求毫秒分隔符是逗号写成点号有些播放器会直接不识别。这个坑我踩过一次排查了半小时才发现是标点问题。4. 科学评测测出属于你自己场景的真实WER4.1 建一个50到100条的小测试集比什么都重要官方榜单再漂亮也不能替代自测。我的做法是从真实业务音频里抽50到100条覆盖你所有的场景类型安静会议室、嘈杂开放区、单人独白、多人抢话、带口音、带专业术语。每条控制在30秒到2分钟人工精校成参考文本。抽样时有个技巧按业务重要性分层抽不要随机抽。会议纪要场景里领导发言和决议段落的权重远高于闲聊段落那就多抽这类。我一般按6:3:1分配——60%核心场景、30%边缘场景、10%极端场景强噪声、重度口音。参考文本的标注规范必须提前定死否则不同人标出来的标准都不一样。规范里至少要写清楚语气词保不保留、数字用阿拉伯还是汉字、英文单词大小写、标点用什么符号集、重复词怎么记。这份规范一旦定下来评测期间不许改。4.2 归一化规则决定你看到的是真错误还是假错误归一化函数要跟参考文本的标注规范严格对应。核心处理包括全角转半角、去除多余空格、统一标点、数字统一转阿拉伯、英文统一小写、繁简统一。下面这个版本可以直接用import re import unicodedata CN_NUM {零:0,一:1,二:2,三:3,四:4, 五:5,六:6,七:7,八:8,九:9,十:10} def normalize(text, langzh): text unicodedata.normalize(NFKC, text) # 全角转半角 text text.lower() if lang en else text text re.sub(r[。、\《》], , text) # 去标点 text re.sub(r\s, , text).strip() if lang zh: # 中文按字切分逐字比对 return list(text.replace( , )) return text.split()中文场景我建议按字切分而不是按词因为分词工具本身的误差会污染评测结果。按字比对虽然对的/地/得这类同音字更敏感但至少口径统一、可复现。4.3 评测脚本与结果解读有了归一化函数算WER就是标准编辑距离def edit_ops(ref, hyp): n, m len(ref), len(hyp) dp [[0]*(m1) for _ in range(n1)] for i in range(n1): dp[i][0] i for j in range(m1): dp[0][j] j for i in range(1, n1): for j in range(1, m1): cost 0 if ref[i-1] hyp[j-1] else 1 dp[i][j] min(dp[i-1][j] 1, # 删除 dp[i][j-1] 1, # 插入 dp[i-1][j-1] cost) # 替换/正确 return dp[n][m] def wer_detail(ref, hyp): ref, hyp normalize(ref, zh), normalize(hyp, zh) total len(ref) dist edit_ops(ref, hyp) return {wer: dist / max(1, total), ref_len: total, dist: dist}跑完之后别只看平均分。我习惯把结果按场景分组看安静场景的WER、嘈杂场景的WER、带热词场景的WER三个数字往往能差出三四倍。平均值好看不代表你的场景好看反之亦然。4.4 一份可复用的评测记录表指标基线模型新模型未开顺滑新模型开顺滑整体CER8.4%4.1%4.3%安静会议室5.2%2.6%2.7%嘈杂开放区13.7%6.8%7.1%专有名词错误率21.3%5.4%5.6%填充词残留率100%100%3.2%人工校改耗时每千字12分钟7分钟3分钟这张表里最值得看的是最后一行。CER从8.4%降到4.1%人工校改时间只从12分钟降到7分钟因为省下来的主要是错字而删语气词这件事还得人来做。开了顺滑之后耗时直接掉到3分钟。对下游使用者来说顺滑带来的价值远大于单纯的错误率下降这一点在立项评估时特别容易被忽略。5. 常见问题与排查技巧实录5.1 问题速查表从现象倒推原因现象最可能的原因排查动作整段空白音频格式不支持或采样率异常用ffprobe看真实编码别信扩展名句尾频繁缺字VAD切分边界削掉了尾音增大重叠区到0.5秒或改静音切分数字全变汉字ITN开关没开检查enable_itn参数是否生效专有名词全错热词没生效或权重太低打印请求体确认热词已传权重调到8同一句话重复出现分块重叠区没去重检查时间戳去重逻辑中英混杂处乱码语言参数写死为zh改双语模式或auto并单独测该子集顺滑后语义反转否定词被误删加否定词增减校验规则这张表我放在项目文档首页新人上手第一周基本都会遇到其中三四条。表格的价值不在于穷尽而在于给排查提供一条从现象到原因的快速路径避免一上来就怀疑模型。5.2 顺滑过头的三个典型场景自动改口误是把双刃剑。我在实际使用中总结了三个高危场景用的时候务必开人工复核。第一个是法律与合规相关的陈述。我记得当时没有签字和我记得当时签了字删掉没有两个字意思完全相反。这类内容建议关掉顺滑或者至少保留原始文本对照。第二个是数字密集的讨论。预算是三十万呃三十五万顺滑之后可能只留三十五万但会议里前面的三十万可能是另一笔预算。数字类自我修正我倾向于保留原文并加高亮标记。第三个是多人抢话。两个人同时说话时模型容易把A的填充词当噪声删掉结果把A的句子和B的句子连成一句语义完全错乱。这种情况分词质量会明显下降建议配合说话人标签做交叉校验。提示顺滑功能上线前务必拿20条以上真实业务音频做人工抽检重点看否定词、数字、人名三类实体。这三类出错的代价远高于其他类型。5.3 中英混杂与方言口音的应对中文会议里夹杂英文术语是常态这个feature下个sprint上这种句子纯中文模型会把它转成这个飞车下个死普林特上。我的处理办法是优先选支持中英混合解码的接口并且在热词表里把高频英文术语加进去用原拼写而不是音译。方言口音是另一个坑。带口音的普通话错误率通常是标准普通话的两到三倍。可行的缓解手段有两个一是换用在该口音区域数据上训练过的模型版本二是把常错的词做成热词。后者治标不治本但见效快适合应急。真正要根治只能自己攒几百小时带标注的领域音频做微调成本不低通常只有日处理量很大的团队才划算。5.4 成本核算什么时候值得上成本这块很多人算不清楚。我的算法是把成本拆成三块推理成本、人工校改成本、返工成本。推理成本按音频时长计人工校改按最终字数计返工成本是错误导致的下游损失。前两块可以量化第三块只能估算但往往是最大的一块。以一个每天处理100小时音频的团队为例粗略估算单位按相对值不涉及具体价格项目旧方案新方案说明推理开销1.01.4新模型单价通常更高人工校改12.03.0按每千字耗时折算下游返工4.01.2错误引发的沟通成本合计17.05.6差距主要来自人工结论很清晰只要人工校改还占成本大头升级就是划算的。反过来如果你的场景是纯机器消费比如给搜索建索引、做关键词抽取根本不需要人读那顺滑功能对你没有价值只需要关注CER和推理成本。6. 把新能力嵌进产品几个容易被忽略的设计点6.1 双轨存储原始稿与整理稿必须分开这条前面提过但值得单独展开。我在设计数据结构时会给每条转录记录存三份内容原始逐字稿带时间戳、带填充词、整理稿顺滑后、以及一份diff记录改写位置。diff这一份最容易被省掉但它在客诉处理时价值极高——用户质疑我没说过这句话时你能立刻定位到是改写引入的还是识别错的。存储成本上三份文本相对于音频来说可以忽略不计。真正需要控制的是音频保留策略这个另说。6.2 置信度分数怎么用多数接口会返回每个词或每句的置信度。这个分数不该只用来做阈值过滤更有价值的用法是驱动人工复核的排序。把置信度最低的10%片段优先推给人工剩下的自动通过。实测下来这种方式能以20%的复核量覆盖70%以上的实际错误效率比全量复核高得多。顺滑后的文本置信度会普遍偏低因为改写本身带有不确定性。所以做排序时要把原始稿的置信度和改写标记结合起来看单纯看整理稿的分数会误伤。6.3 灰度上线的观察指标新模型上线别一次性全量切。我的做法是先切5%流量观察一周重点盯四个指标整体CER、专有名词命中率、人工复核退回率、以及用户主动编辑率。前两个是质量指标后两个是体验指标。经验上用户主动编辑率下降15%以上说明升级是正向的如果这个指标没动说明省下来的错误用户根本没注意到那就要重新评估投入产出。灰度期间还要留一条回滚通路。我一般会保留旧模型的调用入口至少两周配置层面用一个开关控制出问题十秒内切回去。6.4 一个真实的效果对比记录最后分享一组我自己测的数据。同一批60条会议音频平均时长45分钟涵盖三种场景。旧模型整体CER 9.1%新模型未开顺滑3.9%开启顺滑后4.2%顺滑会引入少量改写错误所以CER略升但可读性大幅提升。人工校改耗时从每千字14分钟降到每千字3.5分钟。最明显的改善在专有名词上配置了200条热词之后人名错误从每场平均11处降到2处。也有退步的地方数字密集的财务讨论段落顺滑后需要人工回查的比例上升了因为有些自我修正被合并了。后来我给这类段落加了规则检测到连续数字加修正词不对改成应该是就不做顺滑问题基本解决。踩过几次坑之后我的体会是模型能力提升确实能解决大部分问题但剩下那一小部分永远得靠工程手段兜底。把预处理做扎实、把评测口径统一、把后处理规则配好这三件事带来的收益加起来往往不亚于换一代模型。工具是死的链路是活的谁把链路捋顺了谁就能真正把那2.6%兑现成产品体验。