HaoLiu's blog

折腾 Mac 语音输入:从本地 LM Studio 到 Groq 云方案

Published on
13 mins read

起因

voquill 是个开源语音输入助手(支持按住快捷键说话,松手文字自动填到光标处)。我一直用本地 Whisper + 本地 Gemma 4 e4b 做润色,问题是中文转录基本没标点——Whisper 对中文天生只在停顿处留空格,偶尔蒙出一个问号,绝大多数句子没有逗号句号。

本来以为调一下 system prompt 就能解决。实际踩了一圈坑:LM Studio 的 MLX runtime 升级中断、voquill 配错成 Ollama 协议、CORS 关着、Groq 免费档模型选错 TPM 超限。最后用 Groq 做云端 ASR + 云端 LLM 跑通,单次端到端延迟 500-1000ms。

这篇记录整个链路上所有踩过的坑。

整体架构

voquill 的转录是三段式流水线:

音频 → [ASR] → 原始文本 → [LLM 后处理] → 清理后文本 → 注入光标
  • ASR(Automatic Speech Recognition):语音转文字,典型模型是 Whisper
  • LLM 后处理:加标点、去 filler("嗯""那个")、修正自纠错、格式化列表等

任何一环卡住,最终你看到的就是"原始文本"或根本没输出。

方案一:本地 LM Studio + Gemma 4

架构:ASR 用本地 Whisper Large v3 Turbo,LLM 用 LM Studio 启动的 Gemma 4 e4b(OpenAI 兼容 server on :1234)。

踩坑 1:MLX runtime 升级中断导致 dylib 丢失

症状:

Failed to load LLM engine from path: .../llm_engine_mlx_amphibian.node
dlopen(...): Library not loaded: @rpath/libpython3.11.dylib
Reason: tried: '.../cpython3.11-mac-arm64@10/lib/libpython3.11.dylib' (no such file)

原因: LM Studio 升级 MLX 1.5 → 1.6 时被中断。旧的 cpython3.11-mac-arm64@10 被标记 MARKED_FOR_DELETION 并清空(只剩空壳 lib/python3.11/ 目录),新版 Python 解压到同级目录 .tmp-178668363015875/,但最后的重命名没完成。引擎按 rpath 去找的路径指向被清空的老目录。

修复:

VENDOR="$HOME/.lmstudio/extensions/backends/vendor/_amphibian"
rm -rf "$VENDOR/cpython3.11-mac-arm64@10"
mv "$VENDOR/.tmp-178668363015875" "$VENDOR/cpython3.11-mac-arm64@10"

补完中断的 rename 动作。

踩坑 2:Gemma 4 架构不被支持

修好 dylib 之后新错误:

Error when loading model: ValueError: Gemma 4 support is not ready yet, stay tuned!

原因: MLX 1.5.0 里的 mlx-lm 版本太老(0.21 系列),不认 Gemma 4 的模型架构。必须升级到 MLX 1.6.0(mlx-lm 0.31.3)。

修复: LM Studio 的 Runtime 面板里重装 1.6.0。结果 UI 里按"卸载重装"被 LM Studio daemon 卡死在 0% 下载。换 lms CLI:

lms runtime get -y mlx-llm@1.6.0

也卡在 0%

踩坑 3:CDN 域名错猜,手动下载 tarball

~/.lmstudio/.internal/download-jobs-info.json 里发现真正的 CDN 是 extensions.lmstudio.ai(不是我先猜的 publish.lmstudio.ai 那些假域名),直接 curl 下:

cd /tmp && \
  curl -fSL -o backend-mlx.tar.gz \
    "https://extensions.lmstudio.ai/backend-mlx-llm-mac-arm64-apple-metal-advsimd-1.6.0.tar.gz" && \
  curl -fSL -o vendor-mlx22.tar.gz \
    "https://extensions.lmstudio.ai/vendor-_amphibian-app-mlx-generate-mac14-arm64%4022.tar.gz"

两个包一共 100 MB 左右,几秒下完。解压到正确路径:

BACKENDS="$HOME/.lmstudio/extensions/backends"
tar -xzf backend-mlx.tar.gz -C "$BACKENDS/mlx-llm-mac-arm64-apple-metal-advsimd-1.6.0"
tar -xzf vendor-mlx22.tar.gz -C "$BACKENDS/vendor/_amphibian/app-mlx-generate-mac14-arm64@22"

踩坑 4:仅解压 tarball 不够,要跑 postinstall

重启 LM Studio 报 Exit code: null —— 进程直接崩。

原因: venvstacks 分层 Python 环境需要 pyvenv.cfgsitecustomize.py 指向 base layer。这两个文件是安装脚本动态生成的,光解压 tarball 没有。对比已知能工作的 @21 目录确认这俩文件是缺的。

修复: 手动跑两个 postinstall.py:

PY="$VENDOR/cpython3.11-mac-arm64@10/bin/python3.11"
cd "$VENDOR/cpython3.11-mac-arm64@10" && "$PY" postinstall.py
cd "$VENDOR/app-mlx-generate-mac14-arm64@22" && "$PY" postinstall.py

跑完 @22/pyvenv.cfg@22/lib/python3.11/site-packages/sitecustomize.py 就出现了。

验证 Python 层能工作:

"$VENDOR/app-mlx-generate-mac14-arm64@22/bin/python" -c \
  "import mlx_lm; print(mlx_lm.__version__)"
# → 0.31.3 ✓

至此本地 LM Studio + Gemma 4 可以用 lms load google/gemma-4-e4b 成功加载。

踩坑 5:voquill 配成 Ollama 协议连 LM Studio

LM Studio 起来了,可 voquill 加的标点还是时有时无。

日志显示 LM Studio 每 3 秒收一次 GET /api/tags/v1/chat/completions 一次都没有:

[ERROR] Unexpected endpoint or method. (GET /api/tags). Returning 200 anyway

原因: voquill 设置里 LM Studio 的 provider 被配成了 "Ollama" 类型。Ollama 协议路径是 /api/chat/api/tags,而 LM Studio 只讲 OpenAI 兼容协议/v1/chat/completions)。LM Studio 收到不认识的路径但仍返回 200(内容是错的),voquill 静默 fallback 到"不做后处理"。

修复: 在 voquill 设置里删掉那个 Ollama 卡,新建一张 OpenAI Compatible 类型的卡,填:

  • Base URL: http://127.0.0.1:1234不要/v1
  • Include /v1 path: ON(开关开着,voquill 自己拼)
  • API Key: 任意非空字符串(LM Studio 不校验)
  • Model: google/gemma-4-e4b

踩坑 6:CORS 关着,预检 OPTIONS 失败

卡片建好、GET /v1/models 能通了,/v1/chat/completions 还是没出现。日志里大量 OPTIONS /v1/models 返回 "Unexpected endpoint"。

原因: LM Studio 的 http-server-config.json 默认 "cors": false,不响应 OPTIONS 预检。Tauri / 浏览器环境下的 voquill 先发 OPTIONS,失败就不发真正的 POST。

修复:

# 编辑 ~/.lmstudio/.internal/http-server-config.json
#   "cors": false,  →  "cors": true,

LM Studio UI 里 Stop Server → Start Server 让配置生效。

踩坑 7:Base URL + /v1 toggle 互相抵消

早期配成 Base URL = http://127.0.0.1:1234/v1 + Include /v1 path: ON,结果 voquill 把 /v1 抽掉了发到 /models。换成 Base URL = http://127.0.0.1:1234 + Include /v1 path: ON 才正确拼出 /v1/chat/completions

两种等价的正确组合:

  • Base URL 纯 host + 开关 ON(推荐)
  • Base URL 带 /v1 + 开关 OFF

本地方案的实际速度

全链路搭好后每次后处理在 Gemma 4 e4b(M1 Max 64GB)上:

  • ASR 本地 Whisper:~600-1500ms
  • LLM 后处理:~300-600ms
  • RAM 占用 6.86 GB(只为了这个模型常驻)

4B 级别的本地模型质量也一般。于是转向云端。

方案二:Groq 云

Groq 是家硬件公司,自研 LPU 推理芯片,跑开源模型的速度比任何 GPU 方案都快,价格比 OpenAI/Anthropic 便宜一个数量级。voquill 原生支持 Groq。

Groq 的 ASR:whisper-large-v3-turbo

voquill 代码里 Groq ASR 就这一个选项(packages/voice-ai/src/groq.utils.ts)。中文识别质量比本地 whisper.cpp 好,延迟低。

踩坑 8:Groq 和 xAI 的 Grok 别搞混

Gro-q(Jonathan Ross 创的硬件公司)≠ Gro-k(马斯克 xAI 的聊天模型)。名字差一个字母,新手高发混淆点。

踩坑 9:选错 LLM 模型触发 TPM 超限

Groq 有免费额度但按模型分。我一开始推荐 openai/gpt-oss-120b(最强),跑了就 413:

Error: 413
Request too large for model `openai/gpt-oss-120b`
service tier `on_demand` on tokens per minute (TPM):
Limit 8000, Requested 8723

原因: gpt-oss-120b 免费档 TPM 只有 8000 tokens/分钟。我的 system prompt 1231 字符(~600 tokens) + 转录文本 + 输出 reservation 一次 ~8700 tokens,刚好超。

Groq 常见模型的免费档 TPM/TPD(2026 年):

模型TPMTPD
openai/gpt-oss-120b8 000
moonshotai/kimi-k2-instruct-090510 000
openai/gpt-oss-20b20 000
meta-llama/llama-4-scout-17b-16e-instruct30 000500 000

修复: 换成 meta-llama/llama-4-scout-17b-16e-instruct,TPM 翻 4 倍,prompt 再长也撑得住。中文质量稍不如 120B 和 Kimi K2,但加标点 + 去 filler 这种任务够用。

voquill 配置技巧:一 key 多卡分工

voquill 的 "AI transcription" 和 "AI post processing" 是两个独立面板。建议在同一个 Groq API key 下建两张卡:

用途Model
groq asr语音 → 文本whisper-large-v3-turbo
Groq improvements文本后处理meta-llama/llama-4-scout-17b-16e-instruct

两张卡各自选中 → ASR 和 post-processing 互不干扰。

踩坑 10:voquill UI 的 Model 字段位置反直觉

有个隐藏坑:Model 字段在卡片外部(列表视图),不在点铅笔进去的编辑对话框里。编辑对话框只有 Key name / Base URL / API Key / Include /v1 path。Model 要在列表上那张卡片自身的输入框里填。

找半天以为是缺字段,其实是 voquill UI 设计把它拆开了。

中文 Polished Prompt

voquill 自带的 Polished tone 是英文优化的(filler 只列了 "um/uh/like",标点也是半角)。中文场景最小改动版:

Without changing word-choice, clean up the transcript.
Fix grammar, punctuation, and formatting. For Chinese text use full-width
punctuation (,。?!;:、""《》), for English/code use half-width.
No space between Chinese characters; keep a single space between Chinese
and Latin/number sequences (but not before/after punctuation).
Remove filler words, false starts, and repetitions in any language
(e.g. "那个""就是说""嗯""呃""um""uh""like").
Keep the original meaning intact.
Break the response into paragraphs when appropriate.
Format spoken lists into bulleted or numbered lists.
Convert spoken symbols into their actual character equivalents
(e.g. "hashtag"/"井号""#", "at""@", emojis, `foo.cpp`, etc).
When the speaker corrects themselves, only keep the corrected version.
Convert spoken dates, times, and numbers into their proper numerical forms
(e.g. "下午三点""下午 3 点"; "二零二六年四月十六号""2026-04-16").
Do NOT use em-dash symbols () in your response.
Do NOT add Markdown formatting unless explicitly listed above.
Respond with JSON only: { "result": "<cleaned transcript>" }

保留最后一行的 JSON 包装 —— voquill 代码按 JSON 解析返回值,去掉会解析失败。

建议不要改 upstream 的 prompt 文件,用 voquill "Tone" 系统新建一个自定义 tone(systemPromptTemplate 字段)。upstream 合并没冲突,UI 里也能随时切换。

免费档用量估算

按我这套配置(ASR + Llama 4 Scout)免费档上限:

组件限额
Whisper-large-v3-turbo2 000 req/天,8 小时音频/天
Llama-4-Scout1 000 req/天,500 000 tokens/天

典型用量:

  • 轻度(聊天输入):每天 50-100 次录音,一两万 token → 远低于上限
  • 重度(几十分钟通话转录 ×2):200-400 次录音,50-100 万 token → 接近 TPD 上限

真重度用户(每天 3-4 小时通话转录)直接升 Groq Dev Tier,按量付费,Scout 模型 0.03/M input + 0.11/M output,一个月不到一美元。

最终配置总览

voquill:

  • AI transcription → Groq → whisper-large-v3-turbo
  • AI post processing → Groq → meta-llama/llama-4-scout-17b-16e-instruct
  • Custom Chinese "Polished" tone (上面那段 prompt)

本地:

  • LM Studio 的 Gemma 4 可以 Eject,省 6.86 GB RAM
  • 本地 Whisper 缓存(~/Library/Application Support/com.voquill.desktop/transcription-models/)可删可留,共 ~3 GB

端到端延迟:ASR ~600ms + Post-processing ~250-500ms = 1 秒内拿到带标点的中文

Takeaways

  • 先验证每一层独立能工作再 debug 组合问题:我一度以为后处理坏了,查日志才发现 voquill 根本没发 LLM 请求
  • Ollama 协议 ≠ OpenAI 兼容协议。LM Studio 只讲后者。连 LM Studio 必须用 OpenAI-compatible provider
  • LM Studio 默认 CORS 关着。浏览器/Tauri 环境的客户端先 OPTIONS 预检,CORS 关 = 实际请求不发
  • 本地 4B 模型 vs 云端 17B 速度反常识:Groq LPU 上跑 Llama 4 Scout 17B 比 M1 Max 跑 Gemma 4 e4b 还快
  • Groq 免费档按模型限 TPM,别无脑选最强,挑 TPM 额度和 prompt 长度匹配的

最意外的不是任何单一技术问题,是 voquill UI 的"Model 字段在卡片上不在编辑对话框里"——这种认知上的坑比技术坑更耗时。