Files
DS4Server/MOJO.md
2026-08-29 18:53:28 +02:00

60 KiB

Rust- und Mojo-Umbauplan für die Inferenz

Stand: 29. August 2026

Kurzurteil

Das Ziel ist realistisch, aber nicht als mechanische Übersetzung der .metal-Dateien. Realistisch ist eine Architektur, in der Rust weiterhin Modellformat, Ausführungslogik, Tokenverarbeitung, Sessions, Sampling und Checkpoints besitzt, während Mojo den kompletten GPU-Ausführungspfad übernimmt und aus derselben Quellbasis zielabhängige Metal- oder CUDA-Artefakte erzeugt.

Eine einzige, auf beiden Plattformen identische Modellimplementierung ist erreichbar. Vollständig identische Kernel ohne Hardware-Spezialisierung sind dagegen kein sinnvolles Ziel: Apple-GPUs und NVIDIA Blackwell unterscheiden sich bei Matrixeinheiten, Speicherhierarchie, Synchronisation und optimalen Tile-Größen. Die gemeinsame Mojo-Quelle muss deshalb generische Modellalgorithmen mit kleinen, zur Compile-Zeit gewählten Architektur-Policies kombinieren. Erlaubt sind hardwarespezifische Tiles, MMA-Intrinsics und Launch-Strategien; vermieden werden zwei getrennte Metal- und CUDA-Modellpfade.

Dass Mojo auf beiden Plattformen nicht langsamer als der jeweilige native Referenzpfad ist, kann vorab nicht garantiert werden. Es ist jedoch ein realistisches Entwicklungsziel, weil Mojo Apple- und NVIDIA-GPUs unterstützt und MAX bereits viele benötigte Attention-, KV-Cache-, MoE-, Quantisierungs- und Matrix-Primitiven enthält. Das größte technische Risiko sind die DS4-spezifischen Quantisierungsformate und die stark fusionierten DeepSeek-/GLM-Kernel. Sie benötigen voraussichtlich eigene Mojo-Kernel und eine iterative Optimierung auf beiden Architekturen.

Der Umbau darf deshalb nur stufenweise erfolgen. Der bestehende native Metal-Pfad bleibt während der gesamten Migration verfügbar. Auf DGX Spark muss zusätzlich ein reproduzierbarer nativer CUDA-Referenzpfad bereitstehen. Nach der ersten vollständig verifizierten DeepSeek-Implementierung folgt Qwen3.8-27B als zweite Modellstufe. Erst nach bestandener Korrektheits- und Performance-Matrix darf Mojo der Standard werden oder ein Referenzpfad entfernt werden.

Nicht verhandelbare Ziele

  1. DS4 bleibt das Verhaltensorakel. Tokenfolge, Tokenverarbeitung, Kontextzählung, KV-Cache-Verhalten, Checkpoint-Semantik und Modellausführung dürfen sich nicht ändern.
  2. Das Zielprodukt ist eine Rust- und Mojo-Anwendung. Bestehende native Implementierungen sind während des Umbaus nur Referenz- und Rückfallpfade, nicht die zukünftige Architektur.
  3. Eine Mojo-Modellimplementierung muss aus derselben Quelle für Apple Metal und NVIDIA CUDA gebaut werden. Zielabhängige Compile-Time-Spezialisierungen innerhalb dieser Quelle sind ausdrücklich notwendig.
  4. Es darf keinen stillen Fallback und keine Mischung von nativen und Mojo-Kerneln in einem Benchmarklauf geben.
  5. Korrektheit wird vor Performance geprüft. Ein schnellerer Pfad mit abweichender DS4-Semantik ist nicht akzeptabel.
  6. Das Performanceziel lautet auf jeder Hardware separat: Mojo ist bei der End-to-End-Inferenz mindestens so schnell wie der dortige native Referenzpfad. Mac und DGX Spark werden nicht gegeneinander bewertet.
  7. Jeder tatsächlich verwendete Inferenzbaustein erhält einen isolierten Korrektheits- und Performancevergleich. Zusätzlich folgt ein vollständiger Modellvergleich beider Pfade.
  8. DS4Server bleibt so weit wie technisch möglich unter offenen, permissiven Lizenzen. Eigener Code bleibt MIT; bevorzugte Fremdkomponenten sind Apache-2.0-/LLVM-, MIT- oder BSD-lizenziert.
  9. Eine nur source-available oder anderweitig einschränkende Laufzeit darf weder verpflichtende Produktabhängigkeit noch Bestandteil eines Release-Artefakts werden, solange ihre konkrete Notwendigkeit, Redistributierbarkeit und eine offene Alternative nicht dokumentiert und vom Benutzer ausdrücklich freigegeben sind.
  10. Lizenzgrenzen werden am tatsächlich gelinkten und gebündelten Artefakt geprüft, nicht aus Paketnamen oder einzelnen Quellheadern abgeleitet.

Heutiger Ausgangspunkt

Der aktuelle Metal-Executor ist bereits an einer grundsätzlich geeigneten Grenze geschnitten:

  • Rust besitzt Modellzustand, Graph-/Ablauflogik, Sessions, Token- und Checkpoint-Verhalten.
  • src/engine/metal.rs bindet derzeit 19 Metal-Quelldateien ein.
  • src/engine/metal/gpu.rs deklariert derzeit 117 exportierte GPU-Operationsnamen.
  • Die Metal-Quellen umfassen zusammen ungefähr 21.700 Zeilen. Eine Eins-zu-eins-Portierung wäre deshalb teuer und würde Optimierungsentscheidungen der Metal-Implementierung unnötig konservieren.
  • src/engine.rs enthält bereits einen ignorierten Realmodelltest (metal_executes_real_flash_token), der Prompt, Logits, Argmax und Checkpoint-Wiederherstellung abdeckt. Er ist ein guter Ausgangspunkt, ersetzt aber weder Komponentenbenchmarks noch einen Backendvergleich.

Die bestehende Grenze soll beibehalten, aber gröber genutzt werden: Rust ruft nicht jeden elementaren GPU-Operator einzeln über die Sprachgrenze auf. Mojo soll zusammenhängende Operationen wie prefill, decode_step und gegebenenfalls verify besitzen und die zugehörigen Kernel, Streams/Command-Buffer und temporären Tensoren intern verwalten. Damit werden FFI- und Synchronisationskosten aus dem kritischen Pfad gehalten.

Ergebnis der Online-Recherche

Die folgende Bewertung basiert auf den zum Stichtag verfügbaren offiziellen Modular-Quellen. Vor der Implementierung sind Versionen und APIs erneut zu prüfen und anschließend fest zu pinnen.

Plattform und Compiler

  • Mojo nennt NVIDIA-, AMD- und Apple-GPUs als unterstützte Ziele. DGX Spark beziehungsweise sm_121 und Apple M1 bis M5 werden als bekannte kompatible Ziele geführt. Siehe Mojo system requirements.
  • Mojo kann GPU-Code zielabhängig für NVIDIA und Apple erzeugen; die Dokumentation beschreibt unter anderem PTX für NVIDIA und Apple-GPU-Ausgabe für Metal. Vollständig gelinkte Cross-Compilation ist weiterhin nicht der verlässlichste Weg. Praktisch werden daher aus derselben Quelle separate Artefakte auf beziehungsweise für jede Zielplattform gebaut. Siehe Mojo compilation.
  • DeviceContext stellt CUDA-, HIP- und Metal-Kontexte bereit. Siehe GPU fundamentals.

Damit ist „eine Quelle“ realistisch, „ein universelles Binärartefakt“ aber weder erforderlich noch als Projektziel sinnvoll.

Wiederverwendbare Mojo-/MAX-Bausteine

Benötigter Bereich Verfügbarer Stand Entscheidung für DS4Server
GPU-Kontext, Layouts, Speicher und Profiling Die MAX accelerator library enthält GPU-, Layout-, Linalg-, NN-, Quantisierungs-, KV-Cache- und Benchmark-Pakete. Apache-lizenzierte Quellen bevorzugt verwenden. DeviceContext und jede native Runtime erst nach dem Artefakt- und Lizenzaudit übernehmen; andernfalls den vorhandenen projektnativen Host-/GPU-Pfad als Laufzeitgrenze behalten. Keine allgemeine Ersatzlaufzeit auf Vorrat bauen.
Matrixeinheiten MAX bietet eine einheitliche MMA-Schnittstelle mit architekturspezifischen Implementierungen, einschließlich Apple-MMA und Blackwell/SM100. Als Basis nutzen. Tile- und Pipeline-Policies je Architektur zur Compile-Zeit wählen.
Attention Es existieren Flash-Attention-Kernel einschließlich KV-Cache- und Split-KV-Varianten sowie MHA-/MLA-Bausteine im NN-Paket. Zuerst benchmarken und anpassen. DS4s rohe, komprimierte und indexierte Attention sowie genaue Masken-/Cache-Semantik dürfen nicht als Drop-in-Kompatibilität angenommen werden.
KV-Cache Das KV-Cache-Paket enthält paged/sparse Cache- und Index-Remapping-Primitiven. Layout- und Remapping-Code wiederverwenden, wenn Byte-/Index-Semantik, Kontextzählung und Checkpoint-Restore nachweislich identisch bleiben. Das persistente DS4-Checkpointformat bleibt in Rust.
Norm, RoPE, Softmax, Top-k und MoE Die MAX-NN-Kernel decken diese Grundoperationen sowie gruppierte MoE-Pfade ab. Einzeln gegen die heutigen Operatoren prüfen; nur bei bestandener Parität übernehmen. Modellspezifische Fusionen bleiben wahrscheinlich eigener Mojo-Code.
GLM 5.2 MAX 26.5 nennt explizit GlmMoeDsaForCausalLM, GLM-5.2-MTP, Sparse-MLA-/Index-Sharing und GLM-Sparse-Attention-Korrekturen. Siehe MAX 26.5 release notes. Stärkster vorhandener Referenzpunkt. Modell- und Kernelquellen untersuchen und kompatible Bausteine übernehmen; DS4-Semantik nicht durch die MAX-Pipeline ersetzen.
Qwen3.8-27B Die offizielle Modellkarte beschreibt einen dichten 27B-Hybrid aus Gated DeltaNet und voller Attention, MTP, 262.144 nativem Kontext und Vision-Encoder. MAX hat den Qwen3.5-Unterbau einschließlich GPU-GDN-Kerneln und State-Cache bereits umgesetzt; siehe MAX Linear Attention/GDN tracking. Als zweite Modellstufe nach dem verifizierten DeepSeek-Basispfad einplanen. Gemeinsame Norm-, Matmul-, FFN-, RoPE-, Attention-, Cache- und MTP-Komponenten wiederverwenden; GDN, Conv-State und Vision klar getrennt ergänzen.
DeepSeek MAX dokumentiert DeepSeek V3/V3.2, MLA, Sparse Attention, MoE und Expert Parallelism. Siehe DeepSeek-V3 architecture und supported models. Als Vorlage für MLA/MoE verwenden. Für die von DS4Server verwendeten DeepSeek-Flash-/Pro-/V4-spezifischen HC-, Kompressor- und Indexerpfade wurde keine komplette fertige Mojo-Engine gefunden.
NVIDIA Q4-Matmul qmatmul_gpu enthält NVIDIA-GPU-Kernel für GPTQ-/Q4_0-artige 4-Bit-Matrizen. Siehe qmatmul_gpu. Nur für passende Layouts prüfen. Es deckt die DS4-Quantisierungsmatrix nicht vollständig ab.
Q4_K Ein Q4_KEncoding existiert, der dokumentierte matmul_Q4_K ist derzeit jedoch CPU-orientiert und schlägt für andere Ziele beim Kompilieren fehl. Nicht als vorhandene portable GPU-Lösung einplanen; eigener GPU-Kernel oder neuere offizielle Implementierung erforderlich.
IQ2_XXS, Q2_K, Q5_K, Q6_K, Q8_0 und gemischte Expert-Layouts In den geprüften offiziellen Quellen wurde keine vollständige, direkt nutzbare GPU-Abdeckung für die DS4-Kombination gefunden. Als kundenspezifische Mojo-Kernel budgetieren. Vor Beginn jeder Phase erneut im Modular-Repository suchen.
Benchmark-Hilfen MAX stellt GPU-Benchmark- und Profiling-Hilfen bereit. Für reine Kernelzeit verwenden, aber immer mit einem Rust-seitigen End-to-End-Harness und realen Modellmessungen paaren.

Der Quellcode der relevanten Pakete liegt im Modular-Repository, unter anderem für Flash Attention und Quantisierung. Eine vollständige fertige Mojo-Implementierung der von DS4Server verwendeten DeepSeek-V4-Engine wurde in den geprüften Primärquellen nicht gefunden. Für Qwen3.8-27B existiert noch kein geprüfter DS4Server-Drop-in-Pfad, aber die bereits ausgelieferten MAX-Qwen3.5-/GDN-Komponenten passen zur architektonischen Grundlage von Qwen3.8 und reduzieren das Risiko deutlich. Auch außerhalb der offiziellen Modular-Quellen ergab die Recherche keinen überzeugenden, gepflegten Komplettbaustein, der ohne die hier geforderten Paritätstests übernommen werden sollte.

DS4Server interessiert sich aus MAX nur für die Accelerator-Bausteine layout, linalg, nn, quantization, kv_cache, state_space, die benötigten max.gpu.compute-Primitiven und Entwicklungswerkzeuge für Benchmarking/Profiling. MAX Serve, Python-Modellpipelines, Modellregistry, REST-Server und allgemeine Graph-/Serving-Orchestrierung sind keine Zielabhängigkeiten.

Vor Übernahme muss geprüft werden:

  • welche Teile Quellcode, Bibliothek oder Laufzeitabhängigkeit werden sollen;
  • ob Lizenz und Redistribution von Compiler, Runtime und Bibliotheken zum Distributionsmodell passen;
  • welche konkrete Mojo/MAX-Version auf macOS und DGX Spark identisch reproduzierbar ist;
  • ob die benötigten APIs stabil genug sind oder in einer kleinen projektnahen Kompatibilitätsschicht gekapselt werden müssen.

Lizenz- und Offenheitsstrategie

Die aktuelle Lizenzlage ist komponentenbezogen:

  • Mojo 1.0 einschließlich Sprache, Compiler, Standardbibliothek und Werkzeugen ist laut aktuellem Modular-Lizenztext unter Apache 2.0 mit LLVM Exceptions veröffentlicht. Die LLVM-Ausnahme erlaubt, beim Kompilieren eingebettete Teile in Objektcode weiterzugeben, ohne dadurch das eigene Programm unter Apache stellen zu müssen.
  • Das Modular-Repository und die geprüften MAX-Kernelquellen unter max/kernels tragen gemäß Repository-Lizenz Apache-2.0-/LLVM-Header. Das gilt ebenso für geprüfte Mojo-Wrapper wie max.gpu.host.DeviceContext.
  • MAX als ausgeliefertes Paket ist trotzdem keine einheitlich Apache-lizenzierte Einheit. Teile der nativen Runtime, des Graph Compilers und weiterer Device-/Runtime-Komponenten fallen unter die Modular MAX Community License. Separat gekennzeichnete Apache-Komponenten behalten gemäß Abschnitt 1.4 dieser Lizenz ihre offene Lizenz.
  • Der Apache-lizenzierte DeviceContext ist laut Quelle C++-gestützt und ruft externe AsyncRT_DeviceContext_*-Symbole auf. Deshalb beweist ein Apache-Header im importierten Mojo-Modul nicht, dass das resultierende Binärartefakt ausschließlich offene Komponenten benötigt.
  • Jede transitive Drittbibliothek aus dem Python-/uv-Paket besitzt ihre eigene Lizenz und wird separat erfasst.

Für DS4Server gelten daraus folgende Regeln:

  1. Eigener Rust-, Mojo-, Metal- und CUDA-Code bleibt MIT.
  2. Apache-lizenzierte MAX-Kernel werden importiert oder aus einem exakt gepinnten Modular-Commit gebaut. Vendoring erfolgt nur, wenn eine Änderung zwingend ist; dann bleiben Header, Lizenz und Änderungsvermerk erhalten.
  3. MCL-bedeckter Quellcode wird nicht in das DS4Server-Repository kopiert, übersetzt oder als Grundlage für eine Ersatzimplementierung verwendet.
  4. Eine lokale Entwicklungsinstallation von max darf für den Spike verwendet werden. Daraus folgt keine Freigabe, ihre Runtime-Dateien in eine DS4Server-App zu übernehmen.
  5. Ein Release darf nur Bibliotheken enthalten, deren Lizenz, Redistributierbarkeit, Notices und Herkunft für genau die gepinnte Version belegt sind.
  6. Falls der Standard-MAX-Ausführungspfad eine MCL-Runtime benötigt, ist die bevorzugte Lösung, Apache-lizenzierten Mojo-/MAX-Device-Code über den vorhandenen projektnativen Metal-Pfad beziehungsweise einen projektnativen CUDA-Hostpfad auszuführen. Eine MCL-Runtime wird nur erwogen, wenn diese offene Variante technisch oder leistungsmäßig nachweislich nicht trägt und der Benutzer die Abhängigkeit ausdrücklich freigibt.
  7. DS4Server bleibt als eigener Code MIT-lizenziert. Fremdkomponenten werden in einem Release als separat lizenzierte Bestandteile ausgewiesen; ihre Bedingungen werden nicht als DS4Server-Lizenz ausgegeben.

Für jede potenzielle Laufzeit- oder Kernelabhängigkeit entsteht vor Übernahme ein Eintrag im Lizenzinventar mit:

  • Paket, Version, Quellcommit und exaktem Quellpfad;
  • Lizenzkennung und unverändertem Lizenztext;
  • Verwendung als Build-Werkzeug, Quellimport, statisch eingebetteter Code oder dynamische Laufzeit;
  • den tatsächlich verteilten Dateien;
  • benötigten NOTICE-/Attributionspflichten;
  • einer offenen Ersatzoption und den Kosten ihres Einsatzes;
  • Ergebnis build-only, redistributable, nicht redistributable oder ungeklärt.

ungeklärt und nicht redistributable sind harte Release-Blocker. Für Community-Lizenz-Komponenten genügt nicht die allgemeine Erlaubnis, Anwendungen auszuliefern: Es muss belegt sein, dass genau die betreffende Datei ein erlaubter „Redistributable Component“ ist. Die zum Pin gehörende Lizenzfassung wird zusammen mit dem Inventar archiviert, weil nach Abschnitt 9 der Community License die beim Bezug einer konkreten Version geltenden Bedingungen maßgeblich bleiben.

Das Artefaktaudit läuft nach jedem Toolchain-Upgrade erneut. Auf macOS werden mindestens otool -L und nm -u, auf Linux readelf -d, ldd und nm -u auf die Mojo-Bibliothek und die fertige Anwendung angewendet. Alle nicht-systemischen Bibliotheken und alle AsyncRT, MAX, KGEN oder Modular zuordenbaren undefinierten Symbole werden bis zur bereitstellenden Datei und deren Lizenz zurückverfolgt. Ein erfolgreicher Quellbuild allein ist kein Lizenznachweis.

Zielarchitektur

Rust
  Modell-/GGUF-Laden, DS4-Ablauflogik, Token, Sampling,
  Session, Kontextzählung, Checkpoints, UI/CLI
                         |
                 schmale stabile ABI
                         |
Mojo
  Tensor-/Gerätespeicher, Upload, Prefill, Decode, Verify,
  Kernelplanung, Command-Buffer/Streams, Ereignisse
                         |
      gemeinsame Algorithmen und Datenlayouts
              /                          \
   Apple-Policy zur Compile-Zeit    NVIDIA-Policy zur Compile-Zeit
   Metal, Apple MMA, Split-KV       CUDA, Tensor Cores, Warp-Pipeline

Rust bleibt verantwortlich für

  • GGUF- und Metadateninterpretation;
  • die exakte DS4-Modell- und Tokenablauflogik;
  • Auswahl und Validierung des Modells;
  • Sessions, Kontextgrenzen, Sampling und Ausgabe;
  • das stabile Checkpointformat und seine Kompatibilität;
  • Auswahl des Backends für Tests und Übergangsbetrieb;
  • End-to-End-Telemetrie wie Prefill, Time-to-first-token und Decode-Token/s.

Mojo wird verantwortlich für

  • Gerätekontext, Speicherpools und Tensoransichten;
  • Gewichtstransfer und gerätespezifische gepackte Gewichtsdarstellung;
  • alle GPU-Operatoren und Fusionen;
  • Prefill, einzelnen Decode-Schritt und gegebenenfalls MTP-/Speculative-Verify;
  • KV-/Index-Cache im Gerätespeicher;
  • Stream-/Command-Buffer-Lebenszyklus und geräteseitige Zeitmessung.

Grenze zwischen Rust und Mojo

Die ABI muss klein und explizit bleiben. Als minimale Form werden nur diese Klassen von Aufrufen benötigt:

  • Runtime/Modell erstellen und zerstören;
  • Gewichte beziehungsweise Weight-Shards laden;
  • prefill(...);
  • decode_step(...);
  • optional verify(...) für MTP/speculative decode;
  • Cache exportieren/importieren beziehungsweise Checkpointdaten übertragen;
  • Telemetrie und Fehler abfragen.

Der konkrete Exportmechanismus (@export, Shared Library oder der von der gepinnten Mojo-Version vorgesehene stabile Weg) wird in einem frühen Spike bewiesen. Ein Prozessaufruf pro Token ist ausgeschlossen. Die ABI ist nur eine Sprachgrenze; sie macht das Zielprodukt nicht zu einer C-Anwendung.

Build- und Packaging-Architektur

Cargo bleibt der maßgebliche Build-Einstiegspunkt. Mojo erhält keinen parallelen, manuell zu synchronisierenden Produktbuild.

Gepinnte Toolchain

Im Repository liegen:

  • pyproject.toml mit den direkt benötigten, exakt gepinnten Mojo-/MAX-Buildabhängigkeiten;
  • uv.lock als plattformübergreifender Auflösungsstand;
  • der Mojo-Quellbaum unter mojo/;
  • .venv/ ausschließlich lokal und ignoriert.

Für den ersten lokalen Spike werden nur mojo und das kleinste Paket installiert, das die benötigten MAX-Accelerator-Imports bereitstellt. max[all], max[serve] und das Python-/CLI-Extra max[benchmark] werden nicht verwendet; benötigte Apache-lizenzierte Mojo-Benchmarkbausteine bleiben davon unberührt. uv sync --frozen ist der explizite Bootstrap-Schritt auf einer frischen Maschine; der eigentliche Cargo-Build läuft danach ohne Auflösung oder Netzwerkzugriff.

Cargo-Integration

Das vorhandene build.rs wird wiederverwendet:

  1. Es beobachtet mojo/, pyproject.toml und uv.lock über cargo:rerun-if-changed.
  2. Es ruft den gepinnten Compiler über uv run --frozen --offline --no-sync mojo build auf.
  3. Es erzeugt nativ für das aktuelle Ziel eine Shared Library im Cargo-OUT_DIR: auf macOS libds4_mojo.dylib, auf Linux libds4_mojo.so.
  4. Es meldet Cargo den nativen Link-Suchpfad und ds4_mojo als dynamische Bibliothek.
  5. Es setzt nur die für das jeweilige Ziel nötigen RPaths. Absolute Pfade in .venv, Benutzerverzeichnisse oder den Build-Checkout dürfen nicht im Release verbleiben.
  6. Der bestehende Objective-C-/Metal-Build bleibt macOS-spezifisch. Der Mojo-Build muss vor dem heutigen frühen Nicht-macOS-Return liegen, damit dieselbe Quelle auf DGX Spark für CUDA gebaut werden kann.

Die Shared Library ist zunächst die bevorzugte Form, weil mojo build --emit shared-lib dokumentiert unterstützt ist. Der experimentelle Objektdatei-Pfad wird nicht als Produktbasis gewählt, nur um das Packaging zu umgehen. Cross-Linking zwischen Mac und DGX ist nicht vorgesehen; beide Zielartefakte werden nativ aus demselben Commit und Lockfile gebaut.

ABI

mojo/src/api.mojo exportiert mit @export und abi("C") ausschließlich feste Integer-/Floattypen, opake Handles sowie Pointer-plus-Länge. Mojo-String, List, Exceptions oder interne Layouttypen überschreiten die ABI nicht. Jede exportierte Funktion initialisiert die Mojo-Laufzeit selbst idempotent oder die ABI erzwingt eine einmalige, getestete Initialisierung vor allen anderen Aufrufen. Rust kapselt alle unsafe extern "C"-Deklarationen in einem kleinen sicheren Modul und übersetzt Fehler explizit.

Die erste ABI enthält nur Lebenszyklus, Tensortransfer, einen residenten Matmul-Aufruf, Ergebnis-/Fehlerabfrage und Zeitmessung. Load, Prefill, Decode, Verify und Cache-Transfer werden erst ergänzt, wenn der Spike Build, Laufzeit und Lizenzgate bestanden hat.

App-Bundle und Linux-Artefakt

make bundle bleibt der macOS-Produktbuild. Nach cargo build und cargo packager, aber vor codesign, kopiert er die Mojo-Bibliothek und ausschließlich freigegebene transitive Runtime-Bibliotheken nach DS4Server.app/Contents/Frameworks, normalisiert Install-Namen auf @rpath und prüft das fertige Bundle erneut mit otool -L. Die App muss auf einem System ohne Projekt-.venv und ohne Build-Checkout starten. codesign bleibt der letzte mutierende Schritt.

Das Linux-/DGX-Artefakt erhält dieselbe Prüfung mit readelf und ldd; RPaths dürfen nur auf den relativen, ausgelieferten Bibliotheksort oder Systembibliotheken zeigen. Für beide Plattformen wird aus dem geprüften Abhängigkeitsabschluss die Third-Party-Lizenzbeilage erzeugt beziehungsweise aktualisiert.

Der Produktbuild schlägt fehl, wenn:

  • uv.lock nicht zum Manifest passt oder die Umgebung nicht synchronisiert ist;
  • Mojo-Warnungen als Fehler gemeldet werden;
  • eine erwartete Bibliothek fehlt;
  • ein absoluter Entwicklungs-RPath verbleibt;
  • eine nicht inventarisierte nicht-systemische Bibliothek auftaucht;
  • eine benötigte Datei lizenzseitig ungeklärt oder nicht redistributable ist.

Plattformminimum

DS4Server deklariert derzeit macOS 13, während die aktuelle Mojo/MAX-Toolchain macOS 15 und Apple Silicon voraussetzt. Der Spike darf lokal auf unterstützter Hardware laufen, aber eine Produktintegration muss entweder das Deployment-Ziel nachvollziehbar auf macOS 15 erhöhen oder mit einem reproduzierbaren Artefakttest beweisen, dass der vollständig offene erzeugte Pfad auf macOS 13 unterstützt und lauffähig ist. Eine stillschweigende Anhebung oder ein offiziell nicht unterstütztes Release ist ausgeschlossen.

Bedeutung von „eine Mojo-Implementierung“

Erlaubt:

  • gemeinsame Modell-, Layer- und Operatorlogik;
  • generische Layouts und Algorithmen;
  • Compile-Time-Auswahl von Tile-Größe, Vektorbreite, MMA-Primitive, Thread-/Warp-Gruppierung und Launch-Strategie;
  • einzelne architekturspezifische Mikro-Kernel, wenn sie durch dieselbe öffentliche Mojo-Funktion verborgen sind;
  • separate Build-Artefakte für macOS/Metal und Linux/CUDA.

Nicht erlaubt:

  • kopierte vollständige DeepSeek-, GLM- oder Qwen-Executoren für Metal und CUDA;
  • Laufzeitverzweigungen in inneren Schleifen, die zur Compile-Zeit auflösbar wären;
  • ein universelles „GPU Framework“ über Mojo/MAX hinaus;
  • stiller Rückgriff auf den nativen Pfad, wenn ein Mojo-Operator fehlt;
  • Änderungen an DS4-Modellsemantik, um einen vorhandenen MAX-Kernel passend zu machen.

Verbindliche Struktur des Mojo-Quellcodes

Die Struktur trennt Laufzeit, wiederverwendbare Rechenoperationen, Modellkomposition und Hardware-Tuning. Sie soll beim ersten Modell bereits eingehalten werden, ohne für jede denkbare spätere Variante abstrakte Interfaces anzulegen.

mojo/
  src/
    api.mojo                    schmale, von Rust verwendete ABI
    runtime/
      device.mojo               DeviceContext, Capability-Erkennung
      memory.mojo               Buffer, Pool, Upload/Download
      tensor.mojo               TensorView, Formen, Strides, Layout-Metadaten
      execution.mojo            Streams/Command-Buffer, Events, Fehler
      telemetry.mojo            GPU-Zeit, Speicher- und Launch-Zähler
    targets/
      apple.mojo                Apple-MMA-, Tile- und Launch-Policies
      nvidia.mojo               NVIDIA-MMA-, Warp- und Launch-Policies
    ops/
      embedding.mojo
      quant.mojo                Decode/Packing der unterstützten Q4-/Q8-Formate
      linear.mojo               Matmul und projizierende Fusionen
      norm.mojo
      activation.mojo
      position.mojo             RoPE und Positionshilfen
      attention.mojo            gemeinsame Full-/Flash-/MLA-Bausteine
      cache.mojo                KV-, Sparse- und Index-Cache-Primitiven
      moe.mojo                  Router, Top-k, Experts
      state/
        causal_conv1d.mojo
        gated_delta.mojo        wiederverwendbarer Gated-DeltaNet-Kern
        recurrent_cache.mojo
    models/
      deepseek/
        config.mojo
        weights.mojo
        layer.mojo
        model.mojo
        mtp.mojo                nur wenn tatsächlich benötigt
      glm/
        config.mojo
        weights.mojo
        layer.mojo
        model.mojo
        mtp.mojo
      qwen3_8/
        config.mojo
        weights.mojo
        layer.mojo              Hybridfolge aus GDN und Full Attention
        state.mojo              Conv-/Recurrent-State plus KV-Zustand
        model.mojo
        mtp.mojo
        vision.mojo             Encoder/Projektor, getrennt vom Textkern
  tests/                         Korrektheit, nach ops und models gespiegelt
  bench/                         isolierte Kernel-, Layer- und Modellmessungen

Die genaue Zahl kleiner Dateien darf sich an der tatsächlichen Implementierung orientieren. Entscheidend sind die Verantwortungsgrenzen, nicht ein Verzeichnis pro Funktion.

Abhängigkeitsrichtung

api -> models -> ops -> runtime/targets -> Mojo/MAX
  • runtime kennt kein Modell.
  • targets enthält keine DeepSeek-, GLM- oder Qwen-Semantik.
  • ops kennt Formen und Layouts, aber keine vollständige Layerreihenfolge eines Modells.
  • Ein Modell importiert kein anderes Modell.
  • Gemeinsame Funktionalität wandert ausschließlich über ops, nicht über Cross-Imports zwischen Modellverzeichnissen.
  • Tests und Benchmarks dürfen interne Module direkt importieren; die Rust-Anwendung sieht nur api.mojo.

Zuständigkeit der Schichten

Schicht Besitzt Besitzt ausdrücklich nicht
runtime Geräte- und Speicherlebenszyklus, Tensoransichten, Ausführung, Fehler, Telemetrie Modellgraph, Quantformatlogik, Attention-Semantik
targets zur Compile-Zeit gewählte Hardwareparameter und Intrinsics vollständige Operator- oder Modellkopien
ops semantisch klar benannte, modellübergreifend nutzbare Operatoren und Fusionen Modellreihenfolge, GGUF-Parsing, Sessions
models/<name> Configvalidierung, Tensorbindung, Layerkomposition und modellspezifische Fusionen eigene Geräteverwaltung oder kopierte allgemeine Matmuls
api.mojo stabile grobe Rust-Aufrufe und Modellhandle-Dispatch einzelne Kernelaufrufe im Tokenschritt

Regeln für Wiederverwendung

  1. Ein allgemeiner Operator erhält eine fachliche Schnittstelle mit Formen, Layout und Compile-Time-Policy; ein Modell reicht nur seine Parameter ein.
  2. Ein Modell darf eine Fusion zunächst lokal besitzen. Erst wenn ein zweites Modell dieselbe Semantik benötigt, wird sie nach ops verschoben. Ähnliche, aber numerisch unterschiedliche Fusionen werden nicht künstlich vereinheitlicht.
  3. Quant-Decoding und Weight-Packing liegen zentral in ops/quant.mojo. Modellcode darf Quantformate auswählen, aber nicht erneut implementieren.
  4. KV-Cache und GDN-Recurrent-State bleiben unterschiedliche Zustandstypen. Ein gemeinsamer Speicherpool ist erlaubt; ein künstlicher Universalcache ist es nicht.
  5. Zielabhängige Parameter werden als Compile-Time-Werte übergeben. Keine if metal-/if cuda-Verzweigung innerhalb des Tokenpfads.
  6. Der Rust-seitige Modellloader übergibt eine validierte Tensorbeschreibung. Mojo parst GGUF nicht ein zweites Mal.
  7. Die einzige modellübergreifende Ausführungsform umfasst Load, Prefill, Decode, optional Verify und State-Import/-Export. Ein allgemeiner Graph-IR ist nicht vorgesehen.

Review-Gates für die Struktur

  • Neue Dateien unter models/<name> müssen begründen, warum vorhandene ops nicht passen.
  • Änderungen unter targets müssen auf eine gemessene Hardwaredifferenz zurückgehen.
  • Ein neuer gemeinsamer Operator braucht mindestens zwei reale Verbraucher oder muss bereits für den ersten vertikalen Schnitt zwingend sein.
  • Jeder öffentliche Operator besitzt genau einen Korrektheitstest und einen repräsentativen Benchmarkeintrag; zusätzliche Fälle werden datengetrieben im selben Harness abgebildet.
  • Die Coverage-Liste ordnet jeden nativen GPU-Aufruf einem Mojo-Operator oder einer ausdrücklich dokumentierten entfallenen Materialisierung zu.

Qwen3.8-27B als zweite Modellstufe

Mit „Qwen3.8-27B“ ist das offizielle Modell Qwen/Qwen3.8-27B gemeint. Laut offizieller Modellkarte besitzt der Sprachkern:

  • 27 Milliarden Parameter, Hidden Size 5.120 und 64 Layer;
  • 16 Wiederholungen aus drei Gated DeltaNet -> FFN-Layern und einem Gated Attention -> FFN-Layer;
  • 48 Value- und 16 Q/K-Heads mit Head-Dimension 128 im Gated DeltaNet;
  • 24 Q- und 4 KV-Heads mit Head-Dimension 256 und RoPE-Dimension 64 in voller Attention;
  • FFN-Zwischendimension 17.408;
  • MTP-Unterstützung;
  • 262.144 Token nativen Kontext, mit vom Hersteller genannter Erweiterbarkeit bis eine Million;
  • einen Vision-Encoder für Bild- und Videoeingaben.

Qwen3.8 baut architektonisch auf Qwen3.5 auf. Die bereits vorhandenen MAX-GDN-Kernel sind deshalb ein konkreter Wiederverwendungskandidat: gated_delta.mojo, gated_delta_conv1d.mojo und der slot-basierte Recurrent-State-Cache existieren bereits. Der derzeit dokumentierte MAX-Pfad verwendet jedoch eine sequenzielle zweipassige Rekurrenz statt eines WY-/chunk-parallelen Prefill-Kernels. Das kann für Decode passend und für langen Prefill zu langsam sein. Übernahme erfolgt daher nicht ungeprüft.

Geplanter Qwen-Umfang

Die Qwen-Stufe wird intern in zwei Freigaben geteilt:

  1. Textkern: GGUF-Laden in Rust, Q4- und Q8-Gewichte, Embedding, hybride GDN-/Attention-Layer, FFN, LM-Head, KV-/Recurrent-State, Text-Prefill/Decode, Checkpoint und anschließend MTP.
  2. Multimodal: Bild-/Videovorverarbeitung in Rust, Vision-Encoder und Projektor in Mojo sowie Einbettung der visuellen Token in denselben Textkern.

Der Textkern ist die Pflichtabnahme der zweiten Modellstufe. DS4Server darf Qwen3.8-27B erst dann als vollständig multimodal unterstützt ausweisen, wenn auch der zweite Teil seine Korrektheits- und Performancegates bestanden hat.

Q4-/Q8-Ziel

  • Q4 ist der primäre lokale Performance- und Speichereffizienzpfad. Als erstes konkretes GGUF-Ziel wird Q4_K_M oder das tatsächlich vom gepinnten Qwen-Konverter erzeugte äquivalente K-Quantlayout festgelegt.
  • Q8 ist Pflicht als höherpräziser Vergleichs- und Betriebspfad; bevorzugtes GGUF-Ziel ist Q8_0, sofern das gepinnte Artefakt dies verwendet.
  • Beide Formate werden im gemeinsamen ops/quant.mojo implementiert und von DeepSeek, GLM und Qwen wiederverwendet, wenn Byte-Layout und Semantik identisch sind.
  • Das offizielle Qwen-Artefakt wird derzeit als Transformers/Safetensors beziehungsweise FP8 angeboten. Für GGUF muss deshalb ein konkreter Konvertercommit, das Ausgangsmodell, das erzeugte Artefakt und dessen SHA-256 gepinnt werden. Ein beliebiges Community-GGUF ohne Provenienz ist keine Referenz.
  • Q8 wird nur dort als Performancepfad gewertet, wo Gewichte, Laufzeitzustand und der geprüfte Kontext ohne Swap oder unkontrolliertes Streaming vollständig in den verfügbaren Speicher passen. Andernfalls bleibt Q8 auf dieser Maschine ein kleinerer Korrektheitstest; die vollständige Q8-Performanceabnahme läuft auf geeigneter Hardware.
  • Die offizielle FP8-Variante kann später als NVIDIA-spezifische Erweiterung untersucht werden. Sie ersetzt nicht die gemeinsamen Q4-/Q8-Gates und darf die Quellstruktur nicht in einen separaten Qwen-CUDA-Executor aufspalten.

Qwen-spezifische neue Komponenten

Komponente Ort Wiederverwendung beziehungsweise Abgrenzung
Causal depthwise Conv1D ops/state/causal_conv1d.mojo Aus MAX evaluieren; für weitere GDN-Modelle wiederverwendbar.
Gated-Delta-Rekurrenz ops/state/gated_delta.mojo Gemeinsamer GDN-Kern; getrennte Prefill- und Decode-Tuningpfade hinter derselben Semantik erlaubt.
Recurrent-State-Cache ops/state/recurrent_cache.mojo Slot-/Sequenzzustand; nicht mit KV-Cache semantisch vermischen.
Hybrid-Layerplan models/qwen3_8/layer.mojo Qwen-spezifische Reihenfolge, komponiert gemeinsame GDN-, Attention-, Norm- und FFN-Operatoren.
Qwen-State models/qwen3_8/state.mojo Bündelt GDN-Conv-/Recurrent-State und KV-Cache für Full-Attention-Layer; besitzt Checkpointmapping.
MTP models/qwen3_8/mtp.mojo plus gemeinsame Verify-Abläufe Modellgewichte/-köpfe bleiben Qwen-spezifisch, Scheduling und Verifikation werden geteilt.
Vision zunächst models/qwen3_8/vision.mojo Erst nach einem zweiten identischen Verbraucher nach ops/vision verschieben.

Für Qwen ist ein eigener nativer A/B-Referenzpfad nötig. Ein gepinnter Qwen3.8-fähiger llama.cpp-Metal-/CUDA-Stand mit demselben erzeugten GGUF ist ein geeigneter Übergangskandidat. Er bleibt reines Testorakel und wird nicht Bestandteil der Zielarchitektur. Auf CUDA kann zusätzlich die offizielle Safetensors-/FP8-Ausführung als Diagnose dienen, ist wegen des anderen Gewichtsformats aber kein direkter Token/s-Paritätsmaßstab für Q4/Q8.

DS4 bleibt das Orakel für alle bereits von DS4 definierten Abläufe. Da Qwen3.8-27B kein bestehender DS4-Pfad ist, bilden für dieses Modell die offizielle Modellkonfiguration und ein gepinnter, mit dem identischen GGUF laufender Referenzexecutor gemeinsam das Verhaltensorakel. Abweichungen müssen auf Operator- und Tokenebene aufgeklärt werden; der bequemere Pfad gewinnt nicht automatisch.

Ein aktueller llama.cpp-Fehlerbericht zu Qwen3.8-27B meldet einen starken Decode-Einbruch jenseits ungefähr 80K Kontext, während Prefill schnell bleibt. Das ist kein Beweis für Mojo-Verhalten, aber ein wichtiger Risikohinweis: Qwen-Benchmarks müssen mindestens die Positionen 64K, 80K, 96K, 128K und 262K getrennt prüfen, sofern der Speicher reicht. Ein guter Nullkontextwert genügt nicht.

Übergang mit zwei Referenzpfaden

Während der Migration muss die Backendauswahl explizit und für Testläufe reproduzierbar sein:

native-metal   bestehender Referenzpfad auf dem Mac
native-cuda    gepinnter nativer Referenzpfad auf DGX Spark
mojo           gemeinsame Mojo-Quelle, für das aktuelle Ziel gebaut

Die Auswahl soll über einen internen CLI-/Testparameter oder eine Testumgebungsvariable erfolgen, nicht als neue dauerhaft sichtbare Benutzereinstellung. Jeder Lauf schreibt Backend, Commit, Mojo/MAX-Version, Compilerflags, Modellhash und Hardware in das Ergebnis.

Der aktuelle Rust-Code besitzt noch keinen gleichwertigen nativen CUDA-Pfad. Vor einer Aussage „Mojo ist so schnell wie CUDA“ muss deshalb eine der folgenden Referenzformen festgelegt werden:

  1. bevorzugt: ein vorübergehend in DS4Server auswählbarer, gepinnter nativer CUDA-Referenzadapter;
  2. minimal: ein gepinnter DS4-CUDA-Orakellauf mit exakt demselben Modell, denselben Prompt-Token und demselben Messprotokoll, aufgerufen durch den gemeinsamen Benchmark-Harness.

Die zweite Variante reicht für einen Go/No-Go-Leistungsvergleich, ist aber weniger stark als ein A/B-Test innerhalb derselben Anwendung. Spätestens für die finale Freigabe muss der native CUDA-Referenzlauf automatisiert und zusammen mit dem Mojo-Lauf aus demselben Manifest reproduzierbar sein. Die native Referenz ist Übergangsinfrastruktur und darf nicht die zukünftige Produktarchitektur bestimmen.

Verifikationsstrategie

1. Vollständiges Operationsinventar

Vor dem ersten Port wird aus src/engine/metal/gpu.rs, src/engine/metal.rs und den Modell-Executoren eine Coverage-Liste erzeugt. Jeder heute erreichbare GPU-Aufruf erhält genau einen Eintrag mit:

  • aufrufendem Modell und Phase: Load, Prefill, Decode, Verify oder Checkpoint;
  • Datentyp, Quantformat und relevante Tensorformen;
  • Metal-Referenzbenchmark;
  • CUDA-Referenzbenchmark, sofern der Pfad dort verwendet wird;
  • Mojo-Korrektheitstest;
  • Mojo-Metal- und Mojo-CUDA-Benchmark;
  • Status und begründete Ausnahme.

Diese Liste ist das Lösch-Gate für den nativen Code. Ein Operator ohne Abdeckung darf nicht aufgrund eines grünen Gesamtbenchmarks übergangen werden.

Die anfänglichen Gruppen sind:

  1. Tensorallokation, Views, Upload/Download, Kopie und Speicherpool;
  2. Command-Begin/End, Flush, Events und Synchronisation;
  3. Embeddings;
  4. RMSNorm, Elementwise, Add und SwiGLU;
  5. F16-, F32-, Q8- und quantisierte Matmul-Varianten einschließlich Paired/Fused-Matmul;
  6. DeepSeek HC, QKV, RoPE und KV-Kompression/-Store;
  7. rohe, komprimierte und indexierte Attention in Prefill und Decode;
  8. Router, Top-k, routed MoE und Shared Expert;
  9. GLM-RoPE, Compact-KV, Indexer, Sparse/Indexed Attention und GLM-MoE;
  10. SSD-/Expert-Streaming;
  11. Sampling- oder Logit-Nachverarbeitung, soweit sie tatsächlich auf der GPU liegt;
  12. MTP/speculative decode und Steering, sofern für das getestete Modell aktiv;
  13. Qwen-GDN: depthwise Conv1D, Gate/Decay, Delta-Rekurrenz, Recurrent-State-Update und Hybridwechsel zur Full Attention;
  14. Qwen-Visionencoder und Projektor, sobald der Multimodalteil umgesetzt wird.

2. Reproduzierbare Testdaten

Mikrobenchmarks dürfen nicht nur zufällige kleine Matrizen messen. Für jede Gruppe werden repräsentative reale Formen aus den unterstützten Modellen erfasst:

  • Batch 1 Decode mit kurzen und langen KV-Caches;
  • Prefill mit mindestens 1, 128, 512, 2.048 und 8.192 Token, soweit das Modell dies unterstützt;
  • Kontextgrenzen, an denen Indexer, Sparse Attention oder Cache-Layout wechseln;
  • für Qwen3.8 zusätzlich Decode an 64K, 80K, 96K, 128K und 262K Position, soweit speicherseitig möglich;
  • alle tatsächlich vorkommenden Quantformate und Expert-Layouts;
  • Qwen-Q4 und Qwen-Q8 mit getrennten Fixture- und Ergebnisreihen;
  • residenter und SSD-gestreamter Expertpfad, sofern beide unterstützt werden.

Große Modellgewichte werden nicht ins Repository kopiert. Ein Fixture-Manifest hält Modell-ID, Datei-SHA-256, Tensorname, Bytebereich, Form, Strides, Quantformat und Generatorversion fest. Der Benchmark liest das vorhandene Modell oder erzeugt kleine deterministische Ausschnitte. Damit vergleichen beide Backends identische Bytes.

3. Messprotokoll

Jeder Performancevergleich folgt demselben Protokoll:

  • Release-Builds und identische fachliche Optionen;
  • fester Modellhash, feste Prompt-Token und greedy decode;
  • EOS für eine feste Anzahl erzeugter Token ignorieren;
  • Kompilierung/JIT, Modellladen und erster Upload separat von Steady State messen;
  • Warm-up vor den Messungen;
  • A/B/B/A- oder B/A/A/B-Reihenfolge, um thermische und zeitliche Drift zu reduzieren;
  • gleiche Power-, Thermal- und Hintergrundlastbedingungen;
  • mindestens Median, p95, Streuung und gepaarte Konfidenzintervalle aus mehreren Läufen;
  • GPU-Ereigniszeit für isolierte Kernel und Rust-Wallclock für Layer und End-to-End;
  • Peak-/Resident-GPU-Speicher, Transferbytes und Kernel-/Command-Buffer-Anzahl;
  • Rohdaten als maschinenlesbares JSON oder CSV; zusammenfassender Markdown-Bericht wird daraus erzeugt.

Prefill, erster Decode-Token und stabiler Decode werden getrennt ausgewiesen. Eine einzelne gemischte Token/s-Zahl ist kein ausreichender Nachweis.

4. Performance-Gates

Für jede Hardware wird nur gegen den nativen Pfad derselben Hardware verglichen:

Metal: Mojo-Metal / Native-Metal
CUDA:  Mojo-CUDA  / Native-CUDA

Verbindliches Produktziel:

  • Median der kritischen isolierten Operationen: Verhältnis mindestens 1,00;
  • Median von Prefill und stabilem Decode des vollständigen Modells: Verhältnis mindestens 1,00;
  • p95-Latenz: keine reproduzierbare Verschlechterung;
  • Peak-GPU-Speicher: nicht höher als die native Referenz, sofern eine Erhöhung nicht ausdrücklich begründet und freigegeben wird;
  • kein zusätzlicher Host/GPU-Transfer im Tokenpfad.

Da Messungen rauschen, gilt für die automatische Freigabe zusätzlich: Punktschätzer mindestens 1,00 und untere Grenze des gepaarten 95-%-Konfidenzintervalls mindestens 0,97. Die drei Prozent sind ausschließlich ein Unsicherheitsband, kein erlaubtes Performancebudget. Ein stabil reproduzierbarer Rückstand, auch innerhalb dieses Bands, bleibt ein Fehler und muss untersucht werden.

Ein einzelner nicht kritischer Mikro-Kernel darf nur dann langsamer sein, wenn das Profil beweist, dass er nicht auf dem relevanten kritischen Pfad liegt und Layer- sowie Modellgate trotzdem bestehen. Jede solche Ausnahme wird mit Messdaten dokumentiert. Modellladen und Cold Start erhalten eigene Zahlen und dürfen nicht in Steady-State-Token/s versteckt werden.

5. Korrektheits-Gates

  • Tensorformen, Strides, Quant-Decoding, Expertindizes, Cachepositionen und Kontextzähler müssen exakt übereinstimmen.
  • Für Floating-Point-Zwischenergebnisse werden pro Operator aus der nativen Präzision abgeleitete atol/rtol-Grenzen festgelegt; eine globale großzügige Toleranz ist nicht zulässig.
  • Argmax, gesampelte Token bei identischem RNG-Zustand und die vollständige greedy Tokenfolge müssen identisch sein.
  • Logitfehler dürfen weder Rangfolge der entscheidenden Kandidaten noch spätere Token verändern.
  • Prefill-plus-Decode und reiner inkrementeller Decode müssen denselben Zustand erzeugen.
  • Checkpoints beider Pfade werden gegenseitig geladen, sofern das Checkpointformat backendneutral bleiben soll.
  • NaN, Inf, Out-of-bounds, stiller Precision-Downgrade oder Backend-Fallback sind harte Fehler.

Teststufen

Stufe A: Mojo-Primitiven

Kleine deterministische Tests für Layouts, Quant-Decoding, MMA-Tiles, Reduktionen, Masken, RoPE und Cache-Adressierung. Sie laufen pro Zielplattform und prüfen zunächst gegen eine einfache CPU-/Rust-Referenz oder gespeicherte native Ergebnisse.

Stufe B: Isolierte verwendete GPU-Operationen

Jeder Eintrag des Operationsinventars wird mit echten Formen und Quantdaten gegen Native-Metal beziehungsweise Native-CUDA geprüft und gemessen. Erst Korrektheit, dann Performance.

Stufe C: Fusion, Layer und Cache

Verglichen werden vollständige Attention-, MoE- und Transformer-Layer sowie Cacheübergänge. Diese Stufe erkennt Fälle, in denen einzelne schnelle Kernel durch zusätzliche Launches, Materialisierung oder Synchronisation insgesamt langsamer werden.

Stufe D: Executor und Session

Ausgehend vom vorhandenen Realmodelltest wird derselbe Test backendparametrisiert:

  • Modell laden;
  • festen Prompt prefillen;
  • Logits und Argmax prüfen;
  • mehrere Tokens dekodieren;
  • Checkpoint erzeugen und wiederherstellen;
  • nach Restore identisch weiterdekodieren;
  • Kontextzählung und KV-/Index-Cachezustand vergleichen.

Stufe E: Vollständiger Modell-A/B-Test

Der finale Test verwendet auf einer Maschine nacheinander beide dort verfügbaren Pfade:

  1. identische GGUF-Datei und SHA-256;
  2. identische bereits tokenisierte Eingabe;
  3. greedy decode, fester RNG-Zustand, mindestens 128 erzeugte Token, EOS überspringen;
  4. Logits beziehungsweise entscheidende Top-k-Werte und Token nach jedem Schritt vergleichen;
  5. Prefill, Time-to-first-token, stabilen Decode, Peak-Speicher und Transfers messen;
  6. Reihenfolge über Wiederholungen wechseln;
  7. Rohdaten und Systemmetadaten dauerhaft speichern.

Pflichtmatrix:

Hardware Referenz Kandidat Modelle/Funktionen
Apple-GPU, zunächst die aktuelle M5-Entwicklungsmaschine Native Metal Mojo-Metal primäres DeepSeek-Flash-Modell; danach weitere unterstützte Flash-/Pro-Varianten; kurze und lange Kontexte; Checkpoint
DGX Spark Native CUDA Mojo-CUDA dieselben Modellartefakte, soweit unterstützt; resident und Streaming; kurze und lange Kontexte
beide Plattformen jeweiliger nativer Pfad Mojo GLM 5.2 einschließlich Compact-/Sparse-KV und Indexer; MTP zunächst aus, danach separat an
beide Plattformen gepinnter Qwen3.8-fähiger nativer Metal-/CUDA-Pfad Mojo Qwen3.8-27B Q4 und Q8; GDN-/Attention-Hybrid; kurzer und langer Kontext; Text zuerst, danach MTP und Vision

MTP/speculative decode, Steering und SSD-Streaming werden zunächst deaktiviert, um den Basispfad zu beweisen. Danach erhält jede Funktion eine eigene A/B-Matrix; sie wird nicht durch einen guten Baselinewert implizit freigegeben.

Umsetzung in Phasen

Phase 0: Baselines und Toolchain fixieren

Ergebnisse:

  • Mojo/MAX-Version, Modular-Quellcommit, Rust-Toolchain und Zielcompiler pinnen;
  • pyproject.toml und uv.lock für die minimale Build-Toolchain anlegen und einen frischen Offline-Folgebuild beweisen;
  • komponentengenaues Lizenzinventar einschließlich der zum Pin gehörenden Lizenztexte anlegen;
  • Apache-Kernelquellen von MCL-bedeckten Runtime-/Device-Komponenten trennen und für jede benötigte native Datei die Redistributierbarkeit klären;
  • aktuelle Metal-Baseline mit Rohdaten erstellen;
  • auf DGX Spark einen gepinnten nativen CUDA-Referenzlauf herstellen;
  • Modell-, Prompt-, Hardware- und Messmanifeste festlegen;
  • vollständiges Operationsinventar erzeugen.

Gate: Baselines sind wiederholbar; die Lauf-zu-Lauf-Streuung ist klein genug, um einen realen Performanceverlust zu erkennen. Ohne CUDA-Referenz keine CUDA-Paritätsaussage. Ohne geschlossenes Lizenzinventar für die Build-Toolchain beginnt kein Release-Packaging.

Phase 1: Backendauswahl und gemeinsamer Harness

Ergebnisse:

  • expliziter interner Backendselektor;
  • derselbe Korrektheits- und Benchmark-Harness kann Native Metal, Native CUDA und später Mojo ansteuern;
  • keine Änderung am Standardpfad und keine Änderung des DS4-Verhaltens;
  • Ergebnisformat enthält alle Reproduktionsdaten.

Gate: Native-Metal-Läufe vor und nach Einführung des Selektors sind statistisch identisch. Der Harness selbst verfälscht die Messung nicht.

Phase 2: Mojo-Integrationsspike

Nur der kleinste vertikale technische Nachweis:

  • build.rs baut aus dem gepinnten uv-Lockfile eine Mojo-Shared-Library für das aktuelle Ziel;
  • Rust lädt beziehungsweise linkt die Mojo-Bibliothek und behandelt Fehler sauber;
  • Mojo erkennt Metal beziehungsweise CUDA;
  • ein repräsentativer Tensortransfer und bevorzugt ein vorhandener Apache-lizenzierter MAX-MMA-/Matmul-Kernel laufen;
  • Speicher bleibt über mehrere Decode-Schritte resident;
  • GPU- und Wallclock-Messung funktionieren auf beiden Plattformen;
  • otool/nm beziehungsweise readelf/ldd/nm liefern den vollständigen nativen Abhängigkeitsabschluss;
  • jede gefundene Datei ist im Lizenzinventar klassifiziert;
  • der Spike dokumentiert getrennt, ob nur Apache-/MIT-/BSD-Komponenten benötigt werden oder eine MCL-Runtime technisch in den Pfad gelangt.

Gate: Kein Prozess-pro-Token, keine Synchronisation pro elementarem Operator und kein ungeklärter ABI-, Packaging- oder Lizenzblocker. Benötigt der Pfad eine MCL-Runtime, wird vor Phase 3 zuerst der offene Host-/Dispatch-Pfad geprüft; die MCL-Abhängigkeit wird nicht stillschweigend zur Produktbasis.

Phase 3: Risikofrüher vertikaler Schnitt

Nicht zuerst alle einfachen Elementwise-Kernel portieren. Stattdessen wird ein vollständiger repräsentativer quantisierter Routed-MoE-Layer mit Attention-/KV-Anteil für Prefill und Decode auf beiden Plattformen umgesetzt. Er muss mindestens eines der schwierigsten tatsächlich verwendeten Quantformate und echte Modellformen enthalten.

Gate:

  • identische fachliche Ergebnisse;
  • Mojo-Metal erreicht Native-Metal-Parität;
  • Mojo-CUDA erreicht Native-CUDA-Parität;
  • kein unvertretbarer Speicher- oder Transferzuwachs.

Wenn dieses Gate trotz Profiling, Fusion und architekturspezifischer Policies nicht erreichbar ist, wird der Gesamtport gestoppt und neu bewertet. Das verhindert, dass erst nach einer vollständigen Übersetzung sichtbar wird, dass der zentrale Quant-/MoE-Pfad das Performanceziel verfehlt.

Phase 4: Vollständiger DeepSeek-Basispfad

Ergebnisse:

  • Load, Prefill und Decode für das primäre DeepSeek-Modell;
  • alle benötigten residenten Gewichte, Attention-, KV-, Router- und Expertpfade;
  • jedes verwendete Mojo-Element ist im Operationsinventar abgedeckt;
  • Native Metal und Mojo bleiben auswählbar; CUDA-Referenz und Mojo-CUDA bleiben vergleichbar.

Gate: Stufen A bis E bestehen für Baseline-Inferenz ohne optionale Beschleuniger.

Phase 5: Zweite Modellstufe Qwen3.8-27B Textkern

Die zuvor definierte Mojo-Struktur wird nun durch ein architektonisch anderes Modell validiert. Gemeinsame DeepSeek-Komponenten werden nicht kopiert, sondern über ops verwendet. Neu entstehen nur GDN-/Recurrent-State-Komponenten und die Qwen-spezifische Hybridkomposition.

Ergebnisse:

  • reproduzierbar aus dem offiziellen Ausgangsmodell erzeugte und gehashte Q4- und Q8-GGUF-Artefakte;
  • gepinnter nativer Qwen-Metal-/CUDA-Referenzlauf mit denselben Artefakten;
  • Text-Prefill und Decode für Q4 und Q8;
  • drei GDN-Layer plus ein Full-Attention-Layer als isoliert verifizierter Hybridblock;
  • getrennter GDN-Recurrent-State und KV-Cache mit gemeinsamem Checkpointmapping;
  • wiederverwendete Embedding-, Norm-, Quant-Matmul-, FFN-, RoPE-, Attention- und LM-Head-Operatoren;
  • identische Texttoken gegenüber dem Qwen-Referenzpfad.

Gate:

  • Q4 besteht Korrektheits- und Performanceparität auf Metal und CUDA;
  • Q8 besteht dieselben Gates auf jeder Maschine, auf der das vollständige Arbeitset resident passt;
  • GDN-Prefill, GDN-Decode, Full Attention und der vollständige Hybridblock bestehen jeweils isoliert;
  • kein Modellcode dupliziert Quant-, Matmul-, Norm- oder Cacheoperatoren;
  • kurzer Kontext und die 64K-/80K-/96K-/128K-/262K-Positionen zeigen keinen ungeklärten Leistungseinbruch.

Diese Phase ist die vom Benutzer gewünschte zweite Stufe nach der ersten verifizierten DeepSeek-Implementierung.

Phase 6: Qwen3.8 MTP und Multimodal

Nacheinander, mit getrennten Messreihen:

  1. Qwen-MTP und Verify;
  2. Bildvorverarbeitung und visuelle Tokenisierung in Rust;
  3. Vision-Encoder und Projektor in Mojo;
  4. kombinierter Bild-/Text-Prefill;
  5. Videoeingabe nur, wenn der bestehende DS4Server-Produktumfang sie aufnehmen soll.

Gate: Textperformance bleibt unverändert, wenn kein visuelles Eingabesignal vorliegt. Multimodale Referenzausgaben, Speicherverbrauch und Prefillleistung bestehen separat. Erst dann gilt das Modell als vollständig multimodal unterstützt.

Phase 7: Langkontext und optionale DeepSeek-Pfade

Nacheinander, jeweils mit eigenem Gate:

  1. komprimierte/indexierte und Sparse Attention;
  2. lange Kontexte und Cachegrenzen;
  3. SSD-/Expert-Streaming;
  4. Checkpoint-Cross-Load;
  5. Steering;
  6. MTP/speculative decode.

Kein Punkt wird zusammen mit einem anderen eingeführt, wenn dadurch ein Performanceverlust nicht mehr eindeutig zuordenbar wäre.

Phase 8: GLM 5.2

Zuerst werden die MAX-26.5-GLM-Quellen und ihre Sparse-MLA-/Indexer-Kernel gegen DS4s GLM-Semantik abgeglichen. Passende Mojo-Bausteine werden wiederverwendet; nur die Differenzen werden projektspezifisch implementiert.

Gate: Compact-KV, Indexer, Sparse Attention, Router/MoE, MTP und Checkpoints bestehen jeweils isoliert und anschließend im vollständigen Modell.

Phase 9: Finale Plattformmatrix

  • frische Builds aus demselben Commit;
  • Mac: Native Metal gegen Mojo-Metal;
  • DGX Spark: Native CUDA gegen Mojo-CUDA;
  • alle unterstützten DeepSeek-, Qwen3.8- und GLM-Modelle und aktivierbaren Inferenzmodi;
  • Qwen3.8-27B in Q4 und Q8, soweit das jeweilige Arbeitset resident passt;
  • mindestens drei unabhängige Messserien pro Kombination;
  • vollständiger Korrektheits-, Performance-, Speicher- und Cold-Start-Bericht.

Gate: Alle Pflichtverhältnisse, DS4-Verhaltensprüfungen und Qwen-Referenzprüfungen bestehen. Ungeklärte Ausnahmen verhindern die Freigabe.

Phase 10: Umschalten und späteres Entfernen

Mojo wird zunächst opt-in, dann nach bestandener Matrix Standard. Native Pfade bleiben für mindestens einen definierten Validierungszeitraum als explizite Diagnoseoption erhalten. Entfernt werden sie erst, wenn:

  • das Operationsinventar vollständig geschlossen ist;
  • CI beziehungsweise Hardware-CI beide Mojo-Ziele regelmäßig prüft;
  • keine offenen Korrektheits- oder Performanceabweichungen bestehen;
  • Rollback-Artefakte und Baselineberichte vorhanden sind;
  • der Benutzer die Entfernung ausdrücklich freigibt.

Minimale geplante Artefakte

Die Implementierung soll keine große neue Abstraktionshierarchie erzeugen. Voraussichtlich genügen:

  • pyproject.toml und uv.lock für die exakt gepinnte Build-Toolchain;
  • die Erweiterung des vorhandenen build.rs statt eines zweiten Produktbuildsystems;
  • ein kleiner Rust-Backendselektor an der bestehenden Executorgrenze;
  • ein Mojo-Quellbaum mit gemeinsamen Modell-/Operatorfunktionen und kleinen Architektur-Policies;
  • ein gemeinsamer A/B-Harness;
  • ein Operations-/Fixture-Manifest und ein komponentengenaues Lizenzinventar;
  • maschinenlesbare Benchmarkresultate und daraus erzeugte Berichte.

Die oben definierte Top-Level-Struktur ist verbindlich; einzelne Dateien dürfen zusammengelegt werden, wenn sie sonst nur Weiterleitungen enthalten. Der genaue ABI-Export wird festgelegt, nachdem der Mechanismus in Phase 2 funktioniert. Es wird keine Factory-, Plugin- oder allgemeine Accelerator-Schicht auf Vorrat gebaut.

Hauptrisiken und notwendige Kompromisse

1. Gemeinsame Quelle bedeutet nicht identischen Maschinenpfad

Für volle Performance muss ein gemeinsamer Algorithmus unterschiedliche MMA-, Tile-, Speicher- und Launch-Policies zulassen. Der Kompromiss ist etwas zielabhängiger Mojo-Code auf Mikro-Kernel-Ebene. Ohne diesen Kompromiss ist Parität mit handoptimiertem Metal und CUDA unwahrscheinlich.

2. MAX-Bausteine sind Kandidaten, keine automatische Paritätsgarantie

Ein vorhandener Flash-Attention- oder MoE-Kernel kann ein anderes Layout, eine andere Quantisierung oder andere Cache-Semantik erwarten. Übernahme spart nur dann Arbeit, wenn Adapter und Materialisierungen den Gewinn nicht wieder vernichten. Jeder Baustein durchläuft daher dasselbe isolierte Gate.

3. Quantisierung ist das größte Portierungsrisiko

Die Kombination aus IQ2_XXS, K-Quantformaten, Q8 und fusionierten Expertpfaden ist in den geprüften Mojo-Paketen nicht vollständig GPU-fertig vorhanden. Hier ist mit dem meisten eigenen Kernel- und Tuningaufwand zu rechnen.

4. Qwen-GDN benötigt getrenntes Prefill- und Decode-Tuning

Der vorhandene MAX-GDN-Pfad ist ein wertvoller Startpunkt, seine sequenzielle Rekurrenz ist aber keine Garantie für konkurrenzfähigen langen Prefill. Wahrscheinlich bleibt die Semantik gemeinsam, während Prefill einen chunk-/WY-parallelen Pfad und Decode einen spezialisierten Single-Step-Pfad erhält. Diese Spezialisierung gehört in ops/state/gated_delta.mojo, nicht in getrennte Metal-/CUDA-Modelle.

5. Toolchain- und API-Reife

Mojo/MAX entwickelt sich schnell. Reproduzierbarkeit verlangt einen exakten Pin, lokale Artefakt-Caches und eine bewusste Upgrade-Politik. Ein Upgrade wird wie eine Performanceänderung behandelt und muss die relevante Matrix erneut bestehen.

6. Gemischte MAX-Lizenzgrenze

Die benötigten MAX-Kernel sind überwiegend Apache-lizenziert, ihr üblicher Hostpfad kann aber externe AsyncRT-/MAX-Runtime-Symbole einführen. Das Risiko wird nicht durch eine pauschale Annahme über das max-Paket gelöst, sondern durch den Abhängigkeitsabschluss des erzeugten Artefakts. Wenn eine offene Auslieferung nur mit einer MCL-Runtime möglich wäre, bleibt der native Referenzpfad bestehen und die Architektur wird vor weiterer Portierung neu bewertet.

7. Hardwarezugang ist Teil der Definition of Done

CUDA-Performance kann nicht auf dem Mac simuliert und Metal-Performance nicht aus CUDA-Ergebnissen abgeleitet werden. Jede relevante Phase braucht reale Apple- und DGX-Spark-Läufe. Ohne beide Systeme bleibt die Phase unvollständig.

8. Keine Vorabgarantie von Token/s

Quellvereinheitlichung ist technisch plausibel; Performanceparität ist eine empirische Eigenschaft. Der Plan reduziert dieses Risiko durch den schwierigen vertikalen Schnitt in Phase 3. Scheitert er, bleiben die nativen Pfade erhalten und es wurde noch nicht die gesamte Engine portiert.

Definition of Done

Der Umbau ist erst abgeschlossen, wenn alle folgenden Aussagen belegt sind:

  • Rust besitzt weiterhin die DS4-Verhaltenslogik, Mojo besitzt die GPU-Inferenz.
  • DeepSeek, Qwen3.8 und GLM verwenden dieselbe Mojo-Modell-/Operatorbasis auf Metal und CUDA.
  • Der Mojo-Quellbaum hält die Abhängigkeitsrichtung api -> models -> ops -> runtime/targets ein; Modelle teilen Code nur über klar benannte Operatoren.
  • Zielabhängiger Code ist auf klar begrenzte Compile-Time-Policies und Mikro-Kernel beschränkt.
  • Jeder produktiv verwendete Inferenzoperator ist in der Coverage-Liste korrektheits- und performancegeprüft.
  • Vollständige Modellläufe erzeugen backendübergreifend dieselben Token und denselben beobachtbaren DS4-Zustand.
  • Mojo-Metal ist auf derselben Apple-Hardware nicht langsamer als Native Metal.
  • Mojo-CUDA ist auf derselben DGX-Spark-Hardware nicht langsamer als Native CUDA.
  • Qwen3.8-27B läuft lokal in Q4 und Q8; Q4 ist auf beiden Zielplattformen vollständig performanceverifiziert, Q8 auf jeder ausreichend großen Zielmaschine.
  • Qwen-GDN, Full Attention, Recurrent-State, KV-Cache und Hybridwechsel sind isoliert sowie im vollständigen Modell geprüft.
  • Prefill, erster Token, stabiler Decode, lange Kontexte, Speicher, Checkpoints, Streaming, Steering und MTP sind getrennt verifiziert, soweit sie unterstützt werden.
  • Es gibt keine stillen Fallbacks, keine gemischten Benchmarkpfade und keine ungeklärten Performanceausnahmen.
  • Build, Tests und Benchmarkberichte sind aus gepinnten Toolchains und Manifesten reproduzierbar.
  • Ein frischer Build benötigt nach uv sync --frozen keinen Netzwerkzugriff und erzeugt auf jedem Ziel nativ dasselbe fachliche Mojo-Backend.
  • Das fertige macOS-/Linux-Artefakt enthält keine absoluten Entwicklungs-RPaths und läuft ohne Projekt-.venv.
  • Jede nicht-systemische Binärabhängigkeit besitzt einen geprüften Lizenzinventareintrag und die erforderliche Lizenz-/NOTICE-Beilage.
  • Der Produktpfad hängt nur von MIT-, Apache-2.0-/LLVM-, BSD- oder vergleichbar permissiv lizenzierten Komponenten ab, sofern der Benutzer keine dokumentierte Ausnahme ausdrücklich freigegeben hat.
  • Keine MCL-bedeckte Quelle wurde in das DS4Server-Repository übernommen oder zur Erzeugung eines MAX-Ersatzes verwendet.

Unmittelbar erster Implementierungsschritt

Der nächste Agent soll nicht mit einer breiten Portierung beginnen. Er soll Phase 0 und Phase 1 abschließen und danach in Phase 2 den kleinsten Rust-Mojo-GPU-Spike bauen. Dazu gehören der gepinnte uv-Build über build.rs, eine schmale C-ABI, ein bevorzugt vorhandener Apache-lizenzierter MAX-Matmul, residenter Speicher sowie der vollständige Binär- und Lizenzaudit auf Mac und DGX Spark. Erst wenn dieselbe Mojo-Quelle auf beiden Zielen messbar läuft und der Produktpfad keine ungeklärte oder unfreigegebene MCL-Abhängigkeit besitzt, beginnt der schwierige quantisierte vertikale Schnitt aus Phase 3.

Das ist der früheste Punkt, an dem belastbar entschieden werden kann, ob die angestrebte Quellvereinheitlichung ohne Performanceverlust für diese konkrete Engine erreichbar ist.