Puffer- und Fensterspeicher
Sie implementieren ConversationBufferMemory und ConversationBufferWindowMemory, um die letzten N Gesprächsrunden im Kontext zu behalten, und messen, wie sich die Fenstergröße auf Kohärenz und Kosten auswirkt.
Puffer- und Fensterspeicher ist eine kostenlose AI Engineering Academy-Lektion auf CoddyKit. Dies ist Lektion 2 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des AI Engineering Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der AI Engineering Academy-Kurs umfasst insgesamt 4 Lektionen.
Pufferspeicher: Alles behalten
Der Pufferspeicher ist die einfachste Strategie: Speichern Sie jede Nachricht aus jeder Runde in einer Liste und fügen Sie den vollständigen Verlauf in jeden API-Aufruf ein. Dadurch bleibt der Kontext vollständig erhalten – das Modell kann auf alles Gesagte zurückgreifen. Der Nachteil ist das lineare und unbegrenzte Wachstum des Kontexts. Für kurze Sitzungen, etwa das einmalige Erledigen einer Aufgabe, ist der Pufferspeicher vollkommen geeignet und am einfachsten zu implementieren.
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory(
return_messages=True, # return Message objects, not a string
memory_key='history' # key to inject into prompt template
)
# Add messages manually
memory.chat_memory.add_user_message('What is a neural network?')
memory.chat_memory.add_ai_message('A neural network is a system of layers...')
# Load what will be injected
print(memory.load_memory_variables({}))Pufferspeicher in eine Chain integrieren
Um den Pufferspeicher mit LCEL zu verwenden, binden Sie ihn über RunnableWithMessageHistory ein oder verwenden Sie für den veralteten Ansatz ConversationChain. Das Speicherobjekt enthält den Verlauf, und die Chain verwendet einen MessagesPlaceholder in der Prompt-Vorlage, um ihn einzufügen. Nach jeder Ausführung hängt der Speicher die neue Runde automatisch an.
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.output_parsers import StrOutputParser
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
store = {}
def get_history(session_id: str):
if session_id not in store:
store[session_id] = InMemoryChatMessageHistory()
return store[session_id]
chain = (
ChatPromptTemplate.from_messages([
('system', 'You are helpful.'),
MessagesPlaceholder('history'),
('human', '{input}')
])
| ChatOpenAI(model='gpt-4o-mini')
| StrOutputParser()
)
with_memory = RunnableWithMessageHistory(
chain, get_history,
input_messages_key='input',
history_messages_key='history'
)Das Problem eines unbegrenzten Puffers
Der Pufferspeicher funktioniert, bis das Gespräch zu lang wird und das Kontextfenster des Modells überschreitet. Mit dem 128K-Kontext von GPT-4o-mini kann ein typischer Chat 200–400 Runden dauern, bevor ein Überlauf auftritt. Praktischer gesehen senden Sie selbst bei 50 Runden pro Anfrage mehr als 50.000 Tokens – ein erheblicher Kostenfaktor. Sie benötigen eine Strategie, um die Größe des Verlaufs zu begrenzen.
import tiktoken
enc = tiktoken.encoding_for_model('gpt-4o-mini')
def count_history_tokens(messages: list) -> int:
total = 0
for msg in messages:
total += len(enc.encode(msg.content))
total += 4 # per-message overhead
return total
# Check how big the history has grown
history = store.get('session-1')
if history:
token_count = count_history_tokens(history.messages)
print(f'History size: {len(history.messages)} messages, {token_count} tokens')Fensterspeicher: Die letzten N Runden behalten
Der Fensterspeicher behält nur die letzten K Gesprächsrunden und verwirft ältere Nachrichten. Dadurch wird der Kontext unabhängig von der Gesprächsdauer auf K * avg_tokens_per_turn begrenzt. Der Nachteil ist, dass sehr früher Kontext verloren geht – das Modell kann Dinge vergessen, die der Benutzer viele Runden zuvor gesagt hat. Für die meisten allgemeinen Chatbots bietet ein Fenster von 5–10 Runden eine gute Kohärenz bei akzeptablen Kosten.
from langchain.memory import ConversationBufferWindowMemory
# Keep last 5 turns (10 messages: 5 user + 5 assistant)
memory = ConversationBufferWindowMemory(
k=5, # number of TURNS to keep (each turn = user + AI)
return_messages=True,
memory_key='history'
)
# After 10 turns, only turns 6-10 will be in context
# Turns 1-5 are silently droppedFensterspeicher mit InMemoryChatMessageHistory implementieren
LangChains InMemoryChatMessageHistory behält alle Nachrichten, Sie können den Verlauf jedoch vor dem Einfügen in den Prompt kürzen. Ein gängiges Muster besteht darin, den vollständigen Verlauf für Protokollierungszwecke zu speichern, dem LLM aber nur die letzten N Nachrichten zu übergeben. Verwenden Sie die Python-Slice-Notation für history.messages, um das aktuellste Fenster abzurufen.
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables import RunnableLambda
WINDOW_SIZE = 10 # last 10 messages (5 turns)
def get_windowed_history(session_id: str):
full_history = store.get(session_id, InMemoryChatMessageHistory())
store[session_id] = full_history
return full_history
# In the chain, trim before injecting
def trim_history(messages):
return messages[-WINDOW_SIZE:] if len(messages) > WINDOW_SIZE else messages
# Use in prompt with trimming
from langchain_core.messages import trim_messages
trimmer = trim_messages(
max_tokens=2000,
strategy='last',
token_counter=ChatOpenAI(model='gpt-4o-mini'),
include_system=True
)Fenster nach Tokens oder nach Runden
Die Fenstergröße kann in Runden (den letzten K Paaren aus Benutzer- und KI-Nachricht) oder in Tokens (den letzten T Tokens des Verlaufs) angegeben werden. Ein tokenbasiertes Fenster ist zuverlässiger, weil die Länge von Runden variiert – eine Runde mit Code ist zehnmal länger als eine Runde mit „ja“. LangChains Hilfsfunktion trim_messages() unterstützt beide Strategien und kann die Systemaufforderung beim Kürzen des Verlaufs beibehalten.
from langchain_core.messages import trim_messages, SystemMessage, HumanMessage, AIMessage
# Token-based trimming — keep last 1000 tokens of conversation
trimmer = trim_messages(
max_tokens=1000,
strategy='last', # keep most recent messages
token_counter=len, # approximate: count characters / 4
include_system=True, # always include the system prompt
allow_partial=False, # don't split a message in half
start_on='human' # start window on a human message
)
trimmed = trimmer.invoke(all_messages)
print(f'Trimmed to {len(trimmed)} messages')Kohärenz und Fenstergröße messen
Um die richtige Fenstergröße zu wählen, müssen Sie messen, wie stark die Kohärenz eines Gesprächs abnimmt, wenn das Fenster kleiner wird. Führen Sie eine Reihe von Testgesprächen durch, in denen sich Runde N auf Informationen aus Runde N-5, N-10 und N-20 bezieht. Testen Sie, ob das Modell mit Fenstern von 5, 10 und 20 Runden weiterhin korrekt antworten kann. Daraus ergibt sich die Mindestfenstergröße, die für Ihren konkreten Anwendungsfall erforderlich ist.
def test_reference_at_distance(chain_with_memory, distances=[5, 10, 20]):
results = {}
for distance in distances:
session_id = f'test-dist-{distance}'
# Fill with filler turns
for i in range(distance):
chain_with_memory.invoke(
{'input': f'Turn {i}: filler message'},
config={'configurable': {'session_id': session_id}}
)
# Ask about something said at the start
first_msg = 'Recall that the user said the magic word is AZURE.'
response = chain_with_memory.invoke(
{'input': 'What was the magic word?'},
config={'configurable': {'session_id': session_id}}
)
results[distance] = 'AZURE' in response.upper()
return resultsSystem-Prompt und Fensterspeicher kombinieren
Wenn Sie den Fensterspeicher verwenden, müssen Sie stets den System-Prompt beibehalten – er definiert die Persona und die Regeln der KI. Ohne ihn kann das Modell seine Persona verlieren, sobald das Fenster über die erste Runde hinausgleitet. Verwenden Sie in Trim-Funktionen die Option include_system=True oder fügen Sie die Systemnachricht in Ihrer Prompt-Vorlage immer vor dem Verlauf im Fenster ein.
# Always put system prompt BEFORE the windowed history
prompt = ChatPromptTemplate.from_messages([
('system', 'You are a Python tutor. Always explain with code examples.'),
MessagesPlaceholder('history'), # windowed history injected here
('human', '{input}'),
])
# The system prompt is never trimmed — only the history window is managed
# This ensures the model's persona is always present regardless of windowEntscheidungshilfe: Puffer- oder Fensterspeicher
Verwenden Sie den Pufferspeicher, wenn Gespräche kurz und begrenzt sind (eine einmalige Aufgabe, ein Formularassistent), der vollständige Kontext entscheidend ist (rechtliche Analysen, Code-Reviews) und das Tokenbudget keine Rolle spielt. Verwenden Sie den Fensterspeicher, wenn Gespräche beliebig lang werden können (Kundensupport, allgemeine Assistenten), der aktuelle Kontext wichtiger ist als weit zurückliegender Kontext und Sie vorhersehbare, begrenzte Tokenkosten benötigen.
# Decision matrix in code
def choose_memory_strategy(
expected_turns: int,
max_context_tokens: int = 128000,
avg_tokens_per_turn: int = 200
) -> str:
buffer_tokens = expected_turns * avg_tokens_per_turn
if buffer_tokens < max_context_tokens * 0.5:
return 'buffer' # Safe to keep everything
elif expected_turns <= 20:
return 'window_10' # Keep last 10 turns
else:
return 'summary' # Need summarization for long convos
print(choose_memory_strategy(5)) # 'buffer'
print(choose_memory_strategy(50)) # 'window_10'
print(choose_memory_strategy(200)) # 'summary'Das Fenster in Redis persistent speichern
Speichern Sie in einer produktiven Umgebung den vollständigen Gesprächsverlauf in Redis (für schnellen Abruf) und kürzen Sie ihn beim Lesen auf die Fenstergröße. Redis mit einer TTL sorgt dafür, dass alte Sitzungen automatisch ablaufen. Verwenden Sie ein Sorted Set oder eine Liste mit LRANGE, um effizient nur die letzten N Nachrichten abzurufen, ohne den gesamten Verlauf zu laden.
from langchain_community.chat_message_histories import RedisChatMessageHistory
def get_windowed_redis_history(session_id: str, window: int = 10):
# RedisChatMessageHistory stores all messages
history = RedisChatMessageHistory(
session_id=session_id,
url='redis://localhost:6379',
ttl=3600 # 1 hour TTL
)
# Trim to window size in-memory before use
all_msgs = history.messages
if len(all_msgs) > window * 2: # window turns = window*2 messages
history.messages = all_msgs[-(window * 2):]
return historyDie Gesundheit des Speichers in der Produktion überwachen
Überwachen Sie in der Produktion diese Kennzahlen, um speicherbezogene Probleme frühzeitig zu erkennen: durchschnittliche Verlaufstokens pro Anfrage, um zu erkennen, dass Sitzungen zu groß werden; Auslastung des Kontextfensters (Warnung bei > 80 %); Anzahl der Sitzungen im Speicher, um Speicherlecks im Sitzungsspeicher zu erkennen; sowie die Cache-Trefferquote für Sitzungen, die aus Redis erneut geladen werden. Lösen Sie einen Alarm aus, wenn die durchschnittliche Anzahl der Verlaufstokens einen konfigurierbaren Schwellenwert überschreitet.
import time
from langchain_core.callbacks import BaseCallbackHandler
class MemoryMonitorCallback(BaseCallbackHandler):
def on_chain_start(self, serialized, inputs, **kwargs):
history = inputs.get('history', [])
token_estimate = sum(len(m.content.split()) * 1.3 for m in history)
if token_estimate > 50000:
print(f'WARNING: Large history {token_estimate:.0f} estimated tokens')
def on_chain_end(self, outputs, **kwargs):
# Log usage for dashboards
passKurzer Test
Testen Sie Ihr Verständnis der Strategien für Puffer- und Fensterspeicher.
Zusammenfassung der Lektion
In dieser Lektion haben Sie gelernt: Der Pufferspeicher bewahrt den vollständigen Verlauf, wächst jedoch unbegrenzt und eignet sich daher nur für kurze, begrenzte Gespräche; der Fensterspeicher behält nur die letzten K Runden und sorgt so auf Kosten weit zurückliegenden Kontexts für vorhersehbare, begrenzte Kosten; und tokenbasiertes Kürzen mit trim_messages() ist zuverlässiger als fensterbasierte Begrenzungen nach Runden, weil die Nachrichtenlänge variiert. Als Nächstes sehen wir uns den Zusammenfassungsspeicher für offene, lange Gespräche an.
Häufig gestellte Fragen
Ist die Lektion „Puffer- und Fensterspeicher“ kostenlos?
Ja — der vollständige Text von „Puffer- und Fensterspeicher“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des AI Engineering Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der AI Engineering Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Puffer- und Fensterspeicher“?
Sie implementieren ConversationBufferMemory und ConversationBufferWindowMemory, um die letzten N Gesprächsrunden im Kontext zu behalten, und messen, wie sich die Fenstergröße auf Kohärenz und Kosten… Du übst AI Engineering Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um AI Engineering Academy zu starten?
Keine Vorkenntnisse erforderlich. AI Engineering Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 4.
Wie lange dauert die Lektion „Puffer- und Fensterspeicher“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser AI Engineering Academy-Lektion Code schreiben und ausführen?
Ja. Jede AI Engineering Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Warum zustandslose LLMs externen Speicher benötigen
- Puffer- und Fensterspeicher
- Zusammenfassungsspeicher und tokenbewusstes Kürzen
- Chatverläufe in Redis und PostgreSQL speichern