[!TIP] 受众:经常和 AI 对话、觉得打字慢,又不想把录音传上云端的 Windows 用户与独立开发者。 核心目标:交代清楚本地语音输入工具的选型依据、真实延迟数据,以及从录音到上屏一路踩过的工程坑。 问题-方案映射:

  • 显卡被游戏占满,跑不动大模型 → 选 SenseVoice(sherpa-onnx)纯 CPU 推理,5.6 秒音频耗时 0.29 秒
  • 模拟按键打不出中文,直接覆盖剪贴板又会弄丢截图 → 走剪贴板粘贴,备份改成按格式整份存、整份还原
  • 模型加载硬崩、延迟账算错、打包误删自己数据 → 逐项实测排查,把靠记性的流程写进代码自动化

为什么要对着 AI 说话

平时我自己做点小工具自己用,AI 是主力帮手。现在每天大量时间是在 Claude Code 的输入框里跟 AI 交代需求。需求稍微复杂一点,前因后果加上约束条件,敲字就成了体力活。

所以我做了 VoiceInput。它的用法很简单:按住热键说话,松开后文字直接出现在当前光标处。识别全程在本机完成,音频不上传。目前只支持 Windows。

我做它主要是为了对着 AI 说话代替打字。文字进 Claude Code 的输入框和手打没区别,至于看到文字后该不该操作电脑,由 AI 自己判断,这个工具不掺和。因此我也完全不做“语音命令控制电脑”那套东西,语音只负责老老实实转成文字。

日常用起来就两组默认热键:

  • 按住 Ctrl+Alt+Space 说话:松开后直接把文字粘贴到光标处。
  • 按住 Ctrl+Alt+Enter 说话:松开粘贴文字后,再自动补一个回车,适合说完直接发出去。

两组都能在设置里改。如果被别的程序占了,自检会提示。

软件做成了纯绿色版:配置、历史、日志都在程序目录旁边,不写注册表。唯一的例外是开启“开机自启”时,会往系统的启动文件夹里放一个快捷方式。

选型:为什么是 SenseVoice

在自己动手之前,我也看过现成的开源语音输入软件,但用不上:它的本地引擎里没有 SenseVoice 选项,而它提供的另一个可选模型又不支持中文。

至于底层引擎为什么选 SenseVoice(基于 sherpa-onnx)而没用名气更大的 faster-whisper,结论全看实测数字。我这台机器的显卡日常被 4 个游戏多开实例占满,语音工具必须靠纯 CPU 跑,绝对不能去抢显卡资源。我拿同一句 5.6 秒的话在纯 CPU 下做了对比:

对比维度SenseVoice (sherpa-onnx)faster-whisper差距说明
5.6 秒音频推理耗时0.29 秒37.6 秒推理速度差 116 倍
RTF(实时率)0.0546.317越低越快,小于 1 才能算实时
硬件占用纯 CPU 足够纯 CPU 下几乎不可用不占被游戏塞满的显卡
识别精度与对策略逊,靠“词典”页术语替换兜底较高用词典解决日常专有名词

除了引擎,实现上还有两个关键决定:

  • 为什么走剪贴板而不模拟按键:我另一个项目已经证明,在 Windows 下逐字符模拟按键是打不出中文的。所以这回直接用剪贴板加模拟 Ctrl+V,粘贴完成后再恢复原来的剪贴板内容。
  • 模型版本必须死锁 2024-07-17 那一版:去下载模型时差点掉进大坑。同一个发布页上有一个更新的 2025-09-09 版,两个文件大小一模一样都是 226MB。但 2025-09-09 版其实是粤语特化微调,换上去之后中英日韩全线崩坏,必须认准 2024-07-17 版。

踩过的坑:没报错不等于验证过

这个项目一路做下来,踩坑记录已经攒到了 43 条。回头看这些记录,贯穿始终的一句话就是:没报错不等于验证过。这里挑 5 个最典型的跟大伙聊聊,基本都是我起初以为是 A,结果被实测打脸证明是 B。

1. 拿“推理耗时”当成了“用户感受到的延迟”

很长一段时间里,我所有文档写的延迟都是“0.29 秒”,觉得快得飞起。结果迭代了十几轮下来,端到端的时间我居然一次都没真正量过。

后来老老实实打点实测,从手指松开热键到文字真正出现在屏幕上,总耗时其实是 380 毫秒。把这 380 毫秒拆开看:

  • 模型推理:占 79%(也就是那 0.29 秒左右)。
  • 粘贴前等待:占 21%。
  • 文本后处理 + 剪贴板操作:加起来不到 1 毫秒。

虽然选型结论没变,但之前张口就来的“0.29 秒”实打实低估了约 30% 的真实延迟。把这段等待时间算进端到端里,它和 faster-whisper 的实际体验差距是 99 倍,而不是单看推理算出来的 116 倍。

2. “恢复剪贴板”只对纯文本成立

前面提到,上屏方案是“写入剪贴板 → 粘贴 → 恢复原剪贴板”。我最初以为只要把剪贴板里的东西读出来存着、用完塞回去就完事了,代码写完也没报错。

后来专门挑没验证过的假设去找茬,才发现这套逻辑只对纯文本成立(原来的备份只存了文本,测试也全是纯文本)。遇到其他格式时全是静默丢数据:

  • 原剪贴板里是截图:按住热键说一句话之后,图直接没了。这对跟 AI 聊天的场景简直要命——刚截了张报错图准备贴给 AI,张嘴补了一句描述,图没了。
  • 原剪贴板里是复制的文件:说句话之后,文件退化成了一串 file:/// 路径文本。
  • 原剪贴板里是富文本:粘贴恢复后,原有的富文本格式全部丢光。

后来改成按格式把剪贴板整份存下来、用完整份还原,图片单独走图片接口。修的过程中还发现,阻塞式的粘贴在真实 Windows 上还原不了富内容,换成异步才正常——单元测试的剪贴板不走系统那套机制,看不出这个差别。

3. 系统自带的旧 DLL 顶包导致硬退出

有一次准备加载模型,程序一跑到这里就在 C++ 层直接硬退出,连个遗言都没有,Python 层根本抓不到任何异常。

排查时我连错两次:

  1. 先以为是模型版本太新跟运行库不兼容,手工解析模型文件头一看,版本很老,否定。
  2. 又以为是环境里装的另一个依赖包起了冲突,把那个包删干净实测,照样错,再次否定。

最后才揪出来,是 Windows 的 System32 目录里自带了一个老版本的 onnxruntime.dll,程序启动时优先把它加载进来了。解法其实很简单:装上自带匹配 DLL 的那个包,让程序优先读自己目录里的动态库,问题当场消失。

4. 下拉框里一半的麦克风选项是坏的

在写音频设置页时,我把系统枚举出来的输入设备全塞进了下拉框。以为用户随便选哪个都能录,实测才发现里面有一半的选项点中根本打不开录音。

原因是枚举出来的列表里有一半属于 WASAPI 设备,而 WASAPI 共享模式非常死板,它只接受设备的原生采样率(在我这台机器上是 48000Hz)。但我程序里为了喂给模型,录音采样率直接写死了 16000Hz。参数对不上,一选中 WASAPI 设备录音就失败。

顺带一提,为了防止用户选错设备,我在麦克风标定向导里加了一步:必须真录一句话跑一遍识别,按字错误率给结论,绝不只看音量电平。因为系统默认的输入设备常常是“系统声音回环”,这时候电脑放歌它也有电平跳动,只看电平表根本分不出来。一旦选错,表现就是“按了热键没反应”,用户肯定会怪程序坏了。

5. 打包脚本把我的配置和历史全删了

最痛的一次发生在 2026-08-26。那天我重新打包软件,脚本执行到“清理旧产物”那一步时,顺手把我的 config.toml 和 history.db 一起删了,彻底不可恢复。

原因出在绿色软件的设计上:我平时自己用这个软件,我的个人数据文件和打包生成的产物刚好在同一个目录里。以前每次打包前,全靠我脑子里记着“先手工备份一下配置和历史”。事实证明,工程上凡是靠记性的步骤,就等于没有。

挨了这一下之后,我立刻改了打包流程:脚本自己负责备份、打完包自己还原,而且备份文件强制放在产物目录外面,再也不信自己的记性了。

(类似让人头疼的还有热键问题:最早的默认热键 Ctrl+Win 会被它的所有超集触发,比如用 Ctrl+Win+左右 切换 Windows 虚拟桌面,或者按别的软件的 Ctrl+Win+X,都会误触录音。我自己用着发现“和微信冲突”,查下来其实是这个组合键本身的问题。更糟的是,我早期写的一条测试居然把这个缺陷当成正确行为给钉住了,后来才把测试改成断言这种冲突必须被报告出来。现在的默认热键已经换成 Ctrl+Alt+Space。)

还没做的与局限

这工具目前能满足我每天跟 Claude Code 唠嗑的需求,但还有几件事没做完,得把丑话说在前头:

  • 引擎精度还没用真人语音定标:目前我对精度的判断,全部基于模型自带的测试音频和合成语音,真人实际录音的字错误率还没有系统测过。如果后续测下来真人语音错得太多,可能得回头考虑接云端接口,或者在本地加一层大模型纠错。
  • 静音幻觉靠前置拦截硬挡:实测发现,如果往模型里喂一段纯静音,它会发生幻觉,冷不丁吐出一个韩文字符之类的内容。现在的做法是在送去转写之前,先用静音检测把纯静音音频拦掉。
  • 平台限制:如前所述,从热键、剪贴板到音频接口都是围着 Windows 写的,只支持 Windows。

下载

便携版在 软件下载 页(约 207MB,已经带了模型,解压就能用,不用再联网下载),源码在 GitHub:https://github.com/yoyoset/voiceinput ,MIT 许可证。