Six months of running local LLMs, image generators, and a music-analysis model on the same Apple Silicon box. Decode rates, prefill costs, quality scores, and a stack of dead ends. Everything below is measured — the scripts and raw JSON live in the repo.
After cycling through roughly twenty open-weight models across LLM, image, and music tasks, three slots are settled and a fourth — a general-purpose local audio LLM — is still vacant. The shortlist below is what survived the cuts. Dates are upstream release months — quant uploads and Ollama-MLX repackagings can lag a few weeks behind.
| Slot | Winner | Released | Why it beat the field |
|---|---|---|---|
| Tool-calling agent LLM | Qwen3.6-35B-A3B-coding NVFP4 MLX |
Apr 2026 | 34 tok/s on Ollama-MLX, 41 tok/s on rapid-mlx; 7/7 on the tool-call suite. MoE with 3 B active = bandwidth-class of a 3 B model, capacity of a 35 B. |
| Chat · vision · long-doc LLM | Gemma 4 26B-A4B QAT NVFP4 |
Jun 2026 | 34 tok/s decode (ties Qwen), wins vision (1.6× decode and 4.3× fewer image tokens vs Qwen3-VL-8B), wins long-doc decode (2.3× over Gemma 4 12B at 46 K context). |
| Image generation — speed | FLUX.2 Klein 4B via MFLUX |
Jan 2026 | 60 s per 1024² image at 4 steps. Coexists with an LLM hot in memory — no eviction needed. |
| Image generation — quality | FLUX.2 Klein 9B MLX-Q4 |
Jan 2026 | 115 s per image. Pre-quantized 4-bit MLX (8.9 GB, smaller than 4 B's FP16). Visibly sharper faces, fabric, text. |
| Music structure analysis | SongFormer (ASLP-lab) |
Oct 2025 | 2.97 GB specialist transformer + MuQ SSL encoder. Beats Gemini 2.5 Pro on SongFormBench. Replaced our paid Gemini Flash pipeline. |
| Local audio LLM (general) | — none — | — | Gemma 4 e4b collapses every section to "chorus". Qwen2.5-Omni isn't in mlx-vlm yet. mlx-lm-omni has API rot. |
On a 32 GB Apple Silicon box, the winning recipe is 3–4 B-active MoE at NVFP4 quantization for text, distilled 4-step diffusion for images, and specialist transformers (not omni LLMs) for music — and the throughput ceiling is set by memory bandwidth, not parameter count.
Three physical constraints shape every model decision below. The Mac mini M4 is what it is; the trade-offs follow from the hardware.
Three constraints, in order of how often they decide things:
Tested across four task shapes that map onto how the box actually gets used: short-context reasoning, vision (screenshot Q&A), long-document summarization (≈ 46 K input tokens), and tool-call fidelity (the agentic loop).
| # | Model | Released | Runtime / quant | Decode tok/s | TTFT | Total | Quality |
|---|---|---|---|---|---|---|---|
| 01 | Gemma 4 26B-A4B QAT | Jun 2026 | rapid-mlx · nvfp4 | 34.1 | 2.1 s | 31.1 s | 5/5/5 |
| 02 | qwen-hermes (35B-A3B) | Apr 2026 | Ollama-MLX · nvfp4 | 34.0 | 11.9 s* | 70.7 s | — |
| 03 | gemma-hermes (6.3 B dense) | Mar 2025 | Ollama-MLX · /no_think | 31.9 | 25.4 s* | 64.4 s | — |
| 04 | Qwen3-14B 4-bit | May 2025 | rapid-mlx · --no-thinking | 12.5 | 1.9 s | 98.3 s | 5/5/5 |
| 05 | gemma4:12b-mlx | Apr 2026 | Ollama-MLX · nvfp4 | 11.9 | 1.8 s | 88.9 s | 5/5/5 |
* cold-load TTFTs — model being swapped in. pure prefill on short prompts is 1–3 s.
| # | Model | Released | Decode tok/s | TTFT | Image tokens | Quality |
|---|---|---|---|---|---|---|
| 01 | Gemma 4 26B-A4B QAT | Jun 2026 | 34.0 | 3.0 s | 331 | 5/5/5 |
| 02 | Qwen3-VL-8B 4-bit | Sep 2025 | 21.5 | 10.6 s | 1,436 | 5/5/5 |
| — | Gemma 4 12B-mlx (Ollama) | Apr 2026 | Text-only — Ollama's MLX package ships without the vision projector. | |||
The MoE 26B-A4B at 46 K context decodes 2.3× faster than the dense 12 B and 4.6× faster than the dense 14 B. Its prefill (170 s) is also 3.2× faster than the 12 B's (546 s) — because Apple Silicon prefill scales with active params, not total.
| Model | Released | Architecture | Tool fidelity | Decode tok/s | Cold prefill (~13 K) |
|---|---|---|---|---|---|
| Qwen3.6-35B-A3B 4-bit | Apr 2026 | MoE 3 B-active | 7/7 | 41.5 | 24.5 s |
| Nemotron-3-Nano 30B-A3B | Mar 2026 | MoE 3 B-active | 7/7 | 41.8 | 26.2 s |
| GLM-4.7-Flash 4-bit | Apr 2026 | MoE 3 B-active | 7/7 | 35.2 | 49.8 s |
| Gemma 4 26B-A4B 4-bit | May 2026 | MoE 3.8 B-active | 7/7 | 33.0 | 25.4 s |
| Gemma 4 e4b 4-bit | May 2026 | ~4 B dense | 6/7 | 31.7 | 16.7 s |
| Qwen3-Coder-Next 4-bit | Feb 2026 | MoE 80 B | Disqualified — OOM at 42 GB > 32 GB unified | ||
| Devstral-Small-2505 4-bit | May 2025 | dense 24 B | Broken — chat template ships without tool rendering; 6.3 tok/s anyway | ||
Fidelity doesn't separate the fitting models. Every MoE that fits in 32 GB hits 7/7. The differentiator is decode speed, and decode speed is bandwidth-bound. Qwen3-Coder-Next (MoE 80 B, 42 GB at 4-bit) doesn't fit at all — Metal OOMs on first prefill.
~37 GB on disk total (three Qwen presets share NVFP4 blobs at 21 GB; three Gemma presets share theirs at 16 GB):
| Name | Base | Base released | Use for |
|---|---|---|---|
qwen-chat | qwen3.6:35b-a3b-coding NVFP4 | Apr 2026 | Daily driver. 8 K ctx, think off. ~34 tok/s. |
qwen-reason | qwen3.6:35b-a3b-coding NVFP4 | Apr 2026 | Multi-step reasoning. 64 K ctx, think on. |
qwen-hermes | qwen3.6:35b-a3b-coding NVFP4 | Apr 2026 | Hermes Agent default. 64 K ctx, tool-call sampling. |
qwen-coding-fast | qwen3.6:35b-a3b-coding NVFP4 | Apr 2026 | Long-context refactors. 32 K ctx, 16 K predict. |
gemma-chat | gemma4:26b-a4b NVFP4 | May 2026 | Prose, alternate voice. ~27 tok/s. |
gemma-reason | gemma4:26b-a4b NVFP4 | May 2026 | Tiebreaker vs qwen-reason. |
gemma-agent | gemma4:26b-a4b NVFP4 | May 2026 | Former hermes default. 256 K max ctx. |
Stack: MFLUX (MLX-native FLUX/Qwen-Image/Z-Image port) at ~/.local/bin/mflux-*, weights cached
under ~/.cache/huggingface/hub/, output to ~/imagen/. Step-distilled diffusion
(4 steps, guidance 1.0, no negative prompt) dominates on Apple Silicon.
| Model | Released | Params | Disk | Peak RAM | Per image | Verdict |
|---|---|---|---|---|---|---|
| FLUX.2 Klein 4B | Jan 2026 | 4 B | 22 GB | 6–8 GB | 60 s | Skill default. Co-runs with LLM hot. |
| FLUX.2 Klein 9B MLX-Q4 | Jan 2026 pre-quant Apr 2026 | 9 B | 8.9 GB | 12–16 GB | 115 s | Quality tier. Requires LLM eviction. |
| Z-Image-Turbo | Nov 2025 | 6 B | 5.5 GB | — | 218 s | Deleted. Beat on speed/quality curve by Klein 9B. |
| Qwen-Image-2512 | Dec 2025 | 20 B | 24 GB | swap-bound | 1,300 s | Deleted. Best text rendering — but 22 min/image. |
| FLUX.1-dev | Aug 2024 | 12 B | Download stalled overnight repeatedly. Abandoned for Klein. | |||
| HiDream-I1 | May 2025 | 17 B | Too tight on 32 GB; marginal gain over Klein 9B. Not pursued. | |||
Klein 9B's pre-quantized MLX-Q4 build is smaller on disk than Klein 4B's FP16 (8.9 GB vs 22 GB) but produces visibly sharper output. The size flip is because Klein 4B ships at full precision and quantizes at runtime via -q 4, while Klein 9B was pre-quantized by the community uploader. Do not pass -q 4 to Klein 9B — re-quantizing already-quantized weights degrades them measurably.
Klein 4B (~6–8 GB peak) fits alongside gemma-hermes at 65 K context (~16–18 GB). Klein 9B (~12–16 GB peak) does not. The Hermes skill at ~/.hermes/skills/creative/mflux-local-images/SKILL.md issues ollama stop gemma-hermes before Klein 9B runs and lets the proxy's keep_alive ping reload the LLM on the next turn.
Klein is trained on natural-language descriptive prose, not tag soup. Push toward photo: camera + lens ("shot on Sony A7R V, 85mm f/1.4"), light ("golden hour", "overcast diffused"), texture ("skin pores visible", "fabric weave", "film grain"), genre ("candid photograph", "documentary"). Avoid CGI tells: "8k", "masterpiece", "highly detailed", "cinematic", "trending on artstation". FLUX.2 has no negative-prompt support — express exclusions in the positive prompt.
The use case: detect verse/chorus/bridge boundaries and label them for the Shreddy iPad practice app. A multi-model bake-off ended in an unexpected place — a 2.97 GB specialist transformer beat every general-purpose LLM and audio LLM we tried.
| Approach | Released | Verdict |
|---|---|---|
| Gemini 2.5 Flash · audio-native, cloud | Jun 2025 | Strong labels but hit the free-tier 250 K-token/day cap at ~32 songs. Paid is ~$0.002/song — still cloud, still rate-limited, still external dependency. |
| Claude Vision · on spectrogram screenshots | — | Worked but noticeably worse than audio-native LLMs. Spectrograms throw away too much signal. |
| Gemma 4 e4b · local audio LLM | May 2026 | Collapsed every section to "chorus". Unusable. Other small audio LLMs equally weak. |
| Qwen2.5-Omni · local audio LLM | Mar 2025 | Not loadable — mlx-vlm has no handler as of June 2026. mlx-lm-omni has API rot. |
| librosa HPSS + bar-snap · DSP only | — | Surprisingly good boundary detection — 9 musically-sensible cuts on a Seether track. Fully local. But cannot label sections, just finds the cuts. |
| SongFormer · specialist transformer | Oct 2025 | Winner. 2.97 GB safetensors. MuQ SSL encoder + structure transformer. Beats Gemini 2.5 Pro on SongFormBench. 8-label vocab (intro, verse, chorus, bridge, inst, outro, silence, pre-chorus). Seconds per song on MPS. |
| Music Flamingo 8B · NVIDIA, GGUF | Apr 2026 | Kept on watchlist for narrative reasoning, but NVIDIA noncommercial license blocks commercial use. |
This was the surprise of the whole project. We assumed an audio LLM would win — they're the new shiny — but a 2.97 GB specialist transformer trained on the actual task crushed both audio-native LLMs and image-vision LLMs operating on spectrograms. SongFormer's deterministic output (identical labels on CPU and MPS) is also operationally easier than any LLM call.
Shreddy now ships with SongFormer in a Python 3.11 venv (the deps don't all support 3.14), patched model in the project tree at apps/data/models/songformer/, helper module at apps/scripts/songformer_inference.py. The librosa BPM/key/beats path runs unchanged in parallel. Anthropic and Google API key fields were deleted from the settings UI — they're no longer needed.
Not installed today, but worth re-evaluating when their tooling or licensing changes. Each row names the specific gate that's blocking adoption.
| Model | Released | Why we're watching | What needs to change |
|---|---|---|---|
| GLM-4.5-Air | Jul 2025 | Best published BFCL tool-call score (76.7%; Qwen is 75.7%) | Needs a clean NVFP4 MLX build. Community GGUFs are ~25–30% slower on this rig. |
| Qwen3.6 with native MTP | Apr 2026 | 1.4–1.6× decode on M4 Pro for dense 27 B per the spec | mlx-lm PR #990 must merge into a release. No released runtime supports qwen3_5_moe native MTP today. |
| MTPLX MoE backend | May 2026 | 1.71× verified on dense 27 B on this rig; awaiting MoE MTP-head support. | youssofal/MTPLX#87 — needs a qwen3_next_moe_mtp backend for 46-tensor MoE heads. |
| Gemma 4 vision via rapid-mlx | May 2026 | 26B-A4B QAT already wins vision; would want the 12 B's gemma4_unified path too. |
mlx-vlm 0.6.1 supports it but needs newer mlx-metal than brew supplies. Brew installs without a RECORD file, blocking pip upgrades. |
| Nemotron-3-Nano 30B-A3B | Mar 2026 | Ties Qwen3.6 on decode (41.8 vs 41.5 tok/s) and tool fidelity (7/7). | Nothing — viable drop-in. Kept installed as backup; no reason to switch from a working setup. |
| Music Flamingo 8B | Apr 2026 | Could complement SongFormer with narrative/genre/mood description. | NVIDIA noncommercial license — deal-breaker if Shreddy ever ships commercially. |
| Qwen2.5-Omni / mlx-lm-omni | Mar 2025 | The "general local audio LLM" slot is still vacant. | mlx-vlm needs a Qwen2.5-Omni handler. mlx-lm-omni's API needs stabilizing. |
| Qwen3-Next 80B | Feb 2026 | Would lift the coding ceiling — if it fit. | 42 GB at 4-bit exceeds 32 GB unified. Hard hardware ceiling — needs a 64 GB box. |
The biggest realization from six months of benching: we are at the throughput ceiling for this hardware, and the levers people reach for don't move it. Here's the physics, summarized.
On a 3 B-active MoE at 4-bit, generating one token requires reading roughly 1.5 GB of weights through memory. Apple's M4 mini has ~120 GB/s bandwidth. The arithmetic ceiling is 120 / 1.5 ≈ 80 tok/s; runtime overhead and KV-cache reads halve that to ~40 tok/s. Every 3 B-active MoE we tested clusters at 34–42 tok/s — Qwen, Nemotron, Gemma, GLM, all land there.
Decode reads only the active experts (~3–4 B params) regardless of total size. Prefill on Apple Silicon also scales with active-param count, not total. That's why the 26B-A4B QAT does long-doc summarization 3× faster than the dense 12 B Gemma — same prefill cost as a 4 B model, judged quality of a 26 B.
Speculative decoding gives 1.4–1.7× on dense models — we measured 1.71× on Qwen3.6-27B-dense via MTPLX on this exact box. But its payoff scales with per-token compute, and a 3 B-active MoE is already compute-light. Grafted MTP on Qwen3.6-35B-A3B at depth 1 / 2 / 3 gave 0.94× / 0.73× / 0.58× — speculative makes the MoE slower. Confirmed by mlx-lm PR #990's author independently.
Tried Unsloth's UD-3-bit Qwen3.6-35B-A3B expecting a decode win. Got 34.7 tok/s vs uniform 4-bit's 41.5. The "3-bit" UD quant is mixed-precision: 270 layers at 8-bit, only 117 at 3-bit. In byte terms it's heavier than uniform 4-bit, and mixed-precision dequant kernels add overhead. MLX's 4-bit kernel is also far more optimized than its 3-bit path.
Of all the sampling/runtime tweaks tested, only one moves wall-clock by a factor of five. Disabling thinking on Qwen3.6 cuts a 293 s response to 55 s with no decode-rate change — the model just writes 1,900 tokens instead of 9,500. Everything else (num_ctx, num_predict, temperature, sampling) is in the 1.0–1.5× range.
Even with NVFP4 quantization, the largest model that comfortably fits with a usable context window and KV cache is ~26 GB resident. Qwen3-Coder-Next at 42 GB is a hard out. Mixing two large models hot (e.g. gemma-hermes + Klein 9B image gen) requires explicit eviction. This isn't tunable — it's the hardware ceiling. A 64 GB box would unlock 80 B-class models; a 32 GB box won't.
For text on this rig, Qwen3.6-35B-A3B-4bit at ~41 tok/s on rapid-mlx (or ~34 tok/s on Ollama-MLX) sits at the MLX throughput ceiling. There is no free throughput lever. Revisit only if (a) PR #990 ships and a higher-compute MoE appears, or (b) we upgrade the box.
Caveats up front so the numbers above don't get used in ways they don't support.
Every script that produced a number on this page is checked into ./bench/. Walk-through and run instructions in the bench/README.
| Script | What it measures |
|---|---|
bench_3axis.py | Reasoning + vision + long-doc decode/TTFT against rapid-mlx /v1. Streams SSE, captures content + reasoning. |
judge_3axis.py | LLM-as-judge wrapper around the local claude -p CLI. Scores 1–5 against a rubric. |
bench_toolcall.py | 7-case single-turn function-calling suite + cold prefill on a Hermes-sized prompt. |
bench_server_ttft.py | Cold-prefill TTFT on a ~13 K-token system prefix. |
bench_gemma_swap.py | GGUF q8_0 vs NVFP4 MLX delta on a single coding prompt against Ollama. |
bench_qwen_hermes.py | Tool-call sampling sweep validating the Qwen team's published recipe. |
local_bench_mlx.py | 5-prompt coding bench against Ollama's MLX backend. |
gemma4_mlx_bench.py | Original Gemma 4 12 B MLX harness (pre-26B-QAT generation). |
Raw run JSON and the markdown reports the post draws from are in bench/results/:
REPORT.md — original 3-axis run, Qwen3-14B vs Qwen3-VL-8B (2026-06-03)REPORT_v2_gemma4_vs_qwen3.md — Gemma 4 12 B vs Qwen3 head-to-head (2026-06-04)REPORT_v3_throughput_hermes.md — qwen-hermes / gemma-hermes throughput (2026-06-04)REPORT_v4_gemma4_26b_a4b_qat.md — Gemma 4 26B-A4B QAT NVFP4 across all axes (2026-06-06)Each *.json in the same directory has prompt, comp_tok, ttft_s, total_s, decode_tps, and the full streamed content — so any score can be re-judged with a different rubric or model.