Agentic Coding SDK skalieren: Was Nebenläufigkeit wirklich kostet

Agentic Coding SDK skalieren: Was Nebenläufigkeit wirklich kostet
Deine Reaktion:

Ein Worker-Pool mit fünf parallelen Coding-Agenten verarbeitet einen Batch von 30 Repositories in zwölf Minuten statt in 46. Das klingt simpel, doch die Skalierung eines agentischen Coding-SDKs ist mehr als nur das Verteilen von Aufgaben auf mehrere Prozesse.

Wer das GitHub Copilot SDK kennt, weiß: Eine Agenten-Sitzung ist keine gewöhnliche HTTP-Anfrage. Sie lebt Minuten, hält einen Transkript im Speicher, steuert eine Shell, verändert Checkouts und erzeugt Unterprozesse. Läufst du solche Workloads parallel, multiplizierst du nicht nur die API-Requests, sondern den gesamten Ressourcen-Fußabdruck. Der Autor eines Artikels über einen automatisierten Dependency-Vulnerability-Fixer hat das erfahren und beschreibt, was Nebenläufigkeit auf operativer Ebene bedeutet.

Vom sequentiellen Loop zum Worker-Pool

Die erste Version seines Fixers verarbeitete ein Repository nach dem anderen. Ein repräsentativer Batch von 30 Repositories benötigte rund 46 Minuten. Das Ersetzen der sequentiellen Schleife durch einen Worker-Pool mit fünf parallelen Jobs war der einfache Teil. Doch bevor fünf Agenten sicher nebeneinander laufen konnten, mussten mehrere Voraussetzungen geschaffen werden: isolierte Arbeitsbereiche, zuverlässige Bereinigung, Ressourcenlimits, Rate Limiting und Telemetrie, die zeigt, ob mehr Parallelität überhaupt hilft.

Ein Agent in diesem Kontext ist ein lebender Copilot-SDK-Client samt Sitzung pro Repository. Diese Sitzung kann viele Modell- und Tool-Runden enthalten, einen Transkript im Speicher halten, eine Shell ansteuern und Berechtigungen zum Erzeugen von Branches und Pull Requests besitzen. Anders als eine typische API-Anfrage, die nach kurzer Arbeit zurückkehrt, ist eine Agenten-Sitzung ein langlebiger Workload mit weitreichenden Seiteneffekten. Genau das führt zu den eigentlichen Herausforderungen.

Isolation: Die erste Verteidigungslinie gegen Konflikte

Die erste Implementierung war bewusst schlicht, um Prompt-Qualität, Berechtigungen und Branch-Strategie zu validieren. Sie verbarg jedoch gefährliche Annahmen. Der Prompt klonte jedes Repository in /tmp/agent-workdir. Bei nur zwei gleichzeitigen Agenten konnte eine Installation die Lockfile überschreiben, die ein anderer Agent gerade für seinen Commit vorbereitete. Oder eine Bereinigung löschte die Dateien des anderen Jobs.

Die Lösung bestand darin, jedem Job einen eindeutigen Pfad zuzuweisen und diesen als Auftragsdaten an den Agenten zu übergeben. Dieselbe Logik gilt für Ports, Branches, Cache-Keys und temporäre Dateinamen: Jeder literale Wert wird zu gemeinsamem Zustand, sobald zwei Jobs ihn nutzen können. Ein eindeutiges Verzeichnis verhindert versehentliche Überschneidungen, ist aber keine Sicherheitsgrenze. Repository-kontrollierter Code benötigt eine Wegwerf-Sandbox mit begrenztem Zugriff auf Host und Netzwerk.

Die Bereinigung musste auch Fehler überleben. Die ursprüngliche Version trennte die Sitzung nur nach erfolgreicher Arbeit, sodass eine Exception sowohl die Sitzung als auch die Runtime-Ressourcen leckte. Die korrigierte Lebenszyklus-Logik startet den Client, erstellt eine Sitzung mit eigenem Transkript, setzt die Schleife fort, bis sie inaktiv wird, und macht die Bereinigung unabhängig vom Erfolgsfall. Ein Worker-Pool mit fünf Jobs kann daher fünf Copilot-Runtimes, fünf Sitzungen, fünf veränderbare Checkouts und all ihre Unterprozesse gleichzeitig bedeuten. Die Komponente, die eine Ressource erwirbt, besitzt auch ihren Lebenszyklus. Nebenläufigkeit macht Verstöße nur häufiger, nicht komplizierter.

Ressourcenlimits setzen: Mehr als nur CPU

Die naive Variante await Promise.all(repositories.map(fixRepository)) ist gefährlich, weil sie die Infrastruktur-Politik von der Eingabegröße abhängig macht. Dreißig Jobs mögen funktionieren, aber dreihundert können den Speicher erschöpfen, die Festplatte füllen oder Rate Limits auslösen. Der Autor verwendet stattdessen einen kleinen Worker-Pool mit explizitem Limit. Dieses Limit ist nicht fünf, weil fünf allgemein sicher wäre, sondern weil es ein konservativer Betriebspunkt für diesen spezifischen Workload darstellt.

Die tatsächliche Obergrenze ergibt sich aus dem kleinsten Limit aller beteiligten Ressourcen: Arbeitsspeicher, temporärer Speicher, Unterprozesse, Dateideskriptoren, Provider-Anfragen, Tokens, Quellcode-Verwaltungsoperationen, Netzwerkbandbreite, Kosten und akzeptabler Schadensradius. Eine grobe Speicherberechnung lässt sich anstellen, doch ein Job-Level-Limit ersetzt kein API-Rate-Limiting. Fünf Agenten können gleichzeitig Branches pushen oder Pull Requests erzeugen. Der Quellcode-Client muss unabhängig davon Rate-Limit-Header, Retry-After und Backoff respektieren.

Vom einzelnen Prozess zu mehreren Replicas

Ein prozesslokales Limit funktioniert nur, solange es genau einen Prozess gibt. Bei einem Limit von fünf und vier Replicas kann der Dienst zwanzig Live-Sitzungen erzeugen. Die effektive Parallelität multipliziert sich also mit der Anzahl der Replicas. Ein Autoscaler erhöht diese Zahl genau dann, wenn ein vorgelagertes System bereits unter Druck steht. Dann muss die Job-Verwaltung in eine langlebige Warteschlange oder Datenbanktabelle wandern.

Ein Worker beansprucht einen Job atomar für einen begrenzten Zeitraum, erneuert das Leasing während der Ausführung und zeichnet das Ergebnis auf, bevor er den Abschluss bestätigt. Verschwindet der Worker, läuft das Leasing ab und ein anderer Worker kann den Job erneut versuchen. Ein globaler Begrenzer schützt gemeinsame Provider- und Berechtigungsbudgets. Die Agentensitzung und der Arbeitsbereich bleiben wegwerfbar, während Job-Identität, Leasing, Versuchszähler und externe Effekte dauerhaft gespeichert werden.

Wiederholungen erfordern Abgleich. Öffnet der Agent einen Pull Request und geht die Antwort verloren, kann ein Retry ein Duplikat erzeugen. Dafür gibt es für jede Korrektur einen stabilen Idempotenz-Schlüssel aus Repository und gewünschter Änderung. Dieser Schlüssel erzwingt einen aktiven Job, unterstützt einen stabilen Branch-Namen und ermöglicht es einem Retry, einen vorhandenen Branch oder Pull Request zu finden. Eine atomare Zuweisung oder eine Eindeutigkeitsbeschränkung schließt die Rasse, die eine reine Existenzprüfung nicht abfangen kann.

Metriken, die beim Skalieren helfen

Die Gesamtdauer des Batches reicht nicht aus, um die Poolgröße zu optimieren. Gemessen werden Wartezeit und Ausführungszeit getrennt, außerdem aktive Sitzungen, Peak-Speicher, Workspace-Größe, Unterprozessanzahl, Kosten pro Job, Upstream-Drosselung, Wiederholungen, Bereinigungsfehler und verwaiste Sitzungen. Drei Fragen machen diese Messungen nützlich: Erreicht die aktive Arbeit regelmäßig das Limit? Wächst die Warteschlangenzeit, obwohl die begrenzten Ressourcen noch Luft haben? Steigen Fehler, Latenz oder Ressourcendruck mit der gleichzeitigen Arbeit?

Wenn der Pool nie voll wird, hilft ein höheres Limit nicht. Wenn Warteschlangen wachsen, während die Ressourcen gesund bleiben, gibt es möglicherweise Spielraum. Wenn Fehler mit der gleichzeitigen Arbeit steigen, hat das System eine Grenze gefunden. Sicherheit gehört in dieselbe Diskussion. Der Dependency-Fixer betrachtet Repositories, Installationsskripte und Tests als nicht vertrauenswürdige Eingaben. Nebenläufigkeit vergrößert diese Exposition. Jeder Job benötigt begrenzte CPU, Speicher, Prozesse, Festplatte, Zeit, Netzwerkzugriff und kurzlebige Repository-spezifische Berechtigungen. Es sollte keine Umgebungs-Anmeldeinformationen für Infrastruktur geben und keine Berechtigung zum Mergen. Audit-Trails müssen redigiert werden, da Terminalausgaben, Umgebungsdumps, Remote-URLs und Paketmanager-Logs Anmeldeinformationen enthalten können.

Die Messung zeigt: Fünf Worker sind nicht fünfmal schneller

Bei einem repräsentativen Batch von 30 Repositories zeigte sich: Klonen und Abhängigkeitseinrichtung sank von etwa 10 Minuten auf 4 Minuten. Die Agenteninspektion und -bearbeitung von 22 Minuten auf 5 Minuten. Push und Pull-Request-Erstellung von 12 Minuten auf 3 Minuten. Ein künstlicher Verzögerungsfaktor zwischen Jobs von 1,5 Minuten fiel komplett weg. Die Gesamtzeit sank von 46 Minuten auf 12 Minuten – ein etwa 3,8-facher Geschwindigkeitsgewinn.

Das ist eine operative Messung, kein Benchmark. Das Entfernen der künstlichen Verzögerung trug dazu bei, und der Rest wurde durch ungleiche Jobdauern, Festplatten- und Netzwerk-Konkurrenz, Provider-Latenz und Quellcode-Verwaltungsoperationen begrenzt. Das Ziel ist nicht maximale Parallelität, sondern der beste nutzbare Durchsatz innerhalb der Sicherheits-, Kosten- und Zuverlässigkeitsbudgets. Die Reihenfolge für den nächsten Dienst wäre: jeden Job isolieren, Bereinigung unbedingt machen, einen begrenzten lokalen Pool hinzufügen, messen, dann dauerhafte Claims und Abgleich einführen, bevor Replicas hinzukommen.

Nebenläufigkeit ist kein kostenloser Beschleunigungshebel. Die 3,8-fache Verbesserung war einfach. Isolation, Ressourcenlimits, durable Job-Ownership, Reconciliation und Metriken – das war der Preis, um diese Zahl sicher zu machen. Wenn du ein agentisches Coding-SDK skalierst, frage zuerst, welche Ressource zuerst ausgeht, nicht wie viele Worker du willst. Die Kosten der Parallelität liegen nicht in der Parallelität selbst, sondern in den Systemen, die sie verantwortbar machen.

Quelle: sahansera.dev

Deine Reaktion:
Artikel teilen:
Krötzsch-Check0 — 100
Fakten 90
Relevanz 85
Hype 20
Einschätzung 85
Redaktion 50 Stand 50 · noch keine Stimmen
Ist das Hype?
Sebastian Krötzsch
Autor

Sebastian Krötzsch

Sebastian Krötzsch schreibt auf sebask.de über Künstliche Intelligenz, Automatisierung, digitale Systeme und die Frage, was davon im Alltag wirklich nützlich ist. Ohne Buzzword-Nebel, dafür mit klarem Blick auf Praxis, Tools und echte Wirkung.