Fünf Speicherstrategien in LangChain, vom Buffer bis zum Entity-Memory
Warum Chatmodelle zwischen Aufrufen alles vergessen, und fünf Speichermuster für LangChain und LangGraph: Buffer, Fenster, Zusammenfassung, Summary Buffer und Entitäten, mit ihren Vor- und Nachteilen.
Viele gehen davon aus, dass sich ein Chatmodell merkt, was man ihm gesagt hat. Tut es nicht. Ob GPT-5, GPT-4o, Claude oder Gemini, das Ergebnis ist dasselbe: Jede Anfrage beginnt bei null, und wenn man frühere Nachrichten nicht erneut mitschickt, weiß das Modell nicht, dass es sie gab. Hier die kleinstmögliche Demonstration:
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o-mini")llm.invoke("Hi, my name is Asha.")
llm.invoke("What's my name?")
Der zweite Aufruf weiß nichts vom ersten. Ashas Name wurde nie mitgeschickt, also kann das Modell ihn nicht nennen.
Was Memory in LangChain bedeutet
Magisch ist daran nichts. Memory ist eine Regel für genau eine Frage: Welche Teile des bisherigen Gesprächs gehen mit der nächsten Anfrage zurück ans Modell? Die Antwort darauf bestimmt, wie klug, wie skalierbar und wie günstig die Anwendung wird. Im Folgenden fünf Strategien, die mit LangChain und LangGraph eingesetzt werden, ihre Stärken und Schwächen und wofür sie sich eignen.
Der Grundkonflikt
Angenommen, eine Nutzerin stellt sich als Asha vor, bekommt eine freundliche Antwort und fragt später, wie sie heißt. Für eine richtige Antwort muss die erste Nachricht im neuen Prompt mitfahren.
Schwierig wird es, wenn Chats auf 10, 100 oder 1.000 Nachrichten anwachsen. Alles jedes Mal neu zu senden treibt Tokenverbrauch, API-Kosten, Latenz und den Druck aufs Kontextfenster in die Höhe. Jede Entscheidung tauscht eines gegen das andere:
- Mehr merken, und die Kosten steigen.
- Weniger merken, und die Kosten sinken, aber die Genauigkeit leidet.
- Mehr Kontext senden, und die Antworten werden langsamer.
- Weniger Kontext senden, und die Antworten werden schneller, verlieren aber Informationen.
Strategie 1: Buffer Memory
Buffer Memory behält das komplette Transkript und schickt es bei jedem Aufruf vollständig mit. Man stelle sich eine Chat-App vor, die nie etwas löscht. Der Code ist kurz:
from langchain_core.messages import HumanMessage
history = []def chat(user_input):
history.append(HumanMessage(user_input)) response = llm.invoke(history) history.append(response) return response.content
Ein Beispielgespräch:
User: I live in Chennai.
Assistant: That's great.
Etwas später:
User: Which city do I live in?
Assistant: Chennai
Das Modell nennt Chennai korrekt, weil die frühere Zeile noch in der Historie steht, die es bekommt.
Das Gute: perfektes Erinnern, trivial umzusetzen, und das Debuggen ist angenehm, weil man alles sieht. Das Schlechte: Die Tokens wachsen unbegrenzt, die Kosten steigen, die Antworten werden mit der Zeit langsamer, und irgendwann stößt man an die Kontextgrenze. Passt für kurze Sitzungen, interne Tools, Entwicklungsumgebungen und Tests.
Strategie 2: Window Memory
Hier behält man nur die letzten K Nachrichten. Alles Ältere wird kurzerhand gelöscht, ein bisschen wie ein Whiteboard, auf dem jede neue Notiz die älteste wegwischt.
from langchain_core.messages import trim_messages
trimmed = trim_messages(
history,
strategy="last",
max_tokens=10,
token_counter=len
)
Probieren Sie diesen Austausch:
User: My name is Asha.
Assistant: Nice to meet you.
User: Message 1
User: Message 2
User: Message 3
User: Message 4User: What's my name?
Ist die Nachricht mit dem Namen schon aus dem Fenster gerutscht, muss das Modell passen:
Assistant: I don't know your name.
Diese Information ist endgültig weg. Dafür ist der Tokenverbrauch vorhersehbar, die Antworten kommen schnell, und die Rechnung bleibt niedrig. Der Nachteil: Alte Informationen verschwinden, lange Gespräche funktionieren also nicht. Gemeint sind FAQ-Bots, lockere Chatbots, Kundenservice-Helfer und jede Low-Budget-App.
Strategie 3: Summary Memory
Angenommen, man will nicht alles horten, aber auch nicht alles vergessen. Bei Summary Memory schreibt das Modell ab und zu eine kompakte Zusammenfassung älterer Nachrichten, und diese ersetzt den Rohtext.
Menschen machen das ganz von selbst. Nach einem zweistündigen Meeting erinnert man sich nicht an jeden Satz. Man weiß, dass das Budget besprochen, der Vorschlag genehmigt und für nächste Woche ein Fortschrittsreview angesetzt wurde.
Nach einem langen Chat könnte der gespeicherte Zustand so aussehen:
Summary:
User is building a shipment tracking application.
The discussion focused on Azure deployment and performance optimization.
Statt 100 Nachrichten schickt man das. Eine grobe Implementierung startet mit einer leeren laufenden Zusammenfassung:
running_summary = ""
Sobald die Historie einen Schwellenwert überschreitet, werden ältere Nachrichten verdichtet:
if len(history) > 6:
old_messages = history[:-2] running_summary = llm.invoke(
f"Summarize this conversation:\n{old_messages}"
).content history[:] = history[-2:]
Stärken: Das Tokenwachstum flacht ab, lange Gespräche funktionieren, die Kosten sinken. Schwächen: Der genaue Wortlaut geht verloren, wichtige Details können wegfallen, und das Ergebnis ist nur so gut wie das Modell, das die Zusammenfassung schreibt. Passt für lange Support-Sitzungen, virtuelle Assistenten, Coaching-Apps und stundenlange Chats.
Strategie 4: Summary Buffer Memory
Wer den Code eines echten Produktions-Chatbots öffnet, findet meist irgendeine Variante davon. Sie verbindet die beiden vorherigen: Aktuelle Nachrichten bleiben wörtlich erhalten, ältere werden zusammengefasst. So bekommt man scharfen aktuellen Kontext und bezahlbare lange Gespräche.
Eine gute Assistenz der Geschäftsführung arbeitet genauso. Die Bitte von gestern hat sie exakt im Kopf:
You asked for the deployment status yesterday.
Und den Hintergrund trägt sie in komprimierter Form mit:
This project started in January and focuses on Azure migration.
Frische Details bleiben scharf, alte werden zu verdichtetem Wissen. Eine minimale Version legt fest, wie viele aktuelle Nachrichten behalten werden:
RECENT_LIMIT = 4
running_summary = ""def chat(user_input):
global running_summary history.append(HumanMessage(user_input)) if len(history) > RECENT_LIMIT: older_messages = history[:-RECENT_LIMIT] running_summary = llm.invoke(
f"""
Update this summary:
{running_summary} Using:
{older_messages}
"""
).content history[:] = history[-RECENT_LIMIT:] context = [
SystemMessage(
content=f"Summary: {running_summary}"
)
] + history response = llm.invoke(context) history.append(response) return response.content
Stärken: eine gute Balance aus Kosten und Genauigkeit, Unterstützung für lange Chats, erhaltene aktuelle Details und gutes Verhalten in Produktion. Schwächen: etwas mehr Komplexität und regelmäßige Zusammenfassungsaufrufe. Typische Einsatzfelder sind Copilots, Enterprise-Chatbots, Support-Plattformen und produktionsreife Assistenten.
Strategie 5: Entity Memory
Manchmal muss man nicht das Transkript aufheben, sondern die Fakten. Nehmen wir Aussagen wie diese:
User: My sister's birthday is in March.
User: I work at Contoso.
User: My manager is Priya.
Monate später will man diese Fakten immer noch haben. Entity Memory führt strukturierte Einträge zu den Personen, Orten, Projekten und Firmen, die auftauchen, sodass der ursprüngliche Chat verschwinden kann, während das Nützliche bleibt. Ein Entity-Store könnte Folgendes enthalten:
{
"Priya": [
"User's manager"
],
"Contoso": [
"User works here"
]
}
Die Extraktion beginnt mit einem leeren Store:
entity_store = {}
und eine Funktion bittet das Modell, Entitäten und Fakten herauszuziehen:
def extract_entities(text): prompt = f"""
Extract entities and facts:
{text}
""" return llm.invoke(prompt).content
Stärken: hervorragend für Langzeitgedächtnis, sehr sparsam bei Tokens, und die Daten sind strukturiert. Schwächen: Die Architektur ist schwerer, man braucht Extraktionslogik, und ein Gespräch lässt sich nicht exakt wiedergeben. Geeignet für persönliche Assistenten, CRM-Systeme, Mitarbeiter-Helfer und Tools fürs Beziehungsmanagement.
Der LangGraph-Weg
Ältere Tutorials verwenden Klassen, die man wiedererkennt:
ConversationBufferMemory
ConversationSummaryMemory
ConversationBufferWindowMemory
Das sind inzwischen Legacy-Muster, und aktuelle Arbeit mit LangChain stützt sich auf LangGraph. Früher hat man ein Memory-Objekt erzeugt:
memory = ConversationBufferMemory()
Der neuere Stil nutzt einen Checkpointer wie
MemorySaver()
oder
PostgresSaver()
um den Gesprächszustand zu speichern. Kürzen, Zusammenfassen und Verarbeiten dieses Zustands liegt dann bei einem selbst. Ein Graph-Setup beginnt mit diesen Imports:
from langgraph.graph import (
StateGraph,
MessagesState,
START
)
und die vollständige Verdrahtung samt Kürzen sieht so aus:
from langgraph.checkpoint.memory import (
MemorySaver
)from langchain_core.messages import (
trim_messages
)def call_model(state: MessagesState): trimmed = trim_messages(
state["messages"],
strategy="last",
max_tokens=10,
token_counter=len
) response = llm.invoke(trimmed) return {
"messages": [response]
}graph = StateGraph(MessagesState)graph.add_node("model", call_model)graph.add_edge(START, "model")app = graph.compile(
checkpointer=MemorySaver()
)
Ein Punkt sorgt oft für Verwirrung: Der Checkpointer entscheidet nicht, was gespeichert wird. Er entscheidet nur, wo das Gedächtnis liegt, etwa im Prozess, in einer Datenbank oder in einem anderen Store. Die Wahl zwischen Buffer, Fenster, Zusammenfassung, Summary Buffer oder Entitäten bleibt Ihre Aufgabe.
Kann Azure Blob Storage Memory halten?
Ja. Dort lassen sich Chatverläufe, Zusammenfassungen, Entity-Daten und Session-Checkpoints ablegen. Für Gesprächsgedächtnis in Echtzeit passt es aber meist schlecht: Lesezugriffe sind langsamer als bei Redis, es ist nicht auf häufiges Lesen und Schreiben ausgelegt, und man bräuchte zusätzliche Indexierungslogik. Ein verbreitetes Enterprise-Layout sieht stattdessen so aus:
Redis
↓
PostgreSQL
↓
Azure Blob Storage
In diesem Aufbau hält Redis aktive Gespräche, PostgreSQL die Sitzungshistorie, und Blob Storage archiviert Langzeitdaten.
Die passende Strategie wählen
Die Strategie sollte zum Produkt passen. Kurzlebige oder interne Chats kommen mit Buffer Memory aus. Günstige, lockere Bots können Fenster nutzen. Lange Sitzungen, in denen der Wortlaut wenig zählt, passen zu Zusammenfassungen. Alles Kundennahe und Langlebige will in der Regel den Summary Buffer, und alles, was sich dauerhafte Fakten über Personen oder Organisationen merken muss, braucht Entity Memory.
Zum Schluss
Das Design des Gedächtnisses gehört zu den wichtigsten Entscheidungen in einem KI-Produkt. Ein Bot ohne Gedächtnis wirkt vergesslich, einer mit unbegrenztem Gedächtnis wird teuer und langsam. Es geht nicht darum, sich alles zu merken, sondern das Richtige.
Für die meisten Produktionsanwendungen liefert derzeit die Kombination aus Summary Buffer, Entity Memory und LangGraph-Checkpointing die beste Balance aus Skalierung, Kosten und Nutzererlebnis. Wer Assistenten mit LangChain oder LangGraph baut, verbessert Qualität und Performance mit einem gut durchdachten Gedächtnis stärker als mit fast jedem Prompt-Trick. Die klügsten Systeme sind nicht die, die sich alles merken, sondern die, die wissen, was sie behalten sollten.