AI Engineering Academy · Les

Buffer- en windowgeheugen

U implementeert ConversationBufferMemory en ConversationBufferWindowMemory om de laatste N gespreksbeurten in de context te bewaren en meet hoe de venstergrootte samenhangt met coherentie en kosten.

Les 2 van 413 stappen

Buffer- en windowgeheugen is een gratis AI Engineering Academy-les op CoddyKit. Dit is les 2 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject AI Engineering Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus AI Engineering Academy bevat in totaal 4 lessen.

Buffergeheugen: alles behouden

Buffergeheugen is de eenvoudigste strategie: sla elk bericht uit elke beurt op in een lijst en voeg de volledige geschiedenis toe aan elke API-aanroep. Zo blijft de context volledig behouden — het model kan verwijzen naar alles wat op enig moment is gezegd. Het nadeel is dat de context lineair groeit zonder bovengrens. Voor korte sessies, zoals het voltooien van één taak, is buffergeheugen zeer geschikt en het eenvoudigst te implementeren.

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({}))

Buffergeheugen integreren met een keten

Als je buffergeheugen met LCEL wilt gebruiken, koppel je het via RunnableWithMessageHistory of gebruik je ConversationChain voor de verouderde aanpak. Het geheugenobject bevat de geschiedenis en de keten gebruikt een MessagesPlaceholder in de promptsjabloon om deze in te voegen. Na elke aanroep voegt het geheugen automatisch de nieuwe beurt toe.

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'
)

Het probleem met een onbeperkte buffer

Buffergeheugen werkt totdat het gesprek te lang wordt en het contextvenster van het model overschrijdt. Met het contextvenster van 128K van GPT-4o-mini kan een typisch gesprek 200–400 beurten duren voordat het overloopt. Praktischer gezien verstuur je zelfs bij 50 beurten per aanvraag meer dan 50K tokens — een aanzienlijke kostenpost. Je hebt een strategie nodig om de grootte van de geschiedenis te 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')

Venstergeheugen: de laatste N beurten behouden

Venstergeheugen behoudt alleen de laatste K gespreksbeurten en verwijdert oudere berichten. Hiermee begrens je de context op K * avg_tokens_per_turn, ongeacht hoe lang het gesprek duurt. De keerzijde is dat de vroegste context verloren gaat — het model kan dingen vergeten die de gebruiker veel beurten eerder heeft gezegd. Voor de meeste chatbots voor algemeen gebruik biedt een venster van 5–10 beurten een goede samenhang tegen aanvaardbare 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 dropped

Venstergeheugen implementeren met InMemoryChatMessageHistory

De InMemoryChatMessageHistory van LangChain bewaart alle berichten, maar je kunt de geschiedenis inkorten voordat je deze in de prompt invoegt. Een veelgebruikt patroon is om de volledige geschiedenis te bewaren voor logregistratie, maar alleen de laatste N berichten aan de LLM door te geven. Gebruik de slice-notatie van Python op history.messages om het meest recente venster op te halen.

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
)

Venster op basis van tokens versus beurten

Je kunt de venstergrootte opgeven in beurten (de laatste K-paren van gebruiker en AI) of in tokens (de laatste T tokens van de geschiedenis). Een venster op basis van tokens is betrouwbaarder, omdat de lengte van beurten varieert — een beurt met code is 10 keer langer dan een beurt met 'ja'. De trim_messages()-hulpmethode van LangChain ondersteunt beide strategieën en kan de systeemprompt behouden terwijl de geschiedenis wordt ingekort.

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')

Samenhang meten tegenover venstergrootte

Om de juiste venstergrootte te kiezen, moet je meten hoe de samenhang van het gesprek afneemt naarmate het venster kleiner wordt. Voer een reeks testgesprekken uit waarin beurt N verwijst naar informatie uit beurt N-5, N-10 en N-20. Test of het model nog steeds correct kan antwoorden met vensters van 5, 10 en 20 beurten. Het antwoord geeft je de minimale venstergrootte voor jouw specifieke gebruikssituatie.

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 results

Systeemprompt combineren met venstergeheugen

Wanneer je venstergeheugen gebruikt, moet je altijd de systeemprompt behouden — deze definieert de persona en regels van de AI. Zonder deze prompt kan het model zijn persona verliezen zodra het venster voorbij de eerste beurt schuift. Gebruik de optie include_system=True in inkortfuncties, of voeg het systeembericht altijd vóór de geschiedenis met venster toe in je promptsjabloon.

# 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 window

Keuzehulp: buffer- versus venstergeheugen

Gebruik buffergeheugen wanneer: gesprekken kort en begrensd zijn (een eenmalige taak, een formulierwizard), de volledige context cruciaal is (juridische analyse, codebeoordeling) en het tokenbudget geen probleem vormt. Gebruik venstergeheugen wanneer: gesprekken onbeperkt lang kunnen worden (klantenondersteuning, algemene assistenten), recente context belangrijker is dan verre context en je voorspelbare, begrensde tokenkosten nodig hebt.

# 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'

Het venster opslaan in Redis

Sla voor productiegebruik de volledige gesprekgeschiedenis op in Redis (voor snel ophalen) en beperk deze tijdens het lezen tot de venstergrootte. Redis met een TTL zorgt ervoor dat oude sessies automatisch verlopen. Gebruik een geordende verzameling of een lijst met LRANGE om efficiënt alleen de laatste N berichten op te halen zonder de volledige geschiedenis te 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 history

De gezondheid van geheugen in productie bewaken

Houd deze statistieken in productie bij om problemen met geheugen op te sporen: gemiddeld aantal geschiedenistokens per aanvraag om te detecteren dat sessies te groot worden, gebruik van het contextvenster (waarschuw bij > 80%), aantal sessies in de opslag om geheugenlekken in de sessieopslag te detecteren en cachetrefferpercentage voor sessies die opnieuw uit Redis worden geladen. Geef een waarschuwing wanneer het gemiddelde aantal geschiedenistokens een instelbare drempel overschrijdt.

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
        pass

Korte controle

Test je begrip van buffer- en venstergeheugenstrategieën.

Samenvatting van de les

In deze les heb je geleerd dat buffergeheugen de volledige geschiedenis behoudt maar onbeperkt groeit, waardoor het alleen geschikt is voor korte, begrensde gesprekken, dat venstergeheugen alleen de laatste K beurten behoudt voor voorspelbare, begrensde kosten ten koste van verre context, en dat inkorten op basis van tokens met trim_messages() betrouwbaarder is dan vensters op basis van beurten, omdat de berichtlengte varieert. Hierna bekijken we samenvattingsgeheugen voor open, lange gesprekken.

Gratis beginnen

Leer Python met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
30
Lessen
120

Veelgestelde vragen

Is de les “Buffer- en windowgeheugen” gratis?

Ja — de volledige tekst van “Buffer- en windowgeheugen” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus AI Engineering Academy wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus AI Engineering Academy bevat in totaal 4 lessen.

Wat leer ik in “Buffer- en windowgeheugen”?

U implementeert ConversationBufferMemory en ConversationBufferWindowMemory om de laatste N gespreksbeurten in de context te bewaren en meet hoe de venstergrootte samenhangt met coherentie en kosten. Je oefent met AI Engineering Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met AI Engineering Academy te beginnen?

Ervaring vooraf is niet nodig. AI Engineering Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.

Hoe lang duurt de les “Buffer- en windowgeheugen”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over AI Engineering Academy?

Ja. Elke les over AI Engineering Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. Waarom stateless LLM's extern geheugen nodig hebben
  2. Buffer- en windowgeheugen
  3. Samenvattingsgeheugen en tokenbewuste afkapping
  4. Chatgeschiedenis bewaren in Redis en PostgreSQL
← Terug naar AI Engineering Academy