官方只给 PyTorch + CUDA/vLLM。社区用五条互相独立的路线把模型搬上 Apple Silicon:MLX 逐层重写、通用 MLX 音频库、原生 Swift/Rust、GGUF + Core ML/ANE、以及服务端双后端框架。本报告汇总可复跑的实测数据、优化手法、量化代价与踩坑清单,并标注每类证据的可信边界。
一句话:在 Mac 上跑 Qwen3-ASR,不要走官方 PyTorch/MPS,走 MLX 或 GGUF/Core ML;量化用「decoder 4-bit + encoder 8-bit」这条社区反复验证过的配方;流式与长音频的瓶颈在切分和 KV 复用,不在算子。
四个值得记住的判断
qwen3-asr-server 干脆把 DEVICE=mps 归一化成 cpu。nn.RoPE 代替 Qwen3 的 interleaved MRoPE(sections [24,20,20]),输出「看起来合理但质量下降」;这才是 mlx-qwen3-asr 选择逐层重写而非包装的根本原因。Qwen 团队于 2026 年 1 月开源 Qwen3-ASR 家族(Apache 2.0,技术报告 arXiv:2601.21337):0.6B / 1.7B 两个识别模型 + Qwen3-ForcedAligner-0.6B 非自回归对齐器,支持 30 语言 + 22 中文方言(共 52 种),离线/流式统一,单条长音频最长 20 分钟。0.6B 在并发 128 下官方宣称 TTFT 低至 92 ms、1 秒可转写 2000 秒语音。
| 维度 | 官方提供 | 对 macOS 的含义 |
|---|---|---|
| 推理后端 | qwen-asr 的 transformers / vLLM 两套;流式仅 vLLM | vLLM 官方安装指向 CUDA nightly wheel(cu129),Mac 无对应路径 |
| 设备与算子 | 示例 device_map="cuda:0"、flash-attn(仅 fp16/bf16)、gpu_memory_utilization | FlashAttention 2 与 CUDA graph 均不可用 |
| 实际 fallback | 官方文档未列 Apple GPU 支持 | transformers 后端在 Mac 上落 CPU,社区实测比 MLX 慢 7–20× |
| 服务端兼容路径 | — | SGLang-Omni 的 Torch/MPS 只是「compatibility and correctness path」,且限制很多(见 6 节) |
来源:Qwen 官方博客、QwenLM/Qwen3-ASR、mlx-qwen3-asr 项目背景(DeepWiki 整理) 一手 第三方整理
guoqing1988/qwen3-asr-server README 明确写 DEVICE=mps 会直接归一化为 cpu,macOS 走 vendored QwenASR Rust(CPU)。| 路线 | 代表项目 | 运行形态 / 依赖 | 最突出优势 | 主要短板 |
|---|---|---|---|---|
| A · MLX 重写 | moona3k/mlx-qwen3-asr 一手 | Python 3.10+,仅 mlx / numpy / regex / huggingface-hub;CLI + Session API + HTTP server | 严格 parity 质量门、735 tests、160+ 可复跑 JSON artifacts;优化与质量损失逐项量化 | 需要 Apple Silicon;非 WAV 仍需 ffmpeg;speculative decoding 暂不可用 |
| B · 通用库 | Blaizzy/mlx-audio + mlx-community 一手 | pip 安装,20+ TTS / 15+ STT 共用接口;OpenAI 兼容 REST;Swift package | 量化梯度最全(3/4/6/8-bit),上游生态与 App 最多 | 早期版本有 RoPE 与 30 s 截断问题;model_quant_predicate 阻碍自定义混合精度权重 |
| C · 原生 Swift/Rust | ontypehq/mlx-swift-asr、soniqo/speech-swift、macwispr | SPM 包 / 原生 App,macOS 15+(部分 14+);Swift 6.2+ | 消除 Python 开销;Metal shader warmup、MLState 常驻 KV;适合听写级首延迟 | 模型覆盖与功能少于 Python 线;Core ML 全 ANE 路径要求 macOS 15+ |
| D · GGUF / Core ML | transcribe.cpp、Glimpse Core ML encoder、CapsWriter | ggml C++ / Rust 单二进制;Metal、Vulkan、CPU;GGUF + 可选 .mlmodelc | 无需 Python/torch,Intel Mac 也能跑;1.7B Q4_K_M 仅 1.23 GB 且 WER 1.81% | GGUF 路径暂无原生流式;Core ML encoder 单次仅 15 s;ANE 执行不保证独占 |
| E · 服务端框架 | sglang-omni RFC #1967 | 默认 Torch/MPS;SGLANG_USE_MLX=1 切原生 MLX worker;OpenAI Audio / SSE / realtime WebSocket | 唯一有跨芯片、带 commit 与协议的公开对照;适合服务化部署 | MPS 路径能力受限(60 s、2048 token KV);realtime 在 Apple 双后端尚未完整 qualify |
| 项目 | macOS 上的具体做法 | 值得借鉴的点 |
|---|---|---|
| MacWhisper 0.8.0 一手 | 菜单栏听写 App;Qwen3-ASR 独占 .venv-qwen,默认 mlx-community/Qwen3-ASR-0.6B-bf16(~2.9 GB),1.7B ~7.6 GB 按需下载;macOS 14+ | HF commit 固定(model_revisions.py)避免上游静默变更;热词(context)作领域词表;collapse_repeats 只裁 6+ 次失控重复;v0.8.0 直接移除 Whisper 并自动迁移旧配置 |
| dsh-plugin-local-voice 1.6.1 二手介绍 | DSH Desktop 插件;mlx-audio==0.5.5 + Qwen3-ASR-1.7B-8bit(~2.47 GB,默认从魔搭拉);浏览器内 16 kHz 重采样 + 能量切句(静音 ~0.7 s 出一行、单段 9 s 强制切) | 常驻 qwen3_worker.py 进程,模型只加载一次;首次转写懒启动、空闲 5 分钟回收;启动时探测 darwin/arm64 + 解释器 + 模型目录,任一不满足就不注册 Qwen3 并回落到 SenseVoice;可选 LLM 校对默认关闭以保持零外网 |
| LobeHub Qwen ASR Skill 二手 | 0.6B-4bit(~400 MB)+ FastAPI :8100,/health /info /transcribe_url;国内走 hf-mirror.com | 把模型封装成 Skill 可调用服务;无需 Docker |
| handy-transcribe 一手 | Rust 单二进制 CLI,解码 → VAD 分块 → transcribe.cpp(ggml) → 拼接;M1 Pro 上 972 s 中文技术演讲用 0.6B Q8_0 49 s 转完(~20× 实时) | 适合给智能体/脚本调用的无头批处理;无 Python、无 torch、无 API key |
| Ominix ASR 二手 | Rust + MLX 三级流水线:0.6B 8-bit 识别 → Qwen3-1.7B-4bit 润色/翻译 → Qwen3-4B-4bit 摘要;M4 上 10–20× 实时 | 增强模型空闲自动卸载、MLX 内存软上限 + 清缓存/图编译缓存;domain.txt 术语热加载 |
| qwen3-asr-server 一手 | 兼容 OpenAI Audio API;DEVICE=mps 归一化为 cpu;macOS 走 vendored QwenASR Rust,默认 0.6B | 「两级空闲释放」「远场过滤」等服务端工程;但 Mac 上不是 GPU 路径 |
下表把散落在各仓库 README、模型卡与 PR 里的优化按「框架 → 算子 → 内存 → 数据通路 → 系统」分层,尽量只保留有数字或有明确实现位置的条目。
| 层次 | 手法 | 实现位置 / 命令 | 报告收益 | 证据 |
|---|---|---|---|---|
| 框架 | 用 MLX 逐层重写,绕开 PyTorch/MPS | encoder.py / decoder.py / mrope.py / attention.py;依赖仅 mlx numpy regex huggingface-hub | 相对 Torch/MPS 约 2.3×(M1 Pro)~3.9×(M5 Max)~3× 吞吐(M6) | 一手 |
| 正确的 interleaved MRoPE(sections [24,20,20],stride-3 频率分配) | mrope.py | 不是加速项,是正确性前提;其他 port 常用标准 RoPE 导致质量静默下降 | 一手 背景为第三方整理 | |
| 原生 Swift / Rust 消除 Python 开销 | Qwen3ASRSTT、transcribe.cpp ggml | M1 Pro Swift RTF 0.15–0.27;M1 Pro Rust CLI ~20× 实时 | 一手 | |
| 算子 / 注意力 | 混合 encoder 窗口化(短音频 dense block-diagonal mask,长上下文按窗口分段执行) | hybrid encoder windowing | 长音频最高 4.2× | 一手 |
| GQA 融合注意力,不显式展开 K/V heads | mx.fast.scaled_dot_product_attention | 未单独给出倍数(组合收益) | 一手 | |
| 缓存 mel filterbank 与 Hann window | Whisper-compatible 128-bin log-mel,MAE < 3e-7 vs WhisperFeatureExtractor | 避免重复计算;parity 已验证 | 一手 | |
| Core ML MLState 让 KV cache 常驻 ANE | speech-swift,macOS 15+ / iOS 18+,KV cache 固定 1024 tokens | per-token CoreML latency 降 30–50%(相对早期 stateless) | 厂商 FAQ | |
| 内存 / 长音频 | 预分配 KV cache + in-place slice 写入 + 可回滚裁剪 | generate.py | 组合收益;流式复用完整 8 s attention window 的 encoder 输出与 decoder KV | 一手 |
| 低能量点切 30 s chunk,chunk 间释放内存 | chunking.py;SGLang 默认 max_audio_clip_s=30 | 避免 30 s 特征截断;80 s clips 上 MLX 10.59% vs PyTorch 17.99% primary error | 一手 | |
| 模型与 tokenizer 实例缓存 / 常驻进程 | Session;dsh-plugin 的 qwen3_worker.py | 重复调用免重载;常驻进程 + 懒启动 + 空闲 5 min 回收 | 一手 二手 | |
| 数据通路 | 原生 WAV 二进制 fast path 绕开 ffmpeg 进程启动 | PCM/float WAV 自定义 parser | 量化短片段最高 +25%;WAV 可完全不装 ffmpeg | 一手 |
| 内置 BPE tokenizer,推理路径不依赖 transformers | tokenizer.py | 减少依赖冲突与加载开销 | 一手 | |
| 16 kHz 直采 + Metal shader warmup + 动态 max tokens | macwispr AudioRecorder.swift / warmup / dynamic budget | 免去重采样、消除首次听写冷启动、不再固定 448 tokens | 一手 | |
| 周边任务 | 原生 MLX forced aligner(Fenwick tree / O(n log n) LIS 校正) | forced_aligner.py | 2.64×(0.21 s vs 0.56 s,n=50),100% 文本一致、时序 MAE 5.69 ms | 一手 |
| 说话人分离 offload 到 MPS | --diarize-device {auto,cpu,mps,cuda},默认 auto 优先 MPS | M 系列上从「分钟级」降到「秒级」,输出一致 | 一手 | |
| domain context / 热词注入 system prompt | context="EBITDA non-GAAP FX hedging" | 专业术语纠错;空 system prompt 与官方默认一致 | 一手 |
mlx-qwen3-asr 把投机解码明确标成实验特性且默认关闭:0.6B 给 1.7B 打草稿在短/10 s 片段上只有 0.53–0.55×,原因是 draft audio encoder 的开销吃掉了收益。这是社区里少见的、把失败优化也写进 README 并留下 benchmark artifact 的案例。| 配置 | 短片段 ~2.5 s | 10 s 片段 | RTF (10 s) | 相对 fp16 |
|---|---|---|---|---|
| 0.6B fp16(基线) | 0.17 s | 0.30 s | 0.029 | — |
| 0.6B 8-bit (g64) | 0.10 s | 0.23 s | 0.024 | 1.32× |
| 0.6B 4-bit (g64) | 0.09 s | 0.17 s | 0.018 | 1.71× |
| 1.7B fp16 | 0.36 s | 0.73 s | 0.077 | 慢 2.4× |
质量(LibriSpeech,每子集 100 speaker-balanced 样本):0.6B test-clean WER 2.33% / CER 0.59%,test-other 4.30% / 2.11%;1.7B test-clean 1.94% / 0.57%,test-other 3.45% / 1.48%。FLEURS 10 语言 ×10 样本:0.6B 9.54%、1.7B 6.70%(相对改善 30%,延迟 1.9×)。内存:0.6B fp16 ~1.2 GB,1.7B ~3.4 GB。
来源:moona3k/mlx-qwen3-asr README + docs/BENCHMARKS.md + docs/benchmarks/ 内 160+ JSON artifacts 一手
| 芯片 / 环境 | 工作负载 | MLX | Torch/MPS | 口径 |
|---|---|---|---|---|
| M1 Pro 32 GB · macOS 15.3 | 短 M4A,官方 ckpt 5eb1441,2 warmup + 10 measured | p50 0.24 s / p95 0.26 s;启动 14.7 s;KV 52034 | p50 0.55 s / p95 0.64 s;启动 16.7 s;KV 2048 | 同 checkpoint、同协议,约 2.3× |
| M4 Pro 16-core GPU 24 GB · 26.6.2 | full SeedTTS EN | 4-bit:11.601 samples/s,RTFx 54.945,WER 1.9143%,mean 85.91 ms | — | commit 69ddc6ba |
| M5 Max 24 GB · 26.6.2 | 单请求 smoke,query_to_cars.wav | 4-bit:median 0.047 s / p95 0.048 s,10/10 正确 | BF16:0.182 s / 0.184 s | 约 3.9×;精度不同,非 apples-to-apples |
| M6 24 GB · 27.0.1 | full SeedTTS EN 1,088 clips,3 passes,3,264/3,264 完成 | 4-bit:10.768 samples/s,RTFx 50.999,WER 1.8992%,mean 91.37 ms / p95 110.09 ms | BF16:3.555 samples/s,RTFx 16.837,WER 1.5436%,mean 280.11 ms / p95 365.39 ms | 吞吐约 3×,但 4-bit WER 高 0.36pp |
讨论里的结论原文:MLX/Torch 差异「在吞吐、延迟、RTF、Metal footprint 与 swap 行为上方向一致且量级很大」。RFC 另记录 Fun-ASR 1000-clip 持续负载下 MLX worker RSS 稳定在 ~2.3 GB,而 Torch/MPS 为 2.0–4.1 GB 锯齿(PyTorch MPS caching allocator,有界、非泄漏,但需纳入容量规划);以及未标注模型的一组原始数据:weight load 1.28 s vs 4.51 s、KV pool 6164 vs 2048 tokens、warm request 0.33/0.41 s vs 0.58/0.61 s。
来源:Discussion #2158、RFC #1967 一手 注意:M5/M6 与 macOS 27 的条目为社区自报,未经独立复现。
| 项目 / 条件 | 数据 | 说明 |
|---|---|---|
| mlx-swift-asr,M1 Pro / macOS 15.3,0.6B-6bit ~400 MB | RTF 0.159–0.264(3.8–6.3× 实时);典型 0.15–0.27 | 纯推理耗时,不含模型加载与 Metal warmup(3–5 s) |
| speech-swift FAQ,M5 Pro | Qwen3-ASR-0.6B RTF 0.012 | 厂商自报:约 7× 快于 WhisperKit large-v3 turbo(0.084)、比 whisper.cpp large-v3(0.10)快 40%;0.6B 4-bit 峰值 ~1.0 GB |
| macwispr,M5 系列 ~10 s 音频,MLX 三次取最优 | 0.6B 4-bit 0.60 s / RTF 0.060;0.6B 8-bit ~0.4 s / ~0.04(默认);1.7B 4-bit ~1.20 s / 0.120;1.7B 8-bit 0.77–1.78 s / 0.08–0.18 | 对照 HF PyTorch 0.6B (MPS) 39 s / RTF 1.31 |
| Handy 1.7B GGUF 模型卡,Apple M4 metal backend,全量 LibriSpeech test-clean 2,620 条 | BF16/F16 1.62%(3.80/3.81 GB);Q8_0 1.61%(2.04 GB);Q6_K 1.65%(1.58 GB);Q5_K_M 1.65%(1.41 GB);Q4_K_M 1.81%(1.23 GB) | Whisper 英文 normalizer + jiwer 3.x;BF16~Q5_K_M 落在 bootstrap CI 内,Q4_K_M 仅退化 ~0.2pp → 1.7B 比 0.6B 量化余量更大 |
| handy-transcribe,M1 Pro | 972 s 中文技术演讲,0.6B Q8_0 用 49 s(~20× 实时) | Rust 单二进制,VAD 分块后拼接 |
| 指标(0.6B,100 条多语言) | MLX | PyTorch | 差值 |
|---|---|---|---|
| Primary error rate | 9.54% | 10.34% | −0.81pp |
| WER | 16.00% | 16.69% | −0.70pp |
| CER | 5.43% | 5.64% | −0.21pp |
68% 片段文本完全一致,差异多为数字/拼写/标点的表面形式;encoder 输出与 fp32 PyTorch 参考 MAE 0.003(v0.4.1 tail-padding 修复后尾部降到 0.005 以内);mel MAE < 3e-7。真实会议混合集(AMI IHM + Earnings22,n=200)MLX 23.23% vs PyTorch 23.04%,差 0.19pp。重要 caveat:PyTorch 参考在 Mac 上跑 CPU,慢 7–20×,README 自己声明这不是同硬件 GPU 对比;80 s 长片段 10.59% vs 17.99% 的优势主要来自 MLX 在停顿处切分,而非模型本身更准。
社区在量化上做了两轮独立实验,结论高度一致:别整模型一刀切 4-bit,encoder 与 embedding 要区别对待。
| 配置(0.6B,LibriSpeech 100 speaker-balanced / 子集) | test-clean WER | test-other WER | 速度(10 s clip) |
|---|---|---|---|
| fp16 | 2.33% | 4.30% | 1.00× |
| 8-bit (g64) | 2.33%(输出完全一致) | 4.14% | 1.32× |
| 4-bit (g64) | 2.59% | 5.74% | 1.71× |
mlx-qwen3-asr 官方预量化产物就按这个配方发布:0.6b-4bit 517 MB / WER 2.37%,0.6b-8bit 801 MB / 2.33%(与 fp16 完全一致),1.7b-4bit 1.2 GB / 1.73%,1.7b-8bit 2.0 GB / 1.94%。混合精度权重需要 mlx-qwen3-asr >= 0.4.3 的 per-module loader,旧版本会 shape error。社区模型卡 Alkd/Qwen3-ASR-1.7B-audio8-text4-mlx 做了 16 配置系统消融,选出 audio_tower 8-bit + model.layers 4-bit + embed_tokens 4-bit,与 mlx-community/Qwen3-ASR-1.7B-4bit 在相同条件下对比(n=1000):
| 指标 | 混合精度 | mlx-community 4-bit | 差值 |
|---|---|---|---|
| 磁盘体积 | 1,253 MB | 1,529 MB | −18.0% |
| zh-TW CER | 3.670% | 3.644% | +0.026pp(噪声内) |
| en WER | 6.458% | 6.482% | −0.024pp |
| 速度 zh-TW | 0.244 s/样本 | 0.268 s/样本 | 快 9.9% |
| 速度 en | 0.294 s/样本 | 0.318 s/样本 | 快 7.5% |
| 加载时 RAM 增量 | ~0 MB | +1,095 MB | 显著 |
embed_tokens 量化到 4-bit 时,日语等语言出现 ~172% CER 的幻觉(mlx-community 4-bit 为 174%),是 4-bit embedding 的固有局限,不是某个转换脚本的问题。做中日韩多语种要保留 8-bit/bf16 embedding。model_quant_predicate 硬编码:return not path.startswith("audio_tower") 无条件禁止 audio_tower 量化,导致自定义混合精度权重会被静默加载进未量化 Linear,shape 不匹配并产出空转写。该模型卡给出的绕过方案是:先加载 bf16 基座 → 手动 nn.quantize(...) 两次(audio 8-bit / text 4-bit)→ model.load_weights(saved, strict=True)。| # | 坑 | 现象 | 规避 / 现状 | 严重度 |
|---|---|---|---|---|
| 1 | 标准 RoPE 代替 interleaved MRoPE | 输出「读着通顺但 WER 变差」,极难从单条样本发现 | 用带 parity 门的实现;核对 sections [24,20,20] 与 stride-3 频率分配 | 高 |
| 2 | 30 s 特征截断(mlx-audio Issue #459,第三方整理提及) | 长录音只转出前 30 s | 选支持低能量点 30 s chunking 的实现,或用 SGLang 的 max_audio_clip_s | 高 |
| 3 | ffmpeg@7 + TorchCodec(SGLang Apple Silicon) | 无版本化 ffmpeg 会装到 FFmpeg 9,而 torchcodec==0.11.1 只支持 FFmpeg 4–8;ffmpeg@7 是 keg-only,必须显式加 DYLD_LIBRARY_PATH | brew install ffmpeg@7;不要替换成非版本化 formula;用 M4A/MP3 测解码,WAV 可能不触发 FFmpeg 加载而掩盖问题 | 高 |
| 4 | macOS SIP 剥离 DYLD_* | 经 SIP 保护的可执行文件启动服务时环境变量丢失 | 把 DYLD_LIBRARY_PATH 设在最终的 sgl-omni 进程上,例如在 /usr/bin/time 之类 wrapper 之后放 /usr/bin/env DYLD_LIBRARY_PATH=... | 高 |
| 5 | Torch/MPS 兼容路径能力受限 | tp_size=1、greedy、eager torch_native/sdpa;无 radix caching / chunked prefill / CUDA graphs;KV 预算 2048 tokens;native 与 streaming 都卡 60 s;无 token logprobs | 长音频用 stream=false 让服务端按 30 s 分块;要性能就 SGLANG_USE_MLX=1 | 中高 |
| 6 | 语言 hint 严格 | 不支持的 hint 直接 HTTP 400(不静默回落英文);22 种中文方言名不能强制,只能用 Chinese/zh | 预先规范化;旧写法 cn / zh-* 会被接受为 Chinese | 中 |
| 7 | 流式质量与稳定性 | final text 比 offline 差约 2pp(多语 11.3% vs 9.5%,长音频 11.9% vs 10.6%);stable_text 设计上单调,缩短已稳定前缀的修正不会应用 | 对最终稿再跑一次 offline 或 tail re-decode;SRT/VTT 仅离线模式支持 | 中 |
| 8 | 投机解码负收益 | 短/10 s 片段 0.53–0.55× | 保持关闭,等 draft encoder 开销被优化 | 低 |
| 9 | 长音频重复(SGLang Issue #2150) | 长录音出现循环重复;repetition_penalty > 1 可压制但会伤干净音频准确率 | 仍 open,缺少可复现的原始片段;MLX 路径的 repetition_penalty 转发在 #2157 | 中 |
| 10 | realtime WebSocket 未完成 Apple 双后端资格验证 | VAD、partial/final、clear/cancel、断连恢复、长会话缺完整矩阵;#2214 只有 M4/16 GB 的 MLX smoke | 不要把 uploaded-file SSE 的证据当作 live PCM 的证据 | 中 |
| 11 | Core ML encoder 15 s 上限 / ANE 不独占 | 长音频必须切块;官方模型卡明说部分算子可能跑在 CPU | Glimpse 自动切分;不要把「Core ML」直接等同于「省电 ANE」 | 低 |
| 12 | 版本与口径漂移 | 早期媒体稿写 441 tests / 4-bit 提速 4.7× / 2.5 s 音频 0.46 s;当前 README 是 735 tests / 1.71× / 0.17 s(不同版本与 workload) | 引用时必须带版本、芯片、片段长度与测试协议;以仓库 docs/benchmarks/ 的 JSON artifacts 为准 | 中 |
pip install -U mlx-qwen3-asr
brew install ffmpeg # 仅非 WAV 格式需要
mlx-qwen3-asr meeting.mp3 --model moona3k/mlx-qwen3-asr-0.6b-4bit -f srt -o out/
mlx-qwen3-asr --doctor # 环境自检
pytest -q # 735 tests(源码安装)
python scripts/eval_librispeech.py --subset test-clean --samples 100 \
--sampling speaker_round_robin # 质量复跑
python scripts/convert.py --model Qwen/Qwen3-ASR-0.6B \
--quantize 4 --encoder-bits 8 --group-size 64 --output-dir ./qwen3-asr-4bit
uv run mlx_audio.stt.generate \
--model mlx-community/Qwen3-ASR-0.6B-8bit \
--audio audio.wav --output-path output --stream
# mlx-qwen3-asr 自带 server
pip install "mlx-qwen3-asr[serve]"
mlx-qwen3-asr serve --api-key $(openssl rand -hex 16) # :8765/v1
# SGLang-Omni Apple Silicon(注意 keg-only ffmpeg)
brew install ffmpeg@7
export DYLD_LIBRARY_PATH="$(brew --prefix ffmpeg@7)/lib${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"
SGLANG_USE_MLX=1 sgl-omni serve \
--model-path Qwen/Qwen3-ASR-0.6B --model-name Qwen/Qwen3-ASR-0.6B \
--asr.engine.max_running_requests 1 --port 8000
ffmpeg -i input.mp3 -ar 16000 -ac 1 -c:a pcm_s16le input.wav
build/bin/transcribe-cli -m Qwen3-ASR-1.7B-Q8_0.gguf input.wav
# Core ML encoder:把 .mlmodelc 解压到 GGUF 同目录,运行时自动探测并回落
dsh plugin --profile desktop add dsh-plugin-local-voice
uv venv ~/.local/venvs/mlx-audio --python 3.12
~/.local/venvs/mlx-audio/bin/pip install "mlx-audio==0.5.5" sounddevice numpy huggingface_hub
python3 scripts/prepare_model.py # 1.7B-8bit ~2.47 GB,默认魔搭
python3 scripts/prepare_model.py --source hf-mirror # 或 hf
| 目标 | 推荐 | 理由 / 注意 |
|---|---|---|
| 命令行批处理、CI 可复跑、写技术结论 | mlx-qwen3-asr + 0.6b-4bit(encoder 8-bit) | 唯一把每个优化都绑 quality gate 并留下 JSON artifacts 的实现;docs/BENCHMARKS.md 有 exact commands |
| 要服务化、多并发、OpenAI Audio API | SGLang-Omni + SGLANG_USE_MLX=1;或 mlx-qwen3-asr serve | 前者有分块调度与并发护栏(max_total_audio_s=3600 等);后者更轻,长音频用 async job API 避免 HTTP 超时 |
| 做 macOS/iOS 原生 App、追求首延迟 | ontypehq/mlx-swift-asr(最小)或 soniqo/speech-swift(双后端) | Metal shader warmup、MLState KV 常驻;注意 Swift 库要 macOS 15+ / Swift 6.2+;别忘 warmup 的 3–5 s 要放在启动阶段 |
| 不想引入 Python / 需要 Intel Mac 也能跑 | transcribe.cpp GGUF(Q8_0 或 Q5_K_M) | 1.7B Q5_K_M 1.41 GB、WER 1.65%;GGUF 无原生流式,需自己做 VAD 分块 |
| 中文方言 / 长会议 / 要词级时间戳 | 1.7B 8-bit 或 bf16 + 30 s 能量切分 + --diarize-device mps | 1.7B 多语相对改善 30%,延迟 1.9×;8-bit 在 test-clean 与 fp16 输出一致;diarize 不支持 streaming/mic |
| DSH 插件 / 常驻语音输入 | 参考 dsh-plugin-local-voice 的进程模型 | 常驻 worker + 懒加载 + 空闲回收 + 平台探测降级,是「模型 2.47 GB 不能每次重载」的正确解;若你做新插件,可考虑把后端换成 mlx-qwen3-asr 以拿到 WAV fast path 与原生 aligner |
| Reachy Mini 之类本地语音链路(Mac MPS) | 0.6B 4-bit MLX + 流式窗口(默认 2 s chunk / 30 s context) | RTF 0.08 有充足余量给 VAD 与 TTS;注意 streaming 与 offline 约 2pp 质量差,最终文本可再跑一次 offline 修正 |
qwen-asr + device_map="mps" 期待 GPU 加速;② 不要对日语/韩语用 4-bit embed_tokens;③ 不要为 1.7B 打开投机解码(当前净变慢)。另外,跨项目比 RTF 之前先确认是否含模型加载/Metal warmup——Swift 线普遍标注「inference only」,而 Python 线常含冷启动。| 等级 | 来源 | 用途 |
|---|---|---|
| 一手 | Qwen 官方博客、QwenLM/Qwen3-ASR | 模型规格、后端边界、官方性能口径 |
| 一手 | moona3k/mlx-qwen3-asr README、1.7b-4bit 模型卡 | 路线 A 的全部优化、延迟/WER/parity 数据、预量化配方 |
| 一手 | RFC #1967、Discussion #2158、qwen3_asr cookbook | 双后端设计、跨芯片基准、Apple Silicon 安装坑与 MPS 限制 |
| 一手 | mlx-audio 中 Qwen3-ASR README、mlx-community 4-bit 模型卡、mlx-audio-swift 模型矩阵 | 路线 B 的 API、量化梯度、转换来源(mlx-audio 0.3.1) |
| 一手 | ontypehq/mlx-swift-asr、soniqo FAQ、macwispr README、MacWhisper README | 路线 C 的 Swift 基准、MLState、MPS 不可用对照、App 工程实践 |
| 一手 | Glimpse Core ML 模型卡、Handy 1.7B GGUF 卡(镜像)、handy-transcribe、CapsWriter 模型支持 | 路线 D 的 GGUF WER 阶梯、Core ML 限制、Rust CLI 实测 |
| 一手 | Alkd 混合精度模型卡、qwen3-asr-server | 16 配置消融、model_quant_predicate 坑、macOS CPU 归一化 |
| 二手 | 夜雨飘零:dsh-plugin-local-voice、LobeHub Qwen ASR Skill、Ominix ASR 介绍、BestHub 转载、CSDN mlx-audio-swift 教程、dev.to GGUF 文章 | 中文社区实践、Skill/插件封装、早期版本数据(口径已漂移,见 6 节 #12) |
| 第三方整理 | DeepWiki 项目背景、Next Gen Tech Insider、Bright Coding | 发布时间、mlx-audio 早期 RoPE / 截断问题的转述、speech-swift 概览;这类结论需回原始仓库复核 |
mlx-qwen3-asr 的 MLX vs PyTorch parity 里,PyTorch 参考在 Mac 上跑 CPU(慢 7–20×),README 明确说这不是同硬件 GPU 对比。