Das Dateisystem Ihres Agents ist eine Entscheidung: Erklärung der Deep Agents-Backends
Die Backends von LangChain Deep Agents entscheiden, welche Dateien erhalten bleiben: fünf eingebaute Optionen, die Routing-Funktion von CompositeBackend sowie die Namespace-Falle in Mehrbenutzer-Speichern und Sandboxes.
Quellen: LangChain Deep Agents: Your Agent’s Filesystem Is a Decision. Most People Make It by Accident. IV
Der beängstigendste „Agent-Bug“ führt nicht zum Absturz. Er vergisst leise das Gestrige, gibt die Erinnerungen eines anderen preis oder schreibt wertvolles Wissen in einen Speicherbereich, den man eigentlich nicht verlieren wollte. In LangChain’s Deep Agents ist der Ort, an dem diese Ergebnisse entschieden werden, der Backend – und das Ziel besteht darin, das Dateisystem nicht länger wie Magie zu behandeln, sondern bewusst zu entscheiden, was erhalten bleibt, was verschwindet und wer darauf zugreifen kann.
Jeder Deep Agents-Agent erhält ein Dateisystem, doch wo dieses Dateisystem tatsächlich gespeichert wird, liegt bei Ihnen: im Speicher, auf der Festplatte, in einem dauerhaften Speicher, der mehrere Threads umfasst, oder in einer Kombination daraus. Eine falsche Wahl führt dazu, dass ein Agent zwischen den Gesprächen alles leise vergisst.
Der Bug hinter den verschwindenden Notizen
Nehmen wir an, Sie entwickeln einen Agenten mit aktivierten Dateisystemwerkzeugen und beobachten, wie er mitten in einem Chat Notizen in /memories/findings.md speichert. Später liest er diese Notizen in derselben Konversation erneut ab. Alles in Ordnung – also veröffentlichen Sie den Agenten. Am nächsten Tag kehrt ein Benutzer zurück, erwähnt etwas, von dem der Agent angeblich gestern bereits wusste, doch der Agent hat keine Ahnung. Die Notizen sind verschwunden. Kein Fehler, keine Eintragung im Protokoll. Der Agent hat einfach von vorne angefangen, ohne etwas zu sagen.
Niemand schreibt solche Fehler absichtlich. Sie entstehen durch eine Standardeinstellung: Die Dateien des Agents landen in einem threadbezogenen Zwischenspeicher, der mit dem Ende der Konversation endet. Wenn man die Entscheidung darüber, wo die Dateien gespeichert werden, auslässt, entscheidet das Framework selbst. Für einen Zwischenspeicher ist das in Ordnung, doch für das Gedächtnis ist es die falsche Wahl.
Rechte, Speicher, Sandboxes und Bereitstellung basieren alle auf dieser einen Entscheidung. Wenn der Backend richtig gewählt ist, passt der Rest von selbst zusammen, und bei einem falschen Auswahl muss man stundenlang nach verschwindenden Notizen suchen.
Das Dateisystem ist virtuell und der Backend ist der Ort, an dem es realisiert wird
Der Agent sieht stets ein normales Dateisystem mit gewöhnlichen Pfaden. Der Backend bestimmt, aus was dieses Dateisystem besteht, und man kann Backend-Systeme austauschen, ohne dass sich das Verhalten des Agents ändert.
Es stehen sechs Dateisystem-Tools zur Verfügung: ls, read_file, write_file, edit_file, glob und grep. Für das Modell wirken sie auf einem einfachen Dateisystem. Es schreibt /workspace/plan.md hin, liest es später wieder und durchsucht /repo, als hätte es eine Festplatte – und all das ändert sich unabhängig davon, welches Backend dahintersteht.
Der Backend ist die Implementierung hinter dieser Abstraktion. Er beantwortet Fragen, über die sich der Agent niemals Gedanken macht. Wenn das Modell /workspace/plan.md schreibt, wohin gehen die Bytes? In das Python-Memory, das verschwindet, wenn der Prozess beendet wird? Auf eine echte Festplatte? In eine Datenbank, die über alle Gespräche hinweg erhalten bleibt, die der Benutzer je führen wird? Jede Antwort entspricht einem anderen Backend.
Die Wahl wird getroffen, indem ein Backend an create_deep_agent(model=..., backend=...) übergeben wird. Übergeben Sie nichts, wird die Standardkonfiguration verwendet, was das oben beschriebene Verschwinden der Notizen erklärt.
Ein Tipp, damit Ihr Code mit aktuellen Versionen übereinstimmt: Geben Sie dem Agenten eine fertige Instanz, wie zum Beispiel StateBackend(). Ältere Beispiele verwendeten einen lambda rt:-Wrapper, der heute veraltet und unnötig ist.
Fünf Backends, geordnet nach dem, was erhalten bleibt
Die einfache Methode, die fünf eingebauten Optionen voneinander zu unterscheiden, besteht darin, nach der Lebensdauer und nicht nach den internen Mechanismen zu gehen: Wie lange bleibt eine durch jede dieser Optionen geschriebene Datei bestehen?
StateBackend ist die Standardoption und stellt einen threadbezogenen Zwischenspeicher dar. Dateien befinden sich im Zustand des Agents und bleiben über die einzelnen Schritte einer Konversation (eines Threads) hinweg bestehen, werden aber nicht zwischen Threads geteilt. Es handelt sich dabei um das Notizbuch des Agents, ideal für vorläufige Arbeiten, die zwei Schritte später wieder gelesen werden und beim Ende der Konversation verschwinden. Es ist die richtige Standardoption – zugleich ist es genau jener Backend, der zu der Überraschung führt, dass die Notizen verschwinden, wenn man ihn fälschlicherweise für den Speicher hält.
StoreBackend bietet eine langlebige Speicherung über verschiedene Threads hinweg. Die Dateien werden in einem LangGraph-Speicher abgelegt und über mehrere Gespräche hinweg erhalten bleiben – genau das benötigt eine Langzeitmerkfunktion. Der erhebliche Nachteil dabei ist, dass man dem System mitteilen muss, wessen Daten gespeichert werden sollen. Darauf wird weiter unten eingegangen.
FilesystemBackend und LocalShellBackend nutzen die eigentliche Festplatte des Host-Computers. Sie lesen und schreiben tatsächliche Dateien in einem von Ihnen gewählten Verzeichnis, und LocalShellBackend stellt dem Agenten außerdem ein execute-Tool zur Verfügung, mit dem Shell-Befehle direkt auf Ihrem Computer ausgeführt werden können, ohne Sandbox. Sie eignen sich für einen lokalen Programmierassistenten, den man am eigenen Schreibtisch entwickelt, sind aber an allen anderen Orten gefährlich – weshalb die Dokumentation ausdrücklich davor warnt, sie in eingesetzten Agenten zu verwenden. Roher Zugriff auf den Host in Kombination mit dynamischen Benutzereingaben ist ein Sicherheitsproblem, das nur darauf wartet, einzutreten.
ContextHubBackend ist die native, dauerhafte Option von LangSmith. Die Dateien befinden sich in einem LangSmith Hub-Repository und werden als Commits gespeichert, sodass eine Persistenz über mehrere Ausführungen hinweg gewährleistet ist sowie ein Protokoll jeder Dateisystemänderung vorhanden ist – ohne dass Sie Ihren eigenen Speicher betreiben müssen. Dies macht Sinn, wenn Sie bereits im LangSmith-Ökosystem sind und Persistenz ohne Einrichtung einer Datenbank wünschen.
Wenn man diese Optionen zusammen betrachtet, liegen sie entlang einer einzigen Achse: Nichts wird gespeichert, nur das Gespräch wird gespeichert, alles wird gespeichert oder alles wird zusammen mit der Historie gespeichert. Wählen Sie den Punkt, den Ihre Funktion benötigt.
CompositeBackend: unterschiedliche Wege, unterschiedliche Lebenszyklen
Die Idee, die hinter den Backend-Lösungen steht, ist, dass man selten eine einzige Persistenzrichtlinie für den gesamten Dateisystem verwendet. Arbeitsdateien sollten günstig, schnell und verwendbar sein, während der Speicher dauerhaft sein sollte. Das sind zwei verschiedene Backend-Typen, und CompositeBackend bietet beides innerhalb eines einzigen Dateisystems durch Routing anhand von Pfadpräfixen.
Weisen Sie ihm ein Standard-Backend für die meisten Pfade zu sowie eine Routing-Tabelle, die ausgewählte Präfixe umleitet. Die übliche Struktur besteht darin, alles in einem temporären Bereich zu speichern, wobei der dauerhafte Speicher hinter /memories/ liegt:
from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, StoreBackend
from langgraph.store.memory import InMemoryStore
agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6",
backend=CompositeBackend( # ①
default=StateBackend(), # ②
routes={ # ③
"/memories/": StoreBackend(namespace=lambda _rt: ("memories",)), # ④
},
),
store=InMemoryStore(), # passed to create_deep_agent, not to the backend ⑤
)
Überprüfung der nummerierten Markierungen in dieser Auflistung:
CompositeBackendstellt einem Agenten ein Dateisystem zur Verfügung und leitet jede Operation an den Sub-Backend weiter, dessen Route zum Pfad passt.defaultübernimmt alles, was von keiner Route beansprucht wird. In diesem Beispiel ist das der threadbezogeneStateBackend.routesverknüpft Pfadpräfixe mit Backend-Instanzen. Wenn zwei Präfixe übereinstimmen, gewinnt das längere, sodass/memories/projects/Vorrang vor/memories/hat.- Schreibvorgänge unter
/memories/werden an einen zuverlässigenStoreBackendgesendet, dessennamespace-Funktion die Tupel zurückgibt, die den Eigentümer identifizieren und den Datenrahmen festlegen. - Der LangGraph
storewird ancreate_deep_agentübergeben, nicht an das Backend – ein technisches Detail, das viele beim ersten Mal übersehen.
Die Folge ist, dass alles, was unter /memories/ geschrieben wird, im dauerhaften Speicher abgelegt wird und über mehrere Gespräche hinweg erhalten bleibt, während alles andere – sei es ein Plan in /workspace, eine temporäre Datei oder ein in Cache gespeichertes Ergebnis – zum standardmäßigen StateBackend gelangt und beim Ende des Threads verschwindet. Der Agent kennt dies weder noch kümmert er sich darum; er schreibt lediglich die Pfade auf.
Eine Dateisystemstrategie für einen echten Agenten
Nehmen wir einen Agenten zur Wartung von Code, zum Beispiel einen namens buggy-shop. Wenn er an einem Repository arbeitet, sind die Dateien dieses Repositories im aktiven Zustand. Sie werden geladen, bearbeitet und getestet, und es gibt keinen Grund, dass sie in das nächste Gespräch übergehen. Was der Agent im Laufe der Zeit lernt, ist eine andere Sache – und genau das sollte er bei der nächsten Anfrage behalten: instabile Tests in einem Modul, eine Vorlage, die von mehreren Testsätzen gemeinsam verwendet wird, oder ein zuvor entdeckter Fehler bei der Paginierung.
So verwendet buggy-shop die obige kombinierte Struktur. Das Repository befindet sich unter dem Standard-StateBackend als threadbezogener Zwischenspeicher, während die angesammelten Notizen unter /memories/ in einem persistenten StoreBackend abgelegt sind. Das ist ein Agent mit einer bewussten Lösung dafür, was die Konversation überdauern sollte. Die Trennung des vorübergehenden Arbeitszustands von dauerhaftem Wissen ist der richtige Ansatz, und die Pfadpräfix-Verkehrsteuerung ist die Methode, um dies umzusetzen.
Wo der Code ausgeführt wird und wo die Dateien liegen
Bis jetzt ging es ausschließlich um Dateien, und viele Agenten benötigen nie mehr davon. Doch ein Agent, dessen Aufgabe es ist, einen Fix durch Ausführung von pytest zu beweisen, braucht eine Shell, denn das Ausführen von Befehlen ist keine Dateisystemoperation. Ein Sandbox-Backend bietet genau das: Neben dem Dateisystem stellt es das execute-Tool zur Ausführung von Befehlen bereit – alles innerhalb eines isolierten Containers, sodass der Agent den Host nicht beschädigen kann.
Agenten können auf zwei Arten mit einer Sandbox verbunden werden. Bei der einen Methode wird der Agent in die Sandbox gebracht, wo er auf deren Dateisystem arbeitet. Dadurch bleibt die lokale Entwicklung nah an der Produktivumgebung, doch die API-Schlüssel müssen in die Sandbox gebracht werden. Bei der anderen Methode wird die Sandbox als Werkzeug betrachtet: Der Agent bleibt auf Ihrem Server und ruft lediglich die Sandbox auf, um Code auszuführen. Die Anmeldeinformationen bleiben außerhalb, Sie können die Sandbox wegwerfen, und falls sie abstürzt, bleibt der Zustand des Agenten sicher. Deep Agents kann beides handhaben, was einen klaren Kontrast zu Tools darstellt, die nur die erste Methode zulassen.
Denken Sie daran, dass das Ausführen von Code und das Speichern von Dateien zwei getrennte Aspekte sind. Ein Dateisystem-Backend beantwortet einen davon, ein Sandbox-Backend den anderen – viele ernstzunehmende Agenten benötigen beide.
Die Konfiguration, die man nicht überspringen kann
Sobald StoreBackend mehr als einem Benutzer dient, ist eine Namespace-Factory erforderlich. Fehlt sie, kommt es zwar nicht zu einem Absturz, aber zu einem Datenleck. Der Backend muss wissen, wessen Dateien er speichert, und das erfährt er über einen Namespace – eine kleine Funktion, die den Laufzeitkontext entgegennimmt und ein Tupel mit dem Namen des Eigentümers zurückgibt. Die Einräumung von Berechtigungen nach Benutzer ermöglicht es jedem Nutzer, eigene Speicherbereiche zu nutzen:
from deepagents.backends import StoreBackend
backend = StoreBackend(
namespace=lambda rt: (rt.server_info.user.identity,),
)
Vermeiden Sie den Namespace sowie die veralteten Standard-Scope-Einstellungen durch den Assistenten, damit jeder Benutzer desselben Agents denselben Speicherpool teilt und in die angeblich privaten Daten der anderen einsehen kann.
Dieser Fehler besteht auf Ihrem eigenen Rechner, da Sie der einzige Benutzer sind, und wird erst zum Datenschutzproblem, sobald eine zweite Person sich anmeldet. Behandeln Sie die Namespace-Factory als zwingend erforderlich für alles, was über ein lokales Tool für einen einzigen Benutzer hinausgeht. In der Dokumentation steht, dass sie bald vorgeschrieben wird – schreiben Sie sie daher jetzt und überspringen Sie die Migration später.
Im Standard-Backend ist auch ein kleineres Trap enthalten. StateBackend speichert zu jedem Schritt den gesamten Zustand des Agents, wodurch eine reibungslose Fortsetzung des Gesprächs möglich ist. Der Nachteil ist, dass große in diesem Zustand gespeicherte Dateien Schritt für Schritt immer wieder serialisiert werden, wodurch große Dateien leise die Leistung und den Speicher verbrauchen. Die Lösung ist dasselbe Kombinationsmuster: Senden Sie große oder langlebige Elemente in einen Speicher und nutzen Sie StateBackend nur für kleine, vorübergehende Notizen.
Checkliste für heute
- Erfahren Sie, welches Backend Ihr Agent verwendet. Ohne das Argument
backend=beicreate_deep_agentwirdStateBackendgenutzt, wodurch der Agent zwischen den Gesprächen alles vergisst. Überprüfen Sie, ob das tatsächlich Ihr Wunsch ist.
StoreBackend.CompositeBackend, der standardmäßig auf StateBackend setzt und /memories/ an einen StoreBackend weiterleitet. Der store selbst wird an create_deep_agent übergeben, niemals an den Backend.StoreBackend eine Namespace-Factory. Verknüpfen Sie diese mit der Identität des Benutzers und tun Sie dies, bevor die zweite Person sich anmeldet.StateBackend weiter, damit sie nicht bei jedem Schritt erneut serialisiert werden.Der Backend wird zu einer Entscheidung
Behandeln Sie den Backend als eine Wahl – so vermeiden Sie von Anfang an das Problem des Mittagessenessens. Sie können die fünf eingebauten Optionen nach ihrer Lebensdauer beschreiben, mit CompositeBackend unterschiedliche Pfade für verschiedene Lebensdauern zuweisen, und Sie wissen, dass ein mehrbenutzerfähiges Speichersystem ohne eine Namespace-Factory nicht auskommt. Ein auf diese Weise konzipierter Agent hat einen Plan für seine Dateien: ein temporärer Speicher für das aktive Repository sowie einen dauerhaften Speicher für das, was er sich aneignet.
Eine langlebige Speicherung, in die der Agent selbst schreibt, sollte Sie zum Nachdenken anregen – und das ist gut so. Ein Agent, der Dateien schreiben kann, könnte versehentlich die falsche Datei schreiben, die richtige löschen oder einen Befehl ausführen, den Sie nicht wollten. Ein Dateisystem ist wie das Geben von Händen. Was danach kommt, ist die Leine – also deklarative Berechtigungen, die einschränken, welche Dateien der Agent berühren darf, sowie menschliche Genehmigung, die ihn dazu bringt, innezuhalten und vorher zu fragen. Eine Leine ist nur nützlich, wenn Sie bereits absichtlich festgelegt haben, wo die Dateien gespeichert werden.