1. 先把需求掰开:会议记录到底卡在哪一步
我第一次认真考虑用本地 AI 助手做智能会议记录,是在连续两周的跨部门对齐会之后。那两周我手里攒了十几个音频文件,每个四五十分钟,人工整理一份纪要要两小时起步,而且整理到第三个会的时候,我已经记不清"这个结论是周三那场还是周四那场定的"了。后来我搭了一套跑在本地机器上的会议记录流程,也就是标题里说的 Meetily 这一类本地 AI 助手:录音进、文字出、要点成。它能顶掉的部分是听写、分段、说话人标注、初版摘要这四件重复劳动,留下的是判断和取舍——那部分还得人来做。
这类东西适合谁?三类人受益最明显:一是每周开三场以上会、纪要压身的项目推进者;二是做访谈、用户调研、口述记录的内容工作者;三是对数据不能出本机这件事有硬性要求的团队,比如讨论产品路线、客户报价、内部评审这类内容。它不解决"开会效率低"这种大问题,它解决的是"会开完了,结论没留下来"这个具体的小问题。
标题里"本地"两个字是关键,也是本文大半篇幅要讲的东西。本地意味着模型在你自己的硬盘和显卡上跑,音频不离开你的机器,代价是你要自己管环境、管模型、管参数。所以这篇文章我不打算写成一个说明书,而是按我自己的落地顺序讲:为什么这么选、每一步的原理是什么、参数怎么算出来的、哪里会翻车。
1.1 三个断点:听不全、记不准、理不清
把会议记录这件事拆细,其实卡在三个地方,任何一个没解决,整条链就废。
第一个断点是"听不全"。人耳在嘈杂会议室里能自动过滤空调声、键盘声、隔壁工位的聊天,麦克风不能。笔记本内置麦克风在 3 米开外的拾音信噪比会掉到很难看的程度,后面模型再怎么强也救不回来。我最早的一批录音就是这么废掉的——人声和底噪比例太差,转写出来半篇是乱码。
第二个断点是"记不准"。这里有两层:一层是同音字和专有名词,比如内部项目代号、产品模块名、人名,通用模型大概率写错;另一层是说话人归属,一段"这个方案我们下周再定"如果不知道是谁说的,价值直接归零。
第三个断点是"理不清"。语音转成文字只是把 40 分钟变成一万多字,信息密度并没有提升。真正的纪要需要的是"结论 / 待办 / 负责人 / 时间点"这四样东西。这一步靠本地大模型做结构化抽取,但它的输出质量高度依赖提示词和上下文长度——这也是最容易做得潦草的一步。
我把这三个断点对应到具体的技术环节,就是:采集质量决定上限、识别模型和热词表决定准确度、说话人分离决定可用性、摘要提示词决定最终成品的可读性。后面每一节其实都在给这三个断点找解法。
1.2 本地化方案的取舍:一张表看清楚
很多人问我,直接用在线服务不香吗,为什么要自己折腾环境。这事儿没有标准答案,我把当时的对比表贴出来,你可以对着自己的场景打分。
| 维度 | 在线云服务 | 本地 AI 助手(Meetily 这类) |
|---|---|---|
| 首次上手成本 | 低,注册即用 | 中高,装依赖、下模型、调参数 |
| 音频数据流向 | 上传至第三方 | 全程留在本机磁盘 |
| 长会议成本 | 按时长或订阅计费,越长越贵 | 一次硬件投入,之后边际成本接近零 |
| 识别准确率 | 通用场景很好 | 通用模型接近,垂直术语靠热词表补 |
| 说话人分离 | 通常内置且免调 | 需自己跑分离模型,耗时较高 |
| 定制空间 | 提示词、术语表受限 | 提示词、模型、后处理全可改 |
| 断网可用性 | 不可用 | 完全可用 |
| 运维负担 | 由服务方承担 | 自己承担,升级要手动 |
我选本地的真实原因并不完全是在意"隐私"这个抽象概念,而是长会议的成本结构:我这类工作一小时会议是常态,按量计费累积起来不便宜,而且我需要反复重跑(换提示词、换模型、补热词),云服务每重跑一次都是钱,本地重跑只是多花几分钟电费。这个"可以随便重跑"的自由度,是我最看重的部分。
反过来说,如果你一个月只开两三次会、对术语准确率要求不高、也没有必须留在本机的约束,老老实实用现成服务更划算,别为了折腾而折腾。
1.3 Meetily 这条链路的整体架构
按本地会议助手的通用做法,整条链路大致是这么串的,我把它画成了一条文字流水线(这里只讲结构,具体实现以项目文档为准):
麦克风/系统内录 → 重采样为 16kHz 单声道 → VAD 切片 → 语音识别 → 词级时间戳 → 说话人分离 → 时间轴对齐 → 结构化存储 → 大模型摘要 → 导出
每一段的作用和常见坑:
- 采集段:决定信噪比。能用外接麦就别用内置麦,能录系统内声音轨就别只录房间。
- 预处理段:统一成 16kHz、单声道、16bit PCM,是因为绝大多数语音识别模型的输入就是按这个规格训练的,采样率不对会直接掉准确率。
- VAD 段:语音活动检测,把静音和纯噪声切掉。它的作用是省算力——一场会议真实有人说话的时间可能只占 60%~70%,剩下的都白算。
- 识别段:本地 Whisper 系列模型是当前最通用的一档,中文效果好、多语言、有现成的高效推理实现。
- 分离段:说话人聚类,常见方案是 pyannote 一类的声纹分离模型,输出"谁在第几秒到第几秒说话"。
- 对齐段:把识别出来的词级时间戳和说话人区间做重叠计算,判断每句话归属谁。
- 摘要段:本地大模型(Ollama、llama.cpp 之类跑的量化模型)按模板抽取结论和待办。
这条链路有一个很现实的约束:除了采集,其他每一段的耗时都跟音频时长近似线性。所以一场两小时的会,端到端跑十几分钟是正常的,别指望点一下几秒出结果。理解这一点,后面调参数时你就不会瞎折腾了。
2. 环境准备:硬件门槛、依赖顺序与模型选型
这一节是我踩坑最多的地方。软件装错顺序、模型选大了一号、显存算错,都会让你在第一步就卡住半天。
2.1 硬件门槛怎么算(含显存与磁盘估算)
先把账算清楚,别凭感觉买卡或者选模型。
磁盘:16kHz、单声道、16bit 的原始音频,每秒是 16000 × 2 = 32000 字节,约 31.25 KB/s。算下来:
- 1 小时 = 3600 × 31.25 KB ≈ 112.5 MB(按 1024 进制约 110 MiB)
- 3 小时的长会 ≈ 337 MB
这是原始 wav 的体积。转成 16kbps 左右的压缩格式能压到十分之一,但做识别时建议保留无损,压缩引入的失真会直接吃掉准确率。
显存:以 Whisper 系列为例,参数量和权重大小大致是这么个关系(fp16 精度,每个参数 2 字节):
| 模型档位 | 参数量 | 权重占用(fp16) | 推荐显存 | 相对速度 |
|---|---|---|---|---|
| tiny | 39M | ≈ 0.08 GB | 2 GB | 极快 |
| base | 74M | ≈ 0.15 GB | 2 GB | 很快 |
| small | 244M | ≈ 0.5 GB | 3 GB | 快 |
| medium | 769M | ≈ 1.5 GB | 5 GB | 中 |
| large-v3 | 1550M | ≈ 3.1 GB | 8 GB 起 | 慢 |
注意"权重占用"只是静态部分,实际跑起来还要加上激活值和缓存,峰值通常是权重的 2~3 倍。我当时按 3.1 GB 权重估了 4 GB 显存,结果 large-v3 一跑就爆,最后是 8 GB 卡才稳住。这个错误的根源就是只算了权重,没算中间张量。
如果没有独显,纯 CPU 也能跑,但要有心理准备:medium 在普通桌面 CPU 上的实时率(RTF,处理时长 ÷ 音频时长)大概 0.5~1.0,也就是一小时会议要跑 30~60 分钟。加量化(int8)能快 2~3 倍,代价是准确率略降。
内存:识别本身不占太多内存,但说话人分离模型和本地大模型是内存大户。我的经验值是——纯转写 8 GB 够用,加上分离和摘要,16 GB 是舒适线,32 GB 就不用惦记了。
2.2 依赖安装顺序与踩坑点
装依赖这事,顺序错了会互相打架。我按稳定可复现的顺序来:
# 1. 先固定 Python 版本,3.10 或 3.11 最稳 python -V # 2. 建独立虚拟环境,别往全局装 python -m venv .venv source .venv/bin/activate # Windows 用 .venv\Scripts\activate # 3. 先装深度学习底座,注意和 CUDA 版本匹配 pip install torch torchaudio --index-url https://download.pytorch.org/whl/cu121 # 4. 再装识别与音频处理 pip install faster-whisper soundfile librosa numpy # 5. 最后装分离模型与前端依赖 pip install pyannote.audio几个必须提醒的点:
第一条:不要先装项目依赖再装 torch。很多包会顺手拉一个 CPU 版 torch 进来,等你发现跑在 CPU 上再想换,得先卸载干净的依赖树,很麻烦。
第二条:CUDA、驱动、torch 三者版本要对得上。判断方法很简单,装完跑一句
python -c "import torch; print(torch.cuda.is_available())",输出True才算通。输出False就先解决这个,别往下走。
第三条:ffmpeg 这个外部可执行文件经常被忘掉。音频重采样、格式转换很多底层库要调用它,缺了会报一个很难看懂的错。
ffmpeg -version能出版本号就没问题。
第四条:路径里不要有中文和空格。这条是老生常谈,但每年还是能看到有人被
C:\Users\张三\Desktop\会议记录这种路径坑到。建议专门建一个纯英文的工程目录。
2.3 模型选型:别一上来就上最大号
新手最容易犯的错是"反正 large 最强,直接上"。我的建议反过来:先用 small 把整条链路跑通,再按需要往上加。
理由很实在——链路中有五六个环节会出错,你如果一上来用 large-v3,转写一次一小时会议要 6~10 分钟,调一次参数等一次,一天下来调不了几轮,人先崩了。用 small 的话,同样时长可能只要 1~2 分钟,你能快速验证采样率对不对、切片有没有问题、摘要模板通不通。
我实际的演进路径是这样的:
- tiny 起步:只为了验证录音有没有声音、输出路径对不对。准确率别在意。
- small 打底:跑通端到端,验证说话人分离和摘要模板。
- medium 定稿:日常用这一档,中文普通话场景下 medium 的性价比最高,比 small 明显准,比 large 快一倍多。
- large-v3 兜底:只对重要会议(对外沟通、决策会)用,或者转写完发现某段明显有错时,只对那一段单独重跑。
这个"分段重跑"的技巧值得展开说:你不需要为了修正三分钟的内容重跑两小时。把音频按 VAD 切好的段落单独导出,指定时间区间重新识别,再合并回时间轴就行。这一招在我这里省下的时间比任何参数调优都多。
3. 核心链路拆解:从声波到可读纪要
3.1 音频采集与预处理:先保证"喂进去的是干净数据"
我得把"预处理"这一节放在识别之前,因为采集阶段的损失是后面所有环节都补不回来的。
采样率统一到 16 kHz。原因是语音的有效频带基本在 300 Hz ~ 8 kHz 之间,按奈奎斯特采样定理,16 kHz 采样率能无损覆盖到 8 kHz,再高的采样率对语音识别没有增益,只会让文件变大、计算变多。44.1 kHz 的录音重采样到 16 kHz,用的是带抗混叠滤波的重采样,不是简单抽点,所以别自己写个[::3]去截。
声道转单声道。双声道如果两轨内容相同(比如立体声内录),直接取平均;但如果是"左声道麦克风、右声道系统音"这种分轨录制,千万别混——混完会出现自己说话和自己的电脑声音重叠的情况,识别质量崩掉。正确做法是分开转写,再按时间轴合并。
增益和降噪要克制。我试过给一段信噪比还行的录音做激进降噪,结果转写准确率反而降了——降噪模型把辅音的气音也削掉了,模型听到的是一片糊。经验是:只有在底噪明显影响听感(比如空调轰鸣、风扇直吹麦克风)时才做降噪,而且用温和档位;音量太小就先归一化到 -3 dB 峰值,别过度压缩。
一个实操细节:录音前先做 10 秒测试。让每个人正常音量说一句"测试一二三,我是某某",回放听一遍。这 10 秒能提前发现麦克风增益太低、有明显回声、有人离麦太远这三类问题,比会后再补救便宜太多。
预处理这一段给个可复用的命令,我用它把任意格式统一成识别友好的规格:
ffmpeg -i input.m4a \ -ac 1 \ -ar 16000 \ -sample_fmt s16 \ -af "highpass=f=80,volume=1.5" \ output.wavhighpass=f=80是切掉 80 Hz 以下的低频轰鸣(桌面震动、空调低频),几乎不会伤到人声基频;volume=1.5是我在安静环境下的常用增益,如果你那边环境嘈杂,先别加增益,先解决噪声源。
3.2 VAD 分段与流式转写的平衡
语音识别模型不是喂多长都行。以 Whisper 系列为例,它的训练窗口是30 秒一段,超过这个长度会被内部再切分,切分点如果正好落在词中间,就容易出错。
所以标准做法是用 VAD 先找出"哪里有人在说话",以语句为单位切片,再送进模型。这样既省算力,又避免在静音段产生幻觉文本(模型在纯静音或噪声上偶尔会输出莫名其妙的句子,这是已知现象)。
切片长度怎么定?这是个平衡:
| 切片策略 | 优点 | 缺点 | 适用 |
|---|---|---|---|
| 固定 30 秒硬切 | 实现最简单 | 容易切断句子,首尾丢词 | 快速验证 |
| VAD 按静音切(0.3~0.5 秒静音触发) | 语义完整 | 长句可能超过窗口 | 日常推荐 |
| VAD + 上限 25 秒强制切 | 兼顾语义与窗口 | 需处理超长句 | 我目前的默认 |
我用的参数是:静音阈值 0.3 秒、最小语音段 0.25 秒、最大段长 25 秒、段首尾各留 0.2 秒余量。留余量这个细节很重要——不留的话,句首的"那"、句尾的"的话"这类轻声音节很容易被切掉,转写出来就是"这个方案下周再"这种缺字。
关于"流式还是离线",我的判断标准是:你需要实时看字吗?如果需要(比如远程会要边听边看字幕),就走流式,代价是准确率略低、上下文少;如果只是会后出纪要,就走离线整段处理,准确率更高。我绝大多数场景是离线,因为会后十分钟出结果完全够用,没必要为实时性牺牲准确率。
3.3 说话人分离与时间轴对齐
这一步是"可用"和"不可用"的分水岭。没有说话人标注的转写,读起来是一大段没有主语的独白;有了标注,才能看出"张三提了方案、李四反对、最后折中"。
技术上分两块:
第一块是声纹分离。常见做法是用预训练的说话人分割模型,对整段音频做滑窗,提取每段语音的声纹嵌入向量,然后做聚类——同一个人的声纹向量在空间里距离近,聚成一类。这里有两个关键参数:
- 说话人数量:能提前知道人数就填死(比如"这场是 4 个人"),准确率明显更高。自动估计在 3 人以上、有人中途插话的场景下容易多算或少算。
- 最小语音时长:低于 0.5 秒的片段不参与聚类,否则"嗯""对"这种短回应会制造出一堆幽灵说话人。
第二块是时间轴对齐。识别输出的是词级时间戳,分离输出的是说话人区间,两者做区间交集:
def assign_speaker(word_start, word_end, segments): # segments: [(start, end, speaker), ...] 按时间排好序 best, overlap_max = None, 0.0 for s, e, spk in segments: overlap = max(0.0, min(word_end, e) - max(word_start, s)) if overlap > overlap_max: overlap_max, best = overlap, spk return best这段逻辑朴素但够用:取重叠时长最大的那个说话人作为归属。实测下来,90% 以上的词能正确归属,剩下出错的多是两人抢话的瞬间——那部分本来人也听不清,不必强求。
还有一个细节值得提:说话人标签要先编号再映射名字。先输出SPEAKER_00、SPEAKER_01,然后在导出前统一替换成真实姓名。这么做的好处是,某一次聚类错了你可以只改映射表,不用重跑整条链路。
3.4 摘要环节:提示词模板与本地大模型参数
转写稿变成纪要,靠的是本地大模型。这一步的成品质量差异极大,我用同一个模型、同一个提示词,改了一个参数,输出质量差了一倍——后面会说。
先说上下文长度这个硬约束。一小时中文会议,转写稿大概 8000~12000 字,折算 token 大约 12000~18000。大多数本地量化模型的实际可用上下文是 4k~8k,塞不进去。硬塞的结果是模型只看到开头和结尾,中间全丢,输出一份看起来像模像样但漏掉关键决策的纪要——这比不写还危险。
我的解法是两段式:
- 分块抽取:按话题或按 10 分钟切块,每块单独跑一次"抽取结论/待办/争议点",输出结构化的小片段。
- 汇总合并:把所有小片段(这时候总量小得多)合成一份完整提示词,再跑一次"去重、合并、按主题归类"。
分块的切点我按 VAD 的静音边界找,优先在长静音处切,其次按时间均分。这个细节决定了抽取质量——在句子中间切开,模型会读到一个断头的句子,抽出错误结论。
提示词模板我用的是这一版,你可以直接抄:
你是会议纪要整理助手。以下是会议转写稿的一部分,说话人已标注。 任务: 1. 提取【结论】:已经达成一致的决定,只写确定的事,不要写"讨论了"。 2. 提取【待办】:包含负责人和时间点,若原文未提及负责人,写"待定"。 3. 提取【分歧】:明确有人反对或未达成一致的点。 4. 提取【风险】:被提到但未展开的隐患。 要求: - 每条不超过 40 字,用原文表述,不要自行推断。 - 原文没有的信息一律写"未提及",禁止编造。 - 输出用 Markdown 列表,不要写引言和总结。 转写稿: {transcript_chunk}这个模板里最有用的一句是"原文没有的信息一律写未提及,禁止编造"。本地小模型在信息缺失时非常爱"合理补全",把"下周再定"补成"下周三定",这种错误在纪要里是致命的。
采样参数方面,我固定用temperature=0.2、top_p=0.9,摘要任务不需要创造性,温度高了就开始自由发挥。这里就是我前面说的那个"改一个参数差一倍"的地方——我早期用默认温度 0.8,输出全是漂亮但空泛的套话;降到 0.2 之后才开始出干货。
4. 实操全流程:一场两小时会议的完整跑通记录
这一节我把上周的一场两小时评审会的真实操作过程记下来,参数都是实际用的。
4.1 首次配置:把参数一次性写进配置文件
命令行敲参数敲两次就会烦,所以我全部落到一个 YAML 里。这份配置是我目前用的版本,注释里写了每个值的来由:
audio: sample_rate: 16000 # 与模型训练规格一致,别改 channels: 1 vad_threshold: 0.5 # 语音概率阈值,环境嘈杂调到 0.6 min_silence_ms: 300 # 静音超过 300ms 认为一句结束 min_speech_ms: 250 # 短于此视为噪声 max_segment_sec: 25 # 留 5 秒余量给 30 秒窗口 asr: model: medium # 日常档;重要会换 large-v3 compute_type: int8_float16 # 显存紧张时用,实测准确率损失很小 language: zh beam_size: 5 initial_prompt: "以下是普通话会议记录,涉及产品评审、排期、接口联调。" # 热词注入 diarization: enabled: true num_speakers: 4 # 已知人数就填死,自动估计容易飘 min_segment_sec: 0.5 summary: model: qwen2.5:7b-instruct temperature: 0.2 top_p: 0.9 chunk_minutes: 10 # 按 10 分钟一块做抽取 max_tokens: 1024 output: dir: ./meetings/2025-xx-xx-review format: [md, json]几个值的来由值得单独说:
compute_type: int8_float16这个量化档位,我在 medium 上做过对比:相对 fp16,速度快约 2.2 倍,显存占用降到一半多,中文准确率的差距在我的测试样本上是 1~2 个百分点。除非是特别重要的会,否则我认为这个交换值得。initial_prompt这个字段很多人忽略,它是热词注入最便宜的入口。把这场会会出现的专有名词、项目代号、人名写进去,能显著减少同音错字。我的做法是每次会前花一分钟更新这一行。beam_size: 5是默认值。调到 8 会更准一点但更慢,调到 1 会快但错字变多。5 是平衡点。
4.2 会议进行中的监控与干预
会议进行时我不做转写,只做两件事:监录音量和记时间点。
录音量很简单,隔一会儿瞄一眼电平表,如果发现某个人的电平一直很低(有人离麦太远、或者习惯性小声),中间休息时就提醒一句。这个动作能救回 30% 的识别错误,比任何后处理都有效。
记时间点更关键:会上出现重要决策、数字、专有名词时,我随手在记事本上记一个大概时间(比如"1:12:30 定了 Q3 只做两个模块")。会后校对时,我直接跳到这些位置逐字核对。这两小时的会议,我只精校这五六个关键点,其他段落接受 95% 的准确率。这是我认为最值得分享的一条工作方法——不要试图把转写稿校到 100%,那是不划算的;把关键结论校到 100%,其余够读就行。
另一个经验:如果条件允许,会后再补录一段 30 秒的口头总结,自己对着麦克风说"这场会定了三件事:一是……二是……三是……"。这段自述的识别准确率极高(单人、近场、吐字清楚),可以直接作为摘要的锚点,让模型不至于跑偏。
4.3 会后处理:校对、导出与归档
会后的完整流程我拆成五步,全程大概 15 分钟(两小时会议):
第一步:跑识别与分离。这条命令是串起来的:
python -m meetily.transcribe \ --input ./audio/review.m4a \ --config ./config.yaml \ --out ./meetings/2025-xx-xx-review两小时音频、medium、int8、单张中端显卡,实测跑了 11 分钟,其中识别约 7 分钟、分离约 4 分钟。这个比例挺典型:分离往往比识别还慢,因为它要做滑窗和聚类。
第二步:看质量报告。好的流程会输出一份自检信息,我关注三个数:识别出的总字数、平均置信度、被判定为静音的时长占比。如果静音占比超过 45%,说明录音有问题或者麦克风没收到多少人声;如果平均置信度明显偏低,先怀疑采样率和噪声,别急着换大模型。
第三步:按时间点精校。打开 Markdown,直接搜索我会上记的那几个时间点对应的关键词,逐句核对。数字、人名、项目代号这三类是重灾区,必须逐个确认。
第四步:生成纪要。跑摘要:
python -m meetily.summarize \ --transcript ./meetings/2025-xx-xx-review/transcript.md \ --template ./templates/review.md \ --out ./meetings/2025-xx-xx-review/minutes.md出来之后我一定会做一件事:把纪要里的每一条待办,回到转写稿里 grep 一遍原文。模型编造待办的情况我遇到过不止一次,尤其是"负责人"这一栏,它会从上下文里抓一个最近出现的人名填上去。花三分钟验一遍,能避免会上没说的事被写进纪要。
第五步:归档。我的归档结构是这样的,一年下来也不乱:
meetings/ 2025/ 2025-03-review-q3-plan/ audio.wav # 原始音频(可压,但不建议删) transcript.md # 带时间戳和说话人的转写稿 transcript.json # 结构化数据,便于二次处理 minutes.md # 最终纪要 actions.csv # 待办清单,单独一份便于汇总actions.csv这一份是我后来加的,格式就四列:事项,负责人,截止时间,来源会议。攒够一个月,把它导进表格按负责人透视一下,谁身上压了七件事一目了然。这个小动作的价值超出会议记录本身。
5. 常见问题与排查速查表
这一节是我半年下来攒的问题库,按现象分类,遇到问题直接查表。
5.1 转写质量类
| 现象 | 最可能的原因 | 排查动作 | 解决 |
|---|---|---|---|
| 整段输出乱码或重复同一句 | 音频全静音或全是噪声 | 用播放器听原音频 | 检查麦克风是否静音、增益是否为 0 |
| 中文里夹杂繁体或英文 | 语言未指定或指定错误 | 看配置里的 language | 固定zh,并在 initial_prompt 里给中文样例 |
| 专业名词频繁写错 | 缺少热词引导 | 对比错字是否集中在固定几个词 | 写进 initial_prompt,或在后处理做固定替换表 |
| 句首句尾频繁缺字 | VAD 切太紧 | 看转写稿是否句句断头 | 段首尾各留 0.2 秒余量 |
| 长句被切成两半且语义断裂 | 最大段长设太小 | 检查 max_segment_sec | 调到 25 秒,或按静音优先切 |
| 数字、金额识别错 | 模型对数字不敏感 | 抽查含数字段落 | 会后必校;或在提示词里要求"数字保留原文写法" |
| 说话人标签来回跳 | 聚类不稳定、短片段太多 | 看是否在抢话处跳 | 固定 num_speakers,提高 min_segment_sec 到 0.8 |
这张表里我最想强调"句首句尾缺字"这一条。它太隐蔽了——你读转写稿觉得通顺,但实际少了一两个字,语义就变了,比如"这个方案不用改"变成"这个方案用改"。这类错误靠通读发现不了,只能靠对照音频抽查。我的习惯是每场会随机抽三段各 20 秒,边听边对,能抓出大部分切分问题。
5.2 性能与资源类
显存爆了怎么办?按这个顺序降:先开量化(int8_float16),再降模型档位(large→medium),再降 beam_size(5→3),最后才考虑分批处理。不要一上来就降模型,量化带来的损失通常比降档小。
跑得比预期慢很多?先确认真的在用 GPU:跑一句nvidia-smi看有没有 python 进程占着显存。我遇到过装了 GPU 版 torch 但实际跑 CPU 的情况,原因是环境变量把设备固定成了 cpu,白等了一小时。
分离阶段特别慢?分离模型对长音频是滑窗处理,两小时音频做分离跑四五分钟很正常。如果明显更慢,检查是不是在 CPU 上跑——分离模型换到 GPU 通常能快 3~5 倍。
磁盘涨得飞快?别只删音频,transcript.json里的词级时间戳也很占地方,一场两小时的会大概几 MB 到十几 MB。我的策略是音频保留三个月,转写稿和纪要永久保留。
5.3 稳定性与数据类
中途崩溃了要重跑全程吗?不用。好的实现会把中间结果落盘(切片列表、已完成的段落转写),崩溃后能从断点续跑。如果没有这个能力,我建议你自己在流程里加一步:每处理完一个切片就把结果 append 到一个 jsonl 文件里。这十几行代码能省下无数次重跑。
数据安全这块要注意什么?本地方案的核心优势就是数据不外流,但有两件事仍然要做:一是确认所有模型都是本地加载,不存在首次启动时联网拉取的情况(有些实现会做模型校验);二是定期清理临时目录,切片音频和中间结果经常会散落在/tmp里,忘了删就是一份完整录音躺在临时文件夹。
一句提醒:本地不等于自动安全。硬盘没加密、共享目录权限开着、临时文件不清理,这几种情况下"本地"的意义会打不少折扣。
模型更新了要不要跟?我的做法是:主力环境不追新,另建一个测试环境试用。语音识别模型换版本后,输出格式、标点风格、时间戳粒度都可能变,而你下游的对齐脚本、摘要模板是按旧格式调的。追新之前先在测试环境跑同一段音频,对比输出差异,确认无碍再换。
6. 进阶:把单机工具变成可复用的流程
链路跑通只是开始,真正让它有价值的是把它变成肌肉记忆一样的流程。
6.1 术语表与热词注入
这是我投入产出比最高的一项优化。做法很土:建一个glossary.csv,三列——正确写法, 常见误写, 备注。每次校对发现错字就加一行。
正确写法,常见误写,备注 星轨计划,新鬼计划/星鬼计划,内部项目代号 联调窗口,联调窗口期/连调窗口,排期术语 灰度放量,灰度方量/辉度放量,发布术语攒到一百多条之后,我做了两件事:一是把正确写法拼成字符串塞进initial_prompt(受长度限制,只放最高频的三十个);二是在转写完成后跑一遍正则替换,把误写统一改正。两道防线下来,专有名词错误率从我早期的大约每千字五六个,降到每千字不到一个。
这一步的价值不止于准确率。术语表其实是团队知识的沉淀——新同事拿到这份表,比读十份文档更快搞懂大家在说什么。
6.2 模板化输出与二次加工
不同会议的纪要长得不该一样。我准备了几个模板:
- 决策评审会:结论 / 分歧 / 待办 / 风险,四块,不写讨论过程。
- 周会:按人分块,每人"本周完成 / 下周计划 / 阻塞项"。
- 用户访谈:按主题聚合原话引用,保留语气,不做归纳。
- 复盘会:时间线 / 根因 / 改进项,改进项必须带负责人。
模板本质上是给模型的输出约束。同一个转写稿,用决策评审模板和访谈模板跑出来完全是两份东西。这也是本地方案的优势——模板随便改,改完重跑不要钱。
二次加工我常用一个偷懒的办法:把transcript.json里的说话人维度聚合一下,统计每个人的发言时长和发言次数。这个数据放在周会上意外地有用,能看出谁一直在说、谁一直没说,比凭感觉判断靠谱得多。
6.3 我这套流程的边界在哪
用了半年,我清楚它哪儿不行,说清楚比吹有用。
多人抢话的场景基本无解。三个人同时说话,分离模型会把整段判给音量最大的那个,转写出来也是一团糊。这种会我的做法是会后单独找人补一句口述。
强口音加快速连读,准确率会掉到七成以下。这时候别硬调参数,调不动,直接上 large-v3 加人工校对更省时间。
它不会替你判断。模型能抽出"张三说这个方案有风险",但它判断不了这个风险重不重要、要不要写进最终纪要。这一层始终是人干的活,也是这份活里唯一没法自动化的部分。
我现在对它的定位很清楚:它是一个永不疲倦的记录员,负责把说过的话一字不落地留下来、按人分好、按主题归好;我负责决定哪些话值得留下。这个分工定下来之后,我对它的容错度高了很多——它把"下周"听成"这周",我改一下就行;它要是把整个决策漏了,我会发现问题就出在我的校对环节上,跟模型无关。
最后分享一个小习惯:每次会前我会把这套流程的耗时在心里过一遍——两小时的会,识别分离 11 分钟,校对 10 分钟,摘要 3 分钟,验待办 3 分钟。加起来不到半小时。而我手工整理一场两小时的会,最快也要两小时。这个账算清楚之后,你就知道该在哪个环节省时间、哪个环节别省。我踩过的坑基本都是想在"校对"这一环省时间,结果每次都要返工。