基于Kit真实听写片段的词汇
状态: 研究,2026-10-23。无产品变更。承接自
parakeet-boost-spike.md
(分支 spike/parakeet-boost)、custom-vocabulary.md
和 ../plans/transcription-quality.md。
问题: 在 Kit 自己的日常口述中,带识别提示(hints)的 Qwen3-ASR 1.7B 能否修正 Parakeet Unified 遗漏的词汇,代价是什么?
答案: 部分可以。提示将术语召回率从 7/13(Hex 粘贴出的结果)提高到 10/13,但大部分提升并非来自提示本身。六个未命中中有两个是 Rune 被听成 “Ruin” 和 “Roon”。Parakeet 自身的整段音频解码已经能正确识别这两个词,因此它们是流式错误。未加提示的 Qwen 已经能听出 “grill”。提示列表本身只修正了大小写(Hex 一次、HiveMind)和 dotfiles,而且 dotfiles 是在它从这些片段中被加入列表之后才修正的。Qwen 的整体 WER 是 Unified 的 2 到 3 倍,并且消耗约 5 倍于 Unified 离线模式的计算量。更长的提示列表使 Qwen 在 49 个短片段中的 4 个上返回空文本。基于这一证据,不要为了词汇正确性而将口述识别切换到 Qwen。
方法¶
- 片段。 50 个来自
diagnostic-dictation-audio的保留 WAV(10 月 22 日 23:06 到 10 月 23 日 14:46),转换为 16 kHz 单声道 PCM16 副本。文件名即保存时间,其历史条目在 140–400 毫秒后出现,一一对应。49 个匹配到历史条目。一个 1.1 秒的片段没有条目,不计分。计分音频共 219.9 秒,733 个参考词。每个片段都送入了 OpenCode Beta。 - 参考。 每个参考都以历史文本为起点(原文 = 最终文本,因为 Kit 未配置任何替换、转换或后处理)。在任何模型运行之前,我做了上下文修正:grow→grill(grilling 技能)、defiles→dotfiles、Ruin/Roon→Rune、hex→Hex。我还标记了 12 个措辞不清的片段。推理后,我又做了两处模型一致且上下文支持的编辑,并都做了标记:“only worth”→“probably worth”(Unified 离线模式和每个 Qwen 方案都一致)和 “macro gear change”→“MacBook Air change”(每个 Qwen 方案都一致,而且那周 Air 已离开设备群)。第二处编辑偏向 Qwen,因此下面的召回率列中不包含
MacBook Air。没有播放音频,因此这些是判断性代理指标,而非人工审核。 - 术语。 10 个片段中预先登记了 13 处出现:Dax ×3、Rune ×4、Hex ×2、HiveMind、dotfiles、grill、Adam。名称按大小写敏感匹配,因此 “hex” 计为未命中。如果忽略大小写,每个方案都能得到 Hex。
- 提示。
hints17是 boost spike 的冻结列表(Hex、Cappuccino、OpenCode、Rune、Scrawl、Effect、Anomaly、Dax、Aiden、Kit、Parakeet、Moonshine、GPUI、Sparkle、Argon、Astra、HiveMind)。它是在这些片段出现之前就确定的。hints27增加了 Psychopomp、dotfiles、Qwen、Claude、Opus、Sonnet、Gemini、skulk、Zen 和 “grill me”。dotfiles和 “grill me” 来自这些片段的未命中,因此它的召回率是乐观的。两者都使用 spike 的提示词:Names and technical terms: <list>. - 运行环境。 spike 的
model-runner、未打补丁的transcribe-cpp 0.4.1,运行在 M4 Pro Mac mini 上(64 GB、严格 Metal、单 CPU 线程、每个片段新建会话、平均负载约 6.5)。Studio 的 HiveMind 拒绝执行 cargo 工作,而 Pro 的平均负载为 51。本次运行包括一次预热轮次加两次测量轮次,每个片段的方案顺序轮换。准确度来自第 1 轮,第 2 轮没有转录发生变化。Unified streaming 在 0.4.1 上复现了生产环境在 49 个片段中 48 个的粘贴结果,只是标点不同。 - 修正方案 (d)。 Kit 的
dictation_processing没有替换或重写,personal-commands.json也没有转换。因此,Parakeet 加上修正就是生产环境那一行。
结果¶
| 系统 | 术语召回 (13) | 错误提示插入 | WER,全部 49(733 词) | WER,37 个确信片段(598 词) | 空输出 | 每音频秒中位 ms |
|---|---|---|---|---|---|---|
| 生产粘贴 = Parakeet + 修正(0.2.4 流式) | 7 | 0 | 0.95% | 1.17% | 0 | — |
| Parakeet Unified,流式 | 7 | 0 | 1.09% | 1.17% | 0 | 38.2 总计算量 / 11.9 finalize |
| Parakeet Unified,整段 | 9 | 0 | 3.00% | 2.01% | 0 | 14.6 |
| Qwen3-ASR 1.7B,无提示 | 8 | 0 | 6.55% | 5.02% | 0 | 70.3 |
| Qwen3-ASR 1.7B,hints17 | 10 | 0 | 6.00% | 4.18% | 0 | 74.9 |
| Qwen3-ASR 1.7B,hints27 | 10 | 0 | 8.19% | 6.35% | 4 | 73.1 |
- 若计入推理后的
MacBook Air术语,每个 Qwen 方案都会增加一次命中,而 Parakeet 不会。 - 每个片段的中位时间:Unified 整段为 64 ms,流式 finalize 为 53 ms,三个 Qwen 方案分别为 267、295 和 310 ms。Qwen 的 p95 为 519 到 565 ms,而 Unified 为 100 ms。
- 在使用提示的情况下,Qwen 每音频秒的毫秒数是 Unified 离线模式的 5.1 倍,是流式 finalize 的 6.3 倍,后者大致相当于生产环境中用户松开后的等待时长。对于 5 秒的口述,这大约是 370 ms 对 60 ms。
- WER 是代理指标的不一致程度。生产文本作为参考的种子,因此对 Parakeet 的行有利。
没有哪个提示词被插入到没有说过的地方。 各方案在其他方面会失败。hints27 下的短片段返回空文本(2.0–2.6 秒)。未加提示的 Qwen 将一个无声、不计分的片段转成了中文(“玩呢啊。”),而这个结果会被 Hex 粘贴。Qwen 还会改写措辞。
五个最能说明问题的片段¶
| 片段 | 参考 | 生产 / Unified 流式 | Unified 整段 | Qwen 无提示 | Qwen hints17 | Qwen hints27 |
|---|---|---|---|---|---|---|
| 1792736041649 | push the dotfiles commits and what's up with the MacBook Air change | push the defiles commits … macro gear change | defiles … macro gear change | push the .diff files commits … MacBook Air change | push the death files commits … MacBook Air change | push the dotfiles commits … MacBook Air change |
| 1792735783602 | anything else you'd like to ask me or grill me about | grow me | grow me | grill me | grill me | grill me |
| 1792736219057 | Can we talk to Rune and get this started? | talk to Roon | talk to Rune | Rune | Rune | Rune |
| 1792735967611 | Why don't you measure first | Why don't you measure first | Why don't you measure first? | Why don't you measure first? | Why don't you measure first? | (空) |
| 1792735980294 | … the A-B test. Do whatever you want to do | … A-B test. Do whatever you want to do | 相同 | … AB test. Do it in VLAN two. | … A/B test. Do it in VLAN two. | 与 hints17 相同 |
- Dotfiles 只有在提示列表中出现该词本身时才会被识别出来。冻结列表产生的是 "death files"。
- Grill 的识别并非提示词的功劳。Qwen 在没有任何提示的情况下也能听出来。
- Rune 是 Parakeet 流式解码的错误,而不是词汇表缺口。1792736124209 中也出现了同样的情况:流式版本给出 "I own Ruin",而整段解码两次都给出 "Rune"。在该片段中,每个 Qwen 分支也都把句子改写成 "what I own Rune, we both work on",并漏掉了一个 Rune。
- 空输出是更长提示词的失败模式,在 49 个片段中影响了 4 个。
- VLAN two 看起来是 Qwen 编造的内容。两种 Parakeet 模式对原始措辞都一致,但没有人听过该片段,因此它仍保持标记状态。
主要结论¶
- 在 Kit 的日常听写中,词汇漏识别很少见:在约 3.7 分钟的语音中,13 处词汇出现里有 6 处。大多数并非由缺少词汇表所致。
- 成本最低的实际收益来自 Parakeet 的整段解码,它修复了两次 Rune 漏识别,成本约为每音频秒 15 ms。它还在三个片段中丢失了尾部词语("nice to"、"other principles"、"permodal change"),因此在将其用作最终处理之前要测试尾部填充。
- 带提示的 Qwen 能恢复需要词汇表的名称(
dotfiles、大小写),且没有插入任何错误内容。但它仍需要约 5 倍的计算资源,不支持流式,在这里使代理 WER 变为三倍,并且随着列表增长会退化为空输出。这与 spike 的会议结果一致:名称的召回更好,其他一切更差。 - 字面替换(
defiles→dotfiles、Roon/Ruin→Rune)可以修复这些片段,但这只是因为列表本身就是从相同的片段构建的。custom-vocabulary.md中的冲突警告仍然适用。
注意事项¶
- 49 个片段、13 处词汇出现,一天、一位说话人、一个麦克风。单条片段就会使召回率改变约 8 个百分点。
- 参考标注是根据模型一致性和上下文判断的,而非实际试听。有 12 个片段被标记为不明确(confident-WER 列将其排除),且有两处编辑是在推理之后进行的。
- 计时数据来自两个模型都常驻内存的共享工作进程,且仅覆盖解码器。它们不是从快捷键到粘贴的延迟。
- 汇总数据和逐片段统计位于
vocabulary-real-clips.json。逐片段的转录文本则保留在 git 之外。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 hex19/hex