Praxisartikel · KI & Automatisierung

MLX vs llama.cpp: Wer gewinnt auf Apple Silicon wirklich?

Gleiche Maschine, gleiches Modell, gleiche Agent-Aufgaben. Ein 10er Set realistischer OpenCode-Sessions hat eine unbequeme Antwort geliefert: Speed ist nicht der Entscheider. Memory-Struktur und Context-Headroom sind es.

April 2026 Qwen3.6-35B · Gemma-4-26B · M4 Pro 48 GB v6 OpenCode-Benchmark
Zwei Vintage-Beige-Computer mit CRT-Monitoren beim Armdrücken auf einer Holz-Werkbank — links 'MLX' in grüner Terminal-Schrift, rechts 'LLAMA', warmes Workshop-Licht
±6 %

Speed-Differenz MLX vs llama.cpp

Bei gleicher KV-Bit-Tiefe (q8) auf identischen Agent-Fixtures. Innerhalb der normalen Run-zu-Run-Varianz — faktisch Parität.

2,2×

Preis der KV-Quantisierung

q8-KV gegenüber fp16-KV kostet in beiden Backends denselben Speed-Faktor. Der Preis liegt in der Bit-Tiefe, nicht im Framework.

~3×

mehr Context bei gleichem Budget

Mit q8-KV verdoppelt, mit 3-bit TurboQuant (Qwen-Familie) verfünffacht sich der nutzbare Context im selben GPU-Memory-Fenster.

Seit einem Jahr ist llama.cpp mein Default-Backend für lokale LLMs auf Apple Silicon. Gute Gründe: stabile KV-Cache-Wiederverwendung zwischen Requests, N-gram Lookup Decoding, Speculative Decoding mit Draft-Modell. Alles Features, die Agent-Workloads real schneller machen.

Parallel entwickelt Apple mit MLX eine eigene Inferenz-Runtime, näher an Metal, mit Unified-Memory-Modell. Die intuitive Erwartung: schneller. Die ständige Gegenfrage: was verliere ich, wenn ich wechsle?

Ein Forschungs-PR (ml-explore/mlx-lm#1059) brachte eine zusätzliche Zutat ins Spiel: TurboQuant / PolarQuant — KV-Cache-Kompression auf 2 bis 4 Bit. Das verändert den Vergleich grundlegend.

Dieser Artikel zeigt, was nach einem Tag Benchmark und einer Produktiv-Session übrig bleibt — und wo die ehrlichen Grenzen liegen.

Test-Setup

Hardware M4 Pro · 48 GB Unified Memory
Modelle Qwen3.6-35B-A3B · Gemma-4-26B-A4B
Harness OpenCode v6 · 5 reale Fixtures
Metrik Wallclock · Oracle PASS/FAIL
Kein Benchmark Keine synthetischen t/s

Messung gegen echte Agent-Workloads: Debug, Architektur-Entwurf, Constraint-Solving, Ambiguity-Probe.

Abschnitt 1 · Das Kernergebnis

Gleiche KV-Bit-Tiefe, gleiche Speed

Wer MLX vs llama.cpp bei identischer KV-Quantisierung misst, findet keinen signifikanten Geschwindigkeitsunterschied. Die populäre Erwartung, MLX sei auf Apple Silicon per se schneller, hält dem Praxis-Test nicht stand.

Benchmark Gemma-4-26B auf M4 Pro

Die llama.cpp-Baseline lief mit fp16-KV-Cache (Default). Für einen fairen Vergleich haben wir llama.cpp zusätzlich mit q8-KV neu gebencht — das ist die KV-Quantisierung, die MLX standardmäßig nutzt. Ergebnis: beide Backends auf q8-KV sind auf allen vier vergleichbaren Fixtures innerhalb von ±6% gleich schnell. Was auffällt: Der q8-Switch selbst kostet in beiden Backends je ~2.2× Speed gegenüber fp16.

Fixture ccp · fp16 KV (Baseline) ccp · q8 KV (fair) MLX · q8 KV
v6-ambiguity-probe 14,4 s 31 s 33 s
v6-architecture-choice 22,7 s 45 s 46 s
v6-custom-constraint 8,4 s 28 s 35 s
v6-debug-unmarked 16,3 s 31 s 29 s
Summe (4 direkt vergleichbar) 61,8 s 135 s 143 s

Alle Runs: 5/5 PASS. Oracle-Validierung per Fixture-Script. Wallclock aus Runner-Log.

Abschnitt 2 · Wo der Unterschied liegt

Nicht Geschwindigkeit — Context-Headroom

Wenn Speed bei identischer KV-Quant gleich ist, verschiebt sich die Entscheidung auf die Frage: Wieviel Context passt bei gleichem GPU-Memory-Budget? Dort öffnet sich der eigentliche Abstand.

KV-Variante MB pro 1k Tokens Max Context · 6 GB KV-Budget Max Context · 12 GB KV-Budget
fp16 (llama.cpp Default) ~92 MB ~65 k ~130 k
q8 (MLX oder llama.cpp) ~46 MB ~130 k ~260 k
3-bit TurboQuant (nur Qwen, Fork) ~18 MB ~330 k ~650 k

Werte gerechnet für Gemma-4-26B (46 Layer, kv_dim ~1024). SWA-Full-Modus (Gemma-spezifisch, schützt Context-Kontinuität bei Sliding-Window-Attention) bringt einen Multiplikator obenauf; die Verhältnisse zwischen den Quants bleiben.

Plastisch gemacht

Wo llama.cpp mit fp16-KV bei 65k Tokens anstößt, schafft dasselbe Modell mit q8 bereits 130k, und für die Qwen-Familie mit 3-bit TurboQuant über 300k — im selben Speicherbudget. Für Agent-Sessions mit wachsendem Kontext, für lange Dokument-Pipelines, für Coding-Agenten mit vollem Projekt-Context: genau dort entscheidet sich Brauchbarkeit.

Abschnitt 3 · Der zweite Unterschied

Memory-Verhalten, nicht Memory-Menge

Der interessantere Unterschied zwischen beiden Backends zeigt sich nicht in Steady-State-Messungen, sondern unter Druck — wenn ein zweiter Prozess das GPU-Budget reißt.

llama.cpp hält Metal-Working-Set durchgehend wired. Bei Memory-Druck: Metal-OOM oder der bekannte ggml_metal_rsets_free-SIGABRT beim nächsten Shutdown. Aus erster Hand: ein ganzer Vormittag in dieser Diagnostik-Tiefe verbracht.

MLX allokiert on-demand, gibt zwischen Requests wieder frei. Bei Druck fällt macOS in Swap, aber die Inferenz läuft weiter. Live beobachtet in einer Session, bei der Qwen3.6 einen OpenCode-Agent durchgeführt hat, während parallel ein Diffusion-Modell (mflux) ein Hero-Bild generiert hat — beide belegen zusammen mehr als das Metal-Budget hergibt. Keiner der beiden Prozesse ist abgestürzt. Swap hoch, Speed runter, Ergebnis korrekt.

Für Multi-Tool-Agent-Workloads ist das kein Nice-to-have. Es ist der Unterschied zwischen einem Prototyp, der auf dem Demo-Mac gelegentlich einfriert, und einem produktiv nutzbaren System.

Abschnitt 4 · Produktionsempfehlung

Was wir ab sofort produktiv einsetzen

Aus den Messungen und der Live-Session leitet sich eine differenzierte Empfehlung ab — nicht "MLX pauschal besser", sondern modellabhängig.

Modell

Qwen3.6-35B-A3B

Backend

MLX + TurboQuant-Fork

KV: 3-bit TurboQuant

Begründung

Massiv mehr Context, Memory-robust, paritätische Speed, Multi-Skill-Agent-Loops verifiziert.

Modell

Qwen3-Coder-30B-A3B

Backend

MLX + TurboQuant-Fork

KV: 3-bit TurboQuant

Begründung

Gleiche Qwen-Familie, gleiche Mechanik, hohe Wahrscheinlichkeit für identische Vorteile.

Modell

Gemma-4-26B-A4B-it

Backend

MLX mainline + Server-Patch

KV: q8

Begründung

TurboQuant-Fork kennt Model-Type gemma4 noch nicht — bis zum Upstream-Rebase ist q8-KV der Mittelweg: verdoppelt den ctx-Headroom, keine Quality-Regression.

Abschnitt 5 · Was der Test nicht misst

Ehrliche Grenzen dieses Vergleichs

Keine Perplexity-Sweeps. Wir haben 10/10 PASS — aber keine statistische Proxy-Metrik für Text-Qualitätsdrift bei aggressiver KV-Quantisierung. Das wäre ein eigenes Folge-Experiment.

Kein Stresstest bei ctx 131k. Die Hochrechnungen der Context-Budgets sind theoretisch plausibel, aber empirisch nicht bis an die Grenze getrieben.

Prompt-Cache-Reuse in MLX — einer der ursprünglichen Gründe für unseren llama.cpp-Default — haben wir nicht isoliert gemessen. mlx-lm 0.31 hat solche Pfade, aber wie performant sie gegen llama.cpp sind, steht noch aus.

Speculative Decoding mit Draft-Model funktioniert in llama.cpp out-of-the-box. In MLX läuft es theoretisch auch — getestet haben wir es nicht.

Der TurboQuant-Fork ist experimentell. Er kennt Gemma-4 aktuell noch nicht, braucht zwei Eigen-Patches für Server-Betrieb, und ist bei Upstream noch nicht gemerged. Unsere Beiträge zum PR sind dokumentiert und eingereicht.

Referenzen · Offenes Material

Zum Nachbauen und Überprüfen

  • GitHub: ml-explore/mlx-lm#1059 — PolarQuant KV-Cache-Kompression, inkl. unserer Server-Integration-Diffs als Kommentar
  • GitHub: ml-explore/mlx#3404 — Ursprüngliches Feature-Request für quantisierte SDPA
  • Harness: v6 OpenCode-Benchmark-Suite mit 5 realen Agent-Fixtures, Oracle-basierte Validierung
  • Knowledge-Base (intern): mlx-turboquant-server-setup.md · mlx-vs-llamacpp-v6-vergleich.md