文章

不上云的会议转写:Whisper 与说话人分离

Avenex 编辑团队 · 2026-10-13

会议录音往往不能发送到外部服务:其中有约定、数字和人名。下面介绍我们如何搭建一套完全在工作电脑上运行的转写流程,以及它最终产出什么。这里描述的是我们自己的工作工具,而不是成品。

流程由哪些环节组成

首先用 ffmpeg 把录音转换为 16 kHz 的 WAV,这是语音识别模型需要的格式。接着由 Whisper large-v3 识别文字。在搭载 Apple Silicon 的 Mac 上,我们使用 mlx-whisper 版本,它通过 Metal 在 GPU 核心上运行。模型会自动识别语言,也可以手动指定。

说话人分离(diarization)是单独的一步,由 pyannote speaker-diarization-3.1 完成。Whisper 回答“说了什么”,pyannote 回答“谁说的”。两步的结果合并成一份带说话人标签和时间码的文本。

如何离线工作

pyannote 模型托管在 Hugging Face 上,首次下载需要接受使用条款并提供令牌。之后模型保存在本地。我们的工具有离线模式:只要本地存储缺少任何一个模型文件,转写就会报错停止,而不会悄悄尝试下载缺失的部分。

对于没有独立显卡的笔记本,还有另一种方案。在我们的听写助手中,识别要么通过带 GPU 加速的 Whisper 完成,要么使用针对普通 CPU 优化的 Parakeet 模型。识别之前,语音活动检测(VAD)会去掉静音:多余的计算更少,空白片段上凭空出现的“幽灵”句子也更少。

识别熟悉的声音

pyannote 本身不知道名字:它输出 SPEAKER_00、SPEAKER_01 之类的标签。每次手动标注说话人很麻烦,所以我们维护一个声纹库。pyannote 为每位说话人给出一个平均声音向量,再用余弦相似度与声纹库比对。

只有当最佳候选的得分不低于 0.5,并且比第二名至少高出 0.1 时,才会标上名字。否则保留 SPEAKER_XX:诚实的标签胜过自信地标错人。每个人的声音只需录入一次,依据一份已经标注好的录音。如果已知参会人数,可以把它作为提示提供给说话人分离。

从转写到决定和任务

原始转写还不是会议纪要。得出结论之前,我们会标记谁加入、谁离开,把可靠的发言与静音、重叠和识别重复区分开。每个结论都保留时间码,以便对照录音核实。识别置信度低的片段可以变成待澄清的问题,但不能作为分配给具体某人的任务依据。

最常见的错误是把任何将来时的句子都记成决定。我们区分几个层级:提到了一个想法、未获同意的提议、有负责人和期限的已接受的下一步、有条件的行动,以及最终决定。例如,“如果预算获批,我们就注册”是有条件的目标,而不是决定。

结果存放在哪里

转写内容和声纹都是敏感数据。在我们的工具中,每个项目的数据、访问凭据和结果分开存放,处理只能在明确指定项目配置的情况下运行。内部门户由经过核实的记录——决定、任务、会议——构建,而不是由原始转写构建。

如果您要在自己那里搭建类似流程,请提前决定:录音存放在哪里、保存多久,谁能看到完整转写、谁只能看到最终任务,以及谁在发送前审核会议纪要。