Auf dem Weg zu selbstfahrenden Codebasen

Wir freuen uns über die Resonanz auf unsere Forschung zum Skalieren von langlaufenden autonomen Coding-Prozessen.
Diese Arbeit begann als interne Forschung, um die Grenzen der aktuellen Modelle auszuloten. Im Rahmen der Forschung haben wir ein neues Agent-Harness entwickelt, um viele Tausend Agents zu orchestrieren und ihr Verhalten zu beobachten. Bis letzten Monat war unser System stabil genug, um eine Woche lang ununterbrochen zu laufen und dabei die überwiegende Mehrheit der Commits für unser Forschungsprojekt (einen Webbrowser) zu erstellen. Dieser Browser war nicht für die externe Nutzung gedacht, und wir erwarteten, dass der Code Unvollkommenheiten aufweisen würde.
Selbst mit diesen Eigenheiten fühlte es sich jedoch wie ein Meilenstein an, der es wert war, geteilt zu werden: Tausende von Agents konnten zusammenarbeiten und Ergebnisse produzieren, die fast vollständig ohne menschliches Eingreifen lauffähig waren. Seitdem haben wir unsere Forschung fortgesetzt und wollten nun genauer darauf eingehen, wie das Harness gebaut wurde.
Außerdem stellen wir einen Teil dieser Forschung für einige Nutzer zum Ausprobieren zur Verfügung.
Hintergrund
Unser Forschungsprojekt begann als mein persönliches Nebenprojekt.
Ein Browser schien ein interessanter Benchmark zu sein. Er war komplex genug, um Einschränkungen von Frontier-Modellen sichtbar zu machen, und es gab 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 zu bitten, einen detaillierten Plan zum Bau einer Browser-Engine zu schreiben. Ich stupste es immer wieder mit „mach weiter“ an, um zu sehen, wie weit es den Plan ausarbeiten würde.
Das scheiterte schnell. Das Modell verlor den Überblick darüber, was es tat, hörte häufig auf und erklärte voreilig Erfolg, obwohl es noch weit davon entfernt war, und blieb an komplexen Implementierungsdetails hängen. Aber es zeigte Anzeichen tiefen Wissens und Intelligenz. Es konnte in kleinen Teilen guten Code schreiben.
Das Kernproblem war, dass der Browser als Aufgabe zu überwältigend war und in Unteraufgaben zerlegt werden musste. Als Nächstes ließ ich den Agent einen Abhängigkeitsgraphen der größeren Arbeitspakete planen, die Agents parallel übernehmen konnten. Agents wurden manuell für Aufgaben gestartet und angestupst, wenn sie stoppten. Das erhöhte den Durchsatz, aber die Ergebnisse waren nicht viel besser. Agents konnten nicht miteinander kommunizieren oder Feedback zum Projekt als Ganzem geben. Das System musste dynamischer werden.
Inzwischen begann GPT-5.1 (und später GPT-5.2), bessere Ergebnisse bei der präzisen Befolgung von Anweisungen zu zeigen. Das schien gut zu lang laufenden Agents zu passen, also aktualisierten wir unser Harness auf OpenAI-Modelle, basierend auf diesen Experimenten.
An diesem Punkt konnte das Harness eine einfache Version des Webbrowsers ohne JavaScript bauen, aber eine vollständige Browser-Engine mit einem einzigen Agent zu erstellen, wäre unvertretbar langsam.
Damit begann unsere nächste Forschungsrunde. Könnten wir das 10-Fache an Rechenleistung einsetzen, um 10-mal mehr sinnvollen Durchsatz zu erreichen?
Vom Single- zum Multi-Agent-System
Wir haben ein neues Repository mit einem einfachen, in Rust geschriebenen Harness angelegt.
Anstatt uns mit der Komplexität verteilter Systeme auseinanderzusetzen, ließen wir den Harness auf einer einzelnen, großen Linux-VM (Virtual Machine) mit vielen Ressourcen laufen. Um den Harness zu steuern, verbanden wir uns per SSH mit der VM und nutzten eine einfache Terminaloberfläche.
Wir investierten von Anfang an mehr Zeit in eine saubere Observability, also eine gute Beobachtbarkeit des Systems. Wir protokollierten alle Agent-Nachrichten, Systemaktionen und Befehlsausgaben mit Zeitstempeln, sodass wir Sitzungen analysieren und erneut abspielen konnten. Das war nicht nur hilfreich für unsere manuelle Überprüfung, sondern auch, um die Daten wieder in Cursor einzuspeisen, große Datenmengen zu filtern und schnell Muster zu finden.
Selbstkoordination
Unsere erste Multi-Agent-Idee war die einfachste: Agents mit denselben Rollen sollten eine gemeinsame Statusdatei verwenden, um zu sehen, woran andere arbeiten, zu entscheiden, woran sie selbst arbeiten, und die Datei zu aktualisieren.


Wir gaben möglichst wenig vor, was zu tun ist, und ließen stattdessen die Agents selbst herausfinden, wie sie sich koordinieren. Das scheiterte schnell.
Die Koordinationsdatei schuf schnell mehr Probleme. Agents hielten Sperren zu lange, vergaßen, sie freizugeben, versuchten zu sperren oder zu entsperren, wenn es unzulässig war, und verstanden im Allgemeinen nicht die Bedeutung davon, eine Sperre auf der Koordinationsdatei zu halten. Beim Sperren kann man leicht Fehler machen, und es ist schwer, es wirklich korrekt umzusetzen – mehr Prompting half nicht.
Sperren verursachten außerdem zu viel Konkurrenz um Ressourcen. 20 Agents liefen effektiv nur noch mit dem Durchsatz von 1–3, wobei die meiste Zeit mit Warten auf Sperren verbracht wurde. Wir versuchten, Agents ein Tool zu geben, mit dem sie explizit auf die Arbeit eines anderen Agents warten konnten, aber sie nutzten es selten. Wir versuchten auch einen sperrfreien, optimistischen Concurrency-Control-Ansatz, der den Overhead reduzierte, aber die Verwirrung nicht beseitigte.
Der Mangel an Struktur zwischen Agents bedeutete, dass kein einzelner Agent große, komplexe Aufgaben übernahm. Sie vermieden Konkurrenz und Konflikte und entschieden sich für kleinere und sicherere Änderungen, anstatt Verantwortung für das Projekt als Ganzes zu übernehmen.
Hinzufügen von Struktur und Rollen
Als Nächstes haben wir die Rollen getrennt, um den Agents Verantwortung und klare Zuständigkeiten zu geben:


Ein Planner würde zunächst den genauen Ansatz und die konkreten Ergebnisse ausarbeiten, um Fortschritte in Richtung der Anweisungen des Nutzers zu machen. Dies würde an einen Executor übergeben, der zum alleinigen führenden Agent wurde und 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.
Für kontinuierlichen Fortschritt und klare Verantwortlichkeiten lief im Anschluss ein unabhängiger Judge, nachdem der Executor fertig war, um zu bestimmen, ob die Aufgabe abgeschlossen wurde und ob eine weitere Iteration ausgeführt werden sollte. Dies löste viele Koordinationsprobleme. Eine einzelne Rolle zu haben, die die Ausführung verantwortete und überwachte, ermöglichte es den Workers, sich eng auf ihre Aufgaben zu konzentrieren, während das Gesamtsystem weiterhin Ergebnisse lieferte.
Beobachten und Hill-Climbing
Zu diesem Design zu gelangen, erforderte eine genaue Beobachtung des Systems.
Wenn es ein größeres Problem gab, trat es typischerweise wiederholt und bei vielen Agents und Tool-Aufrufen auf. Zum Beispiel haben wir festgestellt, dass es zu viel Konflikt gab, weil viele Agents gleichzeitig git restore ausgeführt haben. Wir haben Cursor verwendet, um Protokolle zu analysieren und sie mit unseren Prompts zu vergleichen, um zu verstehen, warum das Verhalten nicht den Erwartungen entsprach.
Am Ende stellten wir fest, dass dieses System vom langsamsten Worker ausgebremst wurde. Es war zu starr.
Die gesamte Planung im Voraus durchzuführen, machte es auch schwierig für das System, sich dynamisch anzupassen, sobald neue Probleme entdeckt wurden. Einige Agents liefen am Ende in unproduktive 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 Planer entfernt.
Der Executor konnte nun zusätzlich zum Starten von Tasks auch planen, wie das Ziel erreicht werden sollte. Da er der einzige Agent war, musste er keinen Plan irgendwo niederschreiben, nicht an einem statischen, unveränderlichen Plan festhalten und auch nicht starr darauf warten, dass alle Worker fertig wurden.
Sicherstellung der Aktualität
Um sicherzustellen, dass Agents in allen Rollen über lange Zeiträume nicht vom Kurs abweichen, haben wir Mechanismen zur Wahrung der Aktualität eingeführt:
- Eine
scratchpad.md-Datei sollte häufig überschrieben statt nur erweitert werden. - Einzelne Agents sollten automatisch zusammenfassen, sobald sie ihre Kontextgrenzen erreichen.
- Wir haben Selbstreflexions- und Alignment-Erinnerungen zu den System-Prompts hinzugefügt.
- Agents wurden ermutigt, jederzeit umzuschwenken und Annahmen zu hinterfragen.
Das System war nun äußerst dynamisch und flexibel: Es konnte Code proaktiv erkunden, Entscheidungen überdenken, Worker verwalten, Aufgaben verzahnen und kontinuierlich die neuesten Informationen berücksichtigen. Wir stellten fest, dass Agents Anweisungen zuverlässig genug bis zum Abschluss befolgten, sodass der Judge entfernt wurde, um das System einfach zu halten.


Pathologische Verhaltensweisen
Trotz dieser Verbesserungen zeigte der kontinuierliche Executor pathologische Verhaltensweisen. Er ging ohne ersichtlichen Grund in den Schlafmodus, stellte die Ausführung von Agents ein, erledigte Arbeit selbst, weigerte sich zu planen oder mehr als ein paar eng fokussierte Aufgaben zu erstellen, führte die Änderungen der Worker nicht korrekt zusammen und meldete einen verfrühten Abschluss.
Wir stellten fest, dass er gleichzeitig zu viele Rollen und Ziele zugewiesen bekam, darunter: planen, erkunden, recherchieren, Aufgaben anlegen, Worker prüfen, Code reviewen, Änderungen durchführen, Ausgaben zusammenführen und beurteilen, ob die Schleife abgeschlossen ist. Rückblickend ist es nachvollziehbar, dass er überfordert war.
Das endgültige Systemdesign
Das endgültige Design berücksichtigt all unsere Erkenntnisse:
- Ein Root-Planner verantwortet den gesamten Umfang der Anweisungen des Nutzers. Er ist dafür zuständig, den aktuellen Zustand zu verstehen und konkrete, gezielte Aufgaben zu erzeugen, die das System dem Ziel näherbringen. Er schreibt selbst keinen Code. Er weiß nicht, ob und von wem seine Aufgaben aufgegriffen werden.
- Wenn ein Planner feststellt, dass sich sein Umfang weiter aufteilen lässt, startet er Sub-Planner, die den delegierten, enger gefassten Teil vollständig übernehmen und dafür in ähnlicher Weise die volle Verantwortung tragen – aber nur für diesen Teil. Das geschieht rekursiv.
- Worker greifen Aufgaben auf und sind allein dafür verantwortlich, sie bis zur Fertigstellung voranzutreiben. Sie kennen das größere System nicht. Sie kommunizieren mit keinen anderen Planner oder Worker. Sie arbeiten an ihrer eigenen Kopie des Repos und erstellen, wenn sie fertig sind, eine einzige Übergabe, die das System an den Planner übermittelt, der die Aufgabe angefordert hat.
Interessanterweise entspricht dies tatsächlich der Arbeitsweise mancher Softwareteams heute.


Sub-Planner erhöhen den Durchsatz, indem sie die Arbeit schnell auf viele Worker verteilen und gleichzeitig sicherstellen, dass ein Agent weiterhin die vollständige Verantwortung für das gesamte System trägt. Das half auch bei großen Projekten und Aufgaben, bei denen ein einzelner Planner sonst überfordert wäre und einen Tunnelblick entwickeln würde.
Die Übergabe enthält nicht nur, was erledigt wurde, sondern auch wichtige Notizen, Bedenken, Abweichungen, Erkenntnisse, Gedanken und Feedback. Der Planner erhält dies als nachgelagerte Nachricht. So bleibt das System in kontinuierlicher Bewegung: Selbst wenn ein Planner „fertig“ ist, erhält er weiterhin Updates, zieht das neueste Repo und kann weiter planen und nachgelagerte Entscheidungen treffen.
Alle Agents verfügen über diesen Mechanismus. Dadurch bleibt das System äußerst dynamisch und selbstkonvergent, Informationen werden entlang der Kette nach oben zu Verantwortlichen mit zunehmend globaler Sicht propagiert – ohne den Overhead globaler Synchronisierung oder Cross-Talk.
Entfernen des Integrators
Ursprünglich haben wir einen Integrator hinzugefügt, um eine zentrale, global ausgerichtete Qualitätskontrolle zu ermöglichen und Konflikte zu vermeiden, die entstehen, wenn zu viele Worker gleichzeitig versuchen zu pushen, zu rebasen, Konflikte zu lösen und zu mergen.
Er wurde jedoch schnell zu einem offensichtlichen Engpass. Es gab Hunderte von Workern und nur ein einziges Gate (d. h. „Bürokratie“), durch das sämtliche Arbeit hindurchmusste. Wir haben verschiedene Prompts ausprobiert, uns letztlich aber entschieden, dass er überflüssig war und entfernt werden konnte, um das System zu vereinfachen.
Durchsatz und Abwägungen
Das System erreichte einen Höchstwert von etwa 1.000 Commits pro Stunde über 10 Mio. Tool-Aufrufe innerhalb einer Woche. Nachdem das System gestartet war, benötigte es keinerlei manuellen Eingriff von unserer Seite.
Es wurden bewusst Kompromisse eingegangen, um diesen Durchsatz zu erreichen.
Commit-Korrektheit
Als wir vor jedem einzelnen Commit 100 %ige Korrektheit verlangten, führte das zu starker Serialisierung und verlangsamte den effektiven Durchsatz massiv. Schon ein kleiner Fehler, etwa eine API-Änderung oder ein Tippfehler, konnte das gesamte System zum Stillstand bringen. Worker gingen über ihren eigentlichen Aufgabenbereich hinaus und begannen, irrelevante Dinge zu reparieren. Viele Agents stürzten sich gleichzeitig auf dasselbe Problem und behinderten sich dabei gegenseitig.
Dieses Verhalten war weder hilfreich noch notwendig. Etwas Spielraum zuzulassen bedeutet, dass Agents darauf vertrauen können, dass andere Probleme bald von anderen Agents behoben werden – was auch zutrifft, da das System eine effektive Verantwortungszuordnung und Delegation über die gesamte Codebasis hinweg hat. Fehler treten auf und werden dann schnell behoben. Die Fehlerrate bleibt klein und konstant – vielleicht selten völlig fehlerfrei, aber stabil und beherrschbar, ohne explosionsartig anzusteigen oder sich zu verschlechtern.
Das könnte darauf hindeuten, dass ein ideal effizientes System eine gewisse Fehlerrate akzeptiert, aber ein finaler „grüner“ Branch erforderlich ist, bei dem ein Agent regelmäßig Snapshots aufnimmt und kurz vor dem Release noch einen schnellen Bereinigungsdurchlauf macht.
Synchronisierungs-Overhead
Manchmal bearbeiten mehrere Agents dieselbe Datei oder refaktorieren denselben Code. Anstatt zu versuchen, diese Fälle vollständig zu eliminieren oder eine übermäßig ausgefeilte Lösung zu bauen, akzeptieren wir gewisse Momente der Turbulenz und lassen das System sich über einen kurzen Zeitraum hinweg auf natürliche Weise annähern und einpendeln.
Das verbraucht einige zusätzliche Token und erzeugt lokale Konflikte, hält das System insgesamt aber einfacher: Es ist leichter, Modelle auszurichten, ohne sie zu überfordern, leichter zu verwalten und zu beobachten, verursacht weniger Reibung und erhöht die globale Produktivität. Es vermeidet außerdem übermäßig komplexe Ansätze.
Erkenntnisse zur Infrastruktur
Jede Multi-Agent-Ausführung lief auf einer eigenen großen Maschine mit reichlich Systemressourcen, um vorzeitige Komplexität rund um verteilte Systeme zu vermeiden. Das passte gut, da die meisten Ausführungen bei mehreren hundert Agents ihren Peak hatten, was diese Maschinen typischerweise auslastete, aber nicht überbeanspruchte. Diese Architektur erleichterte es, Systemmetriken zu beobachten sowie Zustand bei Bedarf zu teilen und zu kopieren.
Nachdem die RAM-Nutzung der Agents begrenzt worden war, wurde die Festplatte zum Engpass. Besonders bei einem monolithischen Projekt führten Hunderte von Agents, die gleichzeitig kompilierten, zu vielen GB/s an Lese- und Schreibzugriffen auf Build-Artefakte. Das hatte einen erheblichen Einfluss auf den gesamten Durchsatz des Harnesses – eine interessante Erkenntnis: Projektstruktur, Architekturentscheidungen und Developer Experience können Token- und Commit-Durchsatz beeinflussen, einfach weil die Arbeit mit der Codebasis (z. B. Kompilierung) die Zeit dominiert, statt idealerweise das Nachdenken und Programmieren.
Es gab außerdem Einschränkungen und Ineffizienzen in der allgemeinen Entwicklungsumgebung: Dinge, die für einen einzelnen Workspace sinnvoll oder unbedeutend sind, fallen ins Gewicht, wenn Hunderte von Agents dasselbe auf einer Maschine tun. Eine triviale Lösung wäre, jedem Agent eine eigene Maschine zu geben. Aber es gibt interessante, naheliegende Chancen für große Effizienzgewinne, allein durch das Überdenken und Neugestalten einiger dieser Grundbausteine und Tools.
Viele Tools wie Git und Cargo verwenden zum Beispiel gemeinsame Sperren, vor allem als einfache Mechanismen zur Kontrolle von Nebenläufigkeit. Könnte das Übernehmen etablierter Mechanismen aus nebenläufigen Systemen wie Datenbanken dafür sorgen, dass diese in Multi-Agent-Systemen genauso gut funktionieren? Alle Agents haben ihre eigene Kopie des Repos, aber die meisten Dateien und Artefakte sind identisch; könnten einfache Copy-on-Write- und Deduplizierungsfunktionen, wie man sie in ausgereifteren Speichersystemen in der Produktion findet, ähnliche naheliegende Verbesserungen in einem typischerweise „Single-User“-System bringen, ohne separate Infrastruktur aufzubauen?
Intention gegenüber Agents präzisieren
Die Anweisungen für dieses Multi-Agent-System waren äußerst wichtig.
Anfangs waren sie nicht unser primäres Ziel – wir wollten zuerst ein stabiles und effektives Harness aufbauen. Doch die Bedeutung der Anweisungen wurde schnell deutlich. Im Kern 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.
Mehr Zeit in die anfänglichen Anweisungen zu investieren, ergibt daher Sinn. Letztlich sind Agents immer noch Agents: darauf trainiert, deine Anweisungen strikt zu befolgen, diesen Wegen zu folgen und sie weder zu ändern noch zu übersteuern – selbst wenn sie schlecht sind.
Wir wollten in unseren Forschungsprojekten Erfolg sehen, also haben wir unsere anfänglichen Anweisungen angepasst, während sich Projekt und Harness weiterentwickelten. Wir lernten, wie man einen Browser baut, und gleichzeitig, wie man dieses neue Multi-Agent-System bedient – und konnten sehen, wie sich schlechte oder unzureichend spezifizierte Vorgaben in der Qualität der Ergebnisse widerspiegelten, was nicht am Harness selbst lag. Das Harness folgte lediglich exakt unseren Anweisungen.
Einige Beispiele aus dem Browser-Projekt:
- Anfänglich konzentrierten sich die Anweisungen auf das Implementieren von Specs und das Beseitigen von Bugs. Anweisungen wie „spec implementation“ waren so vage, dass Agents tief in obskure, selten genutzte Features einstiegen, statt intelligent zu priorisieren.
- Wir sind implizit davon ausgegangen, dass es Leistungserwartungen innerhalb benutzerfreundlicher Grenzen gab. Aber es brauchte explizite Anweisungen und erzwungene Timeouts, um Agents dazu zu bringen, Performance gegenüber anderen Zielen auszubalancieren.
- Für komplexe Teile des Systems können Agents Code schreiben, der Memory Leaks hat oder Deadlocks verursacht. Menschen würden das bemerken, aber für Agents war es nicht immer offensichtlich. Explizite, prozessbasierte Werkzeuge für Ressourcenverwaltung waren erforderlich, damit sich das System sauber erholen und defensiver verhalten konnte.
Unsere erste Version des einfachen Browsers ohne JavaScript lief auf eine Architektur hinaus, die ungeeignet war, sich zu einem vollwertigen Browser weiterzuentwickeln. Das war ein Versagen der anfänglichen Spezifikation.
Ähnlich war es so, dass die Agents zwar angewiesen waren, dass das Projekt ein Browser von Grund auf sein sollte, sie aber dennoch einige Dependencies einbanden, die sie selbst hätten implementieren können oder als temporäres Gerüst hätten nutzen können, während die eigentliche Implementierung im Gange war. Das war ein Versäumnis in den Anweisungen. Ein späterer Durchlauf legte die Dependency-Philosophie und die Bibliotheken, die nicht verwendet werden durften, explizit fest, was das Problem behob.
Dieser spätere Durchlauf nahm auch eine größere Umstrukturierung in viele eigenständige Crates vor und entfernte sich von einem Monolithen. Das Repo war in einem stark kaputten Zustand, aber das Multi-Agent-System konvergierte innerhalb weniger Tage zu funktionierendem Code. Das zeigte, dass das System eine starke Fähigkeit zur kollaborativen und intelligenten Arbeit hat, auch in völlig kaputten Zuständen, statt weiter zu zerfallen oder stecken zu bleiben. Dieser Durchlauf verbrachte außerdem deutlich weniger Zeit mit Warten auf Kompilierung und lief mit einem Vielfachen des bisherigen Durchsatzes.
Architektur und Anweisungen sind entscheidend. Agents haben immense Engineering-Fähigkeiten, werden aber Anweisungen kompromisslos bis zum Ende folgen – ob gut oder schlecht. Die Balance zwischen zu engen Metriken und unstrukturierter Freiheit zu finden, war schwierig, ebenso wie zu wissen, was offensichtlich ist und was explizit erwähnt werden muss.
All dies unterstreicht die Bedeutung, Intentionen herauszuarbeiten, zu präzisieren und zu verstehen – was in diesem Maßstab noch bedeutender wird. Steuerbarkeit und Beobachtbarkeit werden interessante Forschungsbereiche bleiben, die es weiter zu erkunden gilt.
Optimierung von Prompts
Prompting war ein wesentlicher Teil des Entwicklungsprozesses.
Wir haben festgestellt, dass es besser ist, das Modell nicht für Dinge anzuleiten, die es ohnehin kann, sondern nur für Dinge, die es nicht kann (z. B. Multi-Agent-Zusammenarbeit) oder die spezifisch für die betreffende Domäne sind (z. B. wie Tests ausgeführt werden, eure Deploy-Pipeline). Behandle das Modell wie eine brillante neue Fachkraft, die sich mit Engineering auskennt, aber nicht mit eurer spezifischen Codebasis und euren Prozessen.
Einschränkungen sind wirkungsvoller als Anweisungen. „Keine TODOs, keine teilweisen Implementierungen“ funktioniert besser als „denk daran, Implementierungen fertigzustellen“. Modelle tun im Allgemeinen standardmäßig sinnvolle Dinge. Einschränkungen definieren ihre Grenzen.
Vermeide eine Checklisten-Mentalität bei höher gelagerten oder tiefergehenden Aufgaben. Gib detaillierte Anweisungen zu deiner Absicht, aber denke daran, dass konkrete To-dos das Modell dazu bringen, sich darauf zu konzentrieren, diese zu erfüllen, statt auf den größeren Kontext. Außerdem priorisierst du implizit alles, was nicht aufgelistet ist, nachrangig. Typischerweise ist es besser, dem Modell sein eigenes Urteilsvermögen und seinen Handlungsspielraum zu lassen.
Wir fanden es hilfreich, konkrete Zahlen und Spannweiten zu nennen, wenn es um den Umfang geht. Anweisungen wie „generiere viele Tasks“ führen tendenziell zu einer geringen Anzahl: konservativer Standard, auf Nummer sicher gehend, formal immer noch befolgt. „Generiere 20–100 Tasks“ signalisiert, dass der Umfang größer sein soll, es ehrgeizig sein darf, und wir haben ein deutlich anderes, breiteres Verhalten beobachtet.
Erkenntnisse aus dem Systemdesign
Wir haben aus unseren Untersuchungen einige Prinzipien abgeleitet:
- Das System sollte antifragil sein. Wenn wir die Anzahl gleichzeitig laufender Agents hochskalieren, steigt auch die Ausfallwahrscheinlichkeit. Unser System muss den Ausfall einzelner Agents verkraften können und es anderen ermöglichen, sich zu erholen oder alternative Ansätze auszuprobieren.
- Empirisch statt annahmegetrieben. Wir wollten Daten und Beobachtungen nutzen, um Anpassungen vorzunehmen, anstatt mit Annahmen darüber zu starten, wie es funktionieren sollte – etwa basierend auf menschlichen Organisationen oder bestehenden Systemdesigns.
- Explizit auf Durchsatz hin auslegen. Das bedeutete, andere Aspekte der Programmierung abzuwägen, zum Beispiel eine kleine, aber stabile Fehlerrate zu akzeptieren, die einen abschließenden Abgleich erfordert, anstatt 100 % perfekt funktionierenden Code anzustreben, der das System drastisch verlangsamen würde.
Solche Systeme sind, wenn sie gut umgesetzt sind, oft elegant einfach, aber es war nicht klar, welcher einfache Ansatz funktionieren würde, bevor wir viele verschiedene Ansätze untersucht hatten. Das aktuelle Systemdesign läuft mit minimalem Overhead und ermöglicht eine lineare Skalierung des Token-Durchsatzes auf sinnvolle Weise. Am Harness selbst waren keine größeren weiteren Iterationen nötig.
Fazit
Während Geschmack, Urteilsvermögen und Richtung von Menschen kamen, war KI ein bedeutender Multiplikator, um diese Forschung schnell iterativ weiterzuentwickeln und zu erkunden.
Das hat eine gewisse Ähnlichkeit mit der „tugendhaften“ KI-Schleife, in der KI verwendet wird, um KI zu entwickeln – und je besser Modelle, Agents und Harnesses werden, desto stärker speist sich das System in sich selbst zurück und beschleunigt immer weiter. Wir formen die Werkzeuge, die uns formen.
In dieser Forschung gibt es eine poetische Ähnlichkeit zu der Art und Weise, wie einige Softwareteams heute arbeiten. Diese Modelle wurden nicht explizit auf diese Weise trainiert, was nahelegt, dass es sich um emergentes Verhalten handelt – und möglicherweise doch um die richtige Art, Softwareprojekte zu strukturieren.
Wir werden weiterhin extrem lange laufende Agents erforschen; unsere Ergebnisse werden die Zukunft unseres Produkts mitprägen.