Waarom geheugen cruciaal is voor agents
Een agent zonder geheugen begint elke taak opnieuw. Hij weet niet wat hij eerder heeft gedaan, welke fouten hij maakte of wat de gebruiker prefereerde. Geheugen maakt het verschil tussen een agent die telkens opnieuw instructies nodig heeft en een die leert en verbetert.
De indeling in vier typen geheugen, in-context, episodisch, semantisch en procedureel, sluit aan op het CoALA-raamwerk (Cognitive Architectures for Language Agents) en is in 2026 de gangbare standaard. Elk type heeft andere eigenschappen:
| Type | Persistentie | Schaalbaar | Doorzoekbaar | Gebruik |
|---|---|---|---|---|
| In-context | Sessie | Nee | Nee | Huidige taak |
| Episodisch | Permanent | Ja | Ja | Ervaringen |
| Semantisch | Permanent | Ja | Ja | Feiten, kennis |
| Procedureel | Permanent | Nee | Nee | Gedragsregels |
In-context geheugen
In-context geheugen is de message-history in het contextvenster. Eenvoudig maar beperkt door de grootte van het venster:
class InContextMemory {
private messages: Message[] = [];
private readonly maxTokens: number;
constructor(maxTokens = 50000) {
this.maxTokens = maxTokens;
}
add(message: Message): void {
this.messages.push(message);
this.pruneIfNeeded();
}
private pruneIfNeeded(): void {
while (estimateTokens(this.messages) > this.maxTokens) {
const firstUserMsg = this.messages.findIndex(m => m.role !== "system");
if (firstUserMsg === -1) break;
this.messages.splice(firstUserMsg, 2);
}
}
getMessages(): Message[] {
return this.messages;
}
}
Episodisch geheugen met vectoropslag
Episodisch geheugen slaat specifieke ervaringen op (tool-aanroepen, resultaten, fouten) en haalt ze op als ze relevant zijn:
import { ChromaClient, Collection } from "chromadb";
class EpisodicMemory {
private collection: Collection;
private embedder: EmbeddingFunction;
async storeEpisode(episode: {
description: string;
outcome: string;
tools_used: string[];
success: boolean;
}): Promise<void> {
const id = `ep-${Date.now()}-${Math.random().toString(36).slice(2)}`;
await this.collection.add({
ids: [id],
documents: [episode.description],
metadatas: [{
outcome: episode.outcome,
tools_used: episode.tools_used.join(","),
success: String(episode.success),
timestamp: new Date().toISOString(),
}],
});
}
async recallSimilar(query: string, limit = 3): Promise<Episode[]> {
const results = await this.collection.query({
queryTexts: [query],
nResults: limit,
where: { success: "true" },
});
return results.documents[0]?.map((doc, i) => ({
description: doc ?? "",
metadata: results.metadatas[0]?.[i] ?? {},
})) ?? [];
}
}
Semantisch geheugen
Semantisch geheugen bevat feiten over entiteiten (gebruikers, producten, projecten):
class SemanticMemory {
private store = new Map<string, Record<string, unknown>>();
upsert(entityId: string, facts: Record<string, unknown>): void {
const existing = this.store.get(entityId) ?? {};
this.store.set(entityId, { ...existing, ...facts, updated_at: new Date().toISOString() });
}
get(entityId: string): Record<string, unknown> | undefined {
return this.store.get(entityId);
}
toContextString(entityId: string): string {
const facts = this.get(entityId);
if (!facts) return "";
return `Bekende informatie over ${entityId}:
${Object.entries(facts)
.filter(([k]) => k !== "updated_at")
.map(([k, v]) => `- ${k}: ${v}`)
.join("
")}`;
}
}
Procedureel geheugen
Procedureel geheugen slaat geleerde gedragsregels op in de system prompt:
class ProceduralMemory {
private rules: string[] = [];
addRule(rule: string): void {
if (!this.rules.includes(rule)) {
this.rules.push(rule);
}
}
toSystemPromptSection(): string {
if (this.rules.length === 0) return "";
return `
Geleerde gedragsregels:
${this.rules.map(r => `- ${r}`).join("
")}`;
}
}
Vul procedureel geheugen aan na succesvolle en mislukte taken:
async function learnFromOutcome(task: string, success: boolean, details: string) {
if (!success) {
const rule = await llm.complete(`
Taak: ${task}
Fout: ${details}
Formuleer een korte gedragsregel (max 1 zin) om deze fout in de toekomst te vermijden:
`);
proceduralMemory.addRule(rule);
}
}
Alles samenbrengen
async function agentWithMemory(userMessage: string, userId: string): Promise<string> {
const userFacts = semanticMemory.toContextString(userId);
const similarEpisodes = await episodicMemory.recallSimilar(userMessage);
const learnedRules = proceduralMemory.toSystemPromptSection();
const systemPrompt = BASE_SYSTEM_PROMPT + learnedRules;
const contextPrefix = [
userFacts,
similarEpisodes.length > 0
? `Relevante eerdere ervaringen:
${similarEpisodes.map(e => `- ${e.description}: ${e.metadata.outcome}`).join("
")}`
: "",
].filter(Boolean).join("
");
inContextMemory.add({ role: "user", content: contextPrefix + "
" + userMessage });
const result = await reactAgent(userMessage, tools, systemPrompt, inContextMemory.getMessages());
await episodicMemory.storeEpisode({
description: userMessage,
outcome: result,
tools_used: extractUsedTools(result),
success: true,
});
return result;
}
Zelf bouwen of een framework gebruiken
De voorbeelden hierboven laten zien wat er onder de motorkap gebeurt. In productie hoef je dit niet altijd zelf te schrijven. In 2026 bestaan er volwassen geheugenlagen die episodisch en semantisch geheugen, samenvatting en vergeten al voor je regelen, zoals Mem0, Zep en de geheugenmodules in LangChain en LlamaIndex. Bouw het zelf als je volledige controle wilt over opslag en privacy, en pak een framework als je snel wilt itereren.
Begin eenvoudig
Start met alleen in-context geheugen. Voeg episodisch geheugen toe als gebruikers terugkerende taken hebben. Voeg semantisch geheugen toe als de agent kennis over entiteiten moet bijhouden. Procedureel geheugen voeg je pas toe als je een duidelijk patroon in fouten ziet dat de moeite waard is om vast te leggen.
Geheugen is een aanvalsoppervlak
Alles wat je opslaat kan later ongefilterd in de context van het model belanden. Een gebruiker of tool kan zo een instructie in het geheugen plaatsen die de agent bij een volgende sessie uitvoert (memory poisoning, een vorm van prompt injection). Behandel opgeslagen geheugen daarom als niet-vertrouwde invoer: scheid feiten van instructies, geef opgeslagen tekst nooit rechtstreeks als system prompt door en valideer wat je terug inlaadt.
Kies opslag op basis van schaal
Voor de meeste teams is pgvector op een bestaande PostgreSQL de eenvoudigste keuze. Chroma is prettig voor lokale prototypes. Pinecone of Qdrant zijn het overwegen waard zodra je richting tientallen miljoenen vectoren of strenge latency-eisen gaat.
Hoe sla ik geheugen op tussen sessies?
Sla episodisch en semantisch geheugen op in een database, bijvoorbeeld PostgreSQL met pgvector, Chroma, Qdrant of Pinecone. In-context geheugen is per definitie vluchtig en hoef je niet te bewaren.
Hoe voorkom ik dat het geheugen vol raakt?
Geef episodisch geheugen een TTL en verwijder episodes ouder dan een ingestelde periode. Beperk semantisch geheugen tot relevante feiten per entiteit. Vat oude episodes eventueel samen tot compactere kennis in plaats van alles te bewaren.
Kan het model foutieve feiten onthouden?
Ja. Bouw een correctie-mechanisme: als een gebruiker een feit corrigeert, werk je het bij in semantisch geheugen. Voorzie feiten van een betrouwbaarheidsscore en een bron, zodat je twijfelachtige feiten lager kunt wegen.
Hoe bescherm ik privacygevoelige geheugeninhoud?
Sla geheugen versleuteld op en beperk wie het kan lezen. Bouw een vergeet-functie die alle geheugen voor een specifieke gebruiker verwijdert op verzoek, zodat je voldoet aan het AVG-recht op vergetelheid.
Wat is het verschil tussen episodisch en semantisch geheugen?
Episodisch geheugen bewaart concrete gebeurtenissen, zoals een specifieke taak die lukte of mislukte. Semantisch geheugen bewaart tijdloze feiten die je uit die gebeurtenissen destilleert, zoals een vaste voorkeur van de gebruiker. Episodisch is het ruwe logboek, semantisch is de samenvatting.
Moet ik dit zelf bouwen?
Niet per se. Frameworks als Mem0, Zep, LangChain en LlamaIndex bieden kant-en-klare geheugenlagen. Bouw het zelf wanneer je volledige controle over opslag en privacy nodig hebt, en gebruik anders een framework om sneller te itereren.