如果你用过 Whisper 这类语音转写工具,一定见过那种原始输出:满屏的 um、uh、说到一半推翻重来的句子、没有标点的长串字符。把它整理成能看的会议纪要,通常要靠人工或者调一次云端大模型。Superwhisper(一款 macOS 听写应用背后的公司)开源了一个专门干这活的小模型 S1-mini:0.6B 参数,Q4_K_M 量化后只有 462MB,普通笔记本 CPU 就能跑。这篇文章记录我在 Apple M4 / 16GB 内存的 Mac 上从下载到跑通的全过程,包括四个文档里不会告诉你的坑。
它只做一件事,而且是流水线的最后一环
先划清边界:S1-mini 不是语音识别模型,它不碰音频。它的位置在 ASR 之后——
音频 → Whisper / Parakeet / 任意 ASR → S1-mini → 干净文稿它基于 Qwen3-0.6B 微调,能力清单很克制:删掉语气词和重复句、把自我纠正收敛到说话人最终采用的表述、补标点和大小写、把口语里的数字/日期/金额/邮箱地址转成书面格式。它不会编造你没说过的话,不会改事实,纯填充词输入时按文档设计应该返回空字符串(这个细节后面有实测反转)。官方在 7519 条内部测试集上报告 94.8% 的 token 准确率——注意这是厂商自测数据,不是第三方基准。
许可证是 Apache 2.0 加一条命名条款(衍生品命名上有约束),商用前建议看一眼模型卡原文:Hugging Face 模型仓库。
部署:三步跑起来
实测环境:Apple M4、16GB 内存、Homebrew 安装的 llama.cpp(llama-server 0.5.0)、Python 3.13.12。
第一步,下载权重(462MB):
curl -L -o s1-mini-q4_k_m.gguf \
"https://huggingface.co/superwhisper/s1-mini-GGUF/resolve/main/s1-mini-q4_k_m.gguf"第二步,启动服务。这里就是第一个坑,启动参数不能省:
llama-server -m s1-mini-q4_k_m.gguf --port 8907 \
--jinja --chat-template-kwargs '{"enable_thinking":false}' \
-ngl 99 -c 4096--jinja --chat-template-kwargs '{"enable_thinking":false}' 是模型卡明确要求的组合。S1-mini 用的是 Qwen3 原封不动的对话模板,而 Qwen3 默认开思维链,S1-mini 训练时思维链是关的。模型卡还特意提醒:不要用 --reasoning-budget 0 来替代这套写法,会劣化输出。我实测这套参数下模型加载不到 1 秒(Apple M4 全 GPU offload),/health 秒回 ok,16GB 内存毫无压力——相比上次跑 24B 级 MoE 时的内存地狱,这个体量才叫真正的端侧友好。
第三步,调用。注意请求里要显式传 temperature: 0——这是第二个坑:GGUF 文件的元数据继承了 Qwen3 的采样参数(temperature 0.6、top_p 0.95、top_k 20),而 S1-mini 的官方评估全部是贪心解码跑出来的。你要复现 94.8% 那个数字,就必须贪心。
提示词契约:三个字段,一个字都不能改
S1-mini 的接口设计很特别:整个交互就是一条「控制行」加原始转写文本。控制行长这样:
[Styling: semi-formal] [Structure: prose] [Context: general]三个轴各有固定取值:Styling 只有 casual / semi-casual / semi-formal / formal 四档,Structure 只有 prose / lists 两档,Context 只有 general / email 两档,全部组合都训练过。模型卡警告:发明新值或者改写系统提示词,输出可能乱码。
调用脚本(我实测用的完整版本):
import json, urllib.request
URL = "http://127.0.0.1:8907/v1/chat/completions"
SYSTEM = ("You are a text normalizer for speech-to-text transcripts. "
"The input begins with a control line specifying the styling, "
"structure, and context settings; clean the transcript to match "
"those settings and output only the cleaned text.")
def clean(control_line, raw_transcript):
body = json.dumps({
"model": "s1-mini",
"messages": [
{"role": "system", "content": SYSTEM},
{"role": "user", "content": f"{control_line}\n{raw_transcript}"},
],
"temperature": 0,
"max_tokens": 800,
}).encode()
req = urllib.request.Request(URL, data=body,
headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=120) as r:
return json.load(r)["choices"][0]["message"]["content"]
print(clean("[Styling: semi-formal] [Structure: prose] [Context: general]",
"So uh the login is broken on mobile, wait no, it's only broken "
"on iOS safari, android is fine, users are getting a blank screen "
"after they enter their password and hit submit."))七组实测:好的地方很好,坏的地方很诚实
我跑了 7 组用例,结果汇总:
| 用例 | 实测结果 | 耗时 |
|---|---|---|
| 填充词+自我纠正+邮箱(semi-formal) | 语气词全删,”wait no” 收敛为最终表述,”support at superwhisper dot com” → support@superwhisper.com | 0.55s |
| 口述行动项+数字(lists) | 自动生成 1/2/3 有序列表,”twenty two thousand” → 22,000 | 0.65s |
| 口述邮件(formal/email) | 补出 “Hi John,” 称呼、金额 → $1,250、结尾落款格式 | 0.41s |
| 纯填充词输入 | 实测返回 ‘um’,不是空串(见下文踩坑三) | 0.06s |
| 控制行写未训练值 professional | 本次输出正常,未乱码(见下文踩坑四) | 0.14s |
| 中文口述输入 | 能补标点、把碎句连成通顺段落 | 0.25s |
| 不传 temperature(默认采样) | 本例输出与贪心一致,但不应依赖这个巧合 | 0.12s |
速度层面可以放心:单条 40-70 token 的清洗任务全程 0.1-0.7 秒,做实时听写的后处理完全够用。如果你在找识别侧的方案,可以看我之前写的腾讯混元 HY-ASR 3.0 语音识别实测,两者正好凑成一条完整的本地语音转写流水线。
四个文档没说透的坑
坑一:模板参数是硬要求,不是建议。 我没有单独做去掉 --jinja 的对照实验(未实测),但模型卡把这点标成了「两大常见失败点」之一,配合 thinking 模式开启时输出前会挂思维链,集成时直接照抄上面的启动命令最稳。
坑二:temperature 必须显式置 0。 GGUF 元数据里的采样参数和官方评估口径是矛盾的,你不覆盖,等于在跑一个「带随机性的清洁工」,同样一句话每次清洗结果可能不同。对文本清洗这种需要确定性的任务,这是致命的。
坑三:「纯填充词返回空串」实测翻车了。 模型卡说 filler-only 输入返回空字符串,且 98.6% 的情况下能正确沉默——注意是 98.6%,不是 100%。我那条 “Um, uh, you know, like…” 就落在了剩下那 1.4% 里,返回了 ‘um’。如果你做集成,空串校验之外还要兜一层「输出是非清洗内容」的检测,别直接把模型输出当唯一事实源。
坑四:控制行别赌。 我试了未训练的 “Styling: professional”,这次输出正常没乱码——但这说明「乱码」不是必然触发,而是概率性的。模型只保证 4×2×2=16 种组合的行为,其他写法没有行为承诺。另外产品版 App 的语气滑杆有五档(含 balanced),开源权重只有四档,两套文档对不上,以模型卡为准。
最后一个意外发现:模型卡写 v1 仅支持英文,但我喂了一段中文口述稿,它居然把标点补齐、碎句连成了通顺段落。不过这不是它的训练目标,输出没有质量保证,你可以把它当彩蛋,别当中文校对模型用。需要中文场景的话,看看Qwen3.8-Omni-Flash 音视频理解 API 实测更实际。
什么场景值得上,什么场景别碰
值得上的:本地会议录音整理(数据不出内网)、听写工具的后处理插件、企业内网批量清洗历史转写档案。462MB 的体积让它可以常驻在任何设备上,成本为零。想把它和小模型家族放到一起看的话,我之前测过同样 CPU 可跑的LibertAI Deem 决策模型和 740M 的EmbeddingGemma 2 嵌入模型,「小模型专精一件事」正在成为一条清晰的产品路线。
别碰的:中文转写清洗(无训练保证)、需要模型补充或改写内容的场景(它被设计得「死板听话」)、没有 ASR 前端只想拿它当聊天模型的场景(它压根不是聊天模型)。
另外两件事我没实测、需要你自己验证:一是接真实 Whisper 输出的端到端效果(我只测了手写的模拟转写文本),二是 ONNX Runtime 部署路径。想看第三方整理的部署教程,Better Stack 的 S1-mini 指南写得很细,含 Ollama Modelfile 方案。
一句话总结:S1-mini 是我今年测过的「定位最清醒」的开源小模型——不贪多,只洗稿,462MB 常驻后台,把云端清洗那一步的钱和隐私顾虑都省了。它的四个坑都有文档背书或我的实测对照,照着抄上面的启动命令和提示词契约,基本一次跑通。