ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Whisper+LLM本地搭建语音转文字清理工作流

Whisper+LLM本地搭建语音转文字清理工作流 先说一下我自己的使用背景。最近在整理录音笔记和口述草稿时频繁在“语音转文字 → 内容清理”这两步之间来回折腾。腾讯会议导出的转写稿口语词太多在线工具又总担心隐私问题尤其涉及未公开方案和客户信息时根本不敢往外传。于是我开始研究完全本地化的听写方案核心思路是把 OpenAI 开源的 Whisper 语音识别模型和大语言模型LLM结合起来先用 Whisper 把录音转成带口语词的原始文本再用本地 LLM 做清理、断句、去口头禅最终输出一份干净的 Markdown 笔记。这个思路英文社区里有一个叫 Dictata 的项目专门做了落地实现。本文会围绕 Dictata 的核心理念展开先梳理 Whisper 和 LLM “转录 清理”这套架构然后给出一套可以直接照着跑起来的本地环境搭建方案包含完整命令、提示词设计、Python 脚本示例以及高频报错排查。不管你是为了做会议纪要还是想搭建私人语音笔记工作流都能在这篇文章里找到可以复用的参考。1. 背景与核心概念为什么需要 Dictata 这种本地听写方案1.1 传统语音转文字方案的痛点先看一个常见场景。你开完一场 40 分钟的会议拿到一份转写稿结果发现通篇都是“然后”、“就是说”、“那个”这类口头禅标点符号乱得离谱大量内容挤在一起一段话里穿插着好几个语气词连 AI 都分不清谁是主语关键数字和专有名词错得比较离谱。如果使用在线听写服务比如讯飞、腾讯会议、Google Speech-to-Text虽然识别率很高但存在几个现实问题隐私边界不清晰音频和转写文本默认会经过云端对于企业用户来说存在合规风险成本随时长线性增长按分钟计费长期使用并不便宜而且几乎不保留历史文本的清理能力口语清理能力不足大部分转写服务给出的是“一个人读到文字稿”没有自动去掉冗余口语词的能力离线场景无法使用没有网络或者网络质量差时识别体验会断崖式下降。1.2 Whisper 是什么语音识别的本地化基石Whisper 是 OpenAI 开源的一个通用语音识别模型它的核心特点是“通用”和“鲁棒性”。它支持多语言语音识别、翻译并且对背景噪声、口音、专有名词有一定的容忍度。Whisper 提供了多个大小的模型从tiny、base、small、medium到large逐级提升识别精度同时也逐步提升算力需求。它解决的关键问题是把“语音转文字”这一步变成可以完全本地运行的模块。你不需要把音频上传到任何服务器用自己的 GPU 或者 CPU 就能完成转录。1.3 LLM 清理把转写稿变成干净文字Whisper 输出的是识别文字但实际使用中它几乎不会帮你清理口语废词。当你说“然后呢就是那个我觉得应该要改一下”Whisper 输出的文本大概率是“然后呢就是那个我觉得应该要改一下”标点符号也可能不对。LLM 清理LLM Cleanup要做的就是第二件事让大语言模型基于提示词Prompt对 Whisper 的输出进行润色。它的任务包括删除“嗯”、“啊”、“然后就是”、“就是说”之类的语气填充词修正明显错误的标点符号对冗长片段做适度断句识别并修正常见同音错别字把口头语转成书面表达但保留原始语义。这一步如果使用本地 LLM整个链路就完全离线了既保护隐私又不受网络限制。1.4 Dictata 的组合思路Dictata 这类工具本质上就是一套“Whisper 转录 LLM 清理”的组合工作流它的创新点不在于某个 AI 模型而在于把开源模型串联成一条本地闭环录音/音频文件 ↓ Whisper 语音识别本地转录输出初稿文本 ↓ LLM 清理Prompt 润色去除口头禅、重排标点、格式化为 Markdown ↓ 干净的笔记/会议纪要/待办事项在这个架构里Whisper 负责“听得懂”LLM 负责“写得好”。两者缺一不可没有 Whisper音频无法变成文字没有 LLM转写稿无法被二次加工阅读成本很高。1.5 适用场景这套方案比较适合以下场景记者、博主、学生党整理访谈录音或课堂录音开发者在不开 IDE 的情况下快速记录思路需要处理客户录音、内部会议录音但不愿意上传云端的职场人群对听写内容有格式要求Markdown 输出的笔记爱好者。2. 环境准备与版本说明在开始搭建之前先梳理整体的工具链。为了让你能快速判断需要安装哪些东西我列了一份“必须组件”和“可选组件”清单。组件用途必装/可选Python 3.10运行 faster-whisper 和辅助脚本必装faster-whisperWhisper 的加速实现基于 CTranslate2必装FFmpeg音频解码转成模型可识别的格式必装Ollama本地运行 LLM 的入口加载 qwen2.5 等模型推荐GPUNVIDIA 显卡加速转录和 LLM 推理可选Git克隆/下载工具代码可选这里说明一点版本需要根据你的项目实际情况调整本文示例以常见环境为例重点演示配置思路。由于 Whisper 和 Ollama 的版本迭代速度都比较快我不会把每个版本号写死而是给出相对稳定的安装和配置方式。2.1 操作系统建议推荐在 Ubuntu 22.04、macOS 13 或 Windows 10/11 的 WSL2 环境中操作。如果你用的是 Windows 原生终端建议优先启用 WSL2因为后续编译音频处理库时 WSL2 比 Windows 原生环境省事很多。2.2 Python 环境准备建议使用venv创建独立的虚拟环境避免和系统 Python 包冲突。# 创建项目目录 mkdir -p ~/dictata-demo cd ~/dictata-demo # 创建虚拟环境 python3 -m venv venv # 激活虚拟环境 source venv/bin/activate # Windows WSL / Linux / macOS # 如果是 Windows CMD使用 venv\Scripts\activate激活虚拟环境后后续所有 Python 包安装都在虚拟环境中完成。2.3 安装 FFmpegFFmpeg 是一个处理音频和视频的开源工具faster-whisper 依赖它来解码多种音频格式。Ubuntu/Debiansudo apt update sudo apt install ffmpegmacOSbrew install ffmpegWindowsWSL 已覆盖在 WSL 里执行上面的 Ubuntu 命令即可。安装完成后验证ffmpeg -version能打印出版本信息说明安装成功。2.4 安装 faster-whisperfaster-whisper 是 Whisper 模型在 CTranslate2 上的重新实现推理速度比原始 Whisper 快很多显存占用也更低。它已经成为社区里比较主流的 Whisper 使用方式。pip install faster-whisper这里不锁定版本号因为 faster-whisper 会跟随 CTranslate2 随后端更新。如果安装过程中出现依赖冲突可以优先尝试把 CUDA 相关库如nvidia-cublas-cu12升级到当前环境支持的版本。2.5 安装 Ollama本地 LLM 运行环境Ollama 是目前在本地跑大语言模型比较省事的工具一条命令就能拉起一个支持 OpenAI API 兼容接口的服务。macOS / Linux 安装curl -fsSL https://ollama.com/install.sh | shWindows 版本直接前往 Ollama 官网下载安装包即可。安装完成后拉取一个适合 CPU/GPU 运行的中文模型。以qwen2.5:7b为例ollama pull qwen2.5:7b对于显存比较紧张的用户也可以选择qwen2.5:3b或llama3.2:3b。这一步会下载几个 GB 的模型文件建议安排在网速较好的时段执行。启动 Ollama 服务ollama serve验证服务状态curl http://localhost:11434/api/tags如果返回一段 JSON其中包含已经下载好的模型列表就说明 Ollama 已经准备好了。3. 核心原理拆解Whisper 转录与 LLM 清理如何协同工作在动手写代码之前有必要先把两个核心模块的原理拆开讲清楚。理解了原理之后遇到问题才知道该去哪一层排查。3.1 Whisper 的转录流程Whisper 模型的输入是音频输出是文本。它内部经历了几个阶段音频预处理把音频切成 30 秒一段并转换成梅尔频谱图Mel Spectrogram这是语音识别模型的标准输入。编码器Encoder处理把梅尔频谱图编码成一组特征向量。解码器Decoder生成文本基于特征向量逐 token 生成转录文本同时可以输出时间戳。使用 faster-whisper 时我们主要关心几个关键参数参数作用model_size模型大小如tiny、base、small、medium、large-v3device设备类型cuda或cpucompute_type计算精度GPU 推荐float16CPU 推荐int8language指定语言如zh、en不指定则自动检测beam_size束搜索大小越大识别越稳定但速度变慢一个最简单的转录代码只需求十几行# 文件路径transcribe.py from faster_whisper import WhisperModel # 加载模型这里以 small 为例 model WhisperModel( small, devicecuda, # 没有 GPU 改成 cpu compute_typefloat16 # CPU 改成 int8 ) segments, info model.transcribe( meeting.mp3, languagezh, beam_size5 ) for segment in segments: print(f[{segment.start:.2f}s - {segment.end:.2f}s] {segment.text})这段代码的作用是加载 Whisper small 模型读取meeting.mp3按中文识别并逐段打印带时间戳的转录文本。实际运行后你会发现Whisper 输出的文本中口语词基本全部保留比如“然后呢”、“就是”、“就是说”等等。这就是为什么需要 LLM 清理。3.2 LLM 清理的核心提示词设计LLM 清理并不是简单地让大模型“帮我校对一下”而是要通过提示词明确指定处理规则。如果提示词写得模糊LLM 可能给你改写出一篇“思想正确但已经不是原话”的文字完全失去转写稿作为原始记录的价值。一个比较有效的清理提示词应该包含下面几点角色定位告诉 LLM 它是什么任务的角色输入类型说明输入是语音识别软件的原始输出存在口语词和标点混乱处理规则明确可以删除什么、保留什么、修正什么输出格式指定输出为 Markdown 或纯文本禁止事项强调不要补充原文不存在的信息不要改写成书面作文。下面是一段可以直接用于 Ollama 调用的提示词示例你是一个专业的语音转写稿清理助手。 请对用户输入的语音识别原始文本进行清理要求如下 1. 删除“嗯”、“啊”、“然后”、“就是说”、“那个”等口语填充词 2. 修正明显错误的标点符号和断句 3. 保留原文的语义和信息禁止添加原文中不存在的内容 4. 保留专有名词、数字、英文缩写不做修改 5. 如果一段话太口语化可以改写为更书面化的表达但不要改变原本的意思 6. 最终输出为 Markdown 格式使用短段落和必要的列表。 禁止输出任何额外解释直接输出清理后的文本。这个提示词的关键在于“保留原文语义”和“禁止添加额外内容”否则 LLM 很容易自由发挥。实际项目里你可以把这段提示词写入一个单独的文件方便反复调用。3.3 选择合适的本地 LLM本地 LLM 的模型选择会直接影响清理效果。如果电脑有 8GB 以上显存推荐qwen2.5:7b或llama3.1:8b如果只有 16GB 内存但无独显可以尝试qwen2.5:3b速度会慢一点但清理口语词这类轻量任务完全够用如果显存达到 24GB可以上更大的模型效果更稳定。对于清理任务不需要代码生成能力也不需要数学推理能力所以不需要刻意追求超大模型。恰恰相反小模型速度快、占用低更适合做文本清理这种“轻量重活”。3.4 完整的数据流拆解把 Whisper 和 LLM 串联起来之后整体数据流可以这样理解audio.mp3 ↓ faster-whisper 转录 raw_text.txt口语词多标点乱无格式 ↓ Ollama qwen2.5 清理按提示词规则 clean_note.md干净、有标点、Markdown 格式如果其中任何一步出了问题定位方向很明确转录错是 Whisper 的问题清理错是 LLM 提示词或模型的问题。4. 完整实战搭建本地录音听写与清理流程接下来从头搭建一个最小可运行的 Dictata 式工作流。整个项目只需要两个 Python 文件和一个音频文件就能跑通。4.1 创建项目结构dictata-demo/ ├── venv/ # Python 虚拟环境 ├── audio/ │ └── meeting.mp3 # 待转录音频 ├── transcribe.py # Whisper 转录脚本 ├── cleanup.py # LLM 清理脚本 ├── prompt.txt # 清理提示词 └── requirements.txt # 依赖清单requirements.txt内容如下faster-whisper requests在虚拟环境中安装依赖pip install -r requirements.txt4.2 编写 Whisper 转录脚本# 文件路径transcribe.py from faster_whisper import WhisperModel def transcribe(audio_path: str, output_path: str) - None: 使用 faster-whisper 将音频转写为文本并保存。 # 初始化模型device 可按实际环境调整为 cpu model WhisperModel( medium, devicecuda, compute_typefloat16 ) # 转录音频 segments, info model.transcribe( audio_path, languagezh, beam_size5, vad_filterTrue # 打开 VAD 过滤跳过静音段 ) # 拼接转录结果 lines [] for segment in segments: text segment.text.strip() if text: lines.append(f[{segment.start:.2f}s] {text}) # 保存到文件 with open(output_path, w, encodingutf-8) as f: f.write(\n.join(lines)) print(f转录完成共 {len(lines)} 段结果已保存至 {output_path}) if __name__ __main__: transcribe(audio/meeting.mp3, output/raw_text.txt)这里需要注意几个细节vad_filterTrue会过滤掉音频中的静音段减少无效输出languagezh明确指定语言为中文避免模型花时间在语种检测上输出格式带时间戳后续如果需要回放定位内容会非常方便。在运行之前需要先创建输出目录mkdir -p output然后运行python transcribe.py如果一切正常你会在output/raw_text.txt中看到类似下面的结果[0.00s] 好那我们现在开始讨论一下方案 [5.20s] 然后就是说这个项目的话目前主要有两个模块 [15.80s] 一个是数据接入一个是数据清洗4.3 编写 LLM 清理脚本清理脚本通过 HTTP 请求调用本地 Ollama 服务把原始转录文本和提示词一起发送给模型最终获得清理后的 Markdown 文本。# 文件路径cleanup.py import requests import json OLLAMA_URL http://localhost:11434/api/generate MODEL_NAME qwen2.5:7b def load_prompt(path: str) - str: 读取提示词文件 with open(path, r, encodingutf-8) as f: return f.read().strip() def cleanup_text(raw_text: str, prompt: str) - str: 调用 Ollama 本地模型进行文本清理。 payload { model: MODEL_NAME, prompt: f{prompt}\n\n{raw_text}, stream: False, # 非流式输出直接拿到最终结果 temperature: 0.2 # 降低温度减少自由发挥 } response requests.post( OLLAMA_URL, jsonpayload, timeout600 ) response.raise_for_status() data response.json() return data.get(response, ).strip() def main(): prompt load_prompt(prompt.txt) with open(output/raw_text.txt, r, encodingutf-8) as f: raw_text f.read() cleaned cleanup_text(raw_text, prompt) with open(output/clean_note.md, w, encodingutf-8) as f: f.write(cleaned) print(清理完成结果已保存至 output/clean_note.md) print(---预览---) print(cleaned) if __name__ __main__: main()这段代码里有一个容易被忽略的点temperature参数。温度越高模型输出越有创造力但同时越容易出现“改写过头”的风险。对于口语清理这类任务建议把温度控制在0.2到0.3之间保证模型输出稳定、忠于原文。4.4 创建提示词文件# 文件路径prompt.txt 你是一个专业的语音转写稿清理助手。 请对用户输入的语音识别原始文本进行清理要求如下 1. 删除“嗯”、“啊”、“然后”、“就是说”、“那个”等口语填充词 2. 修正明显错误的标点符号和断句 3. 保留原文的语义和信息禁止添加原文中不存在的内容 4. 保留专有名词、数字、英文缩写不做修改 5. 如果一段话太口语化可以改写为更书面化的表达但不要改变原本的意思 6. 最终输出为 Markdown 格式使用短段落和必要的列表。 禁止输出任何额外解释直接输出清理后的文本。4.5 运行并验证依次执行python transcribe.py python cleanup.py清理后的clean_note.md大致会是这样好我们现在开始讨论一下方案。 目前这个项目主要有两个模块 - 数据接入 - 数据清洗对比原始的raw_text.txt你会明显发现口语填充词被删除了句子被正确断句并加上标点内容被整理成带列表结构的 Markdown 格式原文语义没有缺失。这就是 Whisper LLM cleanup 这套组合的核心价值。4.6 批量处理多个音频文件如果你有多个音频文件可以写一个批处理脚本依次执行转录和清理# 文件路径batch_process.py import os from transcribe import transcribe from cleanup import cleanup_text, load_prompt DATA_DIR audio OUTPUT_DIR output PROMPT load_prompt(prompt.txt) for filename in os.listdir(DATA_DIR): if not filename.endswith((.mp3, .wav, .m4a)): continue base_name os.path.splitext(filename)[0] audio_path os.path.join(DATA_DIR, filename) raw_path os.path.join(OUTPUT_DIR, f{base_name}_raw.txt) clean_path os.path.join(OUTPUT_DIR, f{base_name}_clean.md) print(f正在处理: {filename}) transcribe(audio_path, raw_path) with open(raw_path, r, encodingutf-8) as f: raw_text f.read() cleaned cleanup_text(raw_text, PROMPT) with open(clean_path, w, encodingutf-8) as f: f.write(cleaned) print(全部处理完成)这个脚本会自动扫描audio目录下的所有音频并生成对应的原始转录稿和清理后文稿。5. 常见问题与排查思路实际操作中最容易踩坑的地方集中在环境依赖、模型加载、Ollama 调用和清理效果这四类。我整理了高频问题供你对照排查。问题现象常见原因解决思路转录时提示CUDA error: out of memoryGPU 显存不足改用small模型或int8精度降低beam_size换 CPU 运行转录速度非常慢使用 CPU 推理且模型偏大改用tiny或base模型开启compute_typeint8使用 VAD 过滤静音Ollama 请求超时模型首次加载慢系统内存不足等待模型预加载完成使用更小的模型调大timeout参数清理结果严重偏离原文提示词没有强调“保留原文语义”在提示词中加入“禁止添加原文中不存在的内容”中文标点恢复效果差模型中文能力弱或模型过小换用 qwen 系列模型增大模型尺寸音频文件无法解码FFmpeg 未安装或版本过旧重新安装 FFmpeg 并验证版本huggingface_hub下载模型超时网络问题手动下载模型到缓存目录或使用代理仅限合规场景5.1 转录结果全是英文或中英混杂这种情况基本是language参数没生效。faster-whisper 会自动检测语言但检测结果有时不准。解决方案是强制指定语言segments, info model.transcribe( audio_path, languagezh, tasktranscribe # 明确是转写任务不是翻译任务 )注意tasktranslate会把中文翻译成英文如果只需要转写务必设置成transcribe。5.2 LLM 清理时额外补充了原文没有的信息这是最让人头疼的问题。大模型有“补全”的倾向当提示词不够严格时它可能自作主张地加入一些常识或解释。我的做法是在提示词里加一行 “如果原文信息不完整请保留不完整状态不要补充缺失内容”。降低温度比如temperature0.1。对输出结果做人工抽查重点关注专有名词、数字和时间。5.3 本地模型在处理长文本时速度明显下降当转录文本超过几千字时Ollama 的推理速度会明显变慢甚至可能超出 API 超时时间。解决方案有两个按段落批次清理而不是一次性把整篇文本都塞进去先按时间戳切分文本每 500 字左右清理一次最后拼接结果。5.4 faster-whisper 下载模型时被卡住faster-whisper 模型默认从 Hugging Face 下载部分地区网络连接不稳定。你可以在环境变量中指定镜像export HF_ENDPOINThttps://hf-mirror.com然后再重新运行转录脚本。6. 最佳实践与工程建议一个能跑的 Demo 和一套能长期使用的本地听写工作流之间还有不少工程层面的差距。下面是我实践下来觉得比较重要的几点。6.1 模型选择要按机器配置“分层”如果你的电脑只有 CPU建议用small或base模型LLM 选择qwen2.5:3b这样能保证基本可用如果有一张 6GB 以上显存的显卡转录模型可以用mediumLLM 上qwen2.5:7b显存超过 12GBlarge-v3转录 qwen2.5:14b清理的效果会比较理想。有一点需要提醒模型并不是越大越好。在录音环境比较嘈杂的时候large-v3的识别质量提升明显在录音质量已经很高的情况下small和medium的差别没有想象中那么大但速度差距却是成倍的。6.2 用 VAD 过滤静音段减少无效转写在实际录音里每个人说话之间都有停顿。faster-whisper 默认支持 VAD语音活动检测推荐开启segments, info model.transcribe( audio_path, languagezh, vad_filterTrue, vad_parameters{min_silence_duration_ms: 500} )这样做的好处是减少静音段被强制转录成无意义文字的概率同时也能提升转录速度。6.3 把提示词视为代码来维护提示词是 LLM 清理效果的核心但它很容易随着调试而变得混乱。建议把提示词单独抽成文件纳入 Git 版本管理每次改动都记录一下“为什么改”。例如V1基础清理去掉口语词V2增加“禁止补充缺失信息”约束V3增加 Markdown 列表输出要求。长期来看这比在 Python 代码里硬编码提示词更容易维护。6.4 保留原始转录稿LLM 清理过程存在“改写过度”的风险所以不要让清理后的文本覆盖原始转录稿。建议把两个文件都保存下来方便后续核对。推荐的目录结构output/ ├── 2025-01-15_meeting_raw.txt ├── 2025-01-15_meeting_clean.md ├── 2025-01-16_interview_raw.txt └── 2025-01-16_interview_clean.md6.5 监控 Ollama 服务状态如果清理脚本长时间没有响应首先检查 Ollama 进程是否还活着ps aux | grep ollama curl http://localhost:11434/api/tags如果 Ollama 服务正常但响应慢看下系统内存和显存占用。Ollama 在加载大型模型时内存占用可能飙升如果系统内存吃紧换用更小的模型是性价比最高的选择。6.6 考虑多级处理的扩展方案当你有大量录音文件需要处理时可以进一步升级这套架构队列化把音频文件放入消息队列使用多个 worker 并行转录增量处理记录断点录音文件新增时只处理增量部分关键词标签转录后用 LLM 提取关键词和待办事项直接生成结构化文档全文检索把清理后的 Markdown 存入本地知识库配合向量检索做语义搜索。6.7 安全与隐私边界虽然这套方案整体本地化但仍要注意确保output目录权限正确转录稿和清理稿可能包含敏感信息Ollama 默认监听本机端口不要直接暴露到公网如果部署在多人共享的开发机上建议为 Ollama 增加访问控制涉及合规审计的项目不要仅依赖 LLM 清理结果原始录音文件也要按规定留存。7. 实战经验小结Whisper LLM cleanup 的“转录 清理”工作流并不复杂但使用体验和工具安装的完成度关系密切。在实践过程中我有几个比较深的感受不要在一开始就追求最完美的模型和最好的清理效果先跑通最小闭环再逐步优化模型和提示词这是最稳妥的路径。Whisper 转录的质量决定了 LLM 清理的上限。如果 Whisper 把关键人名和数字识别错了LLM 很难从上下文里“猜”出正确内容。把提示词当成策略文件来维护比反复在代码里改字符串要靠谱得多。如果你也经常需要处理大量录音建议按本文的流程亲手搭建一遍把transcribe.py、cleanup.py和prompt.txt调整为适合自己场景的版本。下一步你可以试着把这套工作流接入 Obsidian 或任意 Markdown 笔记工具这样录音结束后本机会自动生成一份格式干净的听写稿省去从录音到成稿之间的大量手动整理时间。
返回列表