hier ist die Wahrheit, die niemand KI-Entwicklern sagt.
die meisten bauen Demos
alles, was du brauchst, um zu bauen, ist
ein KI-Agent auf Produktionsniveau
TLDR; wenn du es nicht lesen willst, gib diesen Link deinem Agenten und stell ihm Fragen: ➡️https://github.com/codejunkie99/agentic-harness
hier ist der Tweet, der alles auslöste
Das Problem ist, dass die meisten KI-Ingenieure keine klare Vorstellung davon haben, was sie eigentlich bauen sollen, wenn sie sich ernsthaft mit Agenten befassen.
Manche greifen zu LangChain, weil die Multi-Agent-Demos auf YouTube so sauber aussehen, und verbringen die nächsten zwei Wochen damit, gegen Python-Interop und Async-Runtime-Konflikte zu kämpfen, bevor sie das Ganze verwerfen.
Manche versuchen, eine eigene Orchestrierungsschicht von Grund auf zu bauen: eine Schleife, einen Session-Store, einen Context-Assembler – und werden nie mit dem eigentlichen Agenten fertig, weil die Infrastruktur den Zeitplan gefressen hat.
Andere kopieren das Hello-World-Webhook-Beispiel, bekommen eine JSON-Antwort zurück, nehmen an, sie hätten das System verstanden, und liefern etwas aus, das beim ersten Mal kaputtgeht, wenn eine Session länger als zehn Minuten läuft, eine Remote-Sandbox mitten im Task ausfällt oder der Context-Window ohne konfigurierte Kompaktierung voll läuft.
Das Ergebnis ist meist dasselbe: viel Infrastruktur, keine Produktionsagenten und kein mentales Modell dafür, wie eine Produktions-Agenten-Laufzeitumgebung tatsächlich aussieht.
Wenn dein Ziel für 2026 ist, echte Agenten zu bauen und auszuliefern, musst du keine sechs Frameworks lernen.
Du musst eine Laufzeitumgebung tief genug verstehen, um einen Produktionsagenten vom Handler bis zum Deployment zu beherrschen.
Das bedeutet, zu lernen, wie man:
- die Drei-Schichten-Architektur verdrahtet, sodass deine Handler-Logik Provider-Wechsel und Zieländerungen überlebt, ohne den Agenten-Code zu berühren
- Sessions und Tasks korrekt verwendet, sodass lange Jobs ihren eigenen Context nicht kontaminieren
- Rollen und Skills schreibt, die das Modellverhalten formen, ohne etwas neu zu kompilieren
- Kompaktierung konfiguriert, sodass Sessions, die zwei Stunden laufen, nicht schon nach einer Stunde zu halluzinieren beginnen
- HttpSessionEnv auf Remote-Sandboxes richtet, sodass das Binary lokal läuft, während die Ausführung auf Linux stattfindet
- das richtige Build-Ziel auswählt: native, node oder Cloudflare – ohne Agentenlogik zwischen ihnen umschreiben zu müssen
- Connectors generiert statt Adapter von Hand zu schreiben, und versteht, warum diese Unterscheidung unter echter Last wichtig ist
Dieser Leitfaden ist ein vollständiger technischer Walkthrough, der aus der tatsächlichen agentic-harness-Codebasis, sechs Wochen Bauen und Zerlegen echter Agenten damit und den Fehlermodi, die am meisten Zeit beim Debuggen gekostet haben, erstellt wurde.
Der Beitrag ist 4.000+ WÖRTER lang und bezieht sich direkt auf das Repo und die Docs – keine Second-Hand-Zusammenfassungen oder Demo-Level-Beispiele.
Aber sein eigentlicher Wert liegt darin, dass jeder Abschnitt einen funktionierenden Code-Snippet, eine klare Erklärung, warum die Entscheidung getroffen wurde, und den genauen Fehlermodus enthält, den du treffen wirst, wenn du ihn überspringst.
So kannst du, wenn du mit dem Lesen fertig bist, einen Produktionsagenten von Anfang bis Ende beherrschen – vom ersten Handler über die Sandbox bis zum CI-Job, der ihn unbeaufsichtigt ausführt.
Dieses Verständnis aufzubauen hat mehr als 6 WOCHEN täglicher Arbeit mit der Codebasis gekostet, größtenteils Debugging von Dingen, die korrekt aussahen, bevor sie unter echten Bedingungen kaputtgingen.
Jetzt lass uns loslegen. ⬇️
Die Form des Projekts
Zwei Crates. Ein Binary. Jedes Ausführungsziel ist eine Konfigurationsentscheidung, kein Rewrite.
- Das SDK ist eine Bibliothek, die du in jedes Rust-Projekt einbindest. Das CLI kapselt es. Dein Agent ist ein Rust-Binary, das mit
use agentic_harness::prelude::*;beginnt. cargo buildist die gesamte Pipeline. Kein Bundler. Kein Transpile-Schritt. Keine Sprachlaufzeit auf der Zielmaschine. Ein eigenständiges ausführbares Binary plus eine manifest.json.
Die Designbeschränkung, die alles antrieb: Dasselbe Agenten-Binary sollte auf deinem Laptop im interaktiven Modus laufen, in einem GitHub-Actions-Job, der ein frisches Repo klont, gegen eine Remote-E2B-Sandbox über HTTP und auf einer Cloudflare-Worker-Grenze – ohne eine einzige Zeile Agentenlogik zwischen ihnen zu ändern.
Jede Entscheidung in dieser Codebasis existiert, um diese Einschränkung zu erfüllen.
Die 3 Schichten und warum jede existiert
Das mentale Modell sind drei konzentrische Ringe. Zu wissen, wo jede Grenze liegt, wird dir mehr Debugging-Zeit sparen als alles andere in diesem Leitfaden.
Dein Rust-Code ist der äußere Ring.
- Du schreibst Handler. Handler empfangen einen
AgentContext. Sie rufen Sessions auf. Sessions rufen das Modell auf, lesen Dateien, schreiben Dateien, führen Shell-Befehle aus, spawnen Tasks, verbinden sich mit MCP-Servern. - Du berührst nie direkt einen HTTP-Client. Du parst nie direkt eine Modellantwort. Das SDK übernimmt beides.
Die Harness ist der mittlere Ring.
- Sie verwaltet die Agenten-Registry, routet Identität über URL-Pfade, handhabt Session-Persistenz über Aufrufe hinweg, Context-Kompaktierung, wenn Sessions wachsen, Rollen- und Skill-Erkennung, Modellauswahl-Priorität und das Provider-neutrale
ModelClient-Trait. - Das ermöglicht dir, Anthropic gegen OpenAI gegen eine lokale Ollama-Instanz auszutauschen, ohne Handler-Code zu berühren.
- Die Harness ist das, was deine Agentenlogik über Provider und Ziele hinweg wiederverwendbar macht.
- Sie ist auch der Ort, an dem all die Dinge behandelt werden, die in der Produktion kaputtgehen: Session-Zustand, Context-Überlauf, Provider-Fehler, gleichzeitige Anfrage-Reihenfolge.
Ausführungsziele sind der innere Ring.
- Lokales Dateisystem. CI-Checkout.
HttpSessionEnv, das auf Daytona oder E2B zeigt. Cloudflare-Worker-Grenze. - Die Harness kümmert sich nicht darum, welches du verwendest. Deine Handler auch nicht. Sie rufen
session.shell()undsession.write()auf, und die Harness übersetzt das in das, was das zugrunde liegende Ziel benötigt. - Diese Trennung ist der ganze Punkt. Wenn E2B eine neue API-Version veröffentlicht, aktualisierst du den Connector, nicht deine Agentenlogik.
- Wenn Anthropic
claude-opus-4-7ausliefert, aktualisierst duruntime.json, nicht deine Handler. Der äußere Ring bleibt sauber, weil der mittlere Ring die ganze Veränderung absorbiert.
Laufzeitkonfiguration: Die Datei, die die Modellebene steuert
Bevor du einen einzigen Handler schreibst, brauchst du runtime.json in deinem Workspace.
Lege dies unter .agentic-harness/config.json oder im Workspace-Root als agentic-harness.json ab. load_workspace_context() erkennt es automatisch.
Die Modellauswahl zur Laufzeit folgt dieser Priorität:
PromptOptions::model(...): Überschreibung pro Aufruf- Die Modell-Metadaten der ausgewählten Rolle: Standard pro Rolle
defaultModelaus der Laufzeitkonfiguration: Workspace-Standard
Das Wichtige zu verstehen: Die Modell-ID muss registriert sein, bevor du sie verwenden kannst. openaiCompatibleModels ist die Liste, die die Harness verwendet, um den integrierten Chat-Completions-Client zu verdrahten. Wenn dein Modell nicht in dieser Liste ist, erhältst du einen sauberen Fehler beim Start, anstatt eines verwirrenden Fehlers mitten in einer Session.
Für OpenAI-kompatible Gateways sieht die Konfiguration gleich aus. Setze baseUrl auf dein Gateway:
- Schreibe niemals einen literal API-Key in
runtime.json. VerwendeapiKeyEnvund behalte den tatsächlichen Key in deiner Umgebung. - Die Harness liest die Umgebungsvariable zur Anfragezeit, nicht beim Start – was bedeutet, dass du Keys rotieren kannst, ohne den Server neu zu starten.
Agentenidentität ist ein URL-Pfad, niemals eine Registry-Suche
Das war die erste Designentscheidung, die mich überrascht hat. Jetzt denke ich, dass sie die richtige ist.
Es gibt kein Agenten-ID-System. Keinen Registry-Key. Keine UUID, die du selbst generierst. Die Identität deines Agenten ist POST /agents/<name>/<id>.
- Die Harness verwaltet die gesamte Session-Zustandsbuchhaltung hinter dieser URL.
- Der Grund, warum das funktioniert: Jeder Aufrufer in jedem System weiß bereits, wie er aus dem Kontext eine sinnvolle ID konstruiert. Eine PR-Nummer. Eine Run-ID. Ein Zeitstempel kombiniert mit einem Task-Namen. Ein User-Handle.
- Du brauchst keinen Session-Erstellungs-Endpunkt. Du musst Session-IDs nicht separat speichern. Die URL ist die Session.
Der Agenten-Handler auf der Rust-Seite ruft ctx.id() auf, um die vom Aufrufer bereitgestellte ID zu erhalten:
Sessions: Der zustandsbehaftete Ausführungskontext
Eine Session ist mehr als ein Gesprächsstrang. Es ist der vollständige Ausführungskontext für eine Agenten-Invokation.
Sie enthält:
- Nachrichtenverlauf mit dem Modell
- Workspace-Dateizugriff (lesen, schreiben, bearbeiten, grep, glob, stat, readdir)
- Shell-Ausführung mit cwd- und env-Kontrolle
- Tool-Registrierungen (MCP-Server, benutzerdefinierte Tools)
- Die zugewiesene Rolle und deren System-Prompt-Overlay
- Das Kompaktierungsbudget und den History-Watermark
Du erhältst eine Session, indem du ctx.session_with_id() mit einer beliebigen sinnvollen ID aufrufst:
- Sessions bleiben über HTTP-Aufrufe hinweg bestehen, wenn du dieselbe ID verwendest. Rufe denselben Agenten-Endpunkt dreimal mit derselben Session-ID auf, und das Modell sieht alle drei Austausche als ein fortlaufendes Gespräch.
- Der Verlauf wird automatisch akkumuliert. Du verwaltest ihn nicht.
- Das ist es, was mehrstufige Workflows möglich macht, ohne dass du den Zustand selbst verwalten musst. Du rufst weiterhin
session.prompt()auf, und die Harness erledigt den Rest.
Wenn du große Mengen an Kontext zusammen mit einem Prompt übergeben musst, lies die Datei und formatiere sie inline:
Die Session verwaltet die Token-Zählung, sodass du nicht versehentlich das Context-Window mitten im Gespräch überläufst. Wenn du dich dem Budget näherst, wird die Kompaktierung ausgelöst. Mehr dazu in einem späteren Abschnitt.
Tasks: Fokussierte Kind-Sessions, die das Elternteil sauber halten
- Das ist das Primitive, von dem ich wünschte, ich hätte es am ersten Tag verstanden. Es ist der Unterschied zwischen Agenten, die über lange Jobs hinweg kohärent bleiben, und Agenten, die auf halbem Weg zu halluzinieren beginnen.
- Ein Task ist eine einmalige Kind-Session. Frischer Verlauf. Gemeinsamer Workspace. Gibt ein Ergebnis an das Elternteil zurück. Der Verlauf des Elternteils sieht nie das Zwischen- Reasoning des Tasks.
- Der Research-Task läuft isoliert. Seine gesamte Reasoning-Kette.
- Jede Zwischenbeobachtung, die das Modell über den Code gemacht hat, jedes "Warte, lass mich auch diese Datei überprüfen", bleibt innerhalb des Tasks.
- Die Eltern-Session erhält eine saubere Zusammenfassung. Das ist alles, was sie jemals sieht.Warum das in der Praxis wichtig ist: Wenn du explorative Analysen direkt innerhalb einer langlebigen Session durchführst, füllt sich der Verlauf mit Zwischen-Tool-Aufrufen, Teilantworten und Modell-Reasoning über Dinge, die nicht mehr relevant sind.
- Das Modell verankert sich in diesem Rauschen, wenn es das nicht sollte. Die Kompaktierung wird schließlich ausgelöst und verliert Kontext, den du eigentlich brauchtest. Tasks sind der chirurgische Fix.
Die Regel: Wenn das Teilproblem ein klares Ergebnis hat und nicht den Gesprächsverlauf des Elternteils benötigt, um abgeschlossen zu werden, mach es zu einem Task. Die Schwelle für "Mach es zu einem Task" ist niedriger, als du denkst.
Für parallele Analysen über eine Codebasis hinweg: Das Kartographen-Muster, fächert Tasks aus und sammelt Ergebnisse:
Jeder Task ist sauber. Jeder Task ist auf genau ein Verzeichnis fokussiert. Die Eltern-Session sammelt die Ergebnisse und schreibt das endgültige Dokument.
Wenn du 12 Module hast, führst du 12 fokussierte Tasks aus, jeder beginnt ohne Ballast von den anderen.
Rollen und Skills: Verhalten formen ohne Neukompilierung
- Rollen leben in
.agentic-harness/roles/. Skills leben in.agents/skills/. Beide werden automatisch erkannt, wenn die Harness startet. - Rollen sind System-Prompt-Overlays, die auf einen Aufruf beschränkt sind. Sie werden zur Aufrufzeit angewendet und danach verworfen. Sie bleiben nicht im Nachrichtenverlauf bestehen. Sie akkumulieren sich nicht über Aufrufe hinweg.
Die Prioritätskette: Aufruf-Rolle > Session-Rolle > Agenten-Rolle > keine Rolle.
- Das Modell-Frontmatter ist optional, aber nützlich. Es ermöglicht dir, bestimmte Rollen an bestimmte Modelle zu leiten.
- Deine Erklärer-Rolle läuft auf
claude-sonnet-4-6für Geschwindigkeit und Kosten. Dein Sicherheitsprüfer läuft aufclaude-opus-4-7für Tiefe. Du konfigurierst dies einmal in der Rollendatei und denkst nie wieder darüber nach. - Skills sind Verhaltensbeschreibungsdateien, die das Modell zu Beginn einer Session liest.
- Sie sind Markdown-Dateien in
.agents/skills/. Die Harness findet sie automatisch. Du registrierst sie nirgendwo.
Der praktische Nutzen: Eine Skills-Bibliothek neben deiner Codebasis beschreibt, wie du arbeitest. Commit-Nachrichtenformat, bevorzugte Bibliotheken, Migrations-Namenskonventionen, API-Designmuster, Testanforderungen.
Das Modell liest dies vor jeder Session. Du bearbeitest das Markdown. Das Verhalten wird beim nächsten Lauf aktualisiert. Kein Neukompilieren.
Das Modell liest dies. Es schreibt Commits, die deiner Konvention entsprechen. Du erinnerst es nicht jede Session. Du pflegst eine Datei.
Die Coding-Agent-Schleife im Detail
Die Coding-Agent-Schleife ist der primäre Anwendungsfall, um den das CLI herum gebaut wurde. Sie ist auch der Ort, an dem die meisten Dinge schiefgehen können, wenn du sie falsch konfigurierst.
Der vollständige Befehl mit allen relevanten Optionen:
Was jedes Flag tut und warum es wichtig ist:
--workspace .setzt das Root. Alle Dateioperationen sind hier in einer Sandbox. Der Agent kann außerhalb dieses Pfades weder lesen noch schreiben, erzwungen auf Harness-Ebene – nicht durch Vertrauen auf die Selbstbeschränkung des Modells.--llm autowählt das Modell ausdefaultModelin deiner Laufzeitkonfiguration. Verwende--llm anthropic/claude-opus-4-7für komplexe Aufgaben, die tiefes Reasoning erfordern, oder--llm anthropic/claude-sonnet-4-6für schnellere Iteration.--deny-pathist ein harter Block. Es matcht prefix-artig, also deckt--deny-path config/alles unterconfig/ab. Überprüfe deinen Workspace vor dem ersten Lauf und zähle jeden Pfad auf, der Secrets oder Produktionskonfiguration enthält – nicht nur.env.--approve-dependencieserlaubt Änderungen anCargo.tomlohne menschlichen Genehmigungsschritt. Lass dies weg, wenn du jede neue Crate überprüfen möchtest, bevor sie hinzugefügt wird.--commitstaged alle Änderungen automatisch und committed sie am Ende eines erfolgreichen Laufs mit der von dir angegebenen Nachricht. Ohne dieses Flag landen Änderungen als unstaged Modifikationen, die du überprüfen kannst.--prerstellt einen Pull Request aus dem Commit. Erfordert einen sauberen Git-Zustand vor dem Lauf und einen echten Branch, keinen detached HEAD.
Die Schleife selbst: Inspect → Brief → LLM + Tools → Edit + Test → Commit · PR.
- inspect: Liest die Workspace-Struktur, lädt Skills und Rollen, identifiziert die Dateien, die für den Prompt am wahrscheinlichsten relevant sind.
- Schreibt sein Verständnis in
coding-brief.md, bevor es Code berührt. - brief: Das Modell verpflichtet sich zu einem Plan. Du kannst
.agentic-harness/runs/<id>/coding-brief.mdwährend des Laufs lesen, um zu sehen, was es entschieden hat. - Wenn der Brief falsch aussieht, brich den Lauf ab. Es ist billiger, mit einem klareren Prompt neu zu starten, als den Agenten einen schlechten Plan ausführen zu lassen.
- LLM + tools: Die Edit-Test-Schleife. Das Modell nimmt Änderungen vor, führt die Testsuite aus, liest die Ausgabe, nimmt weitere Änderungen vor. Iteriert, bis Tests bestehen, das Iterationslimit erreicht ist oder es entscheidet, dass die Aufgabe abgeschlossen ist.
commit · PR: Staged, committed, pusht, öffnet den PR mit dem angehängten Diff.
Jeder Lauf schreibt sechs Artefakte nach .agentic-harness/runs/<id>/:
coding-brief.md: Der Plan, zu dem sich der Agent verpflichtet hat, bevor er Code geschrieben hatsummary.md: Für Menschen lesbarer Bericht darüber, was getan wurde, was versucht wurde und warumrun.json: Strukturierte Metadaten: verwendetes Modell, Gesamtdauer, Input/Output-Token-Zahlen, Iterationsanzahl, endgültiger Exit-Statusevents.jsonl: Jeder einzelne Tool-Aufruf in der Reihenfolge mit vollständigen Ein- und Ausgaben, zum Debuggen, was schiefgelaufen istdiff.patch: Der vollständige Diff aller Dateiänderungenchecks.json: Endgültige Test- und Lint-Ergebnisse, die Erfolg oder Misserfolg bestimmt haben
Tipps zum Merken
- Behandle diese als strukturierte Logs, nicht als flüchtige Ausgabe. Ich committe Lauf-Artefakte ins Repo für jede Aufgabe, die ich reproduzieren können muss.
- Die
run.jsonallein – 2 KB – sagt dir das Modell, die Token-Kosten und ob es erfolgreich war. Dieevents.jsonlsagt dir genau, was der Agent getan hat und in welcher Reihenfolge, wenn du einen schlechten Lauf debuggen musst.
Für CI lautet das Muster:
HttpSessionEnv: Das Binary lokal ausführen, remote ausführen
- Das ist die Fähigkeit, die ich am längsten gebraucht habe, um sie vollständig zu verstehen. Ich verwende sie jetzt bei fast jeder Aufgabe, die Infrastruktur berührt.
- Das Agenten-Binary läuft auf deinem Rechner oder in CI. Die Dateisystem- und Shell-Operationen werden innerhalb einer Remote-Sandbox ausgeführt.
- Der Agent weiß nicht und kümmert sich nicht darum, in welcher Umgebung er sich befindet.
Verwende use agentic_harness::HttpSessionEnv;
Das Wire-Protokoll ist JSON über HTTP. Jede Operation:
- exec
- read
- write
- edit
- grep
- glob
- stat
- readdir
- mkdir
- rm hat eine definierte Anfrage-/Antwort-Struktur.
Jede Sandbox, die dieses Protokoll implementiert, funktioniert als HttpSessionEnv-Ziel.
Um eine benannte Sandbox zu verdrahten:
Die integrierten Connectors kümmern sich um Auth- und Lifecycle-Boilerplate für Vercel Sandbox, Daytona und E2B:
- Der konkrete Anwendungsfall, für den ich dies am häufigsten verwende: Reproduktion von CI-Fehlern in einer sauberen Linux-Umgebung.
- Der Agent klont das Repo beim genauen fehlgeschlagenen Commit-Hash, führt den genauen fehlgeschlagenen Testbefehl aus, liest die vollständige Ausgabe, diagnostiziert den Fehler und schreibt einen Bericht.
- Ich lese den Bericht. Ich habe nie meinen lokalen Rechner berührt. Die Sandbox wird verworfen, wenn die Session endet.
Die Performance-Sache, vor der dich niemand warnt: Jeder Shell-Aufruf über HttpSessionEnv ist ein Netzwerk-Roundtrip. Enge Schleifen: edit, test, Ausgabe prüfen, edit – akkumulieren schnell Latenz.
Eine 40-Iterationen-Schleife, die lokal 5 Sekunden dauert, dauert mehrere Minuten gegen eine Remote-Sandbox, wenn jede Iteration drei separate Shell-Aufrufe macht.
Der Fix: Bündele Shell-Arbeit in Skripten.
Ein Aufruf pro Iteration statt drei. Schreibe das Skript einmal, führe es wiederholt aus. Der Latenzunterschied bei einer 40-Iterationen-Schleife ist real.
Build-Ziele: Dieselbe Codebasis, drei Deployment-Formen
native ist die Standardeinstellung. Ein Binary. Ein Manifest. Nichts anderes auf der Zielmaschine. Läuft überall, wo ein natives Linux-Binary ausgeführt werden kann.
node ist für Hosting-Plattformen, die einen Node-Einstiegspunkt erfordern. Der Build generiert server.mjs, das das native Rust-Binary als Kindprozess startet und HTTP an es weiterleitet. Die Agentenlogik läuft weiterhin als Rust. Die Node-Schicht ist ein 30-zeiliger HTTP-Shim.
Cloudflare ist für Edge-Deployment.
- Der Build generiert eine Worker-Grenzdatei und verknüpft einen Worker-kompatiblen App-Adapter.
- Handler kompilieren zu WASM über die WASM JSON ABI.
- Durable Object Bindings handhaben Session-Persistenz über Cloudflare KV.
Die wichtige Einschränkung bezüglich Cloudflare: Worker unterstützen keine langlebigen Shell-Befehle. Sie haben kein echtes Dateisystem.
Sie unterstützen kein cargo oder irgendein Build-Tooling. --target cloudflare ist für Webhook-Handling, Route-Metadaten, kleine Steuerungsendpunkte und Durable Object Routing – nicht für Coding-Arbeit.
Für alles, was cargo test ausführen muss, delegiere an einen nativen Prozess oder eine Remote-Sandbox.
Die praktische Entscheidungsmatrix:
- Ausliefern eines Agenten als API, die andere Dienste aufrufen → native hinter nginx oder einer verwalteten Plattform
- Hosting auf Railway, Render oder einer Plattform, die Node erwartet → node
- Webhook-Aufnahme, leichtes Routing, Durable Object Zustandsverwaltung → cloudflare
- Alles andere → native
Schema-gesteuerte Ausgabe: Typisierte Rust-Structs aus Modellantworten
Das Modell zu bitten, JSON zurückzugeben, und zu hoffen, dass es das tut, ist die halbe Lösung.
Die Harness extrahieren, validieren und in dein Rust-Struct deserialisieren zu lassen, ist die vollständige Lösung.
Das Modell kann Reasoning-Prosa zusammen mit der typisierten Nutzlast in derselben Antwort zurückgeben. Die Harness extrahiert den Ergebnisblock zwischen
--RESULT_START---und---RESULT_END---Markern. Du erhältst ein Rust-Struct. Compile-Zeit-Typsicherheit von der Modellausgabe bis zu deiner Handler-Logik.- Das Schema tut zwei Dinge: Es sagt dem Modell, welche Form es produzieren soll, und es gibt der Harness etwas, gegen das sie vor der Deserialisierung validieren kann.
- Wenn das Modell etwas zurückgibt, das nicht zum Schema passt, erhältst du
PromptError::SchemaValidationFailedanstatt eines Panics drei Aufrufstellen später, wenn du auf ein fehlendes Feld zugreifst.
MCP-Tools: Die Sandbox verlassen
Wenn der Agent Fähigkeiten über Datei und Shell hinaus benötigt, ist connect_mcp die Notluke.
Der Agent erhält das vollständige Tool-Set des MCP-Servers. Keine Tool-Definitionen zu schreiben. Beschreibungen kommen vom Server. Das Modell entscheidet anhand dieser Beschreibungen, wann es welches Tool aufruft.
Du kannst mehrere MCP-Server an eine Session anbinden:
- Das Modell ruft Tools basierend auf ihren Beschreibungen auf. Eine vage Beschreibung wie "Sentry durchsuchen" wird inkonsistent aufgerufen.
- Eine Beschreibung, die sagt: "Rufe dies auf, bevor du auf Fragen zu Fehlern, Incidents oder Produktionsproblemen antwortest", wird zuverlässig aufgerufen.
- Wenn du den MCP-Server kontrollierst, schreibe vorschreibende Beschreibungen: Sage dem Modell, wann es aufrufen soll, nicht nur, was es zurückgibt.
Connectors: Adapter generieren statt schreiben
Anstatt Adapter-Code von Hand gegen eine unbekannte API zu schreiben, leite ein Connector-Rezept an deinen Coding-Agenten weiter:
- Das Connector-Rezept ist eine strukturierte Beschreibung der Sandbox-API und des
SessionEnv-Vertrags, den es erfüllen muss. - Der Coding-Agent liest es, schreibt das Rust-Adapter-Modul, handhabt Authentifizierung, kapselt den Provider-Lebenszyklus und stellt es als
HttpSessionEnvbereit. - Du überprüfst den Diff. Du mergst ihn. Der Adapter lebt in deinem Projekt. Es ist jetzt dein Code.
Ich habe Daytona damit in etwa 20 Minuten inklusive des vollständigen Review-Zyklus verdrahtet. Der Agent hat das Auth-Header-Format beim ersten Durchlauf richtig hinbekommen.
Das Schreiben des Adapters von Grund auf gegen die Daytona-Docs hätte den größten Teil eines Nachmittags und mindestens zwei falsche Annahmen über den Refresh-Token-Flow gekostet.
Sobald der Connector generiert ist:
Automatische Kompaktierung: Lange Sessions handhaben, ohne Kontext zu verlieren
Langlebige Sessions akkumulieren Verlauf.
Irgendwann überlaufen sie das Context-Window des Modells.
Die Harness handhabt dies automatisch, aber du musst es richtig konfigurieren, sonst verlierst du Kontext genau im falschen Moment.
context_window_tokens ist das Gesamtbudget für die Session.
reserve_tokensist das, was du für die Antwort des Modells zurückhältst. Das effektive Limit für den Verlauf istcontext_window_tokens - reserve_tokens.keep_recent_messagesist die Anzahl der Nachrichten am Ende, die unabhängig von der Kompaktierung immer wörtlich erhalten bleiben.
Wenn der Verlauf das Budget überschreitet, bittet die Harness das Modell, alles zwischen dem System-Prompt und dem erhaltenen Ende zusammenzufassen.
Diese Zusammenfassung ersetzt den mittleren Abschnitt. Die Endnachrichten bleiben intakt. Die kompaktierte Session ist kleiner, und der nächste Aufruf passt innerhalb des Budgets.
Der Trade-off ist real: Zusammenfassungen verlieren an Präzision. Eine spezifische Entscheidung, die vor 50 Nachrichten getroffen wurde: "Wir haben authlib gewählt, weil es die einzige Bibliothek mit PKCE-Unterstützung ist, die mit axums Middleware-Modell funktioniert" – könnte in der Zusammenfassung als "wir haben authlib für Auth gewählt" überleben.
Wenn diese Präzision für Entscheidungen später in der Session tragend ist, speichere sie explizit:
- Schreibe Entscheidungen in Dateien. Dateien überleben die Kompaktierung. Das Modell kann sie bei Bedarf zurücklesen. Der Verlauf muss nicht alles tragen, wenn der Workspace es tut.
- Führe
agentic-harness doctoraus, um das tatsächlich gemeldete Context-Window deines Modells zu sehen. Setzecontext_window_tokensauf 80-90 % dieses Wertes. - Der Token-Zähler ist auf der Modellseite nicht perfekt genau, und ein einzelner großer Dateilesevorgang kann dich über die Grenze drücken, wenn du bei 99 % sitzt.
Worauf du achten solltest
- Session-Verlaufskontamination
- Problem: Explorative Analyse innerhalb einer langen Session vergiftet spätere Prompts mit Rauschen aus der Explorationsphase
- Fix: Verwende Tasks. Task-Verlauf berührt niemals das Elternteil. Die Schwelle für "Mach es zu einem Task" ist niedriger, als du denkst
- Rollen-Prioritätsüberraschungen
- Problem: Eine Aufruf-Rolle überschattet die Session-Rolle. Das Modell verhält sich anders als erwartet, und du weißt nicht warum
- Fix: Die Session-Rolle setzt die Identität. Die Aufruf-Rolle schränkt den Fokus ein. Sie schichten sich – die Aufruf-Rolle fügt hinzu, sie sollte nicht aufheben
--deny-path-Lücken
- Problem: Du verbietest
.env. Deine Secrets leben auch in.env.localundconfig/staging.yaml. Der Agent liest eine davon - Fix: Verbiete Präfixe, nicht Dateinamen.
--deny-path config/deckt alles darunter ab
- Detached HEAD in CI
- Problem: Der Agent bearbeitet, Tests bestehen, Commit schlägt fehl – weil es keinen Branch zum Committen gibt
- Fix:
git checkout -b agent-run-$RUN_IDvor dem Aufruf der Harness
- HttpSessionEnv-Latenz in engen Schleifen
- Problem: 40 Iterationen mit drei Shell-Aufrufen pro Iteration sind Minuten reiner Netzwerklatenz
- Fix: Schreibe
agent-check.sh, das alles in einem Aufruf erledigt. Ein Aufruf pro Iteration
- Unterschätzung des Context-Budgets
- Problem: Kompaktierung wird mitten im Task ausgelöst. Das Modell verliert seinen Plan und beginnt, aus der Zusammenfassung zu improvisieren
- Fix: Führe
agentic-harness doctoraus, um das tatsächliche Window zu erhalten. Setze das Budget auf 80-90 % davon
- Laufzeitkonfiguration nach Handler-Registrierung geladen
- Problem: Ein Handler wird vor
load_workspace_context()ausgeführt. Kein Modell registriert. Der Fehler sieht nicht wie ein Konfigurationsproblem aus. - Lösung: Rufen Sie
load_workspace_context()inapp()immer auf, bevor Sie Agents verbinden.
--llmwechselt automatisch zwischen Läufen
- Problem:
defaultModelwird aktualisiert. Zwei Läufe im Abstand von sechs Monaten sind nicht vergleichbar. Sie können den ersten nicht reproduzieren. - Lösung: Fixieren Sie das Modell in
runtime.jsonfür alles, was Reproduzierbarkeit erfordert.
- Löschen von Laufartefakten
- Problem: Sie bereinigen
runs/in einergitignore-Regel. Drei Wochen später müssen Sie eine Regression reproduzieren und alles ist weg. - Lösung: Committen Sie Laufartefakte für jede Aufgabe, die Sie reproduzieren müssen.
run.jsonist 2 KB. Behalten Sie es.
Was ich anders machen würde
- Führen Sie die
agentic-harness-Anleitung aus, bevor Sie irgendetwas anfassen. - Schreiben Sie Session-Level-Tests, bevor Sie Handler-Logik schreiben.
- Verwenden Sie Tasks für alles, was ein Unterergebnis hat.
- Fixieren Sie das Modell ab dem ersten ernsthaften Lauf.
- Speichern Sie Entscheidungen in Dateien, nicht im Session-Verlauf.
- Bündeln Sie Shell-Operationen von Anfang an, wenn Sie entfernte Sandboxes verwenden.
Das Fazit
Die meisten Agent-Frameworks sind Wrapper um einen API-Aufruf. Dies ist eine Runtime.
Ein Wrapper löst „das Modell zum Antworten bringen“. Eine Runtime löst „einen Agenten in die Produktion ausliefern und ihn funktionsfähig halten, nachdem sich das Modell ändert, nachdem sich die Sandbox ändert, nachdem sich die Codebasis ändert, nachdem die Session zwei Stunden läuft und das Kontextfenster überläuft“.
Die 3-Schichten-Architektur
- Ihr Code
- das Harness
- das Ausführungsziel
macht das möglich. Sie schreiben Handler. Das Harness absorbiert die gesamte operative Komplexität. Das Ausführungsziel ist eine Konfigurationswahl.
Die Dinge, die sich nicht ändern: Handler-Logik, Session-Struktur, Task-Muster, Rollendefinitionen, Skill-Dateien. Die Dinge, die sich ändern: Modelle, Anbieter, Sandbox-Anbieter, Bereitstellungsziele.
Die Architektur ist so ausgelegt, dass die sich ändernden Dinge niemals die Dinge berühren, die sich nicht ändern.
Das ist die Wette. Es ist die richtige Wette.
Ich hoffe, Ihnen hat dieser Artikel gefallen und Sie haben einen Einblick bekommen, wie ich für Agents und allgemein entwickle ❣️
Haftungsausschlüsse
Dieser Artikel wurde vom Autor recherchiert und geschrieben, bearbeitet von Minimax-M2.7. Das Thumbnail stammt von Pinterest.
Harrison Chase „Speicher sollte offen sein!“ —
https://x.com/hwchase17/status/2046308913939919232Harrison
Chase: „Your Harness, Your Memory“ —
https://www.langchain.com/blog/your-harness-your-memory
Vivek Trivedi: „The Anatomy of an Agent Harness“ —
https://www.langchain.com/blog/the-anatomy-of-an-agent-harness





