16 Agents, 5.000 Tokens pro Sekunde, 13 Sekunden eine komplette App
Ich bin seit einer Weile fasziniert von Groq. Die bauen spezialisierte Hardware — sogenannte LPUs — die Token mit einer Geschwindigkeit raushauen, die sich mit klassischen GPU-Clustern nicht vergleichen lässt. Dazu kommen die kleineren Open-Source-Modelle: Scout mit 17 Milliarden Parametern, Maverick ebenfalls 17B. Kein GPT-4, kein Claude. Schlank, schnell, fokussiert.
Die Frage, die mich interessiert hat: Wie schnell kann man eigentlich eine komplette App bauen, wenn man nicht ein großes Modell alles sequentiell machen lässt — sondern viele kleine Modelle parallel arbeiten? Also ein agentisches Netzwerk, in dem jeder Agent eine klar abgegrenzte Aufgabe hat. Einer schreibt die Types, einer die Routes, einer den API-Client, einer das Socket-Handling. Alle gleichzeitig.
Ich hab dazu einen Orchestrator in Rust gebaut und über acht Versionen iteriert. Das Ergebnis: 16 Agents schreiben in 13 Sekunden eine komplette Chat-App — 34 Dateien, über 2.200 Zeilen Code, mit einem kombinierten Throughput von über 5.000 Tokens pro Sekunde.
Was Groq anders macht
Groq-Hardware ist nicht einfach eine schnellere GPU. LPUs sind Chips, die speziell für Inferenz gebaut wurden. Die Modelle sind kleiner als das, was man von OpenAI oder Anthropic kennt — 17B statt 70B oder 175B Parameter. Das bedeutet weniger Reasoning-Tiefe pro Agent, aber massiv mehr Geschwindigkeit.
Meine Überlegung war: Wenn ein einzelnes 17B-Modell vielleicht 80% der Code-Qualität eines großen Modells liefert, kann man das durch Spezialisierung kompensieren? Wenn jeder Agent nur eine kleine, klar definierte Aufgabe hat — zwei, drei Dateien mit klarem Scope — dann reichen 17B dafür.
Das war die Hypothese. Ob das funktioniert, musste ich ausprobieren.
Der Aufbau: Three-Pass DAG

Der Orchestrator zerlegt eine natürlichsprachliche App-Beschreibung in drei aufeinanderfolgende Phasen:
graph TD
SPEC["Spec"] --> PLAN["Plan · ~2s"]
PLAN --> P0["Types · ~2s"]
P0 --> P1["8-14 Agents · ~6s"]
P1 --> P2["Wiring · ~2s"]
P2 --> VAL["Validate · ~1.5s"]
VAL --> OUT["34 Files"]
style P0 fill:#FF3D00,stroke:#fff,stroke-width:2px,color:#fff
style P1 fill:#FF3D00,stroke:#fff,stroke-width:2px,color:#fff
style P2 fill:#FF3D00,stroke:#fff,stroke-width:2px,color:#fff
style PLAN fill:#1A1A1A,stroke:#C8FF00,stroke-width:2px,color:#fff
style VAL fill:#1A1A1A,stroke:#C8FF00,stroke-width:2px,color:#fff
style SPEC fill:#1A1A1A,stroke:#fff,stroke-width:2px,color:#fff
style OUT fill:#1A1A1A,stroke:#fff,stroke-width:2px,color:#fffPhase 1: Maverick-17B analysiert die Spezifikation und entscheidet, wie viele Agents es braucht. Das dauert ungefähr zwei Sekunden.
Pass 0: Ein einzelner Types-Agent generiert die zentrale shared/types.ts — die Datei, auf die später alle anderen Agents zugreifen. Ohne diese Datei erfindet jeder Agent seine eigenen Definitionen.
Pass 1: 8 bis 14 Feature-Agents laufen gleichzeitig. Jeder bekommt die Types-Datei als Kontext. Sechs Sekunden später sind alle Dateien da.
Am Ende prüft ein Validator die Konsistenz — stimmen die Imports, passen die Types zusammen, gibt es doppelte Routes. Das Ganze dauert insgesamt 13,3 Sekunden.
Acht Versionen bis es funktioniert hat
Der Weg dahin war nicht geradlinig. Acht Versionen, jede mit eigenen Problemen.
Die ersten Versuche mit vier fest zugewiesenen Agents (v3) lieferten brauchbaren, aber lückenhaften Code. Die Zuständigkeiten waren zu breit — ein Agent für "Frontend" ist zu viel für ein 17B-Modell.
Ab v4 hat der Orchestrator dynamisch entschieden, wie viele Agents es braucht. Das hat geholfen, aber ein fundamentales Problem blieb bis v6 bestehen: Die zentrale Types-Datei existierte nur als Prompt-Beschreibung, nicht als echte generierte Datei.
graph TD
V3["v3 · B- · 4 Ag"] --> V4["v4 · B+ · 8 Ag"]
V4 --> V5["v5 · A- · 12 Ag"]
V5 --> V6["v6 · A · 19 Ag"]
V6 --> V7["v7 · A+ · 12 Ag"]
V7 --> V8["v8 · A+ · 16 Ag"]
style V3 fill:#1A1A1A,stroke:#fff,stroke-width:2px,color:#fff
style V4 fill:#1A1A1A,stroke:#fff,stroke-width:2px,color:#fff
style V5 fill:#1A1A1A,stroke:#C8FF00,stroke-width:2px,color:#fff
style V6 fill:#1A1A1A,stroke:#C8FF00,stroke-width:2px,color:#fff
style V7 fill:#FF3D00,stroke:#fff,stroke-width:2px,color:#fff
style V8 fill:#FF3D00,stroke:#fff,stroke-width:2px,color:#fffv3–v6: Die Agent-Anzahl stieg, aber die Codequalität schwankte. Ohne echte Types-Datei passten die Imports nie zusammen.
v7: Ein dedizierter Types-Agent in Pass 0 erzeugt die Datei als echtes File. Danach lag der Consistency Score erstmals bei 1.0.
v8: Deterministische Import-Pfade, automatische Exports, Code-Pattern-Injection — der Feinschliff, der die letzten Fehler beseitigte.
Die eigentliche Erkenntnis: Dem LLM wegnehmen, was berechenbar ist

Der größte Sprung kam nicht durch bessere Prompts, sondern durch weniger LLM-Arbeit.
Die Erkenntnis klingt simpel: Alles, was deterministisch berechenbar ist, sollte nicht vom LLM kommen. Import-Pfade kann Rust berechnen. Export-Keywords kann ein Regex hinzufügen. Code-Patterns für Express-Routes oder Socket-Handler kann man als Template injizieren.
Vier konkrete Fixes in v8 haben den Unterschied gemacht:
Erstens: ensure_exports() — ein Rust-Regex, der automatisch export vor jede Deklaration in der Types-Datei setzt. Das LLM vergisst das regelmäßig. Der Regex löst es zu 100%, kostet null Tokens.
Zweitens: Deterministische Import-Pfade. Statt das LLM raten zu lassen, ob der Pfad ../../shared/types oder ../../../shared/types heißt, berechnet Rust den korrekten relativen Pfad aus Quell- und Ziel-Position.
Drittens: Ein strukturiertes Export-Map. Services exportieren Instanzen, nicht Klassen. Routes exportieren Router. Klare Regeln statt LLM-Interpretation.
Viertens: Code-Pattern-Injection je nach Datei-Typ. Eine Express-Route bekommt ein konkretes Snippet mit Router() und relativen Paths. Das LLM muss die Struktur nicht erfinden, sondern nur die Business-Logik einfügen.
Der Unterschied: Wenn du dem LLM sagst "Use relative paths", ignoriert es das gelegentlich. Wenn du ihm ein konkretes Code-Snippet gibst, setzt es das fast immer korrekt um.
Was am Ende rauskam

Die Chat-App aus dem Benchmark hat Rooms, Messages, Auth, Socket.IO-Integration und ein Notification-System. Keine Spielzeug-App.
Die Zahlen von v8:
- 34 Dateien mit insgesamt 2.217 Zeilen Code
- 13,3 Sekunden Gesamtzeit
- Kombinierter Throughput: über 5.300 Tokens pro Sekunde
- In der Build-Phase allein: ~6.300 tok/s
- 16 Agents parallel auf Scout-17B
- Consistency Score: 1.0 — alle Imports stimmen, alle Types passen
Der Parallel Speedup liegt bei 4,78x — nicht bei 16x, weil Pass 0 und Pass 2 sequentiell laufen müssen und Groq Concurrency-Limits hat. Das theoretische Maximum wäre irgendwo bei 6-8x.
Was noch nicht funktioniert
React-Komponenten sind nach wie vor schwierig. JSX ist zu kreativ für Templates, da fehlen manchmal Type-Imports. Controller rufen gelegentlich Service-Methoden mit falschen Argumenten auf. Und die DB-Schicht ist inkonsistent — mal Sequelize, mal Raw SQL, mal MongoDB-Style im selben Projekt.
Das sind keine unlösbaren Probleme, aber sie zeigen, wo die Grenze von 17B-Modellen liegt: Bei Aufgaben, die mehr Kontext und Reasoning brauchen als ein paar Dateien.
Wie es weitergeht
Der nächste Schritt ist ein Cartridge-System: Rust-basierte Templates, die das Datei-Gerüst vorgeben — Imports, Exports, Struktur — und das LLM füllt nur noch die Business-Logik-Slots. Das reduziert den LLM-Anteil pro Datei auf vielleicht 30-40% des Codes.
Langfristig soll ein Meta-Agent neue Templates erstellen, wenn kein bestehendes passt, und aus dem Validator-Feedback lernen. Das System verbessert sich dann mit jedem Run. Aber das ist noch Zukunft.