打字指挥 AI 已经很好用了,但总有腾不出手的时候。于是我给 DSH 装上「耳朵」和「嘴」:说一句「你好小智」,AI 就开始听;听完指令,把结果用语音播报给你。整套识别和合成全部跑在本地,免费、离线、不依赖任何云端语音服务。

方案选型:能本地就本地

环节选择为什么
语音识别sherpa-onnx(本地流式)免费、离线、流式,唤醒即说,不用等整段录完
语音合成vits-zh-ll(本地)免费、中文效果好,进程内单例加载后秒出
备用识别豆包 STT(云端)本地识别不稳时的兜底
播放MCI 播放器脚本比 ffplay 启动快、更稳定

整体架构

语音助手拆成两个部分协作:一个常驻的识别守护进程,和一个负责「听懂后干活」的注入插件。

麦克风 ──► sherpa 流式识别(守护进程)
              │  识别出文本
              ▼
         commands.txt ──► voice-core 插件轮询
              │  发现新指令
              ▼
         创建独立新会话执行指令
              │  拿到回复
              ▼
         vits 合成 + 播放语音播报

三个关键设计

1. 唤醒词容错

「你好小智」四个字,识别引擎经常听成「你好小志」「你好小只」。我没有死磕识别精度,而是做了谐音容错:智/志/只/之/知 全部算数。这套思路后来被我用在很多地方——不要追求完美,容错才是工程。

2. 防自播自识别回声

AI 播报时,自己的喇叭声音会被麦克风再录进去,触发「自问自答」的幽灵循环。解法:播放提示音时进入 muteUntil 静默期,期间跳过识别帧;播放完成后再加一小段缓冲才重新开放。就这么一个细节,治好了整个系统的精神分裂。

3. 每条指令开独立新会话

语音指令不污染主对话,而是创建独立的语音会话去执行,执行完播报结果。这样语音操作再多,主聊天区永远干净清爽。

踩过的坑(血泪精选)

坑 1vbs 脚本「编译错误」起不来

Windows 的 wscript 不支持 UTF-8 编码的 .vbs——带 BOM 直接弹编译错误,整行不执行。vbs 必须纯 ASCII,路径用环境变量展开。

✅ 教训:脚本能不用 vbs 就不用;用了就记得 ASCII + 环境变量。

坑 2两个守护进程抢麦克风

录音工具独占麦克风,起两个识别进程,后启动的那个直接崩溃。排查发现是开机自启 + 手动启动双份。

✅ 教训:任何常驻服务都要有「只允许一个实例」的约定,排查用进程命令行过滤确认数量。

坑 3语音朗读死活不触发

排查很久,发现是监听事件时机错了:任务结束时根本没有「用户消息」在尾部,永远匹配不上。改成按会话前缀 + 最后一条助手文本判断,立刻正常。

✅ 教训:不要假设事件流的形状,去打印真实事件再写逻辑。

发布成开源插件

这套东西我整理成了 dsh-voice-assistant 开源插件:一条 node install.cjs 命令,自动安装依赖、下载模型、注册服务、启动守护进程。发布前我专门写了个敏感扫描脚本,把硬编码的 API Key、个人路径全部脱敏——开源代码里绝不能有密钥,这是底线。

想看完整实现?去 GitHub 看 dsh-voice-assistant,或者读本博客的插件页。