Die Gewichte für Qwen3.8-27B kamen am Morgen an, und am selben Tag begann ich ein Abenteuer mit Kimi K3 im Hochdenkensmodus. Ich startete das Ganze mit einer einzigen Frage: könnte dieses frische dichte 27B — leicht das stärkste offene Modell in seiner Größenklasse — meinen Coding-Agenten bei echter Geschwindigkeit auf einem Mac Studio mit einem M1 Ultra, 20 CPU-Kerne, 128 GB einheitlichem Speicher, und 800 GB/s Speicherbandbreite dienen? Allgemeines Wissen besagt, dass dichte Modelle auf Apple Silicon langsam decodieren, weil sie speicherbandbreitengebunden sind, und ich wollte herausfinden, ob dieser viel RAM und Bandbreite das Muster brechen könnte. Die 4-bit MLX-Gewichte kamen auf 15 GB, das Framework war aktuell, nichts anderes lief auf der Box, und die erste Zahl war 12.1 Tokens pro Sekunde. Es fühlte sich falsch.
Ich hatte diese Art von Experiment schon seit einer Weile im Kreis gedreht. Im März, arbeitend mit einer anderen KI in meinem autonomen Verfeinerungslabor, verfolgten wir eine Unter-20-tok/s-Wand für 30B-Modelle auf einem M4 Max zu Speicherbandbreitenknappheit durch OS-level Paging — und diese Untersuchung ließ ein Playbook zurück: powermetrics zuerst, per-Cluster-Sampling, Speicher-Pinning vor Schuldzuweisung. Der Lauf dieses Mal begann aus reiner Neugier: Ich hatte von Qwen3.8's Optimierungen gehört, und ich wollte wissen, ob es aus der Box auf diesem Gerät mit diesem viel RAM schnell laufen würde. Erst mitten im Experiment machte sich die speicherbandbreitengebundene Realität bemerkbar. Was folgte, war ein Sprint kontrollierter Experimente, die wir gemeinsam entworfen haben — Kimi entwarf die Hypothesen und las die Hardwarezähler an meiner Seite, während ich meine Hände auf dem Metall hielt. Jedes Experiment wurde gebaut, um eine einzelne Schicht des Stacks zu befreien oder zu verurteilen. Die Siege kamen von 2 Orten, die lokale Inferenz-Folklore unterbewerten: CPU-Scheduler-Hinweise und spekulatives Decodieren. Die 2 modischen Alternativen — ein GGUF-Build, bedient von llama.cpp, und ein Mixture-of-Experts-Modell, das auf dem Papier unschlagbar schien — verloren beide bei der Messung. Dieser Artikel ist der vollständige Beweispfad, den wir gemeinsam aufgebaut haben, weil die Methode sich als wertvoller erwies als jede einzelne Zahl.

Das Netzwerk-Relay und der Server waren die ersten Verdächtigen, und beide waren unschuldig

Der Serving-Pfad hatte 3 Hops: mein Arbeitsplatz, ein SSH-basiertes Exec-Relay und der Modell-Server auf dem Loopback des Studios. Das Relay zu beschuldigen wäre einfach gewesen, also haben wir es zuerst gemessen. Die eigenen Zeitmessungen des Servers sagten 12.1 tok/s Dekodierung; ein rohes In-Process-Generierungsbenchmark, ohne Server und ohne Relay, produzierte 11.5 tok/s. Der Transport kostete etwa 25% pro Verbindung, und das Modell selbst war die langsame Schicht.
Ein Transportfehler war sowieso zu beheben, und es ist die Art von Detail, das Stunden kostet, wenn man es noch nie gesehen hat: ein Python TCP Relay, das einen gepufferten read(65536) verwendet, wird bei einem chatten lokalen Protokoll blockieren, weil der gepufferte Leser auf einen vollen Puffer oder EOF wartet, bevor er zurückkehrt. Der Wechsel zu read1(), das nach einem einzigen zugrunde liegenden Lesevorgang zurückkehrt, ließ das Relay funktionieren. Das Symptom sah aus wie ein Netzwerk-Stop; die Ursache war stdio-Semantik.
Mit dem Transport freigesprochen, haben wir die übliche sysctl-Schicht durchgearbeitet. Das Erhöhen des GPU-Wired-Memory-Limits (iogpu.wired_limit_mb) änderte nichts bei 128 GB freiem RAM, also haben wir es zurückgesetzt. Der Python Prozess war native arm64, MLX meldete die GPU als ihr Standardgerät, und powermetrics zeigte die GPU bei 54-62% aktiver Belegung, die 20-23 W während der Dekodierung verbraucht. Jeder Verdächtige in dieser Runde ging frei — was selbst das nützliche Ergebnis war, weil es die Untersuchung auf die CPU lenkte.

Der Scheduler hatte die Inferenz auf die Effizienzkerne gelegt

powermetrics pro CPU-Cluster statt pro Maschine zu lesen, offenbarte die erste echte Erkenntnis. Während des Decodes liefen die Effizienzcluster bei 75-93% beschäftigt, während die Performancecluster bei 1-12% idle waren. Alles, was über SSH gestartet wurde, erbt eine Quality-of-Service-Klasse, die macOS als Arbeit mit niedriger Priorität liest, und der Scheduler honorierte diesen Hinweis, indem er eine latenzkritische Arbeitslast auf die langsamen Kerne hielt.
Die Lösung war 1 Zeile von ctypes, ausgeführt bevor die Modellgewichte geladen wurden:
python
import ctypes
ctypes.CDLL("libSystem.B.dylib").pthread_set_qos_class_self_np(0x21, 0) # QOS_CLASS_USER_INTERACTIVE
Diese Pin, plus das Laden der Texttür des Modells über mlx-lm statt über den vollständigen Vision-Stack, verschob das rohe Decode von 11,5 auf 15,1 tok/s — ein Gewinn von 31 % durch Scheduler-Platzierung und einen schlankeren Loader, ohne Änderungen am Modell. Später erkannten wir, dass die Reichweite der Pin ein Limit hat: sie verschiebt den aufrufenden Thread, und die MLX-Worker-Threads behalten ihre eigene Scheduling-Klasse. Für dieses Modell trug der Hauptthread genug Arbeit, um zu zählen.

Spekulatives Dekodieren lieferte den Sprung, den kein sysctl erreichen konnte

Der größte einzelne Gewinn kam von einer Funktion, die das Basismodell bereits besaß. Qwen3.8 wird mit einem Multi-Token-Prediction-Head ausgeliefert – ein kleines Hilfsmodul, das mehrere Tokens vorausplant – und der MLX-Converter lässt diese 15 Tensoren während der Konvertierung stillschweigend fallen. Ein Community-Paket hostet den Head als eigenständigen 253 MB-Drafter, was mir ermöglichte, ihn wieder mit dem Modell zu koppeln, für das er trainiert wurde.
Das Serving-Muster ist Draft-then-Verify: der Drafter schlägt ein paar Tokens vor, das vollständige Modell prüft sie in einem 1 Durchlauf, und akzeptierte Tokens zählen alle. Mit --draft-model und --draft-kind mtp auf dem Server wurde die Draft-Akzeptanz bei realistischen Coding- und Chat-Prompts mit 94% gemessen, und die Dekodierung ging von 15,1 auf 20,3 Tokens/s serverseitig – 13,4 Tokens/s End-to-End über das Relay, anstatt 9,0. Die GPU erzählte die bestätigende Geschichte: 77% aktive Residency, alles bei voller 1296 MHz, verbrauchte 48 W, wobei der Performance-Cluster 97% ausgelastet war. Prefill verbesserte sich in demselben Upgrade von 14.7 Tokens/s auf 18-55 je nach Prompt-Form.
Decode speed by configuration (tok/s, M1 Ultra, 27B-4bit)
Chart data
tokens per second
MLX stackllama.cpp Q4_K_M
raw stack11.59.2
+ text tower13.6
+ QoS pin15.1
+ MTP drafter20.312.2

Der GGUF-Herausforderer verlor um 40%

Community-Posts setzen llama.cpp mit einem spekulativen Draft bei 25-32 tok/s für diese Modellklasse auf M1 Ultra, deutlich vor unseren MLX-Zahlen, sodass wir dem Herausforderer einen fairen Ring gaben: das offizielle Q4_K_M GGUF, ein passendes MTP-Only-Draft-Modell, und ein aktuelles llama.cpp-Build mit aktivem Metal-Acceleration bestätigt. Die GGUF-Lane maß 9.2 tok/s Baseline und 12.2 mit dem Draft – etwa 40% hinter dem MLX-Stack, den es zu stürzen vorgab.
llama.cpp bleibt exzellente Technik; die Lücke liegt wahrscheinlich darin, wie die Metal-Kernel jedes Laufzeitumfelds diesen Checkpoint auf diesem Chip behandeln. Die dauerhafte Lektion ist einfacher: eine Zahl, die jemand anders an seiner Maschine, seinem Build und seinem Checkpoint gemessen hat, ist eine Hypothese über deine. Die 18 GB Challenger-Gewichte verließen die Maschine am selben Nachmittag, und die 50 MB llama.cpp-Binary blieb für zukünftige Rematches. Ich habe diese Regel schon einmal als benchmark-driven development beschrieben – sie trug SEOReport from heuristics to a product – und hier sparte sie eine Migration.

Ein 3B-aktiver MoE hätte gewinnen sollen, und der GPU-Meter erklärte den Verlust

Der letzte Herausforderer hatte die stärkste Theorie — das gleiche allgemeine Wissen, das wir zu Beginn testen wollten. Dichte Modelle dekodieren langsam auf Apple Silicon, weil jeder generierte Token fast alle Gewichte lesen muss; ein Mixture-of-Experts-Modell mit 35B Gesamtparametern aktiviert nur etwa 3B pro Token, sodass es auf einer Bandbreiten-beschränkten Maschine mehrere Male schneller dekodieren sollte als ein dichtes 27B — jeder Token liest etwa 11 % der Gewichte. Wir haben das 4‑Bit MoE und seinen passenden MTP‑Entwurf heruntergeladen, den Server aufgeheizt und 14,7 tok/s Roh gemessen: die gleiche Geschwindigkeit wie das dichte Modell, das es zu demütigen sollte. Mit spekulativem Decoding erreichte es 19 tok/s bei realistischen Prompten und 26.3 bei hochvorhersehbarem Text — ein Ausgleich zum dichten Modell 20.3, ohne Qualitätsargument, das das Gleichgewicht brechen könnte.
powermetrics identifizierte das Regime in 1 Probe. Während des MoE Decodings blieb die GPU bei 0‑3 % aktiver Belegung, während die Effizienz‑Cluster bei 60‑90 % abkühlten. Das Modell verwendet sein pro‑Token-Budget für CPU‑seitige Arbeit, und die operationelle Zeitmessung zeigte, warum: jede ausgelöste Operation kostet 50‑100 µs Overhead, und diese hybride Architektur — GatedDeltaNet lineare Aufmerksamkeit plus 256 Experten hinter einem kleinen 2048‑breiten versteckten Zustand — führt ungefähr 78 Operationen pro Schicht über 40 Schichten aus. Bei Batch‑Größe 1 beendet die GPU jeden winzigen Kernel, bevor die CPU den nächsten einreihen kann. Die Maschine war dispatch‑gebunden, und dispatch‑gebundene Workloads profitieren nicht davon, weniger Gewichte pro Token zu lesen.
Diagram source
graph TB
    A[Langsames Decoding  
bei Batch 1] --> B{GPU beschäftigt  
während Decoding?}
    B -->|ja| C[Bandbreiten‑gebunden  
weniger Bytes gewinnen]
    B -->|nein| D[Dispatch‑gebunden  
weniger Operationen gewinnen]
    C --> E[MoE hilft  
kleinere Quantisierung hilft]
    D --> F[Spekulatives Decoding  
hilft am meisten]

    style E fill:transparent,stroke:#10B981,stroke-width:2px
    style F fill:transparent,stroke:#3B82F6,stroke-width:2px
Um den Kreis zu schließen, haben wir bewiesen, dass der GPU‑Pfad selbst gesund war, mit einem synthetischen Hoger: eine 8192³ Matrix‑Multiplikationsschleife erreichte 10,8 TFLOPS in bfloat16 mit der GPU bei 97‑100 % Belegung und 68 W. Externe Beweise stimmten mit der lokalen Diagnose überein — unabhängige Schätzungen setzen diese MoE‑Klasse nahe 21,7 tok/s auf einem M2 Ultra, und ein OpenVINO‑Problem dokumentiert dasselbe Modell, das bei Backends mit schwächeren Dispatch‑Pfaden gegen ein dichtes 8B verliert. Die dichte 27B mit ihrem MTP-Entwurf behielt den Produktionsslot, und 38,5 GB von MoE Gewichten wurden am selben Abend gelöscht.
GPU active residency during decode (powermetrics, %)
Chart data
GPU active residency (%)
dense 27B + MTP77
MoE 35B-A3B2
matmul hog test100

Was 5 kontrollierte Experimente zurückgelassen haben

Die Maschine liefert jetzt Qwen 3.8-27B bei 20.3 tok/s serverseitig, ein 68%-Verbesserung gegenüber dem Start des Tages, und die dauerhaftere Rendite ist eine Checkliste, die wir bei jedem zukünftigen Gerät wiederverwenden werden:
  • Decode bei Batchgröße 1 hat 2 Regime, bandbreitenbeschränkt und dispatch-beschränkt, und eine 2-Sekunden-powermetrics-Probe identifiziert deine, bevor du einen Download für die falsche Fixierung ausgibst.
  • Spekulatives Dekodieren ist der höchstwirksame Serving-Knob für ein einzelnes Benutzergerät. Es fügte hier 34% hinzu und verstärkt sich mit jeder anderen Optimierung, weil Verifikationsbatches die GPU nutzen, während der Drafter die Leerlaufintervalle aufnimmt.
  • Scheduler QoS ist ein echter Inferenzparameter auf macOS. Alles, was über SSH gestartet wird, sollte seine Threads absichtlich anheften, und die Wirkung des Anhaftens ist pro Cluster verifizierbar und nicht nur durch Stimmung.
  • Community-Throughput-Anforderungen übertragen sich schlecht über Checkpoints, Builds und Chips. Ein lokaler Benchmark ist günstiger als eine Migration.
  • Löschung ist Teil des Workflows. Jeder Herausforderer, der verlor, ließ den Speicher innerhalb des Tages, was das nächste Experiment ehrlich hält und die Maschine schlank macht.
Der befriedigende Teil dieses Abenteuers ist, dass die Antworten alle in den Hardwarezählern lagen, wartend darauf, dass jemand präzise Fragen stellt — und diesmal haben wir sie gemeinsam gestellt. Ein lokales Modell, das du gemessen hast, ist mehr wert als ein größeres Modell, das du geschätzt hast — die gleiche aufkommende Rendite, die ich erhalte, wenn ich lokale KI-Gewinne als Infrastruktur statt Trivia behandle. Ich habe das Ganze am Morgen gestartet, als die Gewichte landeten, und Kimi K3 blieb im Kampf für jedes Experiment, jeden Zählerlesung, und diese Zusammenfassung aus den Labornotizen desselben Abends. Das nächste Experiment ist bereits in der Warteschlange: kompilierten Dekodierungsgraphen versprechen, die pro-Operation-Dispatch-Kosten zu reduzieren, die das MoE-Urteil entschieden haben, und wenn ein MLX-Release kommt, wird die Rematch einen Nachmittag und 1 Download dauern.