Notiz

Die Agentenschleife unter einem Durable-Orchestrator: wo die Grenze verläuft

Agentengraph und Durable-Execution-Engine sind beide Orchestratoren. Ein Monat auf dem Prüfstand zeigte, wo die Grenze verläuft und was sie kostet.

Wohin gehört die Agentenschleife, wenn im System bereits eine Durable-Execution-Engine läuft? Die Weggabelung sieht nach Werkzeugwahl aus — Agentengraph gegen Engine —, doch beide sind Orchestratoren: jeder mit eigener Schleife, eigenem Zustand, eigenen Retries. Die Frage lautet nicht, wer gewinnt, sondern wo die Grenze zwischen ihnen verläuft und was sie kostet.

Es folgt, was ein Monat auf einem Prüfstand gezeigt hat, auf dem diese Grenze gezogen ist: Temporal auf Python, ein Modell-Gateway, Aufruf-Tracing, sieben Szenarien samt Entwickler-Agent und automatisierter SRE-Untersuchung.

Die These am Anfang

Die Regel stand am ersten Tag: ein Modellaufruf ist eine Activity, und der Graph gehört der Durable-Execution-Engine, nicht dem Agenten-Framework.

Die Begründung klang stichhaltig. Wer eine ganze Agentenschleife in eine einzige Activity packt, dem sieht die Engine von außen einen undurchsichtigen Block: ein Fehlschlag bei Schritt acht von fünfzehn spielt ihn ab Schritt eins erneut. Die schrittweise Ausfallsicherheit, wegen der die Engine überhaupt gewählt wurde, verschwindet, und obendrauf entstehen zwei Retry-Schichten, die nichts voneinander wissen.

Eine ehrliche Einschränkung: das ist eine Überlegung, keine Messung. Die Alternative wurde auf diesem Prüfstand nie gebaut, der Monat prüfte also den Preis der Entscheidung, nicht die These. Dieser Preis ist die Datenlage.

Was sich nicht behaupten lässt

„Agenten-Frameworks bieten keine Durability“ ist sachlich falsch. Moderne Agentengraphen persistieren ihren Zustand, mit Wahl des Modus: nur beim Verlassen des Graphen, asynchron oder synchron vor jedem Schritt. Der Unterschied verläuft anderswo.

Erstens die Granularität: was als Schritt gilt, der nicht erneut ausgeführt wird. Zweitens, wessen Budget die Versuche begrenzt. Drittens, was ein Resume tut — Knoten nach dem Wiederaufsetzpunkt laufen erneut, Modellaufrufe und externe Requests eingeschlossen. Der Wiederaufsetzpunkt ist genau die Einheit, für die zweimal gezahlt wird.

Die offizielle Integration zwischen Engine und Agenten-SDK löst genau das: Agentenschleife, Werkzeugwahl und Übergaben leben im Workflow, während jeder einzelne Modellaufruf als Activity läuft und beim Replay deshalb nicht wiederholt wird. Ein Agenten-Framework, eingesperrt in eine Activity, ist schlecht. Eine Agentenschleife unter einem Orchestrator mit einem Zug pro Activity ist gängige, unterstützte Bauweise. Die naive Fassung der These verwischt diesen Unterschied.

Drei Retry-Ebenen, die man nicht stapeln darf

In der Praxis lief es auf eine harte Trennung der Activity-Profile hinaus, und der Unterschied ist wesentlich.

ProfilTimeoutVersucheWarum
Code: Validierung, Rendering, Schreibvorgänge20–30 s3Fehlschlag ist billig und meist transient
Modellaufruf180–240 s1Fehlschlag ist nicht transient und kostet Geld
Effekt in Produktionaus der Policy1ein stiller Replay einer Mutation ist eine Entscheidung, kein Default

Der Retry mit Rückmeldung — Validierungsfehler wandern zurück in den Prompt — sitzt im Schritt selbst. Ein Infrastruktur-Retry darüber wäre eine zweite, unsichtbare Schicht: er kennt den Vertrag nicht, sieht das Episodenbudget nicht und bezahlt jeden Versuch. Davor warnte die ursprüngliche These, nur bestanden die Schichten am Ende aus „Retry des Schritts gegen Retry der Activity“ statt aus zwei rivalisierenden Frameworks.

Der Effekt verdient eine eigene Zeile. Er ist per Schlüssel idempotent und bekommt trotzdem keinen Infrastruktur-Retry: Idempotenz macht die Wiederholung sicher, nicht erwünscht. Eine solche Activity nimmt ihre Frist aus der Policy-Datei statt aus einer Konstante im Code, damit das dort notierte Timeout auch das echte ist.

Wo Autonomie endet

Die Formel, bei der der Prüfstand landete: Freiheit innerhalb der Episode, Determinismus zwischen den Episoden.

Der einzige Ort, an dem das Modell entscheidet, was als Nächstes passiert, ist eine Kind-Episode. Sie wählt, welche Dateien in welcher Reihenfolge geöffnet werden, liefert einen typisierten Vorschlag und stirbt. Außerhalb ändert sich nichts: Snapshot, Versuchsbudget, ob das Ergebnis angewendet wird und ob ein weiterer Durchgang folgt, gehören dem Elternteil. Das Kind hat kein Schreibwerkzeug und keine Shell, und die Lesewerkzeuge lösen jeden vom Modell gelieferten Pfad auf und verweigern alles, was außerhalb landet.

Budgets stehen als Konstanten im Code, nicht als Wünsche im Prompt: ein Zuglimit innerhalb eines Durchgangs, ein Limit für Durchgänge, eine eigene Obergrenze für abgelehnte Antworten — gezählt pro Episode, nicht pro Runde. Eine Obergrenze pro Runde multipliziert sich: drei Runden zu drei Versuchen ergeben neun Aufrufe auf dem schlechtesten Pfad, jeder mit ganzen Dateien im Kontext.

Das Zuglimit verdient sich noch aus einem zweiten Grund, den man vorher kennen sollte. Ein Modell, das dieselbe Datei immer wieder liest, verbraucht das gesamte Budget, ohne voranzukommen. Genau so verhält sich ein Reasoning-Modell, wenn ihm die eigene Historie unter den Füßen umgeschrieben wird — etwa von einem Sanitizer, der Pfade in seinen früheren Werkzeugaufrufen tokenisiert.

Der Fehlschlag, den keine Schicht sieht

Der wichtigste Fund des Prüfstands und der Grund, warum „einpacken und vergessen“ nicht funktioniert.

Eine Generierung, die auf Providerseite in einen Fehler läuft, kommt als HTTP 200 ohne Inhalt und ohne Werkzeugaufruf zurück. Sie verbrennt zehntausende Ausgabetokens und trägt keinen Preis-Header — abgerechnet wird sie nicht.

SchichtReagiert aufWarum sie schweigt
Fallback-Kette des GatewaysHTTP-Fehlerdie Antwort ist 200
Activity-Retry des Orchestratorseine Exceptiones gibt keine Exception
Agenten-SDKeine fehlerhafte Antwortdie Antwort ist wohlgeformt, nur leer

Wo ein Zug ein Werkzeug aufrufen muss, frisst ein leerer Zug einen von zehn Versuchen, und die Episode kann ihr ganzes Budget verbrauchen, ohne etwas zu beantworten. Die Rechnung sieht derweil günstig aus — daher eine eigene Metrik für Aufrufe ohne Preis: sie macht den Verlust sichtbar, statt ihn gratis wirken zu lassen. Welche Spartechniken bei Tokens wirklich tragen und welche überverkauft sind, habe ich gesondert beschrieben.

Der Detektor musste die geparste Antwort lesen statt den HTTP-Body: den Body in einem Transport-Hook zu konsumieren zerstört das Parsing des SDK. Wenn das SDK das Ergebnis zurückgibt, ist der Abschlussgrund längst weg, prüfbar bleibt die Folge — der Zug hat nichts produziert. Die Grenzen dieser Prüfung zählen. „Kein Werkzeugaufruf“ ist falsch für Agenten, die in Prosa antworten; „kein Tokenverbrauch“ würde eine legitim leere Vervollständigung zum Fehlschlag erklären.

Ein gemessener Lauf auf der günstigen Stufe: 167 Züge, davon 97 ohne Preis zurück. Dieselbe Anfrage erneut an dasselbe Modell rettete 0 von 36 — kein einziges Mal. Die starke Stufe beantwortete alle 36, keiner davon leer. Der Anteil beantworteter Fälle stieg von 79 auf 91 Prozent. Der Preis je Zug unterscheidet sich zwischen den Stufen etwa um das Siebenfache.

Wichtiger als die Zahlen: der Fix umgeht den Fehlschlag, er verringert ihn nicht. Die günstige Stufe liefert weiterhin bei mehr als der Hälfte ihrer Aufrufe einen leeren Zug. Ein dritter Weg — nicht die Stufe ändern, sondern die Anfrage: kleineres Werkzeugschema, gelockerte Pflicht zum Werkzeugaufruf — wurde hier nie gemessen und bleibt Vermutung.

Der Preis: ein Schritt lässt sich nicht löschen

Direkte Folge davon, dass jeder Schritt eine Activity ist. Replay läuft gegen die aufgezeichnete Historie, deshalb ist das Entfernen eines Aufrufs, den ein laufender Workflow bereits gemacht hat, ein Kompatibilitätsbruch.

Auf dem Prüfstand tauchte das bei einer Metrik-Migration auf: zwei Activities verloren ihren Zweck, als die Daten direkt in eine durable Tabelle wanderten — und blieben als leere Rümpfe im Code stehen, mit dem Kommentar „Name und Signatur absichtlich beibehalten“. Die Metrik ist keinen Bruch wert, und der Aufruf lässt sich nicht entfernen.

Die Kehrseite derselben Münze ist der ganze Sinn der Konstruktion: der Schritt läuft in einer Activity, also ruft der Replay das Modell nie erneut auf — das Ergebnis steht bereits in der Historie. Ein Worker-Neustart, eine Wiederherstellung nach einem Absturz, eine erneut abgespielte Historie zahlen keine Tokens zweimal. Gekauft wird nicht Atomarität, sondern Wiederholbarkeit ohne zweite Rechnung — dieselbe Logik wie bei einem Rollout, bei dem der Zustandseintrag zuletzt geschrieben wird.

Wann was

SituationWas nehmenWas Sie in Kauf nehmen
Pipeline läuft bereits unter einer Durable-Execution-EngineModellzug = Activity, Schleife im Workflowein Schritt lässt sich nicht löschen; Signaturen bleiben ewig
autonomer Agent, Schritte billig und umkehrbarAgentengraph mit eigener PersistenzKnoten nach dem Wiederaufsetzpunkt laufen erneut, Modellaufrufe inklusive
Effekte in der AußenweltEngine mit expliziten Retry-Profilenmehr Code um jeden Schritt, dafür kontrollierte Retries
Prototyp, ein Fehler kostet nur Zeitweder noch; eine schlichte Schleife im Codekeine Wiederherstellung; beim ersten Produktiveinsatz neu schreiben

Was diese Erfahrung nicht beweist

Ein Agentengraph als Eigentümer der Schleife wurde hier nie aufgesetzt: alles über seine Persistenzmodi stammt aus seiner Dokumentation, nicht aus einem eigenen Lauf. Non-Determinism-Fehler beim Replay traten in einem Monat kein einziges Mal auf — die Daten trennen nicht, ob die Disziplin hielt oder ob sie nie belastet wurde, und der Schluss „Zerlegung schützt vor Non-Determinismus“ folgt daraus nicht. Die Zahlen stammen von einem Prüfstand und ein bis zwei Läufen: Streuung zwischen Sitzungen wurde nie gemessen.

Dass der teure Teil eines agentischen Systems nicht das Harness selbst ist, sondern alles ringsherum, hat einen eigenen Text. Dieser Prüfstand ergänzt eine Korrektur: teuer ist die Grenze. Sie wird einmal gezogen, vor dem ersten Produktiveinsatz, und danach lebt man damit, dass jeder Schritt für immer in der Historie bleibt.

© 2026 axyi.ru · CC BY 4.0