Auf dem Weg zu autonomen Codebasen

Wir freuen uns über die Resonanz auf unsere Forschung zur Skalierung von lang laufendem autonomen Programmieren.
Diese Arbeit begann als interne Forschung, um die Grenzen der aktuellen Modelle auszuloten. Im Rahmen dieser Forschung haben wir ein neues Agent-Framework entwickelt, um viele Tausend Agenten zu orchestrieren und ihr Verhalten zu beobachten. Bis letzten Monat war unser System stabil genug, um eine Woche lang durchgehend zu laufen und den Großteil der Commits für unser Forschungsprojekt (einen Webbrowser) zu erstellen. Dieser Browser war nicht für die externe Nutzung gedacht, und wir gingen davon aus, dass der Code nicht perfekt sein würde.
Doch selbst mit diesen Eigenheiten fühlte es sich wie ein Meilenstein an, den wir teilen wollten: Tausende von Agenten konnten zusammenarbeiten und Ergebnisse hervorbringen, die fast vollständig ohne menschliches Eingreifen lauffähig waren. Seitdem haben wir unsere Forschung weiter vorangetrieben und wollten genauer darauf eingehen, wie dieses Framework aufgebaut wurde.
Außerdem machen wir einen Teil dieser Forschung für einige Benutzer zum Ausprobieren verfügbar.
Hintergrund
Unser Forschungsprojekt begann als mein persönliches Nebenprojekt.
Ein Browser schien ein interessanter Benchmark zu sein. Er war komplex genug, um die Einschränkungen führender Modelle offenzulegen, und es gibt viele verschiedene Subsysteme, die zusammenarbeiten mussten.
Mein ursprünglicher Plan war, das Rendern von Webseiten ohne JavaScript-Unterstützung zu ermöglichen. Ich begann damit, Opus 4.5 mit einem Prompt zu bitten, einen detaillierten Plan für den Bau einer Browser-Engine zu schreiben. Ich forderte es wiederholt auf, „weiterzumachen“, um zu sehen, wie weit es den Plan ausarbeiten würde.
Das scheiterte schnell. Das Modell verlor den Überblick darüber, was es tat, hielt häufig an, um Erfolg zu verkünden, obwohl es noch weit davon entfernt war, und blieb bei komplexen Implementierungsdetails stecken. Aber es zeigte Anzeichen von tiefem Wissen und Intelligenz. Es konnte in kleinen Abschnitten guten Code schreiben.
Das Kernproblem war, dass der Browser als Aufgabe zu überwältigend war und in Teilaufgaben zerlegt werden musste. Als Nächstes ließ ich den Agenten einen Abhängigkeitsgraphen der großen Arbeitsbereiche planen, die Agenten parallel übernehmen konnten. Agenten wurden manuell für Aufgaben gestartet und angestoßen, wenn sie stoppten. Das erhöhte den Durchsatz, aber die Ergebnisse waren kaum besser. Agenten konnten nicht miteinander kommunizieren oder Feedback zum Gesamtprojekt geben. Das System musste dynamischer werden.
In der Zwischenzeit zeigte GPT-5.1 (und später GPT-5.2) bessere Ergebnisse bei der präzisen Befolgung von Anweisungen. Das schien gut zu lang laufenden Agenten zu passen, also aktualisierten wir auf Grundlage dieser Experimente unser Harness, um OpenAI-Modelle zu nutzen.
Zu diesem Zeitpunkt konnte das Harness eine einfache Version des Webbrowsers ohne JavaScript erstellen, aber der Bau einer vollständigen Browser-Engine mit einem einzelnen Agenten wäre unerschwinglich langsam gewesen.
Damit begann unsere nächste Forschungsrunde. Könnten wir 10x mehr für Rechenleistung ausgeben, um 10x mehr sinnvollen Durchsatz zu erzielen?
Von Single-Agent zu Multi-Agent
Wir legten ein neues Repository mit einem einfachen Rust-basierten Harness an.
Statt uns mit der Komplexität verteilter Systeme auseinanderzusetzen, ließen wir das Harness auf einer einzelnen großen Linux-VM (Virtual Machine) mit reichlich Ressourcen laufen. Um das Harness zu steuern, loggten wir uns per SSH in die VM ein und nutzten eine einfache Terminal-Oberfläche.
Außerdem investierten wir von Anfang an mehr Zeit in eine gute Observability des Systems. Wir protokollierten alle Agent-Nachrichten, Systemaktionen und Befehlsausgaben mit Zeitstempeln, damit wir Sitzungen analysieren und erneut abspielen konnten. Das half uns nicht nur beim manuellen Review, sondern auch dabei, die Daten zurück in Cursor einzuspeisen, um große Datenmengen zu durchforsten und schnell Muster zu finden.
Selbstkoordination
Unsere erste Multi-Agent-Idee war die einfachste: Agenten mit gleichwertigen Rollen sollten eine gemeinsame Statusdatei nutzen, um zu sehen, woran die anderen arbeiten, zu entscheiden, woran sie arbeiten, und die Datei zu aktualisieren.


Wir wollten so wenig wie möglich vorgeben und stattdessen die Agenten selbst herausfinden lassen, wie sie sich koordinieren. Das scheiterte schnell.
Die Koordinationsdatei führte schnell zu weiteren Problemen. Agenten hielten Sperren zu lange, vergaßen, sie freizugeben, versuchten zu sperren oder zu entsperren, obwohl das nicht erlaubt war, und verstanden insgesamt nicht, was es bedeutet, eine Sperre auf der Koordinationsdatei zu halten. Bei Sperren kann man leicht Fehler machen; sie sind nur in engen Grenzen korrekt, und auch mehr Prompting half nicht.
Sperren führten außerdem zu zu viel Contention. 20 Agenten fielen auf den Durchsatz von 1–3 zurück, wobei die meiste Zeit fürs Warten auf Sperren draufging. Wir versuchten auch, den Agenten ein Tool zu geben, mit dem sie explizit auf die Arbeit eines anderen Agenten warten konnten, aber sie nutzten es nur selten. Außerdem probierten wir einen sperrenlosen Ansatz mit optimistischer Nebenläufigkeitskontrolle aus, der den Overhead reduzierte, die Verwirrung aber nicht beseitigte.
Der Mangel an Struktur zwischen den Agenten führte dazu, dass kein einzelner Agent große, komplexe Aufgaben übernahm. Sie vermieden Contention und Konflikte und entschieden sich eher für kleinere, sicherere Änderungen, statt Verantwortung für das Projekt als Ganzes zu übernehmen.
Struktur und Rollen hinzufügen
Als Nächstes trennten wir die Rollen, um den Agenten Verantwortlichkeit und klare Zuständigkeiten zu geben:


Ein Planner legte zunächst den genauen Ansatz und die konkreten Ergebnisse fest, um die Anweisungen des Benutzers zielgerichtet umzusetzen. Dies wurde dann an einen Executor übergeben, der als einziger federführender Agent dafür verantwortlich war, dass der Plan vollständig umgesetzt wurde. Der Executor konnte Aufgaben für Workers erzeugen, was lineare Skalierung und höheren Durchsatz ermöglichte.
Um kontinuierlichen Fortschritt und Verantwortlichkeit sicherzustellen, lief nach Abschluss des Executors ein unabhängiger Judge, der beurteilte, ob die Aufgabe abgeschlossen war und ob eine weitere Iteration ausgeführt werden sollte. Dadurch wurden viele Koordinationsprobleme gelöst. Eine einzelne Rolle, die eigens dafür zuständig war, die Ausführung zu steuern und zu überwachen, ermöglichte es den Workers, sich eng auf ihre jeweilige Aufgabe zu konzentrieren, während das Gesamtsystem weiterhin zuverlässig lieferte.
Beobachtung und schrittweise Optimierung
Um zu diesem Design zu gelangen, war eine genaue Beobachtung des Systems erforderlich.
Wenn es ein größeres Problem gab, trat es in der Regel wiederholt und bei vielen Agenten und Tool-Aufrufen auf. Zum Beispiel bemerkten wir, dass es zu viele Ressourcenkonflikte gab, weil viele Agenten gleichzeitig git restore ausführten. Wir nutzten Cursor, um Logs zu analysieren und sie mit unseren Prompts zu vergleichen, um zu verstehen, warum das Verhalten nicht den Erwartungen entsprach.
Letztendlich stellten wir fest, dass dieses System durch den langsamsten Worker ausgebremst wurde. Es war zu starr.
Die gesamte Planung im Voraus machte es für das System außerdem schwierig, sich dynamisch neu anzupassen, wenn neue Probleme entdeckt wurden. Manche Agenten entwickelten sich dadurch in kontraproduktive Richtungen und konnten sich erst in der nächsten Iteration der Schleife selbst korrigieren.
Kontinuierlicher Executor
In der nächsten Version wurde der unabhängige Planner entfernt.
Der Executor konnte nun nicht nur Aufgaben starten, sondern auch planen, wie das Ziel erreicht werden sollte. Da er der einzige Agent war, musste er nirgendwo einen Plan festhalten, sich nicht an einen einzigen statischen, unveränderlichen Plan halten und nicht starr auf alle Worker warten.
Aktualität sicherstellen
Um sicherzustellen, dass Agenten in allen Rollen über längere Zeiträume nicht abdriften, haben wir Mechanismen zur Wahrung der Aktualität eingeführt:
- Eine
scratchpad.mdsollte regelmäßig neu geschrieben werden, statt einfach nur fortlaufend ergänzt zu werden. - Einzelne Agenten sollten beim Erreichen von Kontextlimits automatisch Zusammenfassungen erstellen.
- Wir haben den System-Prompts Erinnerungen zur Selbstreflexion und Ausrichtung hinzugefügt.
- Agenten wurden dazu ermutigt, jederzeit den Kurs zu ändern und Annahmen zu hinterfragen.
Das System war nun hochdynamisch und flexibel: Es konnte proaktiv Code erkunden, Entscheidungen überdenken, Worker verwalten, Aufgaben verschränken und fortlaufend die neuesten Informationen berücksichtigen. Wir stellten fest, dass Agenten Anweisungen bis zum Abschluss recht gut befolgten, daher wurde der Judge entfernt, um das System einfach zu halten.


Pathologische Verhaltensweisen
Trotz dieser Verbesserungen begann der kontinuierliche Executor, pathologische Verhaltensweisen zu zeigen. Er schlief scheinbar zufällig ein, ließ keine Agenten mehr laufen, erledigte die Arbeit selbst, weigerte sich, zu planen und mehr als einige wenige eng umrissene Aufgaben zu starten, Änderungen von Workern nicht korrekt zu mergen und meldete vorzeitig, fertig zu sein.
Wir stellten fest, dass ihm gleichzeitig zu viele Rollen und Ziele zugewiesen wurden, darunter: planen, erkunden, recherchieren, Aufgaben starten, nach Workern sehen, Code reviewen, Änderungen vornehmen, Outputs mergen und beurteilen, ob die Schleife fertig ist. Rückblickend ist es nachvollziehbar, dass er überfordert war.
Das finale Systemdesign
Das finale Design vereint all unsere Erkenntnisse:
- Ein Root-Planer verantwortet den gesamten Umfang der Anweisungen des Benutzers. Er ist dafür zuständig, den aktuellen Zustand zu verstehen und spezifische, gezielte Aufgaben zu liefern, die das Ziel voranbringen. Er schreibt selbst keinen Code. Er weiß nicht, ob seine Aufgaben übernommen werden oder von wem.
- Wenn ein Planer das Gefühl hat, dass sich sein Umfang unterteilen lässt, erzeugt er Unterplaner, die den delegierten, eng umrissenen Teil vollständig übernehmen und auf ähnliche Weise die volle Verantwortung tragen, jedoch nur für diesen Teil. Dieser Prozess ist rekursiv.
- Worker übernehmen Aufgaben und sind allein dafür verantwortlich, sie zum Abschluss zu bringen. Sie kennen das größere System nicht. Sie kommunizieren weder mit anderen Planern noch mit anderen Workern. Sie arbeiten an ihrer eigenen Kopie des Repos, und wenn sie fertig sind, verfassen sie eine einzelne Übergabe, die das System an den Planer übermittelt, der die Aufgabe angefordert hat.
Interessanterweise entspricht das der Arbeitsweise einiger Softwareteams heute.


Unterplaner erhöhen den Durchsatz, indem sie Aufgaben schnell auf mehrere Worker verteilen und gleichzeitig sicherstellen, dass das gesamte System vollständig einem Agent zugeordnet bleibt und von ihm verantwortet wird. Das half auch bei großen Projekten und Aufgaben, bei denen ein einzelner Planer sonst überfordert wäre und einen Tunnelblick entwickeln würde.
Die Übergabe enthält nicht nur, was erledigt wurde, sondern auch wichtige Hinweise, Bedenken, Abweichungen, Erkenntnisse, Gedanken und Feedback. Der Planer erhält dies als Folgemitteilung. Dadurch bleibt das System kontinuierlich in Bewegung: Selbst wenn ein Planer „fertig“ ist, erhält er weiter Updates, zieht den neuesten Stand des Repos und kann weiter planen und nachfolgende Entscheidungen treffen.
Alle Agenten haben diesen Mechanismus, der es dem System ermöglicht, unglaublich dynamisch zu bleiben und sich selbst zu konsolidieren, wobei Informationen entlang der Kette nach oben an Verantwortliche mit zunehmend globaleren Sichtweisen weitergegeben werden, ohne den Overhead globaler Synchronisierung oder Querkommunikation.
Entfernen des Integrators
Ursprünglich haben wir einen Integrator für eine zentrale, systemweit informierte Qualitätskontrolle hinzugefügt, um Reibungsverluste zu vermeiden, die entstehen, wenn zu viele Worker gleichzeitig versuchen zu pushen, zu rebasen, Konflikte aufzulösen und zu mergen.
Er wurde jedoch schnell zu einem offensichtlichen Engpass. Es gab Hunderte von Workern und nur ein einziges Nadelöhr (d. h. „Bürokratie“), durch das jede Arbeit hindurchmusste. Wir haben Änderungen an den Prompts ausprobiert, letztlich aber entschieden, dass er unnötig war und entfernt werden konnte, um das System zu vereinfachen.
Durchsatz und Abwägungen
Das System erreichte über einen Zeitraum von einer Woche einen Spitzenwert von ~1.000 Commits pro Stunde bei insgesamt 10 Mio. Tool-Aufrufen. Sobald das System einmal lief, waren keinerlei Eingriffe unsererseits mehr erforderlich.
Um diesen Durchsatz zu erreichen, mussten bewusst Abwägungen getroffen werden.
Korrektheit von Commits
Als wir vor jedem einzelnen Commit 100 % Korrektheit verlangten, führte das zu starker Sequenzialisierung und verlangsamte den effektiven Durchsatz erheblich. Schon ein einzelner kleiner Fehler, etwa eine API-Änderung oder ein Tippfehler, konnte das gesamte System nahezu zum Stillstand bringen. Worker gingen über ihren Zuständigkeitsbereich hinaus und begannen, irrelevante Dinge zu beheben. Viele Agenten stürzten sich auf dasselbe Problem und behinderten sich dabei gegenseitig.
Dieses Verhalten war weder hilfreich noch notwendig. Etwas Spielraum zu lassen bedeutet, dass Agenten darauf vertrauen können, dass andere Probleme bald von anderen Agenten behoben werden, was auch zutrifft, da das System über die gesamte Codebasis hinweg effektiv Zuständigkeiten und Delegation abbildet. Fehler entstehen und werden dann schnell behoben. Die Fehlerquote bleibt niedrig und konstant — vielleicht nur selten vollständig sauber, aber stabil und beherrschbar, statt zu eskalieren oder sich zu verschlechtern.
Das könnte darauf hindeuten, dass ein ideales, effizientes System eine gewisse Fehlerquote akzeptiert, aber ein finaler „grüner“ Branch nötig ist, in dem ein Agent regelmäßig Snapshots erstellt und vor der Veröffentlichung noch einen kurzen Korrekturdurchgang macht.
Synchronisations-Overhead
Manchmal arbeiten mehrere Agenten an derselben Datei oder refaktorieren denselben Code. Statt zu versuchen, das vollständig zu verhindern oder eine überkomplizierte Lösung zu bauen, akzeptieren wir Phasen gewisser Turbulenz und lassen das System über einen kurzen Zeitraum auf natürliche Weise konvergieren und stabilisieren.
Das kostet einige zusätzliche Token und führt lokal zu Konflikten, hält das System insgesamt aber einfacher: Modelle lassen sich leichter aufeinander abstimmen, ohne sie zu überfordern, das System ist leichter zu verwalten und zu beobachten, verursacht weniger Reibung und verbessert die Gesamtproduktivität. Außerdem vermeidet es unnötig komplexe Ansätze.
Erkenntnisse zur Infrastruktur
Jeder Multi-Agent-Lauf wurde auf einer eigenen großen Maschine mit reichlich Systemressourcen ausgeführt, um die vorzeitige Komplexität verteilter Systeme zu vermeiden. Das passte gut, da die meisten Läufe bei mehreren hundert Agenten ihren Höchststand erreichten, was diese Maschinen typischerweise auslastete, aber nicht überbeanspruchte. Diese Architektur machte es einfacher, Systemmetriken zu beobachten und bei Bedarf Zustand zu teilen und zu kopieren.
Nach der Begrenzung der RAM-Nutzung der Agenten wurde die Festplatte zum Engpass. Besonders bei einem Monolith-Projekt führten Hunderte von Agenten, die gleichzeitig kompilierten, zu vielen GB/s an Lese- und Schreibvorgängen für Build-Artefakte. Das hatte erhebliche Auswirkungen auf den Gesamtdurchsatz des Harness und war eine interessante Erkenntnis: Projektstruktur, Architekturentscheidungen und die Entwicklererfahrung können den Token- und Commit-Durchsatz beeinflussen, einfach weil die Arbeit mit der Codebasis (z. B. die Kompilierung) die meiste Zeit beansprucht, anstatt idealerweise das Denken und Programmieren.
Es gab auch Einschränkungen und Ineffizienzen in der allgemeinen Entwicklungsumgebung: Dinge, die für den Workspace eines einzelnen Benutzers sinnvoll sind oder kaum ins Gewicht fallen, können bei Hunderten von Agenten, die auf einer Maschine dasselbe tun, deutlich hervortreten. Eine triviale Möglichkeit, das zu lösen, besteht darin, jedem Agenten eine eigene Maschine zu geben. Aber es gibt interessante naheliegende Möglichkeiten für große Effizienzgewinne, allein durch das Überdenken und Neugestalten einiger dieser Grundbausteine und Tools.
Zum Beispiel nutzen viele Tools wie Git und Cargo gemeinsame Sperren, größtenteils als einfachen Mechanismus zur Steuerung von Parallelität. Könnte die Übernahme gut etablierter Mechanismen aus nebenläufigen Systemen wie Datenbanken dazu führen, dass sie auch in Multi-Agent-Systemen genauso gut funktionieren? Alle Agenten haben ihre eigene Kopie des Repo, aber die meisten Dateien und Artefakte sind identisch; könnte das Hinzufügen einfacher Copy-on-Write- und Deduplizierungs-Features, wie sie in ausgefeilteren Produktionsspeichersystemen zu finden sind, ähnliche einfache Vorteile in ein typischerweise „Single-User“-System bringen, ohne separate Infrastruktur aufzubauen?
Absicht für Agenten spezifizieren
Die Anweisungen für dieses Multi-Agenten-System waren von entscheidender Bedeutung.
Anfangs machten wir sie nicht zu unserem Hauptfokus, sondern konzentrierten uns stattdessen auf ein stabiles und effektives Harness. Doch die Bedeutung der Anweisungen wurde schnell deutlich. Im Grunde interagierten wir mit einem typischen Coding-Agent – nur mit um Größenordnungen mehr Zeit und Rechenleistung. Das verstärkt alles, auch suboptimale und unklare Anweisungen.
Es lohnt sich also, mehr Zeit in die anfänglichen Anweisungen zu investieren. Letztlich sind Agenten eben Agenten: darauf trainiert, deine Anweisungen strikt zu befolgen, diesen Pfaden zu folgen und sie nicht zu ändern oder zu überschreiben – selbst dann, wenn sie schlecht sind.
Wir wollten in unseren Forschungsprojekten Erfolge sehen, also passten wir unsere anfänglichen Anweisungen an, während sich das Projekt und das Harness weiterentwickelten. Wir lernten, wie man einen Browser baut, und gleichzeitig, wie man dieses neue Multi-Agenten-System steuert. Dabei konnten wir sehen, wie sich schlechte oder zu wenig präzise Spezifikationen in der Qualität der Outputs niederschlugen – und zwar nicht wegen des Harness selbst. Das Harness befolgte lediglich unsere Anweisungen exakt.
Einige Beispiele aus dem Browser-Projekt:
- Anfangs konzentrierten sich die Anweisungen auf die Umsetzung von Spezifikationen und das Beheben von Bugs. Anweisungen wie „Spezifikationsimplementierung“ waren so vage, dass Agenten tief in obskure, selten genutzte Features einstiegen, statt sinnvoll zu priorisieren.
- Wir gingen implizit davon aus, dass es implizite Performance-Erwartungen innerhalb benutzerfreundlicher Grenzen gab. Doch erst explizite Anweisungen und erzwungene Timeouts brachten die Agenten dazu, Performance gegen andere Ziele abzuwägen.
- Bei komplexen Teilen des Systems können Agenten Code schreiben, der Speicherlecks hat oder Deadlocks verursacht. Menschen würden das bemerken, für Agenten war das jedoch nicht immer offensichtlich. Explizite, prozessbasierte Tools für das Ressourcenmanagement waren nötig, damit sich das System sauber erholen und defensiver verhalten konnte.
Unsere erste Version des einfachen Browsers ohne JavaScript lief auf eine Architektur hinaus, die sich nicht zu einem vollständigen Browser weiterentwickeln ließ. Das war ein Fehler in der anfänglichen Spezifikation.
Ähnlich war es bei den Abhängigkeiten: Obwohl den Agenten gesagt wurde, dass das Projekt ein Browser von Grund auf sein sollte, zogen sie dennoch einige Dependencies hinzu, die sie selbst hätten implementieren können oder als temporäres Gerüst hätten nutzen können, während die eigentliche Implementierung entstand. Das war ein Versäumnis in den Anweisungen. Ein späterer Durchlauf legte die Dependency-Philosophie und die Bibliotheken, die nicht genutzt werden durften, explizit fest, was das korrigierte.
Dieser spätere Durchlauf brachte außerdem eine größere Umstrukturierung in viele eigenständige Crates mit sich und entfernte sich von einem Monolithen. Das Repo war in einem stark beschädigten Zustand, aber das Multi-Agenten-System arbeitete sich innerhalb weniger Tage wieder zu funktionierendem Code vor. Das zeigte, dass das System stark dazu fähig ist, kollaborativ und intelligent zu arbeiten – selbst in vollständig kaputten Zuständen, statt weiter zu degradieren oder stecken zu bleiben. Dieser Durchlauf verbrachte außerdem deutlich weniger Zeit mit Warten auf die Kompilierung und lief mit einem mehrfach höheren Durchsatz als zuvor.
Architektur und Anweisungen sind wichtig. Agenten verfügen über enorme Engineering-Fähigkeiten, folgen Anweisungen aber kompromisslos bis zum Ende – egal ob gut oder schlecht. Die Balance zwischen zu engen Metriken und unstrukturierter Freiheit zu finden, war schwierig, ebenso wie die Frage, was offensichtlich war und was explizit erwähnt werden musste.
All das zeigt, wie wichtig es ist, Absicht hervorzulocken, zu spezifizieren und zu verstehen – und auf dieser Größenordnung wird das noch wichtiger. Steuerbarkeit und Beobachtbarkeit werden spannende Forschungsfelder bleiben, die weiter untersucht werden sollten.
Prompts optimieren
Prompting war ein wesentlicher Teil des Entwicklungsprozesses.
Wir haben festgestellt, dass es besser ist, keine Anweisungen für Dinge zu geben, die das Modell bereits kann, sondern nur für Dinge, die es nicht weiß (z. B. Multi-Agent-Zusammenarbeit) oder die für den jeweiligen Bereich spezifisch sind (z. B. wie man Tests ausführt, deine Deploy-Pipeline). Betrachte das Modell wie einen brillanten neuen Mitarbeiter, der sich mit Engineering auskennt, aber nicht mit deiner spezifischen Codebase und deinen Prozessen.
Einschränkungen sind wirkungsvoller als Anweisungen. „Keine TODOs, keine Teilimplementierungen“ funktioniert besser als „denk daran, Implementierungen fertigzustellen“. Modelle machen standardmäßig meist das Richtige. Einschränkungen definieren ihre Grenzen.
Vermeide bei übergeordneten oder tiefergehenden Aufgaben eine Checkbox-Mentalität. Gib detaillierte Anweisungen zu deiner Absicht, aber denk daran, dass konkrete Vorgaben dazu führen, dass sich das Modell eher darauf konzentriert, diese umzusetzen, statt den größeren Zusammenhang im Blick zu behalten. Außerdem stufst du implizit Dinge herab, die nicht gelistet sind. In der Regel ist es besser, das Modell sein Urteilsvermögen und seine Eigenständigkeit nutzen zu lassen.
Wir fanden es jedoch nützlich, konkrete Zahlen und Spannen anzugeben, wenn es um den Umfang geht. Anweisungen wie „generiere viele Aufgaben“ führen tendenziell zu einer kleinen Anzahl: konservativer Standard, auf Nummer sicher gehen, technisch gesehen den Anweisungen aber trotzdem folgen. „Generiere 20–100 Aufgaben“ vermittelt, dass die Absicht einen größeren Umfang hat, dass es ambitioniert sein sollte, und wir haben ein deutlich anderes, breiteres Verhalten beobachtet.
Erkenntnisse zum Systemdesign
Aus unserer Forschung haben wir einige Prinzipien abgeleitet:
- Das System sollte antifragil sein. Wenn wir die Anzahl der gleichzeitig ausgeführten Agenten erhöhen, steigt auch die Wahrscheinlichkeit von Ausfällen. Unser System muss den Ausfall einzelner Agenten verkraften, sodass andere sich davon erholen oder alternative Ansätze ausprobieren können.
- Empirie statt Annahmen. Wir wollten Daten und Beobachtungen nutzen, um Anpassungen vorzunehmen, anstatt von vornherein Annahmen darüber zu treffen, wie das System auf Basis menschlicher Organisationen oder bestehender Systemdesigns funktionieren sollte.
- Explizit auf Durchsatz auslegen. Das bedeutete, andere Aspekte des Codings bewusst zurückzustellen – etwa eine kleine, aber stabile Fehlerrate zu akzeptieren, die einen abschließenden Abgleichsdurchlauf erfordert, anstatt auf 100 % perfekt funktionierenden Code zu bestehen, der das System drastisch verlangsamen würde.
Diese Systeme sind oft elegant einfach, wenn sie richtig umgesetzt werden, aber es war nicht klar, welcher einfache Ansatz funktionieren würde, bis wir viele verschiedene Ansätze erprobt hatten. Das aktuelle Systemdesign läuft mit minimalem Overhead und ermöglicht auf sinnvolle Weise eine lineare Skalierung des Token-Durchsatzes. Am zugrunde liegenden Harness waren danach keine größeren weiteren Iterationen nötig.
Fazit
Während Geschmack, Urteilsvermögen und Richtung von Menschen kamen, war KI ein erheblicher Multiplikator, um diese Forschung schnell zu iterieren und zu erkunden.
Das ähnelt in gewisser Weise dem „virtuous“ KI-Kreislauf, bei dem KI genutzt wird, um KI zu entwickeln: Je besser Modelle, Agenten und Harnesses werden, desto stärker speist sich das System selbst und beschleunigt sich immer weiter. Wir formen die Tools, die uns formen.
Diese Forschung hat auch etwas Poetisches, das daran erinnert, wie manche Software-Teams heute arbeiten. Diese Modelle wurden nicht explizit auf diese Weise trainiert, was darauf hindeutet, dass es sich um emergentes Verhalten handelt und möglicherweise doch um die richtige Art, Softwareprojekte zu strukturieren.
Wir werden unsere Forschung zu extrem langlebigen Agenten fortsetzen, und unsere Befunde werden in die Zukunft unseres Produkts einfließen.