从语音转写到智能会议纪要:我用 Python + SenseVoice 实现五人会议识别与说话人分离
前言
上一篇文章,我记录了如何在 Anolis OS 8.10 上,从零部署 SenseVoice + sherpa-onnx 离线语音识别服务,实现普通话、粤语及多语种语音识别。
文章发布后,我开始思考一个更实际的问题:
如果把语音识别真正应用到企业会议中,仅仅把录音转换成文字,够用吗?
显然不够。
企业会议真正需要的并不是一份没有结构的转写文本,而是一份能够回答以下问题的会议记录:
- 谁在什么时候说了什么?
- 不同发言人能否自动区分?
- 普通话和粤语混合发言能否识别?
- 能否将「说话人1、说话人2」关联到真实员工?
- 能否自动整理会议讨论、决议和待办事项?
- 能否将整个过程接入企业现有办公系统?
因此,我在之前的离线语音识别服务基础上,继续增加了自动标点、说话人分离和声纹识别能力,并尝试将其集成到自己研发的 AI Agent 平台 TaskWeave 中。
这篇文章记录整个实现思路,以及一次真实的五人会议音频测试。
一、整体技术架构
这次实现没有直接依赖云端语音识别 API,而是尽可能将语音处理能力部署在本地服务器。
主要使用以下技术:
| 模块 | 技术方案 | 主要作用 |
|---|---|---|
| 开发语言 | Python 3.11 | 语音服务开发 |
| 语音推理 | sherpa-onnx 1.13.8 | 本地模型推理 |
| 语音识别 | SenseVoice | 普通话、粤语等多语种识别 |
| 自动标点 | sherpa-onnx 标点模型 | 恢复文本标点 |
| 说话人分离 | Pyannote segmentation ONNX | 区分不同发言人的时间片段 |
| 声纹识别 | 3D-Speaker ERes2Net | 提取和比对说话人声纹 |
| REST 接口 | FastAPI | 提供 HTTP 服务 |
| 实时通信 | WebSocket | 提供语音服务通信能力 |
整个处理过程可以拆分为六个阶段:
音频上传 → 语音识别 → 自动标点 → 说话人分离 → 声纹识别 → 会议纪要生成
这里需要说明一个容易混淆的概念:
说话人分离(Speaker Diarization)和说话人识别(Speaker Recognition)不是同一个功能。
- 说话人分离:判断一段录音中不同时间片段分别属于哪个说话人。
- 声纹识别:通过声音特征,与已有的声纹样本进行比对,辅助判断说话人的身份。
例如,分离结果可能是 SPEAKER_00、SPEAKER_01,而声纹识别可以进一步尝试将其关联到已经录入声纹的员工。
这也是我在会议助手中重点探索的方向。
二、第一步:搭建离线语音识别服务
之前已经完成了 SenseVoice 的离线部署,这里不再重复介绍模型安装过程。
部署环境如下:
- 操作系统:Anolis OS 8.10
- Python:3.11
- Conda 环境:taskweave-asr
- sherpa-onnx:1.13.8
- 推理方式:ONNX Runtime 本地推理
使用 SenseVoice 的主要原因是它支持多语种语音识别,适合普通话、粤语等混合语言的实际交流场景。
在企业会议中,尤其是广东地区,参会人员不一定全程使用普通话。
有些人使用普通话,有些人使用粤语,也可能在同一段发言中出现语言切换。
因此,我希望语音识别模块不仅能够识别标准普通话,还能够应对更接近真实会议的语音环境。
本地部署还有一个实际优势:
语音文件可以在自己的服务器上进行处理,减少对外部语音识别服务的依赖。
不过,本地部署并不意味着天然安全,仍然需要做好音频文件权限、访问控制、存储加密和日志管理。
三、第二步:自动标点,让转写文本更容易阅读
语音识别模型输出的原始文本,通常不一定具备完整的标点结构。
例如:
原始识别结果:
大家下午好我们开始今天的项目周会今天主要看一下语音模块目前的开发进度重点验证语音识别自动标点和说话人分离几个功能
直接展示这样的文本,阅读体验并不好。
尤其是会议内容较长时,用户很难快速理解每句话的边界。
因此,我额外接入了 sherpa-onnx 标点模型。
处理后:
大家下午好,我们开始今天的项目周会。
今天主要看一下语音模块目前的开发进度,重点验证语音识别、自动标点和说话人分离几个功能。
这样就可以将原始语音识别结果进一步整理为可阅读的文本。
需要注意,自动标点主要负责文本断句和标点恢复,不代表能够自动修正所有语音识别错误。
四、第三步:说话人分离,解决多人会议的发言归属问题
这是本次开发中比较重要的一部分。
假设一段会议录音中有五个人:
- 张国强
- 李敏
- 陈伟
- 王强
- 刘芳
如果只进行普通语音识别,最终得到的可能是一整段连续文本。
但在会议场景中,我们需要知道每段内容究竟是谁说的。
例如:
| 时间 | 说话人 | 发言内容 |
|---|---|---|
| 00:00:01 | SPEAKER_00 | 大家下午好,我们开始今天的项目周会。 |
| 00:00:15 | SPEAKER_01 | 我这边已经测试过粤语识别。 |
| 00:00:31 | SPEAKER_02 | 我觉得还需要继续测试。 |
为此,我接入了 Pyannote segmentation ONNX 模型。
它主要用于分析音频中不同说话人的活动区间,得到对应的说话人时间片段。
处理逻辑大致如下:
- 读取会议音频。
- 对音频进行必要的预处理。
- 运行说话人分离模型。
- 获取不同说话人的时间区间。
- 将说话人区间与语音识别结果进行时间匹配。
- 整理出带有说话人标识的转写记录。
这里有一个工程上的细节:
语音识别和说话人分离是两个不同的处理过程,最终需要通过时间戳进行关联。
不能简单地假设一次语音识别结果就能直接得到准确的说话人归属。
尤其是多人同时发言、短时间插话、声音重叠的情况,需要额外考虑时间区间匹配和结果纠正。
五、第四步:声纹识别,让 SPEAKER_00 尝试对应真实员工
完成说话人分离之后,我们已经能够区分不同的发言人。
但还有一个问题:
SPEAKER_00 究竟是谁?
这就需要用到声纹识别。
本次使用的是 3D-Speaker ERes2Net Base SV 中文 16k ONNX 模型。
它的主要作用是提取说话人的声纹特征,并在已有声纹样本之间进行相似度比对。
整体设计思路:
第一步:员工声纹注册
提前采集员工的语音样本,提取声纹特征,并与员工档案建立关联。
第二步:会议发言人分离
通过说话人分离,得到 SPEAKER_00、SPEAKER_01 等不同说话人的音频片段。
第三步:提取会议发言声纹
对满足时长和音质要求的发言片段提取声纹特征。
第四步:声纹比对
将会议发言的声纹特征与已注册的员工声纹进行相似度比对。
第五步:人工确认
满足匹配条件时提供员工身份候选,必要时由用户确认后绑定。
这里特别强调:
声纹相似度不等于身份确认。录音质量、说话时长、环境噪声和相似声音都会影响结果,不能直接把一次模型匹配当作身份认证。
如果没有匹配到可靠的员工声纹,就继续保留 SPEAKER_00 这样的临时标识。
六、第五步:真实五人会议音频测试
为了验证这套方案,我准备了一段五人会议音频进行测试。
这次不是简单地使用几句录音进行演示,而是使用了一段真实会议场景的测试音频。
测试数据:
| 测试项目 | 数据 |
|---|---|
| 会议时长 | 385.80 秒 |
| 参会人数 | 5 人 |
| 发言段数 | 25 段 |
| 语言 | 普通话、粤语 |
| 测试内容 | 项目周会讨论 |
| 测试重点 | 语音识别、标点、说话人分离 |
1. 普通话识别
会议开场:
张国强:
大家下午好,我们开始今天的项目周会。今天主要看一下 TaskWeave 语音模块目前的开发进度,重点验证语音识别、自动标点、说话人分离和声纹识别这几个功能。
2. 粤语识别
李敏:
我呢边已经测试过粤语识别,整体效果都几好。普通嘅粤语对话基本上都可以识别到,不过有啲比较口语化嘅表达,同埋讲话速度比较快嘅情况,我觉得仲需要继续测试。
这部分主要用于验证模型对粤语口语表达的支持情况。
3. 多人发言区分
在完成语音处理后,将识别文本与说话人分离结果进行关联,得到按时间排序的发言记录。
例如:
[00:00:01.000 --> 00:00:14.224]
SPEAKER_00 张国强
大家下午好,我们开始今天的项目周会。
[00:00:15.025 --> 00:00:31.153]
SPEAKER_01 李敏
我呢边已经测试过粤语识别,整体效果都几好。
[00:00:31.743 --> 00:00:49.599]
SPEAKER_02 陈伟
……
以上展示的是测试 Ground Truth 中的发言内容格式,用于说明最终希望得到的结构化结果,不代表所有模型输出都能自动达到人工标注的准确程度。
七、第六步:将语音能力接入 TaskWeave 会议助手
完成独立语音服务后,我希望它最终不只是一个可以通过命令行调用的模型,而是能够成为实际 AI 应用的一部分。
因此,我将语音处理能力封装成独立服务,通过 HTTP 和 WebSocket 提供调用能力。
目前服务接口划分如下:
| 服务 | 地址 | 作用 |
|---|---|---|
| WebSocket | 6006 | 语音识别通信 |
| REST API | 8088 | HTTP 语音服务 |
/asr/transcriptions | REST | 语音转写 |
/punctuation | REST | 自动标点 |
/speakers | REST | 说话人相关处理 |
这样做的好处是:
语音识别模块不需要与 TaskWeave 主业务代码耦合在一起。
后续无论是会议助手,还是其他需要语音识别能力的 AI 应用,都可以复用这套服务。
在 TaskWeave 会议助手中,整体业务流程可以设计为:
- 用户上传会议音频。
- 后端调用离线 ASR 服务。
- 获取语音转写和时间信息。
- 结合说话人分离结果整理发言记录。
- 根据已有员工声纹信息辅助匹配发言人。
- 将结构化会议内容交给大模型。
- 生成会议摘要、讨论结论和待办事项。
- 用户确认、纠正和编辑会议成果。
这里最重要的是将语音处理和大模型总结分开。
ASR 负责尽可能忠实地还原语音内容。
说话人分离负责组织发言归属。
大模型负责在这些结构化信息的基础上提炼会议内容。
不能让大模型随意补充会议中没有出现过的决议、人员和时间。
对于无法确认的内容,应当明确标记为待确认。
【配图6:TaskWeave 会议助手真实界面截图,建议展示转写、发言人、会议总结三个区域】
八、实际开发中遇到的一些问题
在这次开发过程中,我认为有几个问题值得单独记录。
1. 语音识别不等于会议理解
ASR 的任务是将语音转换为文字。
会议总结则需要理解讨论主题、上下文、结论和行动项。
两者应该分开处理。
2. 说话人分离不等于声纹识别
分离模型能够区分不同说话人的发言区间,但不一定知道这个人真实叫什么。
如果需要与员工档案关联,还需要声纹注册、特征提取、相似度比对和人工确认。
3. 时间戳非常重要
如果只有文本,没有时间信息,后续很难定位原始录音中的具体内容。
因此,在设计数据结构时,需要尽可能保留发言开始时间、结束时间以及对应的音频信息。
4. 离线部署也需要考虑工程化
模型能够运行只是第一步。
真正提供给业务系统使用,还需要考虑:
- 服务启动和异常恢复。
- 并发请求与资源管理。
- 音频文件格式兼容。
- 长音频分段处理。
- 请求超时和失败重试。
- 日志与运行状态监控。
- 文件访问权限和数据安全。
这些工作往往比单独跑通一个模型更接近真实项目。
九、总结:从一个 ASR 模型到企业会议助手
这次实践让我更加明确:
语音识别本身并不是最终产品。
从语音转写到说话人分离,再到声纹匹配和会议纪要生成,中间涉及多个独立的技术模块。
只有把这些能力组织成完整的业务流程,才能真正解决企业会议中的问题。
目前,我正在通过 TaskWeave 持续探索 AI Agent 在企业办公场景中的应用。
后续还会继续完善:
- 会议发言人的快速纠正。
- 声纹与员工档案的绑定。
- 会议结论与待办事项提取。
- 会议记录的可追溯和二次编辑。
- 离线语音服务的稳定性与并发能力。
这只是一次持续迭代中的工程实践,距离完整的企业级会议产品还有不少需要完善的地方。
但我认为,AI 应用开发真正有价值的地方,不是简单地接入一个大模型,而是把多个 AI 能力组合起来,解决实际工作中的问题。
如果你也在使用 Python、ONNX、SenseVoice 或 sherpa-onnx 开发语音应用,欢迎交流。
关于作者
我是张国军(网名 Armys),一名长期从事企业业务系统开发、持续探索 AI 应用落地的独立开发者。
AgentWeave 是我的个人 AI 技术品牌与网站,持续记录 AI Agent、企业知识库 RAG、语音识别和企业 AI 应用开发实践。
TaskWeave 是我正在持续研发的企业级 AI Agent 应用平台,重点探索智能体、会议助手、材料写作、知识库和工作流的结合。
- 官方网站:www.agentweave.site/
- TaskWeave 产品介绍:www.agentweave.site/taskweave/
- AI Agent 开发:www.agentweave.site/ai-agent/
- 企业知识库 RAG:www.agentweave.site/rag/
相关文章:
《从零搭建离线语音识别服务:SenseVoice + sherpa-onnx 实战,支持普通话、粤语及多语种识别》