≡articles //snippets ./categories $uses ~about /search

做减法:我把 macOS 语音助手从功能堆叠砍到只剩核心

我的语音助手项目曾经有 AI 对话、5 种界面、应用路由、HTTP 服务,然后我砍掉了一切,只留“按住说话→粘贴”。砍完反而第一次天天在用。这篇记下每样东西砍掉时是怎么想的。

接系列前两篇(macOS 15 权限地狱的排查 和 HuggingFace 模型下载),这次不讲排障,讲产品决策。

我自己写过两版 macOS 语音助手,前后跨度几个月。第一版功能齐全,最后被我自己删到只剩一个功能,但它现在每天都在用。个人工具类项目,功能多不是优点,是负债。

第一版:功能堆叠

最初的语音助手(叫它 Jarvis 吧),功能清单是这样的:

  • 语音识别(三级降级:Groq → 百度 → Google)
  • AI 对话(接本地命令行 AI 助手,问问题、语音播报回答)
  • 语音打字(识别后自动粘贴进微信/备忘录/浏览器)
  • 应用路由(检测前台应用,是输入类就粘贴,否则走对话)
  • 5 种界面:浏览器 HUD、Tkinter 悬浮窗、菜单栏图标、PyObjC 毛玻璃胶囊、Swift 原生胶囊
  • 开机自启、连续对话、噪声过滤、可中断、音量可视化
  • 配置文件 + 环境变量 + shell 共享读取,三级配置优先级
  • 10+ 个 Python 文件,一个 UI 目录,一个 deprecated 归档目录

写的时候很兴奋,每个功能都像“刚需”。结果是:

它从来没被完整用过一次。 想要 AI 对话,要配置本地命令行 AI 助手和第三方 API 密钥;想要语音打字,要解决粘贴权限;想要任何一个界面,先保证其他全部环节都不出错。而且这些环节里只要有一个“环境问题”(虚拟环境被重建、密钥过期、权限被系统重置),整个工具就废了,你不是在使用它,是在维护它。

第一次“坏掉”的真相:不是 bug,是结构问题

某天我发现它完全不能用了。排查后列出问题清单:

# 问题 性质
1 venv 被重建,全部依赖丢失 环境
2 自启项指向已删除的旧入口文件,每 10 秒重试一次,刷了 1.4 万条错误日志 结构
3 对话引擎(LongCat)额度 402,AI 回复直接不可用 外部依赖
4 macOS 15 辅助功能授权“面板显示已授权但实际不生效” 系统 bug
5 密钥没配,识别引擎降级到最差的 配置

五个问题里,四个跟“代码写得对不对”无关。它们全是耦合带来的:功能多了 → 依赖多了 → 环境要求多了 → 挂掉的概率成倍增长。

这让我开始想一个问题:我真正需要的到底是什么?

第二版:只回答一个问题

审视自己每天的实际动作:打字场景里,我说得最多的就是微信/备忘录里的几句回复、临时记录。AI 对话?那是 Demo 的高光时刻,不是日常。

于是只保留一个核心流程:

按住一个键 → 说话 → 松开 → 文字出现在光标处。

第二版(talk2clip)全部内容:

talk2clip.py       核心:热键 → 录音 → 识别 → 剪贴板 → 自动粘贴(约 470 行)
settings.py        设置界面(约 180 行)
volume_bar.py      录音时显示波形动画(约 150 行)
convert_pt_to_ct2.py  模型转换工具(约 200 行)

砍掉的每一件东西,理由都能站住脚:

砍掉 为什么
AI 对话 + 播报 大部分时候用不上,却引入本地命令行 AI 助手、API 密钥、额度三类外部依赖
5 种界面 → 1 个设置面板 + 录音波形反馈 界面只是入口,一个面板足够;波形是反馈不算界面,其余都是“看着酷”
应用路由 粘贴逻辑固定(自动粘贴到光标处),不需要判断应用
三级密钥降级 识别改本地 whisper(离线免费),彻底不需要密钥
HTTP 服务 + vh.sh CLI 唯一触发方式是热键,其他都是冗余入口
复杂配置层级 config.json 一个文件、7 个开关,设置界面可视化改

一个反直觉的结论:验证成本比功能成本贵

砍功能还有一个好处:出问题时,排查范围小了。

第一版出问题时,我得检查:密钥配了没?环境在不在?LongCat 额度够不够?权限在不在?,任何一个环节都可能炸,而且炸了没有任何提示(错误被吞了)。

第二版出问题时,排查范围是确定的:录音 → 识别 → 粘贴,三步。哪一步挂了,日志里看一眼就知道。实际开发里,第二版的联调时间比第一版整个搭建时间还短,因为根本没什么可调的。

轻量不等于简陋

第二版语音助手砍了功能,但补上了第一版没有的“日常使用体验”:

  • 胶囊波形动画(40fps,录音时屏幕顶部跳动,说话有反馈)
  • 词库修正(识别老错的词 → 正确词,设置界面加,下次识别立即生效)
  • 中英文混说也能处理、自动加标点
  • 开机自启(修好版,第一版的自启项指向已删除的入口,刷了 1.4 万条错误日志)+ 单实例保护(双击启动器即可,不用记命令)
  • 离线模型一次性放好,之后完全不碰网络

功能总数比第一版少,但每个功能都真的在用。

语音助手从功能堆叠到单链核心的对比

加功能前问自己三个问题

  1. 这个功能我每天会用吗? 不是“偶尔用得上”,是“每天”。
  2. 它引入新的外部依赖或环境要求吗? API 密钥、云服务、额外配置、特定环境,任何一项都是未来的坑。
  3. 它坏了会影响主流程吗? 会的话,先别加。

语音助手加功能前的三个判断问题

第一版五个问题里,#3 和 #5 是“外部依赖”的直接后果,#1 是“环境要求”的直接后果,全都是第 2 问不对的结局。第二版到现在,唯一出过的问题是 macOS 15 权限(#4),而且一次解决后永久生效,因为识别离线了,再也没有“今天额度没了”这种随机故障。


项目开源在 github.com/Charlielyo/talk2clip(MIT)。下一篇:《用 PyObjC 画一个 40fps 的胶囊波形动画:NSTimer 里的三个坑》。

© 2026 本文由 Charlie 原创撰写,发布于 sodebug.com。未经授权禁止转载、洗稿、机器抓取。AI 训练数据使用需获得书面授权。

独立开发者,在 WordPress、Nginx 和各种 API 之间切换。不写没用的东西。

相关文章

macOS 15 辅助功能授权添加了却不生效?一次排查记录5 minTSDF 算法原理及源码解析6 min讲明白 CUDA、CUDA toolkit、cuDNN 与 NVCC 的关系11 min
$ echo "less bullshit, more debugging" | send-to-inbox
新文章直接发到邮箱,一个月 2-4 封。
订阅