AI活用

自制完全在Mac内运行的语音输入工具:用Whisper large-v3和Qwen3-8B调校的试错过程

自制完全在Mac内运行的语音输入工具:用Whisper large-v3和Qwen3-8B调校的试错过程

早上好,我是まさきん。

我在自己的 Mac 上用着这样一个语音输入工具:只在按住右 Control 键的期间录音,松开后就转成文字并替我粘贴出来。语音转写和文字整理,都是在 Mac 内部运行的。

制作时犹豫过的地方、测出来的数字、没能成功的尝试,我在这里整理一下。改良和测量是在 AI(Claude Code)的协助下进行的。代码没有公开,所以请当作一份思路记录来读。

※本文内容以发布时为准。模型和库的规格请以官方信息为准。

POINT
  • 只在按住录音键期间录音,松开后转成文字并粘贴到光标位置
  • 语音转写用 Whisper large-v3,文字整理用 Qwen3-8B 的4bit版。两者都用 MLX 运行
  • 从 turbo 和 Qwen2.5-3B 换过来之后,每次发言只慢了0.3至0.8秒左右
  • 思考模式每次发言要花4至22秒,同音词的混淆也没怎么改对,所以放弃了
  • 粘贴目标对准按下录音键时位于最前面的应用

这是个什么样的工具

使用方法很简单。把光标放在文本框里,按住录音键说话。松开键之后稍等一下,文字就会被粘贴进去。

录音键默认是右 Control 键。工具常驻在菜单栏里,可以从菜单换成别的键。当前状态能从图标的显示看出来。

只有 Apple Silicon 的 Mac 才能运行。因为语音转写和文字整理都是用 MLX 来跑的。MLX 是面向 Apple silicon 的机器学习框架,官方 README 里有这样的说明。

使用的组件如下。

作用使用的组件补充
语音转写mlx-whisper模型是 whisper-large-v3-mlx
文字整理mlx-lm模型是 Qwen3-8B 的4bit版
录音sounddevice以16kHz单声道录制
录音键的检测pynput右 Control 等
菜单栏rumps用图标显示状态
运行环境uvPython 3.11至3.12

mlx-whisper 是用 MLX 运行 Whisper 的组件。据官方说明,Whisper 是 OpenAI 的开源语音识别模型,大小从约3,900万到约15亿参数不等。

处理流程

从松开键到文字被粘贴出来,会按下面的顺序处理。

  1. 只在按住录音键期间录音。松开之后还会继续录0.3秒
  2. 丢弃无声的录音,以及短于0.4秒的录音
  3. 用 Whisper 转写。同时传入术语提示
  4. 用替换规则修正写法
  5. 丢弃同一个词反复出现的结果,以及置信度低的结果
  6. 用 Qwen3 去掉口头填充词(“嗯”“那个”之类),再补上标点
  7. 再套用一次替换规则
  8. 通过剪贴板粘贴。剪贴板里原有的内容会恢复回去

中途设了比较多的丢弃环节,是这套做法的特点。Whisper 有时会从无声里凭空编出句子。所以,声音太小的录音根本不会交给语音转写。

整理之后也有一道保险。如果整理的结果和原来的句子相差太大,就改为粘贴整理前的句子。因为用提问的口吻说话时,LLM 有时会直接把回答写出来。

运行所需的条件

条件如下。我手头确认过能运行的,只有一台 MacBook Pro。

项目条件
芯片Apple Silicon(M1 及以后)
系统macOS 14 及以后。我手头确认过的只有 macOS 26
内存常驻时约8GB,峰值约10GB。建议24GB 以上
磁盘模型约7.2GB,Python 环境约1.2GB
网络只有首次获取模型时需要。装好之后,没有网络也能启动
键盘要有能当录音键的键。默认是右 Control
麦克风内置、外接、蓝牙的都可以

内存是实测的数值。16GB 的 Mac 再加上其他应用,可能会不够宽裕。

内存不足时,换成 turbo 和 Qwen2.5-3B 就能降下来。只算模型的话,估计约3GB。代价是精度会下降。

MacBook 的内置键盘上没有右 Control 键。要么用外接键盘,要么在菜单里换成别的键。因为只在按住的期间才用,我觉得单独按下也不会发生任何事的修饰键比较合适。

仅首次获取模型,就会产生约7GB 的流量。在家里的网络下,这个量不会让人在意。不过,如果在外面用手机热点开始,可能会担心流量。

无需签约也能获得100积分的资费模拟 为首次获取模型做好准备,顺便用乐天移动重新看看手机的网络线路

点击后会跳转到乐天登录页面,登录后即可看到活动内容。

变慢了多少:实测

模型变大,耗时自然会增加。到底慢了多少,我在自己的 Mac 上测了一下。机器是搭载 Apple M5 Pro、内存48GB 的 MacBook Pro。

环节更换前更换后耗时参考
语音转写whisper-large-v3-turbowhisper-large-v3从0.2至0.3秒增加到0.4至0.7秒
文字整理Qwen2.5-3BQwen3-8B从0.25秒左右增加到0.4至0.6秒

两者加起来,每次发言大约慢了0.3至0.8秒左右。如果是短句,我觉得这个差别并不会让人在意。

我也测了长一点的发言。说了25秒时,语音转写和文字整理各用了1.9秒。合计约3.9秒。耗时会随长度增加,但还没到让人等不及的程度。

不过,这张表只是用简短的合成语音测的。次数也少,请当作参考来看。

在实际使用应用的时候,也有发言花了3.6秒或5.3秒。光凭发言的长度解释不了,原因我还没有查。

语音转写:从 turbo 换成 large-v3

turbo 是把 large-v3 的解码器层数从32层减到4层的模型。官方模型卡里写着,它快了很多,代价是质量略有下降。

一开始我为了速度用的是 turbo。可是用合成语音一试,片假名写的产品名被它误认成了读音相同的普通词。换成 large-v3 后,输出的写法接近原来的拼写。

话虽如此,这次确认只用了3段简短的合成语音。换成真人的声音是否还有差别,我还没能确认清楚。耗时会略有增加,但我还是倾向于减少误认这一边。

关于模型大小和数字听错的问题,我在Whisper会把金额数字弄错里也写过。

文字整理:从 Qwen2.5-3B 换成 Qwen3-8B

整理的职责,只是去掉填充词、整理标点。不会增加内容,也不做概括。提示词里也是这么写的。

可是,3B 的模型在面对混乱的输入时会往里添词。在实际使用中出现过的一个混乱句子里,它加上了「のです」(no desu,表示解释语气的句尾)和「にゃあい」(nyaai,模仿猫叫“喵”的拟声词)。连「お日に」(o-hi-ni,一个语义不完整的片段)也被连语序一起改写成了「毎日」(mainichi,每天)。

换成 8B 之后,它基本上会把输入原样返回。填充词方面,3B 留下了「あのー」(anō,“那个……”)和「えーと」(ēto,“嗯……”)。8B 则连「あのー」「えっと」(etto,同样是“嗯……”)「ですね」(desu ne,句尾的语气词,相当于“是吧”)「まあ」(mā,“嘛”)都去掉了。

Qwen3 默认会输出思考过程。整理用不着这个,所以我用 enable_thinking=False 把它关掉了。模型卡里说明,这个参数是严格停止思考行为的开关。

prompt = tokenizer.apply_chat_template(
    messages, add_generation_prompt=True, tokenize=False,
    enable_thinking=False,
)

输出的长度也设了上限:最多为输入字数2倍的 token 数。这样即使整理环节失控,也不会无休止地写下去。

思考模式和更大的模型都放弃了

要纠正误转写,或许可以让模型多想一想。Qwen3 有思考模式,所以我试了试能不能用在文字整理上。

最开始,我试了 8B 的思考模式。每次发言,耗时增加了6至20秒。

接着,我还试了大小约16GB 的30B 思考专用模型。它是7至30秒。遇到长句时,用了2,500个 token 也没想完,还一直在用英语思考。

模型卡里给出了思考模式的推荐设置:Temperature 为0.6、TopP 为0.95、TopK 为20。还写着要避免贪婪生成。

为慎重起见,我按这个设置重新测了一遍。每个句子各试2次,结果如下表。

输入的句子(含缩短处理过的)想改正的地方结果耗时(2次)
今週の試作について共有します把「試作」(shisaku,试制)改成「施策」(shisaku,措施)2次都没改对9.2秒、12.1秒
前年同月費と比較します把「費」(hi,费用)改成「比」(hi,比率),即「前年同月比」(与去年同月相比)2次都没改对。1次删掉了字词,1次添加了多余的话20.9秒、22.1秒
原因を分析して、改善作を検討します把「作」(saku)改成「策」(saku),即「改善策」(改善对策)2次都改对了8.1秒、8.6秒
新商品の試作品が届いたので、来週の会議で確認します不用改(正确的句子)2次都原样保留5.8秒、4.0秒

在想改正的3个句子里,干净地改对的只有1句。耗时为4至22秒。在另一个句子里,它还把输入里原有的一个助词去掉了。

注意

思考模式不但要等很久,也不一定能改对。即使等上几秒到20秒,同音词的混淆仍可能留下来。

测试的数量很少,请只当作一种倾向来看。话虽如此,对于简短的语音输入来说,要等几秒到20秒,我判断不划算。也可以考虑只在长发言时才启用的可选模式。不过,从这次的结果看,效果与耗时并不相称。

我还试过在整理用的提示词里补充术语和指示。改对的只有写进术语里的那个词。遇到长句时,还出现过被改成别的词的情况。

同音词的混淆,上下文似乎有效

用着用着,「施策」(措施)有时会被转写成「試作」(试制)。它们是同音词,光靠声音是分不出来的。但如果知道前后在聊什么,应该就能分清。

于是我试了把上一句发言追加到 Whisper 的提示里。在3段合成语音中,「施策」被写成「試作」的那个例子被改对了。耗时从0.39秒变为0.43秒,几乎没有变化。

另外2段,加不加都能正确转写。也就是说,确认到的只有1个例子。

这个方法我还没有采用。想先用真人的声音确认之后再定。追加上一句发言,也会关系到丢弃“提示原样照抄”的判断。这一点也打算一并重新考虑。

术语文件和替换规则

专有名词和专业术语,光凭声音有时会写成别的拼写。所以我准备了术语文件。写法有2种。

# 每行一个词: 作为语音转写的提示传入
Whisper
Qwen
# 左 => 右: 转写之后进行替换
ビッグクエリ => BigQuery

传给提示的词最多30个。上面的例子只是为了展示写法,和实际的内容不同。最后一行,是把片假名写的「ビッグクエリ」(biggu kueri,BigQuery 的日语读法)替换成 BigQuery。

设置替换规则时我注意的是,不要替换普通的词。为别的用途做的误转写词典里,有把普通词换成另一个词的条目。挪用到口述上,就连普通的句子也会被改坏。所以我没有挪用,而是另外为口述准备了一份。

让粘贴目标对准应用

在说完话之前,有时会切换到别的应用。这时如果直接粘贴,文字就会进到切换后的应用里。它未必是按下录音键时想输入的那个应用。

于是,我让工具记住按下录音键时位于最前面的应用。到粘贴的时候,如果最前面是别的应用,就先把记住的那个应用调到最前面,再粘贴。

最前面的应用用 lsappinfo 来查。调到最前面时,把 Bundle ID 交给 open -b。到变成最前面为止,大约0.3秒。

lsappinfo info -only bundleid "$(lsappinfo front)"
open -b com.apple.TextEdit

这里我踩了一个坑。一开始我用 NSWorkspace 的 frontmostApplication 来查最前面的应用。可是在没有运行事件循环的进程里,它会一直返回旧值。明明已经调到最前面了,却被判断成没有调到。

所以我换成了始终返回最新状态的 lsappinfo。

还有一点,正在打字的时候不会切换。打字途中如果最前面的应用变了,正在打的字就会进到别的应用里。所以会等输入停顿约0.6秒。最多等2秒,超过就切换。

应用已经退出、或者没能调到最前面时,不会粘贴。只是把文字放进剪贴板并通知一声。

这里也有限制。

遇到的坑

不把 AirPods 戴进耳朵就是无声

一开始,出现过看上去录上了音、文字却进不来的状态。原因是 macOS 的默认输入设备是 AirPods。当时没有戴在耳朵里,所以声音完全没传过来,音量一直是0。

对策有两个。第一个,让菜单里可以固定输入麦克风。第二个,在每次录音之前重新生成设备列表。

负责处理声音的组件 PortAudio,会一直保留启动时的设备列表。这样下去,就跟不上接上 AirPods 之后默认输入的变化。重新生成的耗时是几毫秒。

丢弃提示原样照抄的判断过于严格

把原样输出提示文本的结果,我会直接丢弃而不粘贴。因为传入提示之后,在安静的部分有时会输出提示本身。在之前的文章里,faster-whisper 在安静的片段中也出现过重复提示的情况。

可是,最初的判断过于严格了。连只说了提示里的短词的正确发言,也被丢掉了。例如只说了「日本語の音声」(“日语的语音”)的时候。

于是我给匹配的长度设了下限。提示的基本句子在10个字符以上,带术语的整段提示在24个字符以上时,才会丢弃。

测试时覆盖了自己的剪贴板

粘贴的测试会碰到真实机器的剪贴板。当时漏掉了对写入剪贴板的函数的替换。结果测试用的句子覆盖了我自己的剪贴板。原来的内容没能恢复。

测试会触碰真实机器的处理时,要把可能被调用的函数全部替换掉。还要确认测试前后剪贴板里的内容没有变化。这就是这件事留下的教训。

其他限制

适合的人·不适合的人

方面适合的人不适合的人
Mac使用 Apple Silicon,内存比较宽裕使用 Intel 的 Mac,或内存较少
用法经常输入较短的文字要写一字一句都必须准确的文档
环境首次能获取约7GB 的数据一直在节省流量
态度不介意自己修改设置文件想要装好就能用的应用

误转写不会变成零。所以我认为,这是一个粘贴出来的文字需要先用眼睛确认一遍的工具。

开始之前要确认的事

为想在 Mac 上尝试类似工具的朋友,整理了一下条件。

我觉得尤其重要的是内存和麦克风这两项。因为这两项要是运行之后才发现,返工的代价会很大。

CHECK
  • 优先精度时:语音转写用 large-v3,文字整理用 Qwen3-8B。每次发言会多等0.3至0.8秒左右
  • 想节省内存时:用 turbo 和 Qwen2.5-3B。代价是精度下降
  • 不需要整理时:在菜单里关掉。转写结果只套用替换规则就会被粘贴

常见问题

Q. Intel 的 Mac 也能运行吗?

我想是不能的。MLX 在官方 README 里被说明为面向 Apple silicon。我试过的也只有 Apple Silicon 的 Mac。

Q. 内存只有16GB 的 Mac 也能用吗?

常驻时用了约8GB,峰值约10GB。再加上其他应用,可能会不够宽裕。换成较轻的模型组合,内存会减少。代价是精度会下降。

Q. 没有网络也能用吗?

装好之后可以用。模型设置成只使用已获取的,我也确认过在无法联网的状态下能够启动。需要网络的只有首次获取模型。

Q. 录音键可以更换吗?

可以从菜单里的“录音键”更换。可选的有 Control、Option、Command、Shift 的左右两侧,以及 F1 至 F20。会输出字符的键、Enter 和 Space 不能用。右 Control、右 Option 和 F13 及以后的键,我想不容易和平时的快捷键冲突。

Q. 可以关掉整理吗?

可以。在菜单的“整理”开关里可以打开或关闭。关掉之后,不经过整理,只套用替换规则就粘贴出来。重启之后会恢复为打开。

Q. 说长一点的话,要等多久?

说25秒的话,约3.9秒。说10秒左右的话,2秒上下。耗时会随长度增加,所以说得越长,等待就越久。

Q. 切换到别的应用,也能正确粘贴吗?

会粘贴到按下录音键时所在的应用。如果已经切换走了,就先把那个应用调到最前面再粘贴。不过,能区分的只是应用这个层级。即使在同一个应用里切换标签页,也区分不出来。

参考的官方信息

总结

用 Whisper 转写,再用 Qwen3 整理。流程很简单。不过,模型的选择和粘贴目标的对准方式,让使用的手感发生了很大变化。

归根结底,起作用的是一些不起眼的功夫。比如,换成大一些的模型。让句尾不被截断的0.3秒,以及粘贴到按下键时所在的应用,也都有效。而思考模式这类花哨的方法,耗时和效果并不相称。

还有没试过的东西。比如把上一句发言加进上下文的方法,以及把语音转写和文字整理的耗时分开记录。想尝试语音输入的朋友,不妨先只运行 mlx-whisper 试试。

关于把自己的工作交给 AI 的话题,我在自动生成早间简报的文章里也写过。获取模型要用到流量,所以线路宽裕的话会更容易开始。

无需签约也能获得100积分的资费模拟 为了获取和更新模型,顺便用乐天移动比一比每月的网络线路

点击后会跳转到乐天登录页面,登录后即可看到活动内容。

本文包含联盟营销广告。如果您通过本站链接申请相关商品或服务,我们可能会从合作企业获得报酬。此外,运营者是乐天集团的员工,也可能通过员工推荐计划获得报酬。文章内容与评价均基于运营者的真实体验与调查完成,与是否存在广告无关,但请您在阅读前了解上述关系。详情请参阅免责声明与联盟营销说明。 免责声明与联盟营销说明

本文包含机器翻译内容。正式条件请以乐天移动官方网站的多语言页面为准。

如果您对乐天移动的通信区域·信号状况有疑问,可以通过官方的 电波改善调查申请表 进行咨询。

ABOUT THE AUTHOR
まさきん

乐天集团员工·数字营销人(持有FP资格)

40岁出头,双职工家庭、四个孩子的父亲。在乐天集团担任数字营销工作的同时,也活用理财规划师(FP)资格,专注于家庭理财与资产配置。

查看简介

相关文章

RELATED
Gemini(Google AI Pro)家庭共享最多5名家人|设置步骤与共享范围 AI活用

Gemini(Google AI Pro)家庭共享最多5名家人|设置步骤与共享范围

Google AI Pro除管理员外最多可与5名家人共享。Gemini App和存储空间可以共享,YouTube Premium Lite仅限管理员,Flow的上限由全家分摊。本文根据官方帮助整理了设置步骤和儿童账号的处理方式。

2026.10.13 · 阅读约9分钟
AI订阅扣款日与记账对不上的3个原因|Claude升级后扣款日会改变 AI活用

AI订阅扣款日与记账对不上的3个原因|Claude升级后扣款日会改变

Claude在月中升级到Max时,计费周期会重置,当天成为新的扣款日。美元换算日元的汇率在数据到达发卡公司时确定,账单和记账App的同步也会晚几天。本文整理了以收据邮件为准来确定月份的5个步骤。

2026.10.13 · 阅读约10分钟
把freee会计的未处理明细改成每月一次的核销班次:每月5日7:30、分3类、最多15条交给人处理的设计 AI活用

把freee会计的未处理明细改成每月一次的核销班次:每月5日7:30、分3类、最多15条交给人处理的设计

freee会计里有大约18条未处理明细,连续6次每周检查都原封不动地留着。这里整理一下每月5日早上7:30在家里的Mac上运行的核销班次的设计,以及“能确定的部分每月合并成1个任务、拿不准的明细逐条交给人、上限15条”的界线。

2026.10.12 · 阅读约11分钟
转到乐天移动,最高可获14,000积分 无需签约也能获得100积分的资费模拟 →
立即申请 →