Nach unseren langen Versuchen mit MiniMax M2.7 lag Tencent HY3 als nächster Kandidat nahe. Das 295B-A21B-MoE hatte einen guten Ruf bei Coding und Reasoning, ein vielversprechender gemischter GGUF-Quant war lokal verfügbar, und unsere acht GPUs brachten zusammen genug VRAM mit, um den Versuch zumindest vernünftig erscheinen zu lassen.
Was danach geschah, war für lokale Inferenz ungewöhnlich aufschlussreich. HY3 lieferte keinen einfachen Erfolg, aber auch kein spektakuläres Scheitern. Das Modell wirkte in unseren Aufgaben erstaunlich gut und wurde bei großem aktivem Kontext so langsam, dass seine praktische Eignung fraglich blieb. Später stellte sich heraus, dass im GGUF bereits ein zusätzlicher MTP-Layer steckte, den unsere erste Runtime schlicht nicht nutzte. Mit passender Unterstützung verschob sich die Grenze erheblich, ohne dass die Architekturkosten verschwanden.
Der vorherige Artikel über lange Agentenlast vergleicht MiniMax, HY3 und Qwen übergreifend. Hier geht es um den vollständigen HY3-Diagnoseweg: zwei Quants, mehrere Split-Modelle, KV-Cache-Grenzen, Multi-Token Prediction und einen Benchmarkzustand, der sich beharrlich weigerte, nur eine einzige Zahl zu sein.
Der Aufbau: 192 GB VRAM, aber kein gemeinsamer Speicher
Unser lokales LLM-Rig besteht aus sieben RTX 3090 und einer RTX 3090 Ti. Zusammen sind das rund 192 GB VRAM auf einer Consumer-PCIe-Topologie. Es gibt keinen NVSwitch, der aus acht Karten einen eng gekoppelten Beschleuniger macht.
Bei einem Modell dieser Größe wird deshalb jede Entscheidung teuer:
- die Inferenz-Engine,
- das Quantisierungsformat,
- der Datentyp des KV-Caches,
- der Split-Modus,
- und gelegentlich auch die Stromverteilung im Rig.
HY3 besitzt 295 Milliarden Parameter, von denen pro Token 21 Milliarden aktiv sind. Es hat 80 reguläre Layer, acht KV-Heads und ein natives Kontextfenster von 256K. Das Modell passt in geeigneter Quantisierung über unsere Karten. Damit ist allerdings nur die Kapazitätsfrage beantwortet. Ob acht GPUs ein Token bei 100.000 oder 200.000 aktiven Tokens noch schnell genug erzeugen, ist eine andere Rechnung.
Der schnelle vLLM-Pfad hatte kaum Platz für Kontext
Unser erster Versuch sollte HY3 im schnellen Stack halten:
AngelSlim/Hy3-GPTQ-Int4,- vLLM 0.25.1,
- Tensor Parallelism über alle acht GPUs,
max_model_len=262144,gpu_memory_utilization=0.92.
Bei kurzem Kontext erreichte diese Konfiguration ungefähr 56 tok/s. Für ein Modell dieser Klasse war das ordentlich. Der Decode-Kernel bereitete uns auch keine Sorgen. Der verbleibende KV-Speicher tat es.
Nach dem Laden des Modells meldete vLLM pro TP-Rank beziehungsweise GPU nur ungefähr 0,47 GiB nutzbaren KV-Speicher. In genau dieser Konfiguration begrenzte das den effektiven Kontext eines einzelnen Requests auf rund 12.400 Tokens. Für unsere Agentenarbeit, die regelmäßig über 100.000 aktive Tokens wächst, war der Pfad damit praktisch erledigt. Ein konfiguriertes max_model_len=262144 erzeugt schließlich keinen Speicher, der nach dem Laden der Gewichte nicht mehr vorhanden ist.
Der GPTQ-Pfad lieferte uns also einen brauchbaren kurzen TG-Messpunkt und wenig mehr. Als dauerhaftes lokales Arbeitsmodell war HY3 auf diesem Weg für unsere Last nicht einsetzbar.
Mit UD128 und llama.cpp startete HY3 bei 262K
Der interessantere Versuch verwendete YanissAmz/Hy3-295B-A21B-GGUF, konkret die gemischte Variante UD128, auf llama.cpp.
Zunächst startete gar nichts. Unser älteres Container-Image brach mit dieser Meldung ab:
unknown model architecture: 'hy_v3'
Die Ursache war fehlende Architekturunterstützung im Build. Nach dem Wechsel auf ein neueres llama.cpp-Image lud HY3 korrekt. Bei neuen Open-Weight-Modellen gehört diese Fehlerklasse früh in die Diagnose: Ein vermeintlich beschädigter Quant kann sich als zeitlicher Abstand zwischen Modell und Toolchain erweisen.
Die funktionierende Basiskonfiguration verwendete:
split-mode tensor,flash-attn on,q8_0für Key- und Value-Cache,ctx-size 262144.
Damit startete HY3 sauber. Der Unterschied zum vLLM-GPTQ war erheblich: Das GGUF reservierte auf demselben Rig das vollständige 262K-Fenster und beantwortete Requests. HY3 war auf acht Consumer-GPUs also grundsätzlich lauffähig. Zum ersten Mal sah der Versuch nach einem möglichen lokalen Arbeitsmodell aus und nicht bloß nach einem erfolgreichen Ladevorgang.
Die erste Decode-Rate machte Hoffnung
Bei kurzem Kontext erreichte UD128 mit dem schnelleren Tensor-Split ungefähr 44,8 tok/s. Diese historische Baseline verwendete normales autoregressives Decoding. Der zusätzliche MTP-Block, der bereits in der GGUF-Datei lag, wurde zu diesem Zeitpunkt nicht ausgeführt.
Für einen Quant dieser Modellgröße auf Consumer-GPUs war das schnell genug, um weiterzumessen. Der entscheidende Test begann jedoch erst mit einer großen aktiven Historie.
Bei 100K und 200K kam die Full-Attention-Rechnung
Unsere Agentensitzungen bestehen aus langen Prompts, Tool-Ausgaben und einer stetig wachsenden Historie. Deshalb belasteten wir HY3 mit Promptgrößen, die dem tatsächlichen Einsatz näher kamen.
Bei ungefähr 100.024 Prompt-Tokens maßen wir ohne MTP:
- Prompt-Verarbeitung: ungefähr 643 tok/s,
- Decode: ungefähr 12,3 tok/s.
Bei ungefähr 200.024 Prompt-Tokens fiel der Durchsatz weiter:
- Prompt-Verarbeitung: ungefähr 216 tok/s,
- Decode: ungefähr 4,6 tok/s.
Aus knapp 45 tok/s bei kurzem Kontext wurden damit zunächst 12,3 und später 4,6 tok/s. Bei 200K war das Modell weiterhin benutzbar im wörtlichen Sinn, aber kaum noch angenehm als interaktiver Langzeitagent. Jeder neue Token musste die große aktive Historie durch 80 Full-Attention-Layer tragen.
Genau an dieser Stelle unterschied sich HY3 von unseren problematischeren MiniMax-Läufen. HY3 wurde langsam, ohne dabei erkennbar den Verstand zu verlieren.
Inhaltlich war HY3 der stärkste Teil des Versuchs
In einem realen Analyseauftrag mit großem Kontext blieb HY3 kohärent, schrieb korrektes Deutsch, hielt die Aufgabe fest und fand sogar Lücken in der laufenden Analyse. Es überstand den Kontext formal und arbeitete auch inhaltlich weiter.
Bei ernsthaften Kontextlängen wirkte UD128 qualitativ besser als alle quantisierten MiniMax-Varianten, die wir bis dahin lokal eingesetzt hatten. MiniMax zeigte unter langer Last neben den hohen Decode-Kosten wiederholt Schleifen, Sprachlecks und schwankende Urteile. HY3 hatte in unserem Lauf gute Instinkte und eine schlechte Tokenökonomie.
Das ist für die Diagnose ein wichtiger Unterschied. Ein inkohärentes Modell wird durch eine Beschleunigung lediglich schneller inkohärent. Bei HY3 gab es dagegen etwas zu retten: Die fachliche Ausgabe überzeugte, während die Ausführungskosten den praktischen Einsatz begrenzten.
Layer-Split und Tensor-Split nutzten das Rig verschieden
Wir verglichen außerdem die Split-Modi. Deren Namen klingen nach Implementierungsdetail, beschreiben auf einem PCIe-System aber zwei deutlich verschiedene Arten, die Hardware einzusetzen.
Beim Layer-Split besitzt jede GPU vollständige Transformer-Layer einschließlich der zugehörigen KV-Cache-Anteile. Ein einzelner Decode-Schritt läuft weitgehend nacheinander durch diese Layergruppen: Eine GPU verarbeitet ihre Layer und reicht den Hidden State an die nächste weiter. Der Kommunikationsbedarf zwischen den Karten bleibt vergleichsweise klein. Dafür wartet ein großer Teil der aggregierten Speicherbandbreite, während jeweils eine Teilmenge des Modells arbeitet.
Beim Tensor-Split werden Gewichte, Attention beziehungsweise KV-Heads und die Arbeit innerhalb eines Layers über alle acht GPUs verteilt. Jede Karte kann am selben Layer mitarbeiten. Dafür fallen kollektive Reduktionen über Consumer-PCIe an. Als Gegenleistung steht beim Decode mehr aggregierte Speicherbandbreite gleichzeitig zur Verfügung.
HY3 besitzt acht KV-Heads, also genau einen pro GPU bei einem achtfachen Tensor-Split. Reale Kernel und Platzierungsregeln sind komplizierter als diese Skizze, doch die Geometrie lässt sich günstig teilen.
Für unseren UD128-Aufbau ergaben sich bei kurzem Kontext:
- Layer-Split: ungefähr 40 tok/s,
- Tensor-Split: ungefähr 45,7 tok/s.
Der Tensor-Split gewann in diesem TG-Test rund 14 Prozent. Bei MiniMax hatte der falsche Split-Modus Leistung teilweise halbiert oder andere Probleme ausgelöst. HY3 profitierte in unserem Build von der parallelen Bandbreite stärker, als es unter den zusätzlichen PCIe-Reduktionen litt.
Das Ergebnis gilt für diesen Quant, diesen llama.cpp-Stand, diese Flags und unsere Topologie. Der Tensor-Modus war in dem verwendeten Build experimentell. Aus den 14 Prozent lässt sich daher keine allgemeine Rangfolge der Split-Modi ableiten.
Der interessante TP4/PP-ähnliche Hybrid blieb Theorie
Der Vergleich legt einen Zwischenweg nahe. Ein reiner Layer-Split lässt Bandbreite ungenutzt. Ein achtfacher Tensor-Split beschäftigt alle GPUs in jedem Layer, bezahlt dafür aber auch in jedem Layer achtfache Reduktionen über PCIe. Attraktiv wäre eine Verteilung, bei der vier GPUs innerhalb eines Layers parallel arbeiten und verschiedene Layer oder Graphbereiche insgesamt auf alle acht Karten verteilt werden.
Der Graph-Splitter von ik_llama.cpp verspricht ungefähr diese Form. Das von uns erfolgreich verwendete Upstream-llama.cpp bot die Modi none, layer, row und den experimentellen tensor-Split, aber keinen Graph-Modus. ik_llama.cpp stellt zusätzlich -sm graph, --max-gpu N, -grt und -ts bereit.
--max-gpu 4 bedeutet auf einem Host mit acht GPUs nicht, dass nur vier Karten verwendet werden. Global können alle acht am Modell beteiligt bleiben; ein einzelner Layer darf sich jedoch höchstens über vier GPUs erstrecken. Aufeinanderfolgende Layer oder Teilgraphen können auf anderen Vierergruppen liegen. Vereinfacht sieht die Idee so aus:
Layer/Teilgraph A -> GPUs 0,1,2,3 (vierfache Parallelität im Layer)
Layer/Teilgraph B -> GPUs 4,5,6,7 (vierfache Parallelität im Layer)
spätere Bereiche -> andere Vierergruppen nach Entscheidung des Graph-Placers
Das ähnelt TP4 innerhalb eines Layers plus einer PP-artigen Verteilung über acht GPUs. Auf Consumer-PCIe könnte ein solcher Kompromiss mehr parallele Bandbreite als der Layer-Split und kleinere Reduktionsgruppen als TP8 bieten.
Eine Gleichsetzung mit vLLM-artigem TP4+PP2 wäre trotzdem falsch. Es gibt keine zwei expliziten Pipeline-Stufen, keinen üblichen Microbatch-Zeitplan und kein entsprechendes Modell aus Überlappung und Pipeline-Bubbles. -grt steuert den Datentyp der Graph-Reduktionen; -ts beeinflusst Verteilung und Platzierung. Beides sind Graph- und Kommunikationsoptionen, keine alternative Schreibweise für konventionelles Pipeline Parallelism.
Wir wollten genau diesen Aufbau testen und hatten dafür den falschen Runtime-Stand. Der installierte ik_llama-Build endete ebenfalls bei:
unknown model architecture: 'hy_v3'
Deshalb gibt es von uns keinen gültigen HY3-Vergleich zwischen Graph- und Tensor-Split und auch keine belastbare HY3-Zahl für --max-gpu. Ein HY3-spezifischer Community-Fork war vorhanden, wurde von uns aber nicht lokal validiert. Der Row-Modus ergab ebenfalls kein sauberes Resultat, das wir als Messwert veröffentlichen würden.
Als reine Plausibilitätsprüfung des Mechanismus brachten MiniMax-Läufe mit --max-gpu 2 und 4 ungefähr ein bis sechs Prozent. Diese Messung hält die Idee am Leben, lässt sich aber nicht auf eine andere Architektur übertragen. Acht KV-Heads machen den HY3-Hybrid theoretisch elegant. Ohne kompatiblen und validierten Lauf bleibt es bei Theorie.
Höher präziser KV-Cache passte nicht
Eine naheliegende Frage betraf den q8_0-KV-Cache: Würden f16 oder bf16 den Rechenpfad vereinfachen und damit die Decode-Rate verbessern?
Unsere Versuche beantworteten zunächst nur die Speicherfrage:
f16-KV startete nicht,bf16-KV startete nicht,- beide scheiterten bei 262K,
- und in diesem Tensor-Pfad auch bei deutlich kleineren getesteten Kontexten.
Unter den von uns getesteten höher präzisen KV-Varianten war q8_0 damit die einzige, die den gewünschten High-Context-Aufbau ermöglichte. Ein künftiger Versuch mit Q4-Ziel-KV ist eine eigene Abwägung zwischen Geschwindigkeit und Qualität. Die damalige Verlangsamung ließ sich jedenfalls nicht beheben, indem wir auf einen höher präzisen KV-Datentyp wechselten.
Eine andere Engine beseitigt die Kontextsteigung nicht automatisch
Wir prüften auch die naheliegende Ausweichfrage: War der Einbruch ein llama.cpp-Problem, das Transformers, KTransformers, SGLang oder TensorRT-LLM längst gelöst hatten?
Für genau diese Klasse von Full-Attention-Modellen fanden wir keinen belastbaren Beleg, dass eine dieser Engines den Single-Stream-Einbruch bei 100K bis 200K einfach verschwinden lässt. SGLang war in einem kurzen MiniMax-Benchmark zwar zeitweise rund 26 Prozent schneller als vLLM, lief in einer echten High-Context-Agentenaufgabe jedoch langsamer und weniger stabil. Der Gewinn des Mikrobenchmarks überstand die Zielbelastung nicht.
Prefix Caching, Radix Caching, PagedAttention und Chunked Prefill sind reale Optimierungen. Sie sparen Prefill-Arbeit oder verbessern die Speichernutzung. Der aktive KV-Bestand, den Full Attention bei jedem neuen Decode-Schritt verarbeitet, wird dadurch nicht kleiner.
Die Kontextsteigung stammt also nicht allein aus einer ungeschickten Runtime. Spezialisierte Split-K- oder Graph-Attention könnte Konstanten verbessern, und der Graph-Hybrid blieb ein interessanter Ansatz. Testen konnten wir auf HY3 letztlich einen anderen Hebel: spekulatives Decoding mit dem nativen MTP-Layer.
Der zusätzliche Layer lag bereits in der Datei
An diesem Punkt schien die Geschichte abgeschlossen. HY3 war klug, passte mit 262K in den Speicher, erreichte bei kurzem Kontext einen brauchbaren Durchsatz und wurde bei großer aktiver Historie schmerzhaft langsam.
Die UD128-GGUF enthielt insgesamt 81 Blöcke:
block_count = 81
80 target layers
1 NextN / MTP layer
Der zusätzliche quantisierte Block belegte ungefähr weitere 2 GB in der Datei. Wir schleppten also rund 2 GB für einen Layer mit, der einfach schlief. Quant, Modelldownload und vorhandene GPUs reichten bereits aus. Uns fehlte eine Runtime, die den vorhandenen Block ausführen konnte.
Die Unterstützung der hy_v3-Architektur einschließlich --spec-type draft-mtp wurde im Juli 2026 in Upstream-llama.cpp aufgenommen (PR #25395). Mit einem aktuellen Build änderte sich die Leistungsgeschichte deutlich.
Was Multi-Token Prediction hier tut
MTP steht für Multi-Token Prediction. Für unseren Aufbau lässt sich der Ablauf so beschreiben: Der zusätzliche NextN-Layer schlägt kommende Tokens vor, das vollständige 295B-Zielmodell prüft diese Vorschläge.
- Ein gültiger Vorschlag wird übernommen.
- Ein falscher Vorschlag wird verworfen.
- Das vollständige Zielmodell behält die Entscheidungshoheit.
Der Draft-Layer übernimmt Vorarbeit für das vollständige Zielmodell, das seine Ergebnisse anschließend verifiziert. Die Trefferquote des Drafts bestimmt den möglichen Geschwindigkeitsgewinn. Ungeprüfte Tokens darf er nicht in die Ausgabe einschleusen, weshalb korrekt implementiertes spekulatives Decoding die Qualität nicht systematisch senken sollte.
Wir verwendeten auf beiden Seiten Q8-KV:
- Q8 für den Ziel-KV-Cache,
- Q8 für den Draft-KV-Cache.
Die Quantisierung des Draft-Caches kann beeinflussen, wie nützlich seine Vorschläge sind. Das Zielmodell prüft die Ausgabe weiterhin.
Mehr spekulierte Tokens waren zunächst viel langsamer
Die erste intuitive Einstellung war zugleich die falsche. Wenn ein vorausgesagtes Token hilft, müssten drei doch mehr helfen. Unser erster Versuch verwendete:
n_max = 3
p_min = 0.75
Bei kurzem Kontext erreichte die Konfiguration nur ungefähr 18 tok/s und war damit weniger als halb so schnell wie normales Decoding. In einem späteren kontrollierten Durchlauf mit drei Messungen lag derselbe Parametersatz sogar nur bei durchschnittlich 15,6 tok/s.
Eine spekulative Tiefe von eins half in einem weiteren Erkundungslauf. Solange die Vertrauensschwelle bei 0.75 blieb, kamen jedoch nur ungefähr 26 bis 27 tok/s heraus. Dieser konkrete Punkt wurde später nicht noch einmal unter dem formalen Sweep-Protokoll gemessen und ist deshalb nur als Richtungshinweis zu verstehen.
Der brauchbare Punkt war die unspektakulärste Kombination:
n_max = 1
p_min = 0
Pro spekulativem Schritt entstand höchstens ein Draft-Token. Keine Vertrauensschwelle unterdrückte den Versuch; unbrauchbare Vorschläge durfte das Zielmodell selbst ablehnen. Unser aktueller Produktionspfad verwendet Upstream-llama.cpp, einen gleichmäßigen achtfachen Tensor-Split, ctx-size 262144, Q8-Ziel- und Draft-KV, n_max=1, p_min=0 und ubatch=256.
Bei kurzem Kontext ergaben drei Messungen nach einem getrennten Warmup:
| Lauf | Decode-Rate |
|---|---|
| 1 | 54,62 tok/s |
| 2 | 54,51 tok/s |
| 3 | 53,86 tok/s |
| Mittelwert | 54,33 tok/s |
Die gewichtete Draft-Akzeptanz lag bei ungefähr 63 Prozent. Derselbe Ziel-Quant stieg auf derselben Hardware damit von rund 45 auf etwa 54 tok/s.
Der Parametersweep bestrafte aggressivere Einstellungen
Ein partieller Sweep bestätigte den Befund. Jeder Tabellenwert ist der Mittelwert aus drei Messläufen nach einem separaten Warmup; TG bezeichnet den Durchsatz der Token-Generierung.
n_max |
p_min |
kurzer TG | kurze Akzeptanz | 100K TG | 100K-Akzeptanz |
|---|---|---|---|---|---|
| 1 | 0 | 54,33 | 63,2 % | 23,48 | 74,6 % |
| 2 | 0 | 45,60 | 43,2 % | 14,68 | 47,6 % |
| 3 | 0 | 47,92 | 42,1 % | 13,87 | 36,2 % |
| 2 | 0,75 | 15,75 | 87,7 % | 13,17 | 93,5 % |
| 3 | 0,75 | 15,60 | 85,6 % | 13,69 | 92,3 % |
| 1 | 0,25 | 35,35 | 62,1 % | 13,57 | 72,4 % |
n_max begrenzt die Zahl der Draft-Kandidaten, die rekursiv über den einzelnen NextN-Layer von HY3 erzeugt werden. Auf unserem Rig waren tiefere Drafts durchgehend langsamer. Zusätzliche Draft-Arbeit, Synchronisation und die sinkende Nützlichkeit später Kandidaten sind eine plausible Erklärung. Der Sweep belegt das Ergebnis zuverlässiger als den Mechanismus dahinter.
Auch die hohe Akzeptanz bei p_min=0.75 half nicht. Die dafür bezahlte Arbeit überwog den Nutzen. Diese Optimierung ließ sich nicht nach der aggressivsten oder auf dem Papier saubersten Einstellung wählen; wir mussten sie messen.
Bei 100K verdoppelte sich der kontrollierte Durchsatz fast
Die historische Non-MTP-Messung bei ungefähr 100K aktivem Kontext lag bei 12,3 tok/s. Mit n_max=1, p_min=0, Q8-Ziel- und Draft-KV und weiterhin für 262K konfiguriertem Server ergab der formale Drei-Läufe-Sweep:
| Lauf | Decode-Rate |
|---|---|
| 1 | 24,68 tok/s |
| 2 | 23,26 tok/s |
| 3 | 22,51 tok/s |
| Mittelwert | 23,48 tok/s |
Gegenüber den früheren 12,3 tok/s ist das beinahe eine Verdopplung. Beide Ergebnisse verwendeten dasselbe aktuelle llama.cpp-Image, dasselbe Modell, Q8-KV, Tensor-Split und dieselbe 100K-Promptform. Der MTP-Lauf nutzte allerdings das sicherere ubatch=256 und ein strengeres Warmup-Protokoll.
Deshalb bleibt eine direkte Kontrolle mit --spec-type none auf exakt demselben Build und unter demselben Protokoll offen. Der beobachtete Pfad ist erheblich schneller; bevor wir jeden Prozentpunkt allein MTP zuschreiben, gehört diese Kontrollmessung noch dazu.
Für acht Consumer-GPUs und 100K aktive Tokens verändert der reproduzierbare Wert dennoch die praktische Bewertung. Rund 23,5 tok/s sind keine kleine Benchmarkkorrektur. Aus einem schmerzhaft langsamen Modell wurde ein plausibel einsetzbares Werkzeug für lange Kontexte.
Ein frischer Lauf landete bei 31,5 tok/s
Ein weiterer frischer Lauf lag später zwischen dem kontrollierten Mittelwert und unserem ungewöhnlichsten Warmzustand. Er arbeitete nicht nur auf einem bereits gecachten Prefix: Der Server verarbeitete den vollständigen Prompt und generierte direkt danach.
- Prompt: 100.024 Tokens,
- Prompt-Verarbeitung: 548,87 tok/s,
- Decode: 31,50 tok/s,
- Ausgabe: 256 Tokens,
- Draft-Akzeptanz: 103 / 151 = 68,21 Prozent,
- Laufzeit: 190,53 Sekunden.
Die 31,5 tok/s sind eine reale Beobachtung, und der vollständige Prefill macht sie interessanter als eine rein gecachte Warmmessung. Sie ersetzen trotzdem nicht den kontrollierten Mittelwert von 23,48 tok/s. Warmzustand und Protokolldetails hatten erheblichen Einfluss auf den gemessenen Durchsatz; für die Planung zählt die wiederholbare Messreihe mehr als der schnellste Einzelrun.
Der 37-tok/s-Zustand blieb ein Rätsel
In einer separaten, stark aufgewärmten Sequenz mit nominell denselben MTP-Einstellungen und einem gecachten Prefix von ungefähr 100.023 Tokens maßen wir:
| Lauf | Decode-Rate | akzeptierte Drafts |
|---|---|---|
| 1 | 37,81 tok/s | 107 / 148 |
| 2 | 37,06 tok/s | 107 / 147 |
| 3 | 36,15 tok/s | 107 / 148 |
| Mittelwert | 37,01 tok/s | 321 / 443 |
Das entsprach ungefähr dem Dreifachen der ursprünglichen 100K-Rate ohne MTP. Es war echter Decode-Durchsatz gegen einen aktiven gecachten Prefix, keine Verwechslung mit Prompt-Verarbeitung. Die Draft-Akzeptanz lag bei rund 72 Prozent.
Der spätere kontrollierte Sweep reproduzierte diesen Zustand nicht. Trotz ähnlicher nomineller Einstellungen und ungefähr 75 Prozent gewichteter Akzeptanz pendelte er sich bei rund 23,5 tok/s ein. Frische Läufe machten das Bild noch weniger ordentlich: Der erste Lauf nach einem vollständigen Prefill von rund 510 tok/s decodierte mit 24,95 tok/s, ein späterer vollständiger Prefill führte zu 31,50 tok/s. Die Maschine kann also auch reale Zustände zwischen dem kontrollierten und dem stark aufgewärmten Extrem erreichen. Welcher davon im normalen Betrieb zuverlässig entsteht, ist offen.
Zu den Verdächtigen gehören:
- die Anzahl vorangegangener Decode-Warmups,
- die Wiederverwendung von CUDA Graphs,
- Zustand von KV- und Prompt-Cache,
- Layout von Allocator oder Caches,
- GPU-Takte und allgemeiner Hardwarezustand.
Ein Benchmarkwert ist keine feste Eigenschaft, die auf der Modellverpackung steht. Er entsteht aus Modell, Runtime, Graphzustand, Cachezustand, Topologie und Messprotokoll.
Unsere belastbare Aussage lautet daher: Der neue MTP-Pfad verschob die gemessene HY3-Konfiguration bei 100K reproduzierbar aus dem früheren Bereich um 12 tok/s auf ungefähr 23,5 tok/s. Ein frischer Lauf erreichte 31,5 tok/s, eine auffällige Warmsequenz 37 tok/s. Die höheren Zustände müssen noch erklärt und reproduziert werden; außerdem fehlt die Non-Speculative-Kontrolle auf demselben Build.
Ein startender Server war weiterhin kein belastbarer Server
Der erste MTP-Server verwendete eine Microbatch-Größe von 512. Er startete, beantwortete kurze Prompts und wirkte gesund. Beim echten 100K-Prompt lief GPU0 dann in einen CUDA-Out-of-Memory-Fehler.
Die Änderung
ubatch = 512 -> 256
stabilisierte die für 262K konfigurierte Instanz unter der 100K-Last. Wir reduzierten den maximalen Kontext bewusst nicht auf 131K, nur um günstigere Benchmarkbedingungen zu schaffen. Der Aufbau sollte weiterhin das vollständige 262K-Fenster bereitstellen.
Damit wiederholte HY3 eine Grundregel unseres Projekts: Ein erfolgreicher Start und einige kurze Antworten beweisen nicht, dass eine Konfiguration den vorgesehenen Workload überlebt.
MTP verbessert die Kosten, schafft sie aber nicht ab
Die Architektur erklärt, weshalb auch der schnellere Pfad eine Kontextwand behält:
| Modell | Full-Attention-Layer | KV-Heads | Head-Dimension | relative BF16-KV-Arbeit |
|---|---|---|---|---|
| Qwen3.5-122B | 12 von 48, Rest linear/rekurrent | 2 | 256 | 1x |
| MiniMax M2.7 | 62 von 62 | 8 | 128 | ungefähr 10,3x |
| HY3 | 80 von 80 | 8 | 128 | ungefähr 13,3x |
HY3 führt in allen 80 Ziel-Layern Full Attention aus. Bei jedem generierten Token arbeiten diese Layer über die aktive Historie. Aus Layerzahl, KV-Heads und Head-Dimension ergibt sich gegenüber Qwen3.5-122B eine architekturbasierte Vergleichsgröße von ungefähr 13,3-facher KV-Arbeit pro Token. Selbst gegenüber MiniMax liegt HY3 damit etwa beim Faktor 1,3.
Die acht KV-Heads bedeuten zunächst mehr lokale KV-Daten und Attention-Arbeit pro Token. Der PCIe-Verkehr wächst dadurch nicht automatisch um den Faktor acht. Tensor-parallele und Graph-Kollektive erhöhen die Konstanten; die lineare Kontextsteigung stammt aus dem Attention-Muster selbst.
Qwen3.5-122B verwendet Full Attention nur in einem Viertel seiner 48 Layer und besitzt zwei KV-Heads. Der übrige hybride Stack trägt Historie in kompaktem rekurrentem Zustand. Deshalb bezahlt Qwen eine grundsätzlich andere Langkontextrechnung.
Auch eine einzelne Unified-Memory-GPU würde bei demselben Full-Attention-Modell mit wachsendem Kontext langsamer. Unsere acht Consumer-GPUs, PCIe-Synchronisation und Topologie verschärfen einen bereits architektonisch angelegten Effekt.
Dann imitierte die Hardware einen Modellfehler
In verschiedenen Läufen fielen wechselnde GPUs aus. Einmal traf es GPU1 an 41:00.0 beziehungsweise SLOT2, ein anderes Mal GPU6 an C1:00.0 beziehungsweise SLOT3. Nach Änderungen an der Stromverteilung wanderte der Fehler.
Das sprach gegen eine einzige defekte Karte oder einen einzigen schlechten Slot und für ein breiteres Zusammenspiel aus:
- PSU-Verteilung,
- Versorgungszweigen,
- transienten Lastspitzen,
- PCIe-Link-Retraining unter Last.
Die zeitliche Fehlersuche behandeln wir ausführlich in „Wenn die GPU vom Bus überfahren wird“. Für HY3 war die Konsequenz einfach: Wenn Karten unter Last aussteigen oder ihre Links in degradierte Zustände zurückfallen, werden Modellvergleiche wertlos. Oberhalb des Treibers sehen Strom- und Linkprobleme schnell wie tote Worker, CUDA-Fehler oder eine instabile Inferenz-Engine aus.
Gerade ein achtfacher Tensor-Split belastet den Aufbau anders als ein kleineres TP- oder PP-Layout. Bevor wir eine ungewöhnliche Decode-Rate der Software zuschreiben, müssen deshalb alle acht Karten vorhanden sein, ihre Links unter Last plausibel arbeiten und Stromversorgung, Temperaturen, Takte sowie AER-Zähler unauffällig bleiben.
Was HY3 auf Consumer-Hardware praktisch bedeutet
Die passende Bewertung hängt stark von der geplanten Arbeit ab.
Kurzer Kontext
UD128 ist auf unserem Rig keineswegs absurd langsam. Normales Decoding erreichte rund 45 tok/s, der abgestimmte MTP-Pfad nach Warmup ungefähr 54 tok/s. Der vLLM-GPTQ war mit etwa 56 tok/s ähnlich schnell, bot in unserer Konfiguration aber nur rund 12.400 Tokens nutzbaren Kontext.
Große aktive Kontexte
Ein Modell, das mit einem Kontextfenster von 262K startet, arbeitet darin nicht automatisch komfortabel. Ohne MTP fiel HY3 bei ungefähr 100K in den niedrigen zweistelligen Bereich. Mit n_max=1 und p_min=0 lag der kontrollierte Wert bei ungefähr 23,5 tok/s.
Die separate 37-tok/s-Sequenz ist dokumentiert, sollte aber keine Kauf- oder Bereitstellungsentscheidung tragen. Auch die 4,6 tok/s bei 200K stammen aus dem älteren Non-MTP-Pfad. Einen vergleichbaren MTP-Sweep bei 200K haben wir noch nicht abgeschlossen. Eine direkte Hochrechnung des 100K-Gewinns wäre daher nicht vertretbar.
Intelligenz pro Token
HY3 verdient Respekt. In unserer großen Analyseaufgabe blieb es kohärent, schrieb gutes Deutsch und fand echte Lücken. Das war kein Fall eines riesigen lokalen Modells, das nur Speicher belegt. Gerade diese qualitative Stärke machte die Optimierung sinnvoll.
Allround-Modell für den Alltag
Für lange, gemischte Agentenarbeit blieb unsere Antwort eher Qwen als HY3. Die hybride Attention-Architektur von Qwen kommt mit großen aktiven Kontexten wirtschaftlicher zurecht. MTP machte den Vergleich interessanter, hob die architektonische Differenz aber nicht auf.
HY3 verlangt damit eine ungewöhnlich klare Abwägung: bessere qualitative Leistung, als wir vom lokalen Quant erwartet hatten; mit MTP deutlich bessere Langkontextökonomie; weiterhin aber 80 Full-Attention-Layer mit einer realen Rechnung für jeden aktiven Token.
Das Urteil änderte sich, aber nicht vollständig
HY3 UD128 lehrte uns etwas anderes als MiniMax. Bei MiniMax zweifelten wir unter langer Last wiederholt am Urteil des Modells. HY3 wurde langsam und behielt dabei unsere fachliche Achtung. Sein Engpass war in den beobachteten Läufen vor allem betrieblich.
Der native MTP-Pfad verschob die relevante Grenze: Bei kurzem Kontext stieg die Decode-Rate von Mitte 40 auf Mitte 50 tok/s, und der kontrollierte 100K-Wert bewegte sich vom früheren niedrigen Zehnerbereich auf rund 23,5 tok/s. HY3 bleibt architektonisch von Qwen verschieden, und seine 80 Full-Attention-Layer berechnen die aktive Historie weiterhin bei jedem Token. Ob sich alle 262.144 Tokens komfortabel nutzen lassen, ist damit noch nicht belegt. Für die direkte Zuordnung des Geschwindigkeitsgewinns steht außerdem die --spec-type none-Kontrolle auf demselben Build aus.
Wäre der vLLM-GPTQ unser einziger Pfad geblieben, hätten wir HY3 für lange Arbeit schnell aussortiert. UD128 zeigte, dass das Modell mit 262K laden und inhaltlich sehr gut arbeiten konnte. Die MTP-Unterstützung brachte das kluge Modell in seinem langsamen Körper schließlich deutlich besser in Bewegung.
Für zumindest einen Teil des großen Kontextbereichs wurde aus einer interessanten technischen Demonstration ein plausibler ernsthafter Arbeiter. Der entscheidende Leistungshebel lag bereits als zusätzlicher Layer in der Modelldatei und wartete darauf, dass die Runtime ihn verstand.
Nerd-Anhang: Der genaue MTP-Aufbau
Die funktionierende Runtime war:
llama.cpp version: 10103 (c588c4f47)
full commit: c588c4f47683e73ad2d69f50480bec6cc85fd0f7
image: ghcr.io/ggml-org/llama.cpp:server-cuda
image digest: sha256:72ca3a0323ec891af9332afc8d501396557a45eca2b1b3712828d5cf57e36743
Die genaue Startkonfiguration:
docker run -d --name hy3_ud128_mtp \
--entrypoint /app/llama-server \
--gpus all --ipc host --shm-size 64g \
-p 8005:8080 \
-v /bigData/llama-models/YanissAmz-Hy3-UD128:/models \
ghcr.io/ggml-org/llama.cpp:server-cuda \
--model /models/Hy3-UD128-00001-of-00003.gguf \
--host 0.0.0.0 --port 8080 \
--ctx-size 262144 \
--flash-attn on --n-gpu-layers 999 \
--cache-type-k q8_0 --cache-type-v q8_0 \
--batch-size 2048 --ubatch-size 256 \
--split-mode tensor --tensor-split 1,1,1,1,1,1,1,1 \
--threads 24 --parallel 1 \
--chat-template-file /models/hy3-chat-template.jinja \
--spec-type draft-mtp \
--spec-draft-n-max 1 --spec-draft-p-min 0 \
--spec-draft-type-k q8_0 --spec-draft-type-v q8_0
Das Messprotokoll gehört zu den Ergebnissen:
- Der Server blieb stets für 262.144 Tokens konfiguriert.
- Ziel- und Draft-KV verwendeten durchgehend Q8.
- Vor jeder Messgruppe lief ein nicht gewerteter Warmup.
- Danach folgten drei gemessene Läufe.
- Pro Lauf wurden 256 Tokens generiert.
- Für reproduzierbare Ausgaben stand die Temperatur auf null.
- Der Langkontext-Messpunkt verwendete ungefähr 100.024 Prompt-Tokens.
- Bei Cached-Prefix-Läufen wurde
cache_n=100023geprüft.
Die offenen Arbeiten sind bewusst eng begrenzt:
- eine
--spec-type none-Kontrolle mit demselben Protokoll und exakt diesem Build, - die Erklärung der Zustände mit 23, 31,5 und 37 tok/s,
- der fehlende Messpunkt für
p_min=0.5, - ein Versuch mit
ubatch=384, ohne die 262K-Konfiguration zu verändern, - derselbe MTP-Messablauf bei 200K aktivem Kontext.
Bis diese Punkte abgeschlossen sind, planen wir mit 23,5 tok/s bei 100K. Die gemessenen 37 tok/s sind ein Untersuchungsziel, kein Versprechen.