Startseite / Artikel

Erklärung des Agentenmemorys: Kontextfenster, RAG und persistenter Zustand

Das Agentenmemory umfasst drei verschiedene Komponenten. Erfahren Sie, wie sich das Kontextfenster, die Informationsabrufung und der persistente Zustand voneinander unterscheiden, was jede Komponente kostet und wie man zunächst die richtige auswählt.

Verlag: REACTAPP.TOP10 Min. Lesezeit2195 Wörter

Quellen: Agent Memory Explained

Nur wenige Begriffe verursachen bei der Entwicklung von Agenten so viel Verwirrung wie „Gedächtnis“. Wenn jemand sagt, sein Agent habe ein Gedächtnis, könnte das bedeuten, dass die Konversation lang ist, dass eine Vektordatenbank verbunden ist oder dass Fakten in einer Datei gespeichert werden, die auch nach einem Neustart erhalten bleibt. Das sind drei getrennte Systeme mit unterschiedlichen Kosten, verschiedenen Ausfallmöglichkeiten und unterschiedlichen Existenzgründen.

Eine einzige Aussage beseitigt den größten Teil der Verwirrung. Das Modell verfügt über kein Gedächtnis, nur über eine Eingabe – und das, was die Leute als Gedächtnis bezeichnen, ist lediglich eine Strategie zur Auswahl dessen, was in diese Eingabe gelangt.

Das Modell ist zustandslos. Jeder API-Aufruf beginnt von Null aus, ohne Erinnerung an Ihre letzte Nachricht, Ihre letzte Sitzung oder den Namen, den Sie ihm gegeben haben. Was es während eines Aufrufs weiß, ist ausschließlich das, was in der Anfrage enthalten ist – und nichts anderes.

Daher lautet die wichtige Frage nicht, ob der Agent ein Gedächtnis hat. Vielmehr geht es darum, was in dieser Anfrage einen Platz erhält und woher es stammt. Es gibt drei Antworten, und die Aufgabe besteht darin, sie voneinander zu unterscheiden.

Stateless-Modell, stateful-Anwendung

Anfänger gehen davon aus, dass das Modell ein Gespräch führt. Das ist nicht der Fall. Die Anwendung führt das Gespräch und wiedergibt es. Wenn Sie eine vierte Chat-Nachricht senden, überträgt Ihr Code jedes Mal alle Nachrichten 1, 2, 3 und 4. Das Gefühl der Kontinuität entsteht durch das Wiederversenden der Historie, wobei das Modell einfach eine längere Eingabe als zuvor erhält.

Angesichts dessen sind die drei Ebenen nicht mehr abstrakt:

  • Das Kontextfenster ist das, was derzeit in der Anfrage enthalten ist.
  • Retrieval (RAG) ist die Methode, mit der man Material findet, um es in die Anfrage aufzunehmen.
  • Persistenter Zustand bedeutet, dass Informationen über einen Anfragezeitraum hinaus erhalten bleiben, damit sie später wieder hinzugefügt werden können.
  • Ein Container, eine Abfragefunktion und ein Speicher – drei unterschiedliche Elemente. Wenn man diese miteinander vermischt, führt das dazu, dass eine Vektordatenbank für Probleme eingesetzt wird, die mit einer preferences.json-Datei gelöst werden könnten.

    Ebene 1: das Fenster, oder der Schreibtisch des Modells

    Betrachten Sie das Fenster als alles, was das Modell derzeit sehen kann. Der Systemprompt, die Historie, Definitionen von Tools, Ausgaben von Tools, abgerufte Dokumente sowie die gerade geschriebene Antwort nutzen alle denselben gemeinsamen Token-Budget.

    Stellen Sie sich einen Schreibtisch vor. Alles, worüber das Modell nachdenken muss, muss physisch darauf liegen – ein Aktenschrank in einem anderen Raum zählt nicht dazu.

    Seine Stärke: Unmittelbarkeit. Alles, was im Fenster zu sehen ist, ist ohne zusätzliche Abfragen vollständig sichtbar, und das Modell kann gleichzeitig über alles nachdenken. Bei einer Aufgabe mit begrenztem, bekanntem Material ist das Befüllen des Fensters der einfachste und oft auch richtige Weg.

    Kosten:

    1. Geld und Latenz hängen davon ab, was erneut gesendet wird. Das Umwandeln von 51 Nachrichten einer langen Unterhaltung bedeutet, dass 50 Nachrichten der Vorgeschichte erneut gesendet werden. Ein langer Kontext ist nicht kostenlos, nur weil er hineinpasst.
    2. Die Aufmerksamkeit ist ungleichmäßig verteilt. Modelle nutzen in der Regel am zuverlässigsten den Anfang und das Ende eines langen Eingabetextes und am wenigsten die Mitte – das weit verbreitete Phänomen des „Verlorengehens in der Mitte“. Ein Fakt, der 60 % des Weges in einer sehr langen Anfrage versteckt ist, existiert zwar, wird aber möglicherweise nie effektiv genutzt. Hineinpassen bedeutet nicht, gelesen zu werden.
  • Es endet. Sobald die Sitzung beendet ist, verschwindet das Fenster. Ein Kontextfenster speichert niemals etwas dauerhaft. Das ist der häufigste Anfängerfehler: Eine lange Unterhaltung wirkt wie Erinnerung, doch es handelt sich dabei um einen Puffer, nicht um einen Speicher.
  • Die gesamte Funktionsweise lässt sich in wenigen Zeilen beschreiben:

    messages = []
    
    def turn(user_text):
        messages.append(
            {"role": "user",
             "content": user_text}
        )
        # every call resends
        # the ENTIRE history
        reply = client.messages.create(
            model="claude-opus-5",
            max_tokens=1024,
            messages=messages,
        )
        messages.append(
            {"role": "assistant",
             "content": reply.content[0].text}
        )
        return reply
    
    # messages grows forever.
    # so does your bill.
    

    Diese Liste ist hier die „Erinnerung“. Sie existiert nur innerhalb Ihres Prozesses, sodass sie mit Ende des Prozesses ebenfalls verschwindet.

    Das Fenster allein reicht aus, wenn die Aufgabe kurz ist, das benötigte Material begrenzt und im Voraus bekannt ist sowie nichts über die Sitzung hinaus bestehen muss. Ein Zusammenfasser, ein Prüfer für eine Datei oder eine einmalige Extraktion benötigen nichts weiter. Fügen Sie dort keine zusätzlichen Komponenten hinzu.

    Ebene 2: Abruf, die Referenzbibliothek

    Schneller oder später passt das Material nicht mehr oder lohnt sich die Bezahlung nicht mehr. Es könnte sich um 10.000 Support-Tickets, eine interne Wiki oder einen Codebase handeln. Sie können nicht alles in jeder Anfrage berücksichtigen – und sollten es auch nicht.

    Durch generatives Verfahren mit Abrufunterstützung wird die Arbeit aufgeteilt: Zunächst wird ein Index im Voraus erstellt, anschließend werden Informationen abgerufen, wenn eine Frage gestellt wird.

    Zuvor teilen Sie die Dokumente in Abschnitte auf, wandeln jeden Abschnitt in einen Embedding um (einen numerischen Vektor, der die Bedeutung erfassen kann), und speichern ihn. Wenn eine Frage eintrifft, wandeln Sie diese in einen Embedding um, finden die Abschnitte, deren Vektoren am nächsten liegen, und fügen diese wenigen in das Kontextfenster neben der Frage ein.

    # 1. AHEAD OF TIME (once, offline)
    for chunk in split(documents):
        store.add(
            text=chunk,
            vector=embed(chunk),
        )
    
    # 2. AT QUESTION TIME (every request)
    def answer(question):
        hits = store.search(
            embed(question), top_k=5
        )
        context = "\n\n".join(h.text for h in hits)
        return client.messages.create(
            model="claude-opus-5",
            max_tokens=1024,
            # retrieved chunks land in the same request
            messages=[{
                "role": "user",
                "content": f"{context}\n\nQ: {question}",
            }],
        )
    

    Achten Sie darauf, was tatsächlich passiert ist. RAG hat dem Modell kein Gedächtnis bereitgestellt. Es lieferte Ihnen lediglich eine Auswahlstrategie für das Fenster. Die abgerufenen Fragmente landen in derselben Anfrage wie alles andere, wodurch RAG lediglich ein Kanal in Schicht 1 darstellt und keine Alternative dazu ist.

    Vorteile: Skalierbarkeit und Aktualität. Millionen von Dokumenten können unabhängig von Ihrem Code geändert werden, während das Modell nur die wenigen betrachtet, die für diese Frage relevant sind.

    Kosten:

    1. Das Ergebnis wird früh entschieden. Die Größe der Fragmente, das Embedding-Modell sowie die Indexstruktur sind bereits bei der Erstellung des Index festgelegt. Ein Fakt, der sich über zwei Fragmente erstreckt oder anders formuliert ist als die Frage der Benutzer, wird einfach nicht gefunden, und das Modell antwortet dann selbstbewusst auf der Grundlage dessen, was es erhalten hat. Für einen Beobachter sehen mangelhafte Informationsabrufung und Halluzinationen identisch aus.
  • Es ist größtenteils nur zum Lesen da. Klassisches RAG funktioniert wie eine Bibliothekskarte und nicht wie ein Notizbuch. Der Agent sucht nach Informationen, schreibt aber nichts auf, und das, was er in einer Sitzung lernt, gelangt nicht ins Index – es sei denn, man erstellt diesen Pfad explizit.
  • Es gibt einen zusätzlichen Schritt. Das Einbetten der Abfrage und das Suchen im Index verursachen Verzögerungen bei jeder Anfrage.
  • Retrieval eignet sich dann, wenn die Wissensbasis groß ist, für alle Benutzer gemeinsam und selten ändert – beispielsweise Dokumentationen, Richtlinien, Produktkataloge und Code. Ein Indikator dafür ist, dass ein einziges Korpus allen Benutzern dient. Wenn das, was man sich merken möchte, einem einzelnen Benutzer gehört und im Laufe des Gesprächs ändert sich, eignet sich Retrieval nicht gut – dann braucht man Layer 3.

    Layer 3: persistenter Zustand, das Notizbuch

    Der persistente Zustand ist das, was übrig bleibt, wenn der Prozess beendet wird. Es handelt sich dabei nicht um das, was der Agent über die Welt weiß, sondern um das, was er gelernt hat und was länger bestehen sollte als diese Sitzung: Benutzerpräferenzen, Zwischenstände von Aufgaben, bereits getroffene Entscheidungen, ausprobierte und aufgegebene Optionen sowie zusammenfassende Übersichten früherer Ausführungen. Dies sind kleine, spezifische, wertvolle Fakten, die der Agent selbst notiert hat.

    Musterhaft verläuft dies in einem Zyklus aus Lesen, Ändern und Schreiben innerhalb der Sitzung:

    # session start: load
    with open("state.json") as f:
        state = json.load(f)
    
    system = (
        "Known about this user:\n"
        f"{json.dumps(state)}"
    )
    
    messages = []
    
    def turn(user_text):
        messages.append(
            {"role": "user",
             "content": user_text}
        )
        reply = client.messages.create(
            model="claude-opus-5",
            max_tokens=1024,
            system=system,   # state in
            messages=messages,
        )
        return reply
    
    # ... along the way ...
    state["prefers"] = "metric units"
    state["last_checkpoint"] = "step_4_done"
    
    # session end: save
    with open("state.json", "w") as f:
        json.dump(state, f)
    

    Konzeptionell ist nichts weiter notwendig. Eine JSON-Datei gilt als echte Implementierung – genauso wie eine Datenbankzeile, ein Schlüssel-Wert-Speicher oder ein Ordner mit Markdown-Notizen. Das Medium ist der langweilige Teil, interessant ist vielmehr, wer entscheidet, was gespeichert und was wieder geladen werden soll.

    Die richtige Entscheidung zu treffen, ist der schwierige Teil – und genau hier unterscheiden sich die Agent-Frameworks. Die direkteste aktuelle Option überlässt diese Aufgabe dem Modell: Mit Anthropics Speichertools erhält Claude eine kleine Reihe von Datei-Befehlen (ansehen, erstellen, str_replace, einfügen, löschen und umbenennen), die in einem abgeschotteten /memories-Verzeichnis funktionieren. So entscheidet der Agent, was gespeichert werden sollte, und liest diese Notizen zu Beginn der nächsten Sitzung. Ihre eigene Anwendung führt die Operationen auf dem von Ihnen gewählten Speicher aus. Das Tool läuft clientseitig, wodurch die Dateien in Ihren Händen bleiben.

    Stärken: Kontinuität, Personalisierung und langfristige Arbeitsweise. Ein Agent, der eine mehrtägige Aufgabe dort fortsetzt, wo er aufgehört hat, benötigt dies genauso wie einer, der nicht zweimal nach Ihrer Zeitzone fragen sollte.

    Kosten:

    1. Jemand muss die Inhalte verwalten. Schreiben Sie alles auf – dann entsteht ein unsuchbares Protokoll. Schreiben Sie zu wenig, bricht die Kontinuität. Ein guter, dauerhafter Zustand ist nur mit großer Sorgfalt zu gewährleisten.
    2. Veraltete Informationen sind schlimmer als gar keine. Eine acht Monate alte Präferenz, die nie wieder überprüft wird, wird weiterhin zuverlässig angewendet. Fehlschläge bei der Abrufung führen zu Unklarheiten, während veralteter Zustand zu falschem Verhalten führt.
    3. Das Laden ist nicht kostenlos. Was auch immer geladen wird, nimmt weiterhin Platz im Fenster ein – daher beeinflusst auch Schicht 3 Schicht 1.

    Schließen Sie sich einem persistenten Zustand an, wenn derselbe Benutzer oder dieselbe Aufgabe den Agenten wiederholt auslöst und das, was bei Ausführung n gelernt wird, die Ausführung n+1 verändern sollte.

    Die drei Ansätze nebeneinander

    Kontextfenster Auswertung Persistenter Zustand
    Rolle Der Schreibtisch Die Bibliothek Das Notizbuch
    Enthält Alles in dieser Anfrage Ein großes, gemeinsam genutztes Korpus Kleine Fakten, die der Agent geschrieben hat
    Aufgefüllt von Ihre Anwendung, pro Aufruf Indexierungsjob Der Agent oder Ihr Code
    Überlebt ein Neustart? Nein Ja Ja
    Hauptrisiko Kosten, Datenverlust im Laufweg Übersehene Teile Veraltete Fakten

    Die wichtigste Zeile ist die über die Neustarts. Sie bildet die Trennlinie zwischen einem langen Chat und einem Agenten mit Gedächtnis.

    Sie erstellen

    Ein echter Agent verwendet alle drei Elemente, und es ist hilfreich, zu beobachten, wie sie in einer Anfrage zusammenarbeiten. Ein Support-Agent wird gefragt, ob eine Bestellung für das verlängerte Rückgabefenster in Frage kommt.

    1. Zuerst wird der Persistent State geladen: Dieser Kunde hat den Geschäftsplan und bevorzugt kurze Antworten. Zwei Fakten, etwa vierzig Tokens.
    2. Dann erfolgt die Retrieval-Phase, bei der anhand der Frage der Abschnitt zur Rückgabepolitik für Geschäftspläne sowie die beiden neuesten Ausnahmen abgerufen werden. Drei Datenblöcke, etwa tausendzweihundert Tokens.
    3. Schließlich wird der Context Window mit beidem, zusammen mit dem Live-Chat und den Tool-Definitionen, verwendet, wodurch das Modell über den gesamten Kontext hinweg zusammenfassend urteilen kann.
  • Nach der Antwort schreibt der Agent eine Zeile in den persistierenden Zustand: Im Mittel August wurde nach der Rückgabepolitik gefragt, weshalb die nächste Sitzung sie nicht als Erstkontakt behandelt.
  • Eine Anfrage, drei Ebenen. Das Fenster ist der Ort, an dem alles landet, während Abruf und persistierender Zustand zwei getrennte Wege dorthin sind.

    Deshalb wird auch empfohlen, langlaufenden Agenten Gedächtnisfunktionen mit Kontextbearbeitung zu kombinieren: Alte Tool-Ergebnisse werden aus dem Fenster gelöscht, um es übersichtlich zu halten, und die wichtigen Fakten wurden bereits gespeichert, sodass das Fenster klein bleibt, ohne Wissen zu verlieren.

    Welches brauchen Sie eigentlich?

    Anfänger greifen fast immer zuerst zu einer Vektordatenbank. Das ist der am meisten sichtbare Teil des Stack, doch selten die richtige Lösung. Klettern Sie lieber die Leiter hinauf.

    Fangen Sie mit dem Fenster an. Passt alles Relevant in eine einzige Anfrage zu einem für Sie akzeptablen Preis? Dann hören Sie auf. Kein Index, kein Speicher.

    Fügen Sie den persistenten Zustand hinzu, sobald der Agent zum zweiten Mal ausgeführt wird. Wenn die zweite Sitzung wissen sollte, was die erste Sitzung gelernt hat, ist Layer 3 erforderlich, und eine JSON-Datei ist die richtige Lösung. Erledigen Sie das vor der Abrufphase – es ist günstiger, einfacher und entspricht dem, was die meisten Menschen tatsächlich wollen, wenn sie sagen, der Agent solle sich an sie erinnern.

    Fügen Sie die Abrufphase hinzu, wenn das Korpus größer ist als das Fenster. Das bedeutet viele Dokumente, die zwischen Benutzern geteilt werden und separat von Ihrem Code bearbeitet werden. Es handelt sich um die aufwendigste Schicht, die erstellt und am Laufen gehalten werden muss – nutzen Sie sie daher nur, wenn es wirklich notwendig ist.

    Eine Falle, der man ausweichen muss: Die Erstellung eines RAG-Pipelines für etwas, das eigentlich ein Präferenzdatei war, und anschließend das Rätseln darüber, warum der Agent immer noch den Namen einer Person vergisst. Die Abrufsuche durchforstet ein Korpus – dieses wird niemals die Tatsache enthalten, dass eine Person Metriekonzepte bevorzugt.

    Kurzfassung

    • Context-Window: der Schreibtisch. Sofort sichtbar, teuer pro Token und wird sofort gelöscht, sobald die Sitzung beendet ist.
    • Abruf: die Bibliothek. Sehr umfangreich, suchbar, nach einem festen Zeitplan aktualisiert und etwas, das der Agent nur liest.
    • Persistenter Zustand: das Notizbuch. Klein, vom Agenten geschrieben und die einzige Schicht, die eine Lektion vom heutigen Tag auf den morgigen überträgt.

    Das Modell selbst speichert nichts. Die scheinbare Erinnerung ist eine ingenieurtechnische Entscheidung, die bei jeder Anfrage neu getroffen wird: Was erhält einen Platz in diesem Window – und woher soll es stammen?

    Zur weiteren Lektüre behandeln Anthropics technische Beiträge zum effektiven Kontextmanagement sowie zur Erstellung leistungsfähiger Agenten zusammen mit der Dokumentation zum Speichermittel und zur Kontextbearbeitung dieses Thema ausführlicher.