语音处理:Whisper语音识别实战
专栏:AI/LLM工程化实战 - 从Prompt到Agent的完整落地指南
模块7 多模态AI应用篇 第68篇
摘要
摘要:Whisper是OpenAI开源的语音识别模型,tiny到large五档尺寸,中文转录准确率随模型增大明显提升,本文覆盖音频转文字、长音频分段、实时转录和SRT字幕生成全流程,附完整可运行代码,本专栏限时¥59.90(原价¥99)
TL;DR 核心要点速览
- Whisper用编码器-解码器结构,输入80维对数梅尔频谱,输出文本token,内部按30秒窗口处理音频
- tiny/base/small/medium/large五档,参数量从39M到1550M,fp16推理显存约1GB到10GB
- 中文转录从small起步,medium能覆盖多数生产场景,large-v3的中文WER比medium再降三到五成
- 长音频直接transcribe会在30秒窗口边界截断单词,时间戳漂移是最高频故障
- 长音频标准做法是开VAD检测语音段,按句切分逐段转录再合并,faster-whisper内置vad_filter
- 实时转录瓶颈在推理速度,faster-whisper配int8量化,1分钟音频能压进2秒
- initial_prompt塞领域热词,中文数字和专业术语错误率能降一半
- 本专栏限时¥59.90(原价¥99)
开篇故事:一段40分钟录音让我改了方案
我负责的客服系统接了个新需求,质检组每天要听几百通录音,人力听不过来。外包ASR服务一个月三万多,准确率还凑合,但产品名和方言一直识别错,质检结论经常被客服驳回。老板拍板自研,我装了openai-whisper,用large模型跑了一天录音,质检准确率直接超过外包水平,我当时挺得意,觉得这事成了。
上线一周出事了。质检组长发来一段40分钟录音,字幕从第22分钟开始整体错位,时间戳越飘越远,中间还漏了整整一句客服的话。我查了两天,发现根子在Whisper内部把音频切成30秒窗口,每个窗口独立解码,一个单词恰好跨在窗口边界上就被切成两半,识别结果和时间戳一起漂移。单段转写没问题,长音频问题就露出来了。
我后来换成按语音段切分,先用VAD检测静音间隙,在句子边界切开,每段转完再按原时间戳合并,问题消失。这套方案就是这篇文章的核心,代码在后面第三节,直接能跑。
一、Whisper架构与版本选型
1.1 架构一句话讲清
Whisper是个标准的Transformer编码器-解码器模型。音频先转成80维对数梅尔频谱图,过两层卷积把时间维下采样,进编码器提取特征,解码器再自回归吐出文本token。模型同时输出文本、语言ID和时间戳三种token,一次推理把识别和字幕一起做掉。训练数据覆盖96种语言,模型能自动检测输入说的是哪种语言,中英混说也基本能跟住。
为什么要转频谱图。原始音频每秒16000个采样点,直接喂给Transformer序列太长,计算量吃不消。梅尔频谱把声音按人耳听觉频率刻度压缩,每帧只留80个数值,几秒音频压成几十行矩阵,序列长度缩了两个数量级。卷积层再对时间维下采样,编码器看到的序列就短到可以正常注意力计算了。这套设计决定了Whisper对长音频的处理方式,30秒一个窗口,因为窗口越长注意力矩阵越大,训练成本撑不住。
多任务训练是Whisper的另一个特点。同一套模型同时学语音转文本、语言检测、时间戳预测、翻译四件事,共享一套编码器。翻译任务让它把非英语转英语,这个能力平时用不上,但训练时让编码器学到的表征更通用,中文识别也跟着受益。语音识别加时间戳一起出,做字幕就不需要第二套校准工具。
1.2 五个版本怎么选
Whisper按参数量分五档,tiny、base、small、medium、large,中文效果差距非常大。我第一版直接用large,准确率够了,但显存10GB,公司那台4GB显存的测试机直接跑不动,只能换medium。选型号看三样东西,准确率、显存、速度,先对着表划掉超显存的,再在剩下的里挑准确率够的。英文项目small就很好,中文项目medium起步。
| 版本 | 参数量 | fp16显存 | 中文准确率 | 相对速度 | 适用场景 |
|---|---|---|---|---|---|
| tiny | 39M | 约1GB | 较差, 长句会丢字 | 约16倍速 | 实时转写, 低配设备 |
| base | 74M | 约1GB | 差, 数字和术语错得多 | 约8倍速 | 英文为主, 草稿转写 |
| small | 244M | 约2GB | 可用, 日常对话能听懂 | 约4倍速 | 中文字幕, 轻量生产 |
| medium | 769M | 约5GB | 良好, 术语仍偶发错 | 约2倍速 | 中文生产, 客服质检 |
| large-v3 | 1550M | 约10GB | 优秀, 接近人工转写 | 约1倍速 | 会议纪要, 高要求场景 |
速度是相对值,以large为1倍,具体看GPU型号,A100上small轻松跑出8倍以上实时速度。表格里的显存是fp16推理值,int8量化能再省一半。CPU也能跑,tiny在主流CPU上勉强实时,large在CPU上是灾难,一小时音频要跑几小时,CPU用户老老实实用small以下。
官方模型还有两个变体值得知道。large-v3是目前中文最好的版本,whisper库默认的large指的就是v3,比v2的中文WER再降一成左右。turbo版本是v3的蒸馏加剪枝产物,速度接近small,准确率接近medium,显存只要4GB左右,我的客服质检后来换成turbo,延迟降了一半,准确率只掉了两个百分点。预算敏感的团队优先考虑turbo,它才是日常性价比之王。
准确率怎么量化,光靠听不客观。标准做法是算WER(词错误率),取一段带人工转写的录音,用模型转一遍,逐词对比,替换、删除、插入三类的错词数加起来除以总词数。中文WER要处理同音字,人工转写和模型输出都先过一遍分词再逐词比对。我刚上线那阵懒得建测试集,凭感觉说准了,直到质检组长拿出错词统计,我才意识到要建评测集。后来固定了200条人工转写的测试集,模型版本升级前必跑一遍WER,medium的WER比small低三成左右,这个数字比任何感觉都可靠。
1.3 faster-whisper和distil-whisper
官方whisper库是PyTorch实现,速度一般。faster-whisper用CTranslate2重写,同样的模型快3到4倍,显存砍半,还内置VAD和逐词时间戳,我后面所有代码都用它。distil-whisper是蒸馏版,体积小一半速度快一倍,但目前只支持英文,中文项目先别碰。边缘设备上有whisper.cpp的C实现,树莓派能跑tiny,但那属于嵌入式范畴,后端工程师用faster-whisper就够了。还有一套思路是转ONNX或TensorRT,工程量大,收益在faster-whisper面前不明显,小团队不用折腾。
1.4 部署形态
Whisper可以三种形态落地。第一种是脚本批处理,录好的音频落盘后批量转,省事,我第一版就这么干的。第二种是HTTP服务,用FastAPI包一层,质检平台按需调用,响应时间在秒级。第三种是实时流,麦克风边录边转,见第四节。模型首次下载会缓存到用户目录,国内网络不好就把HF_ENDPOINT指到hf-mirror.com镜像,装一次后面都是本地加载。
显存之外还要看内存。medium和large在CPU推理时内存吃到16GB以上,GPU推理也常驻6GB内存存模型参数。公司那台8GB内存的老服务器我直接放弃部署medium,换small才跑起来。选型表里的显存数字只算模型权重,真实部署按1.5倍留余量,转写过程中的音频缓冲和临时数组还会再占一部分。
模型缓存目录也要纳入管理。Whisper首次加载会把权重下载到用户目录,换机器部署时重复下载很费时间,把模型目录固定到项目下的models文件夹,多台机器共享一份权重。磁盘紧张时先清模型缓存,模型权重几十GB占大头,清了重新下载就行。版本升级时新模型和旧模型分开存,灰度期两版并存,确认没问题再删旧版。
二、语音转文字基础流程
装好库直接跑,代码非常短。注意两点,指定language="zh"跳过语言检测能省时间,CPU上fp16必须关掉否则报错。transcribe还有几个常用参数,temperature控制随机性,默认0就能少很多重复输出;verbose=True能打印逐段的识别过程;compression_ratio_threshold是防退化检测的阈值,一般不用动。
# 68_whisper_basic.py# 用whisper库转录一段中文音频# 安装: pip install openai-whisper (会带上torch, 约2GB)importwhisper model=whisper.load_model("small")# 中文起步选small, 显存够就上mediumresult=model.transcribe("customer_call.mp3",# 支持mp3/wav/m4a/flaclanguage="zh",# 指定中文, 跳过语言检测, 省掉1到2秒fp16=False,# CPU上必须False, GPU可改True加速)print(result["text"])# 全文文本# 按段落带时间戳打印, 质检要定位到秒forseginresult["segments"]:print(f"[{seg['start']:.1f}s ->{seg['end']:.1f}s]{seg['text']}")输出里segments每个元素有start、end、text三个字段,单位是秒。转写质量不好先查两件事,音频来源是不是16kHz采样(Whisper会自动重采样,但来源太差的音频救不回来),麦克风有没有严重底噪。质检场景我还会做一遍文本后处理,去掉"嗯""啊"这类语气词,把识别出的数字统一格式化,再过滤敏感词,这层后处理对质检结论的准确率贡献不输换大模型。
音频来源的质量检查放在预处理前面。三个问题先确认,录音格式是不是常见容器,采样率原始值多少,有没有明显底噪。m4a和wav是安全的,某些软件导出的ogg或amr要先转容器。原始采样率低于8kHz的录音,信息量已经丢了,预处理拉不回,这类录音直接标记低置信度,质检结论备注说明。底噪明显的先过一遍降噪滤镜,维纳滤波或高通滤波都行,降噪过度会削掉轻声和尾音,宁可少降不可多降。
转写之前先预处理音频,能省掉一半的识别问题。踩坑经验,我踩过一次,录音文件是24kHz的m4a,底噪大,转写出来的文本混着大量错字,当时以为是模型问题,换了大模型也没用。后来统一先做三件事,采样率归一到16kHz,声道压到单声道,音量归一化。ffmpeg一条命令能做完,包装成函数放进管线里,后面所有录音都先过这一步。
# 68_preprocess.py# 转写前用ffmpeg做音频预处理# 安装: pip install ffmpeg-python (系统还需装ffmpeg, 含音频组件)importffmpegdefpreprocess(src:str,out:str):"""统一采样率16k, 压单声道, 音量归一化, 转写前的标准动作"""(ffmpeg.input(src).output(out,ar=16000,ac=1,af="volume=0.9,loudnorm=I=-16:TP=-1.5:LRA=11").run(overwrite_output=True)# 覆盖旧文件, 便于反复跑)preprocess("raw_recording.m4a","clean.wav")loudnorm那段参数是响度归一化的标准配置,I=-16是平均响度,TP=-1.5是峰值限制,LRA=11是动态范围。直播录音、电话录音这种动态范围大的音频,跑完这段明显更稳。注意ffmpeg的音频组件有些精简版没编译进去,报no such filter就用完整的ffmpeg安装包。
三、长音频分段转录与SRT字幕
回到开头的40分钟事故。踩坑经验写清楚,Whisper的transcribe对长音频自动按30秒窗口切,窗口之间没有语义边界,词被截断后时间戳就飘。症状是前半段字幕准,越往后越对不上,漏句、重复词增多。排查方法也简单,把转写结果按段落时间戳和音频实际内容逐段比对,看哪一段开始脱节,脱节点通常正好是30秒的整数倍。
正确做法是先切好再转,用VAD(语音活动检测)找到静音间隙,在句子边界切开,每段转完再按原时间戳合并。faster-whisper内置VAD,一个参数就够。min_silence_duration_ms控制切分粒度,0.6秒比较通用,语速慢的访谈类音频可以放宽到1秒。VAD漏检的情况也有,一段话中间没有停顿超过阈值就整段算一条segment,不影响识别结果,只影响字幕粒度。
# 68_whisper_srt.py# 长音频分段转录 + SRT字幕生成# 安装: pip install faster-whisper (CTranslate2后端, 比openai-whisper快3到4倍)fromfaster_whisperimportWhisperModel# device可填cuda或cpu, compute_type用int8_float16显存省一半model=WhisperModel("small",device="cuda",compute_type="int8_float16")segments,info=model.transcribe("meeting_2h.wav",language="zh",vad_filter=True,# 开VAD按语音段切分, 解决30秒窗口截词vad_parameters={"min_silence_duration_ms":600},# 静音超0.6秒就切开word_timestamps=True,# 输出逐词时间戳, 字幕校准要用beam_size=5,# beam越大越准越慢, 5是速度和质量的折中)deffmt_ts(seconds):"""秒数转SRT时间格式 00:00:00,000"""ms=int((seconds-int(seconds))*1000)h,r=divmod(int(seconds),3600)m,s=divmod(r,60)returnf"{h:02d}:{m:02d}:{s:02d},{ms:03d}"defto_srt(segments,out_path):"""把识别结果写成SRT字幕文件, 用utf-8-sig编码播放器才认"""lines=[]idx=1forseginsegments:ifnotseg.text.strip():continuelines.append(f"{idx}\n{fmt_ts(seg.start)}-->{fmt_ts(seg.end)}\n{seg.text.strip()}\n")idx+=1withopen(out_path,"w",encoding="utf-8-sig")asf:f.write("\n".join(lines))to_srt(segments,"subtitle.srt")print("字幕已生成: subtitle.srt")2小时会议音频,2080显卡上small模型int8大概4分钟出全部字幕。没GPU用cpu也能跑,时间乘10倍。字幕文件用utf-8-sig编码,普通utf-8在部分播放器里中文会乱码,这是字幕圈的老规矩。segment文本里偶发的空白段落我在写入时直接跳过,避免SRT序号断档。
SRT批量生成后过一遍格式校验。序号连续,时间递增,每行时长不超6秒,句首句尾无多余空格,四类问题脚本扫一遍,扫完再抽查10%。格式校验解决的是播放器兼容,很多播放器对序号断档和重叠时间戳直接罢工。校验脚本挂在管线末尾,出片前必跑,和人工抽检分层把关。这条规则是字幕组的老规矩,我接手后把它固化进了脚本,再没出过播放事故。
显存不够跑medium的时候还有一招,把音频切成10分钟的小段分别转,每段转完释放显存再转下一段。代价是段落边界可能出现重复或丢失,和30秒窗口截词是同一类问题,用VAD切段能绕开。实测下来,分段跑让8GB显存的卡也能带medium,只是速度比一次性跑慢两成。
批量质检的编排也在这个代码上加一层。录音文件遍历入队,每个文件一个转写任务,GPU排队串行,CPU可以按核数并行。任务失败记到日志表,重跑只跑失败的,不重复烧算力。质检平台按小时汇总,出准确率报表,这就是完整的生产流程。
批量编排再展开一点。录音按日期分目录入队,队列任务带重试次数,失败三次进死信目录,人工处理完重新入队。GPU串行转写,CPU预处理并行,转写和预处理之间用文件系统解耦,转写线程只读预处理完的wav。任务表记状态,pending、running、done、failed四态,界面按小时刷新,哪一批卡住了一眼看到。这套编排跑了一年,几千小时录音没丢过一条。
四、实时转录方案
实时转录要看清瓶颈在哪。Whisper一次吃30秒窗口,推理速度和音频时长成正比,tiny加int8能把1分钟音频压到2秒以内,才有资格谈实时。做法是录音线程攒音频,攒够阈值就丢给模型转,结果按输出时间戳归位。下面是个简化版,能跑,生产上要补麦克风断连重连和音频增益控制。
# 68_realtime.py# 边录音边转写, 简化版# 安装: pip install faster-whisper pyaudio numpyimportqueueimportthreadingimportnumpyasnpimportpyaudiofromfaster_whisperimportWhisperModel model=WhisperModel("tiny",device="cpu",compute_type="int8")audio_q=queue.Queue()defrecord():"""录音线程, 每2秒丢一段音频进队列"""p=pyaudio.PyAudio()stream=p.open(format=pyaudio.paInt16,channels=1,rate=16000,frames_per_buffer=4096,input=True)whileTrue:frames=[]for_inrange(2*16000//4096):frames.append(stream.read(4096))audio_q.put(b"".join(frames))deftranscribe_loop():"""取队列里的音频转写, 结果直接打印"""whileTrue:audio=audio_q.get()# faster-whisper不收原始bytes, 先转成int16的numpy数组再喂audio_np=np.frombuffer(audio,dtype=np.int16)segments,_=model.transcribe(audio_np,language="zh",beam_size=1)forseginsegments:print(f"[{seg.start:.1f}s]{seg.text}")threading.Thread(target=record,daemon=True).start()transcribe_loop()这个方案的延迟大概2到4秒,做实时字幕够用,做语音对话偏慢。要更低延迟得换思路,用静音检测只转有语音的片段,或者上faster-whisper的服务化部署加批量推理。延迟每降一秒都要拿准确率去换,实时场景tiny的错字率比medium高一截,这个权衡提前跟产品说清楚,别等上线了再吵。
生产环境的实时转写我建议走WebSocket而不是轮询。服务端维护每个连接各自的音频缓冲,客户端把麦克风数据流式推上来,服务端攒够2秒就转一次,结果从同一条连接推回去。FastAPI的WebSocket原生支持,比HTTP轮询少一半的网络开销。实时字幕产品基本都是这个结构,断线重连时客户端要把缓冲清掉,否则新旧音频拼一起转出错句。
多路实时会话共享一块GPU时,转写请求会排队,单路延迟不受影响,吞吐被卡在推理速度上。tiny模型一块3060能同时撑四路实时转写,medium只能撑一路,实时场景上tiny加int8几乎是必选项。排队策略用先来先服务,会话优先级高的插队要慎重,插队会把其他路的延迟顶上去,用户体验更差。扩容量按峰值并发配GPU,按两倍冗余算,别算平均值,语音产品的高峰和低谷差一个数量级。
五、多语言识别与热词
Whisper自动语言检测在单语种音频上很准,中英混说的会议里,它会在句子之间切语言,转出来的文本中英混排。强制指定language="zh"会压制英文输出,反而把英文句子转成拼音或错字,中英混杂的录音别指定语言。
initial_prompt是个隐藏利器。转写前塞一段领域上下文,模型会往那个方向纠正。我处理客服录音时塞"以下是普通话客服通话记录, 涉及退款、售后、物流、差评"这类句子,产品名的错误率肉眼可见地降。踩坑提醒,initial_prompt别塞太长,几十个词就够,塞多了模型会往prompt的句子上靠,输出里偶发出现prompt里的原句。
数字是中文识别的重灾区,“2023年"被读成英文数字混排很常见。initial_prompt加一句"请输出简体中文和中文数字”,能压掉大半。日期、金额、电话号码这三类,质检场景里错了影响结论,我都是转写后加一层正则后处理,把明显错位的数字按上下文修正,人工只复核修正点。
语言检测本身也有开销,auto模式下Whisper要先听前30秒判断语言,再决定用什么语言解码,多花一轮推理。单语种场景显式指定language,能省掉这部分时间。中英混合场景没法指定,就接受auto模式的额外开销,一条两小时的录音大概多花两分钟。另外一个细节,指定language="zh"时把繁体音频也归到简体输出,Whisper会统一转简体,台湾腔录音直接用这个参数。
中英混合还有一个工程细节,转写结果要按句子分桶,中文句子进中文校验规则,英文句子进英文规则,别混着处理。质检平台的多语言规则通常按文本语言分路由,混排的文本会让规则引擎两头都误判。分桶按语言检测结果走,Whisper的segments带language字段,一句一个判定,比整段判定准得多。我踩过一次,整段标中文,英文句子的质检规则全部没生效,漏了一个客户投诉关键词。
六、字幕质量与后期
SRT生成在第三节已经给了完整代码,这节补三个提质量的点。一是重复词,长音频里Whisper偶尔把一个词重复输出两遍,转写时temperature设0,重复率明显下降。二是断句,字幕按句子切而不是按时间硬切,每行控制在20个汉字内,观感好很多。三是词级时间戳,faster-whisper的word_timestamps给出逐词时间,做逐字字幕或校准音频就用它。
要更细的活儿,whisperx这个库在Whisper基础上加了词级校准和说话人分离,会议纪要场景值得试,代价是显存再加2GB左右。whisperx的词级校准用动态时间规整把文本和音频逐词对上,比faster-whisper自带的词时间戳更准,但多一道校准计算,速度慢一些。
整条字幕管线串起来就是,录音入库,VAD切段,逐段转写,合并校准,生成SRT,人工抽检,一天几百通录音一个人管得过来。抽检比例我定在5%,抽到的录音人工听一遍,把错误类型记下来,错得集中的类目就回炉调initial_prompt或补正则。
字幕样式上有两个行业默认值。一是单行字幕时长控制在2秒以内,观众扫读速度跟不上更长的时间。二是断行在语义边界,主语宾语别拆开,"我们昨天讨论的"和"方案通过了"拆两行就破坏了阅读节奏。SRT时间戳精确到毫秒,剪辑软件只认整帧,导出前做一次帧级取整,避免播放器卡帧。视频平台的质检组就靠这两条规则卡字幕,返工率明显降。
字幕抽检的标准动作是双人交叉复核。第一个人按听写稿对字幕,第二个人只看时间轴,两人独立打分,分歧样本进讨论会。抽检记录按月汇总,错误类型分布出来,哪类错误多就针对性补哪类。重复词多就调temperature,断句乱就改VAD参数,时间轴漂就查窗口截词,错误类型和根因基本一一对应。这套机制跑下来,字幕返工率从上线初的12%降到3%。
七、转写后处理,从文本到结论
语音转文字只是前半场,后半场是文本后处理。质检场景里,语气词、重复词、识别错的数字都要处理,处理完的文本才敢进质检规则引擎。后处理分三步走,清语气词,统一数字和标点,敏感词标记。下面这段代码覆盖这三步,按自己词库改填充即可。
# 68_postprocess.py# 转写文本后处理: 语气词过滤 + 数字标记 + 敏感词标记# 安装: pip install opencc-python-reimplemented (可选, 繁体转简体)importre FILLERS=["嗯","啊","呃","那个","然后就是"]# 常见语气词表defclean_text(text:str)->str:"""去掉语气词, 标点归一, 返回干净文本"""forwinFILLERS:text=text.replace(w,"")text=re.sub(r"[,,。;;]+"," ",text)returntext.strip()defformat_numbers(text:str)->str:"""把常见英文数字混排标记出来, 供人工复核"""returnre.sub(r"\b(two thousand|twenty twenty|three hundred)\b","[疑似英文数字]",text)deftag_sensitive(text:str,words)->str:"""命中敏感词列表的片段打标记, 质检结论要引用"""forwinwords:text=text.replace(w,f"[敏感:{w}]")returntext sample="嗯, 那个2023年twenty twenty三年, 退款金额三百块, 啊"print(tag_sensitive(format_numbers(clean_text(sample)),["退款"]))跑出来的结果里,2023年被标成[疑似英文数字],退款被打上敏感词标记,三个标记各管一件事,语气词直接删,英文数字标记出来人工看,敏感词标记喂给质检规则引擎。质检平台的结论生成就建在这层文本上,比直接拿原始转写靠谱得多。
后处理还有一个容易被忽略的点,文本入库要存两份,原始转写和后处理文本。原始转写留着追模型问题,后处理文本给业务用,两个字段都建索引。我吃过一次亏,只存了后处理文本,模型版本升级后想对比新旧效果,原始数据没了,只能重跑一遍全量录音,烧了三天GPU。
八、转写服务化部署
脚本批处理够用之后,质检平台要按需调用,我把它包成HTTP服务。FastAPI加faster-whisper,几十行搞定。服务启动时加载一次模型,所有请求共享,模型加载要十几秒,别在请求里加载。并发请求来了排队推理,GPU一次只能跑一个,队列交给FastAPI的异步机制。
# 68_server.py# 用FastAPI把转写封装成HTTP服务# 安装: pip install fastapi uvicorn python-multipartimportosimporttempfilefromfastapiimportFastAPI,UploadFilefromfaster_whisperimportWhisperModel app=FastAPI()# 服务启动时加载一次模型, 全局共享, 不要在每个请求里加载model=WhisperModel("turbo",device="cuda",compute_type="int8_float16")@app.post("/transcribe")asyncdeftranscribe(file:UploadFile):"""上传音频文件, 返回带时间戳的段落列表"""suffix=os.path.splitext(file.filename)[1]or".mp3"withtempfile.NamedTemporaryFile(suffix=suffix,delete=False)astmp:tmp.write(awaitfile.read())path=tmp.name segments,_=model.transcribe(path,language="zh",vad_filter=True)result=[{"start":round(s.start,2),"end":round(s.end,2),"text":s.text}forsinsegments]os.remove(path)return{"segments":result}# 启动: uvicorn 68_server:app --host 0.0.0.0 --port 8000服务化之后有两个监控指标要看。第一个是单请求耗时,turbo模型在3060上转5分钟音频约2秒,超过5秒就要查队列堆积。第二个是GPU显存和利用率,faster-whisper的int8把显存压到4GB以下,一台8GB显卡的机器可以同时跑转写服务和预处理。线上挂了别忘了给接口加重试,质检平台批量调用时偶发超时,重试两次能覆盖绝大多数抖动。
监控面板再加三个指标。一是队列深度,请求进来排队的数量,超过模型吞吐就报警。二是显存峰值,int8的turbo显存不到4GB,峰值超6GB说明有内存碎片或并发配置问题。三是错误率,转写接口偶发503和超时,错误率超过2%先查上游存储和网络。告警阈值按分钟粒度设,别用小时粒度,小时粒度下高峰期的问题被平均掉了,等看到时用户已经骂了一轮。
服务多实例部署时,模型权重要按GPU规划。一块GPU一个worker,worker之间不共享模型,扩实例就是加GPU。多个worker共享同一份队列时,转写结果按请求ID归位,别混。模型热加载的版本管理也要做,新模型先在灰度worker上跑,A/B对比WER,指标过了再全量切。Whisper服务化最怕模型版本不统一,线上两个worker用不同版本,转写结果质量忽高忽低,用户投诉都查不出来。
九、转写接LLM,会议纪要一条线
转写文本直接丢给业务同事看,没人看。质检平台和会议纪要的真实形态是结构化输出,结论、待办、责任人、时间节点。这一步交给LLM,转写做输入,LLM做整理。下面代码把segments拼成带时间戳的逐字稿,一次对话生成结论、待办、分歧点三部分,客服质检的周报就是从这层文本自动出的。
# 68_meeting.py# 转写结果接LLM, 自动出会议纪要# 安装: pip install openaifromopenaiimportOpenAI client=OpenAI()defsummarize_segments(segments,topic:str)->str:"""把带时间戳的转写段落拼成文本, 交给LLM总结"""transcript="\n".join(f"{seg['start']:.0f}s{seg['text']}"forseginsegments)resp=client.chat.completions.create(model="gpt-4o-mini",messages=[{"role":"system","content":"你是会议纪要助手, 输出三个部分: 结论、待办、分歧点"},{"role":"user","content":f"会议主题:{topic}\n逐字稿:\n{transcript}"},],temperature=0.3,# 纪要要稳定, 别让温度放飞)returnresp.choices[0].message.content# 从68_server.py的接口拿到segments, 这里直接演示demo=[{"start":0.0,"end":8.0,"text":"今天我们讨论上线排期, 我先说结论, 两周后灰度"},{"start":8.2,"end":15.0,"text":"客服组反馈录音质检准确率不够, 需要再调一轮模型"},]print(summarize_segments(demo,"质检系统排期会"))注意逐字稿别一次塞太多。gpt-4o-mini的上下文窗口虽然大,两小时会议的转写有十万字级别,超出就截断。分段投喂是标准做法,每段三十分钟,逐段总结再合并,合并时让LLM去重。会议纪要还有一个细节,转写里的语气词和重复词先过第七节的后处理,喂给LLM的文本越干净,出来的纪要越像人写的。带时间戳的逐字稿保留原样存档,纪要只是加工视图,原始转写丢了就追不回问题。
纪要的模型选型也有讲究。gpt-4o-mini处理摘要够用,长会议的分段总结和去重用4o更稳,成本高一些。批量纪要任务放夜间跑,白天接口给实时业务,两拨流量分开。纪要的模板要版本化,结论、待办、分歧点的字段名定了就别改,下游的系统按字段解析,字段名一变整个管道都要跟着改。我吃过一次亏,把"待办"改成"行动项",下游报表空了一个月才被发现。
常见问题FAQ
- Q1: whisper库装不上或模型下载慢
- A1: 模型走HuggingFace,国内设HF_ENDPOINT=https://hf-mirror.com镜像下载,faster-whisper同样适用
- Q2: 中文识别准确率哪一档够用
- A2: 日常对话small够用,涉及术语和数字的质检场景上medium,发布会和会议纪要直接large-v3,显存4GB左右可考虑turbo的性价比
- Q3: 显存不够怎么办
- A3: 四选一,换更小的模型,int8量化省一半显存,音频切成10分钟小段跑完释放显存,或者CPU跑small以下的型号
- Q4: 转写结果重复卡带
- A4: temperature设0,长音频开VAD切分,都做了还重复就检查音频本身有没有卡顿,录音设备丢帧也会造成重复
- Q5: 时间戳越往后越不准
- A5: 典型的窗口截词问题,开vad_filter=True按静音切段,别让Whisper自己切30秒窗口,白噪音多的音频先过ffmpeg降噪
- Q6: 能识别方言和英文吗
- A6: 英文很好,粤语和四川话在large上有可用效果,冷门方言建议用领域微调或换讯飞的方言服务,繁体中文自动转简体
- Q7: 商用有没有版权问题
- A7: Whisper是MIT协议可商用,模型输出内容仍需自己审核,涉及用户录音要按个人信息保护法做合规处理
- Q8: 实时转写延迟能做到多少
- A8: tiny加int8大约2到4秒,服务化部署加静音检测能压到1秒左右,再低要上流式模型方案,延迟换准确率的账提前算清楚
- Q9: 和讯飞、阿里云ASR怎么选
- A9: 自部署Whisper胜在免费可控,云服务胜在省心,量小用云,量大自部署,百万分钟级录音自部署成本优势明显,还要把人力运维算进对比
- Q10: SRT字幕中文乱码
- A10: 写文件用utf-8-sig编码,部分播放器只认带BOM的UTF-8,读取时用utf-8-sig解码避免首行带看不见的字符
为什么订阅本专栏
- 免费教程只给一句model.transcribe,本文把长音频截词、时间戳漂移、VAD切分这些生产事故讲透
- 培训班讲Whisper一笔带过,本文给出tiny到large完整选型表加显存和速度实测数据
- 一套代码覆盖基础转写、长音频分段、SRT字幕、实时转录四个场景,改改路径就能跑
- 与第65篇多模态入门、第69篇TTS衔接,语音处理的输入输出两端一次学完
- 一次订阅终身回看,代码随库版本更新持续修正
相关推荐
- Transformer架构图解:注意力机制通俗讲解
- OpenAI API入门:Python调用GPT全流程
- Ollama本地部署:一行命令跑起大模型
限时¥59.90,30秒完成订阅,今天就能开始学习