← Insights

EN — English version

#15 · Ein Modell für das Team: Qwen3.8-27B auf zwei Vierer-Clustern

· LYTH-REST-Publisher

Qwen3.8-27B ist bei uns seit Ende August der Endpunkt, gegen den mehrere Entwickler gleichzeitig mit ihren Coding-Agenten arbeiten. Dahinter stehen zwei Cluster aus je vier RTX 3090 und ein eigener Proxy, der die Anfragen verteilt. Für die Clients hat sich nur die Adresse geändert; Modellname und Schnittstelle sind dieselben geblieben.

In #14 lief dasselbe Modell auf einer einzelnen Karte. Hier geht es um die Ausbaustufe darüber — und um die Frage, die dabei den meisten Aufwand gekostet hat: Was passiert, wenn mehrere Agenten gleichzeitig mit einem 120.000-Token-Prompt ankommen?

Der Aufbau

Der Dienst belegt acht RTX 3090 in zwei Vierergruppen. Jede Gruppe fährt eine eigene Instanz von SGLang, der Inferenz-Engine, die das Modell ausliefert, mit Tensor-Parallelismus 4, kurz TP=4: Jede Gewichtsmatrix ist in vier Teile zerlegt, und nach jedem Schritt führen die vier Karten ihre Zwischenergebnisse zusammen. Die FP8-Gewichte belegen 7,62 GB je Karte.

Dazu kommt spekulatives Dekodieren mit DFlash2: Ein kleines Entwurfsmodell schlägt acht Tokens auf einmal vor, das große Modell prüft sie in einem Durchlauf und übernimmt im Mittel 3,9 davon. Deshalb erreicht eine einzelne Session bei rund 120.000 Tokens Kontext noch 124 bis 133 tok/s.

Rolle GPUs Kontextfenster Tokenpool Parallele Anfragen
Standard-Cluster 4 262.144 800.000 6
Langkontext-Cluster (YaRN, optional) 4 524.288 650.000 6
Proxy — — — verteilt nach Länge und Auslastung

Tokenpool und Anfragegrenze sind zwei unabhängige Schranken: Der Pool hält die zwischengespeicherten Gesprächsteile aller Sessions, die Anfragegrenze bestimmt, wie viele davon gleichzeitig rechnen. Unsere Planung rechnet mit fünf Personen zu je zwei bis drei Subagenten, also 10 bis 15 Sessions à rund 100.000 Tokens; auf eine Vierergruppe passt das nicht. Beide Cluster zusammen tragen 1,45 Millionen Tokens und zwölf parallele Anfragen.

Warum zwei Cluster und nicht ein großer

Eine Anfrage durchläuft zwei Phasen: Erst liest der Server den Prompt ein (Prefill), dann entsteht die Antwort Token für Token (Decode). SGLang gibt dem Prefill Vorrang und schaltet den gemischten Betrieb bei spekulativem Dekodieren zwangsweise ab: Ein Decode-Schritt ist hier kein einzelnes Token, sondern Entwurf plus Prüfung über acht Tokens.

Praktisch heißt das: Ein einzelner Prefill über gut 120.000 Tokens hält rund 136 Sekunden lang jede laufende Antwort derselben Instanz an. Bei zwei Instanzen trifft das nur die Hälfte der Nutzer. Das ist der eigentliche Gewinn der Aufteilung, wichtiger als der Durchsatzzuwachs.

Alle acht Karten in eine Instanz zu stecken, wäre einfacher gewesen und war messbar schlechter: Tensor-Parallelismus 8 lag im Kurzlauf, unserem Messprofil mit rund 400 Tokens Prompt, 31 Prozent unter TP=4; beim Decode mit rund 80.000 Tokens Kontext 38 Prozent, bei drei parallelen Sessions 26 Prozent. Die Karten hängen an PCIe ohne NVLink, direkte GPU-zu-GPU-Übertragung ist auf diesem Board defekt und abgeschaltet. Jedes Zusammenführen läuft deshalb über den Hauptspeicher, und mehr Karten je Instanz erzeugen dort vor allem mehr Verkehr.

Der Zusammenbruch, der die Aufteilung erzwungen hat

Am 21. August brach der Dienst unter echter Agentenlast zusammen: Sechs Sessions mit je gut 120.000 Tokens lieferten zusammen 7,78 tok/s, einzelne 0,87 bis 2,54 tok/s, das erste Token kam nach über 190 Sekunden. Ein Speicherproblem war es nicht, der Tokenpool war zu 54 Prozent gefüllt. SGLang reiht Prefill-Aufträge hintereinander und lässt dazwischen kaum Decode zu; sechs kalte Sessions sind 732.000 Tokens Prefill und damit rund zehn Minuten Stillstand für alles andere.

Zwei Einstellungen haben das behoben: --prefill-max-requests 2 begrenzt die gleichzeitigen Prefills, --enable-session-radix-cache schützt den bereits verarbeiteten Teil aktiver Sessions vor der Verdrängung aus dem Cache.

Sechs Sessions à gut 120.000 Tokens vorher nachher
je Session 0,87 bis 2,54 tok/s 34,95 bis 44,02 tok/s
gesamt 7,78 tok/s 233,07 tok/s

Faktor 30, gemessen auf der langsameren GPU-Gruppe. Der Zusammenbruch war damit weg, die 136 Sekunden Stillstand je großem Prefill blieben. Dagegen half erst die zweite Instanz.

Der Proxy: warum kein fertiger Router

Die beiden Cluster sind unterschiedlich konfiguriert: Der eine fährt das native Kontextfenster von 262.144 Tokens, der andere 524.288 per YaRN — ein Verfahren, das die Positionskodierung streckt und dem Modell ein größeres Fenster gibt, als es trainiert wurde.

SGLang bringt einen eigenen Router mit: Er schickt eine Anfrage bevorzugt an den Cluster, der ihren Gesprächsanfang schon zwischengespeichert hat, und gleicht sonst die Auslastung aus. Die Prompt-Länge kennt er nicht, das Kontextlimit seiner Instanzen ebenso wenig. Eine zu lange Anfrage beantwortet der Standard-Cluster dann mit HTTP 400 — und erneut zugestellt wird nur bei 408, 429 und 5xx.

Seit dem 4. September steht deshalb ein eigener Proxy davor. Er entscheidet in dieser Reihenfolge:

# Bedingung Ziel Grund
1 über 253.952 Tokens, gezählt als Prompt plus reservierte Ausgabe (262.144 minus 8.192 Sicherheitsabstand) Langkontext-Cluster passt nicht mehr in den Standard-Cluster
2 Session bekannt, dort Platz bisheriger Cluster ein Wechsel erzwingt einen kalten Prefill
3 Standard-Cluster frei Standard-Cluster volle Qualität, kein YaRN
4 Standard voll, Langkontext frei Langkontext-Cluster Überlauf statt Leerlauf
5 beide voll kürzere Schlange das Warten übernimmt SGLang

Regel 4 ist der Grund für den Umbau: Ohne sie konkurrieren zehn kurze Sessions um die sechs Plätze des Standard-Clusters, während der andere leerläuft. Gemessen am 4. September: zehn gleichzeitige kurze Anfragen, sechs auf dem Standard-Cluster, vier per Überlauf auf den anderen, alle in 9,7 Sekunden bedient, keine wartete.

Regel 2 verhindert den teuersten Fehler, denn ein Clusterwechsel bedeutet kalten Prefill: bei rund 80.000 Tokens gemessene 67 Sekunden. Der Proxy erkennt Sessions an einem Hash der ersten 4.000 Zeichen — der Anfang bleibt über alle Runden stabil, während das Gespräch hinten wächst. Zwei Sessions mit identischem Anfang gälten damit als eine; beobachtet haben wir das bisher nicht.

Fällt der Langkontext-Cluster aus oder schalten wir ihn ab, um die vier Karten anderweitig zu nutzen, läuft alles über den Standard-Cluster weiter; ein Wächter prüft das alle fünf Sekunden. Zu lange Anfragen bekommen dann HTTP 503 mit einer Erklärung.

Was das gestreckte Kontextfenster kostet

Qwen dokumentiert die Erweiterung über 262.144 Tokens hinaus selbst und warnt zugleich davor: Alle verbreiteten Frameworks setzen YaRN statisch um, der Streckungsfaktor gilt also auch für einen 20k-Prompt und kann die Qualität kürzerer Texte beeinträchtigen. Umstellen solle man die Positionskodierung nur, wenn lange Kontexte wirklich gebraucht werden.

Wie viel Faktor 2 dabei kostet, ist nirgends gemessen, auch nicht von Qwen. Die einzigen Zahlen stammen aus dem YaRN-Paper zu Llama-2, Faktoren 16 und 32: dort 0,48 bis 1,05 Prozentpunkte bei kurzem Kontext. Dass Faktor 2 weniger kostet, ist eine Vermutung. Die Aufteilung umgeht die Frage, statt sie zu beantworten — kurze Anfragen laufen auf dem unveränderten Modell, nur wirklich lange auf dem gestreckten.

Durchsatz kostet die Streckung jedenfalls keinen.

Standard, 262.144 Langkontext, YaRN 524.288 Differenz
Decode, Kurzlauf 120,69 tok/s 118,88 tok/s −1,5 %
Decode bei rund 80.000 Tokens 111,10 tok/s 111,52 tok/s +0,4 %
Zeit bis zum ersten Token, Kurzlauf 0,31 s 0,31 s identisch
Prefill bei rund 80.000 Tokens 1.204 tok/s 1.216 tok/s +1 %

Beide Abweichungen liegen innerhalb der Streuung; allein im Kurzlauf beträgt die Standardabweichung 9,99 tok/s. Dazu passt der Quelltext: Die gestreckten Positionswerte entstehen einmalig beim Start.

Die Kapazität sinkt dagegen spürbar: Eine einzige 512k-Session belegt 524.288 von 650.000 Tokens, also 81 Prozent des Clusters. Alle Clients pauschal auf 512k zu stellen, wäre deshalb ein Fehler — dann drängen sich alle Sessions im Langkontext-Cluster, in den real eine hineinpasst, während der Standard-Cluster leerläuft.

Der größte Einzelgewinn hatte mit Durchsatz nichts zu tun

Bei null laufenden Anfragen zogen die acht Karten dauerhaft 1.030,6 W. Die Ablaufsteuerung von SGLang fragt im Leerlauf durchgehend nach Arbeit: Acht Server-Prozesse drehten mit 90 bis 99 Prozent CPU-Last leer und hielten die Karten im Boost-Takt. Mit --sleep-on-idle wartet die Ablaufsteuerung stattdessen blockierend.

ohne Flag mit Flag
Leistung, acht GPUs 1.030,6 W 255,7 W
je Karte 106 bis 148 W 22 bis 44 W
Leistungszustand P2 P8
SM-Takt 1.695 bis 1.995 MHz 210 MHz
Zeit bis zum ersten Token nach Leerlauf 67 ms 99 ms
Decode-Durchsatz unverändert

775 W gespart, 75 Prozent, bei einem überwiegend wartenden Rig rund 18 kWh am Tag. Bezahlt wird das mit 32 Millisekunden mehr auf das erste Token, was neben einem sekundenlangen Prefill niemand bemerkt. Unsere Annahme, die Karten blieben wegen des bestehenden CUDA-Kontexts ohnehin in P2, war falsch: Erst die ständigen Zugriffe halten sie oben.

Was unter Teamlast gemessen ist — und was nicht

Die belastbarste Messung stammt vom 24. August: 15 bis 20 Minuten mit drei parallelen Coding-Agenten. Beide Cluster waren damals identisch konfiguriert, den gestreckten Kontext und den eigenen Proxy gab es noch nicht.

Kennzahl Instanz 1 Instanz 2
Cache-Wiederverwendung 89,8 % 92,2 %
Tatsächlich geprefillte Tokens 153.973 149.864
Aus dem Cache bedient 1.353.924 1.770.944
Decode-Durchsatz, Median 95,4 tok/s 95,9 tok/s
Decode-Spitze 212,5 tok/s 178,1 tok/s
Warteschlange durchgehend 0 durchgehend 0

Rund neun von zehn Prompt-Tokens kamen aus dem Cache, weil jede Folgeanfrage nur den neu hinzugekommenen Teil des Gesprächs einlesen muss. Die tatsächliche Prefill-Last lag bei etwa 167 tok/s gegen 1.050 tok/s Kapazität; von Sättigung war der Aufbau weit entfernt.

Was die Zahlen nicht belegen: 20 Minuten sagen nichts über Tage oder über mehr als drei gleichzeitige Agenten, und der Proxy selbst ist unter echter Teamlast noch gar nicht vermessen. Ein Vorfall vom selben Tag ist bis heute ungeklärt: Einer von drei gleichzeitig gestarteten Agenten geriet in eine Endlosschleife, was auf einen beschädigten rekurrenten Zustand deutet und nicht auf die Ablaufsteuerung. Wir haben zwei kurz zuvor eingeführte Einstellungen zurückgenommen; in den 20 Minuten danach trat er nicht wieder auf — ein Indiz, kein Beweis.

Zur Einordnung gehört die Streuung. Die meisten Messreihen stammen vom Vorgänger-Rig mit denselben Karten; nach dem Umbau liegen wir über 54 Läufe rund 11,7 Prozent darunter. Die Streuung beträgt 11,20 tok/s, drei Läufe je Konfiguration ergeben also ±13 tok/s. Effekte unter 15 Prozent sind damit nicht nachweisbar — die YaRN-Messung oben eingeschlossen. Was darunter liegt und was der Proxy im Alltag trägt, zeigt erst längerer Betrieb.

Nachtrag vom 8. September 2026: Ohne Deckel auf die Denkphase kommt keine Antwort

Qwen3.8 denkt, bevor es antwortet: Vor dem eigentlichen Text erzeugt das Modell einen internen Gedankengang, die Denkphase. Bei anspruchsvollen Aufgaben findet dieser Gedankengang kein Ende. In fünf von fünf Läufen verbrauchte das Modell das komplette Ausgabebudget im Denkteil — rund 32.700 Denk-Tokens bei 32.768 erlaubten — und lieferte im Mittel nach 277 Sekunden keine einzige Zeile Code. Das Modell hört von selbst nicht auf; es füllt aus, was man ihm gibt.

Das ist dasselbe Fehlerbild, das Ende August unsere Coding-Agenten getroffen hat: Die übergeordnete Steuerung der Agenten meldete leere Antworten, und die Ursache blieb lange unklar. Jetzt ist sie reproduzierbar.

Der naheliegende Hebel dagegen wäre die Einstellung reasoning_effort, die wir lange auf medium stehen hatten. Sie ist bei unserem Aufbau wirkungslos. Das Chat-Template des Modells — die Vorlage, die aus den Nachrichten eines Gesprächs den eigentlichen Prompt-Text baut — kennt nur drei Stufen und wirft bei allem anderen einen Fehler; unser Server nimmt aber auch high und max klaglos an. Der Wert erreicht das Template also gar nicht: SGLang übersetzt ihn vorher nur in ein Ja/Nein für das Denken. Dazu passt die Messung bei gleicher Frage: xhigh 959, medium 958, low 996 Denk-Tokens. Damit ist auch unsere eigene frühere Notiz widerlegt, medium sei dreieinhalbmal schneller.

Wirksam ist ein hartes Budget in der Token-Auswahl. Bei jedem Schritt entscheidet eine Maske, welche Tokens überhaupt gezogen werden dürfen; ist das Denkbudget aufgebraucht, bleibt in dieser Maske nur noch das Zeichen übrig, das die Denkphase abschließt. Das Modell muss aufhören zu denken und mit der Antwort beginnen — kein Appell im Prompt, sondern Zwang beim Sampling. Eingestellt wird das über die Umgebungsvariable SGLANG_MAX_THINK_TOKENS, seit dem 8. September mit dem Wert 5000 im Betrieb. Einen Wert je Anfrage kennt nur der native Pfad der Engine, nicht der OpenAI-kompatible Endpunkt; Clients können ihn also nicht mitschicken, und das Budget gilt für alle.

Diese Maske muss irgendwo durchgesetzt werden, und das hat einen Preis: Das Budget erzwingt einen Wechsel beim Grammatik-Backend, der Komponente, die erlaubte Token-Folgen absichert. Es stand bei uns auf „aus“ und läuft jetzt mit einer echten Implementierung. Geprüft: Grafikspeicher kostet der Wechsel keinen, der Speicherstand blieb unverändert, und das Modell ruft weiterhin Werkzeuge auf.

Gemessen haben wir an einer Aufgabe, die sich hart bewerten lässt: eine Funktion, die Dauer-Angaben wie 1h30m in Sekunden umrechnet, geprüft an 38 echten Testfällen. Der erzeugte Code wird ausgeführt, gezählt werden die bestandenen Tests. 16 der Fälle verlangen eine Fehlermeldung; eine Attrappe, die immer einen Fehler wirft, käme also auf 16 von 38. Das ist die Messlatte. Fünf Läufe je Stufe:

Denkbudget Median Mittel schlechtester Lauf Zeit je Lauf
4000 38/38 36,4 30 38 s
5000 38/38 37,2 35 46 s
6000 38/38 36,8 34 53 s
7000 38/38 34,4 28 61 s
ohne Budget 0/38 0,0 0 277 s

5000 hat den besten Mittelwert und den besten schlechtesten Lauf, bei acht Sekunden Aufschlag gegenüber 4000. Bei 7000 kippt es: Ein Lauf rechnete 1h30m in 1800 Sekunden statt 5400 um und verstieß damit gegen die einfachste Grundregel der Aufgabe. Das passt zu dem, was das Paper „When More Thinking Hurts“ (ACL Findings 2026) Overthinking nennt — das Modell verwirft eine bereits korrekte Zwischenlösung, nachdem es sie noch einmal abgewogen hat. Der Kipppunkt liegt dort ebenfalls bei rund 7000 Tokens, gemessen an einem anderen Modell und an Wettbewerbsmathematik. Dass zwei unabhängige Wege zur selben Größenordnung führen, macht die Zahl glaubwürdiger.

Viel trägt diese Reihe nicht: fünf Läufe je Stufe, eine einzige Aufgabe. Die Unterschiede zwischen 4000, 5000 und 6000 betragen ein bis zwei Tests von 38 und sind nicht signifikant. Belastbar sind zwei Aussagen: 7000 ist schlechter als der Bereich von 4000 bis 6000, und ohne Budget kommt gar nichts.

Das Budget ist eine Obergrenze, keine Zielvorgabe. Einfache Anfragen kommen mit 500 bis 1900 Denk-Tokens aus und werden davon nie berührt. Es greift nur in den Fällen, die ohnehin ausufern — also genau in denen, die bisher leer zurückkamen.

Ein Nebenbefund zum Schluss: Zwei identische Anfragen bei Temperatur 0, also bei einer Auswahl, die eigentlich immer dasselbe Token zieht, ergaben 996 und 1144 Denk-Tokens — 15 Prozent Streuung. Spekulatives Dekodieren ist bei uns nicht bitgenau. Für Messungen ist das relevant, auch für die fünf Läufe je Stufe weiter oben.

Kommentar schreiben

Deine E-Mail-Adresse wird nicht veröffentlicht. Der erste Kommentar wird manuell freigegeben.