AI Agent Memory: schema-gestuurde state en provenance

Automatische vertaling Dit artikel is automatisch vertaald vanuit de oorspronkelijke Engelse versie.

Long-running agents halen vaak verouderde feiten op, omdat gewone semantic memory geen regel heeft om te bepalen welke waarde actueel is.

Wanneer een gebruiker een paspoortdeadline wijzigt van 15 juli naar 30 juni, kan vector search beide uitspraken ophalen. Een stateful memory-laag moet vastleggen dat de waarde van 30 juni de eerdere waarde vervangt.

Voor engineers die long-running of multi-tenant agents bouwen, is dit stale-fact-probleem precies waarom memory aparte runs moet overleven en tegelijk current state en tenant boundaries moet afdwingen. Het onderstaande ontwerp laat zien hoe je typed records schrijft en current versus point-in-time reads test, zonder vector recall als source of truth te behandelen.


De context-window-valkuil

De context window is de input die beschikbaar is voor één model call. Een applicatie kan messages meenemen naar latere calls, maar application policy moet bepalen welke oude feiten nog kloppen en wie ze mag zien.

Long-running agents moeten preferences, task status, customer facts, tool decisions, compliance notes en eerdere fouten onthouden. De eenvoudige aanpak is om summaries toe te voegen of oude notes in een vector store te dumpen. Dat werkt totdat een van die onthouden feiten verandert.

De agent heeft dan twee paspoortdeadlines, twee voorkeuren voor formats of twee projectbeslissingen. Semantic search kan ze allebei ophalen. Een summary kan er één overschrijven. Een lange context kan het verouderde feit naast het actieve feit bevatten. Deze ontwerpen halen tekst op, maar dwingen de current value niet af.

Het memory contract moet concrete vragen beantwoorden:

  • Wat is nu waar?
  • Wat was waar op 2 juni?
  • Wie heeft het gezegd?
  • Bij welke tenant hoort het?
  • Welk ouder feit heeft dit feit vervangen?
  • Kan ik het verwijderen of laten verlopen?

Schema-Guided Agent Memory (SGAM) slaat deze antwoorden op als fields en relations, in plaats van ze impliciet in prose te laten.


Wat SGAM betekent

Drie vergelijkbaar benoemde concepten bakenen de scope van SGAM af.

Schema-Guided Dialogue (SGD) is de 2019 Google task-oriented dialogue dataset. Het schema beschrijft service APIs, intents en slots, zodat een dialogue model state kan bijhouden voor services die het nog niet heeft gezien. Het is een nuttig precedent voor schema-based tracking, met een scope die beperkt blijft tot dialogue services.

Schema-Guided Memory (SGM) is de researchterm die Mei et al. gebruiken in According to Me: Long-Term Personalized Referential Memory QA. De paper vergelijkt free-text Descriptive Memory (DM) met fixed-schema key-value memory items. Beide representaties bevatten dezelfde broninformatie, maar in verschillende structuren.

In dit artikel gebruik ik Schema-Guided Agent Memory (SGAM) voor een engineering pattern waarin schemas writes, updates, retrieval en deletion aansturen. Het schema definieert application state en de lifecycle daarvan.

ATM-Bench laat zien waarom de representatie ertoe doet. De benchmark gebruikt ongeveer vier jaar aan persoonlijke data uit emails, images en videos. De vragen vereisen personal references, location, meerdere stukken evidence en updates door de tijd heen. Op de hard split rapporteert de paper dat SGM DM overtreft voor retrieval en question answering binnen de geteste setup. SGM maakt fields zoals time, source, location, entities en tags zichtbaar in een fixed representation. Ik beschouw die representatie en de gerapporteerde resultaten als de ondersteunde conclusie; de paper toont geen direct field-addressing mechanism aan.

SGM versus DM beantwoordt een storagevraag: moet memory free text blijven, of named fields gebruiken? Een production agent heeft vóór storage nog een ander probleem. Het moet een unstructured conversation omzetten in een voorgestelde memory update. Schema-Guided Reasoning (SGR) maakt die beoogde decision path inspectable: de response kan evidence, subject en attribute, een vergelijking met de current state en een candidate write bevatten. De model response dwingt geen dependencies of order tussen die fields af. Separate calls, validators en application policy handhaven die regels; SGAM past de storage- en lifecycle-regels toe na de model call.


Scheid model extraction van memory ownership

De memory write loopt over drie lagen. Structured Output (SO) handhaaft de shape van het candidate object. Schema-Guided Reasoning (SGR) maakt de intended fields en decision intent inspectable in een gestructureerde response. Schema-Guided Agent Memory (SGAM) beheert de candidate als durable state na de model call. Separate calls, validators en application policy handhaven dependencies, order en lifecycle.

Een verdict, route of plan verloopt meestal samen met de huidige request. Een andere run kan dagen later een memory candidate uitlezen of die gebruiken om een tool call te kiezen. Die langere levensduur vereist storage rules die SGR niet levert.

SGR structureert één model call rond een intended reasoning topology. Voor een memory write kan de response source evidence, een normalized subject en attribute, een vergelijking met current state en een proposed update bevatten. Pydantic of JSON Schema beschrijft die fields. Provider-native Structured Output of een guided decoding runtime zoals XGrammar houdt de response in die shape.

Die shape maakt de door het model gedeclareerde fields en intent inspectable. Ze garandeert geen correcte conclusie en bewijst niet dat het model die fields in de juiste volgorde heeft gebruikt. Separate calls, validators en application policy vormen de enforcement boundary voor dependencies, order en lifecycle.

SGAM bepaalt wat er gebeurt zodra dat object bestaat. Moet het worden opgeslagen? Vervangt het een ouder feit? Welke tenant mag het zien? Is het current of historical? Welke source episode ondersteunt het?

De tabel beschrijft het ownership en de failure mode van elke laag:

DimensieSOSGRSGAM
DoelEen object retourneren dat aan een schema voldoetIntended fields en decision intent inspectable makenDurable memory beheren na de model call
ScopeEén generated responseEén model response; cross-step policy kan meerdere calls omvattenRecords die tussen calls, sessions en runs worden gebruikt
Rol van het schemaDefinieert output fields, types en toegestane waardenBeschrijft evidence, intermediate fields en candidate decisionDefinieert stored records, relations en lifecycle
EnforcementConstrained decoding blokkeert schema-invalid outputAlleen shape; separate calls, validators en policy handhaven dependencies en orderApplication validation, database constraints en conflict rules handhaven lifecycle
LevensduurHuidige call, tenzij de applicatie het object opslaatReasoning trace wordt meestal na de decision verwijderdBlijft bestaan totdat het wordt bijgewerkt, expired of verwijderd
Failure modeValide shape met de verkeerde betekenisFields zijn aanwezig, maar reasoning of dependency handling kan nog steeds verkeerd zijnStale, polluted, unscoped of unauditable state

Op de write path is de volgorde:

SGR reasoning schema + Structured Output -> candidate write -> SGAM policy and persistence

Het volgende illustratieve fragment uit memory_models.py definieert het object dat van extraction naar de SGAM write service gaat. Dit block heeft Pydantic nodig en wordt daarom gemarkeerd als no-run in de example checks voor environments waarin die optional dependency niet is geïnstalleerd:

from datetime import datetime
from pydantic import BaseModel, Field

class MemoryDelta(BaseModel):
    tenant_id: str = Field(description="Isolation boundary, e.g. acme")
    subject: str = Field(description="Normalized entity ID, e.g. mira")
    attribute: str = Field(description="Property being updated")
    value: str = Field(description="New value")
    valid_from: datetime
    source_episode_id: str

MemoryDelta legt vast wat het model heeft geëxtraheerd. De SGAM write service bepaalt nog steeds of het object wordt rejected, merged of opgeslagen.


Write- en read paths hebben verschillende taken

Alleen de write path muteert opgeslagen state. De read path selecteert records voor de huidige request.

De ingestion flow is de write path:

  1. Leg een raw episode vast uit messages, tool results of business events.
  2. Extraheer typed candidates via structured output.
  3. Valideer het schema en reject malformed writes.
  4. Reconcile conflicts, sluit stale facts af en bewaar provenance.
  5. Commit het record naar de SGAM store.

De request flow is de read path:

  1. Begin met de user question.
  2. Bepaal of de vraag current state of point-in-time state nodig heeft.
  3. Filter op tenant, memory type, subject, attribute en validity window.
  4. Voeg vector- of graph-expansion alleen toe als de exacte state lookup niet volstaat.
  5. Stel de kleinste cited context voor het model samen.

Schema-Guided Agent Memory-architectuurSchema-Guided Agent Memory-architectuur

Lees dat diagram van links naar rechts in twee lanes. De bovenste lane schrijft memory, de onderste leest het. Beide gebruiken dezelfde store.


Wat in een memory schema hoort

Een minimaal SGAM-record heeft meer nodig dan text.

tenant_id
memory_id
subject
attribute
value
memory_type
schema_version
valid_from
valid_to
supersedes_memory_id
source_episode_id
confidence
retention_policy

Met deze fields kan een nieuwe paspoortdeadline de vorige deadline sluiten zonder de history te wissen. Dezelfde tabel kan current en point-in-time queries beantwoorden en het resultaat vervolgens terugleiden naar de source episode. schema_version ondersteunt migrations, terwijl retention_policy deletion jobs vertelt wat ze nog meer moeten verwijderen.

Gebruik RAG om documents op te halen en SGAM om mutable state te beheren. Vector search hoort nog steeds in het systeem thuis voor fuzzy recall, clustering en expansion. De current value van mira.passport_deadline moet uit een scoped memory record komen, niet uit het chunk dat toevallig het hoogst gerankt werd.


Een stale-fact-voorbeeld

Beschouw een synthetische trace met twee episodes, weergegeven als een DM-baseline en een SGAM-ledger:

e1: Mira prefers concise answers. Her passport deadline is 2026-07-15.
e2: Mira corrected the deadline. It is now 2026-06-30.

Een DM-baseline bewaart beide episodes als free text, waardoor text search e1 kan retourneren omdat die de juiste woorden bevat. SGAM extraheert uit elke episode een typed fact, keyed by tenant, subject en attribute. Het moet e2 als current state retourneren en e1 bewaren voor een historical query.

Het volgende is een self-contained SQLite write path. Deze gebruikt ISO-8601 UTC-strings voor timestamps, configureert sqlite3.Row voordat er op column name wordt gelezen en representeert facts als half-open intervals: [valid_from, valid_to). De tabel reject invalid intervals en heeft een partial unique index voor één open fact per tenant, subject en attribute. replace_fact beheert één transaction; SQLite serializeert concurrent writers, dus callers moeten de volledige transaction retrien na een lock- of uniqueness error.

import sqlite3
from dataclasses import dataclass

@dataclass(frozen=True)
class MemoryFact:
    tenant_id: str
    subject: str
    attribute: str
    value: str
    valid_from: str
    source_episode_id: str

def open_db() -> sqlite3.Connection:
    db = sqlite3.connect(":memory:")
    db.row_factory = sqlite3.Row
    db.executescript(
        """
        create table memory_facts (
            fact_id integer primary key,
            tenant_id text not null,
            subject text not null,
            attribute text not null,
            value text not null,
            valid_from text not null,
            valid_to text,
            source_episode_id text not null,
            check (valid_to is null or valid_from < valid_to)
        );
        create unique index one_open_fact
        on memory_facts (tenant_id, subject, attribute)
        where valid_to is null;
        """
    )
    return db

def replace_fact(db: sqlite3.Connection, fact: MemoryFact) -> None:
    with db:
        exact = db.execute(
            """
            select fact_id
            from memory_facts
            where tenant_id = ? and subject = ? and attribute = ? and valid_from = ?
            """,
            (fact.tenant_id, fact.subject, fact.attribute, fact.valid_from),
        ).fetchone()
        if exact:
            raise ValueError("equal valid_from requires an application conflict policy")

        containing = db.execute(
            """
            select fact_id, valid_to
            from memory_facts
            where tenant_id = ?
              and subject = ?
              and attribute = ?
              and valid_from < ?
              and (valid_to is null or valid_to > ?)
            limit 1
            """,
            (
                fact.tenant_id,
                fact.subject,
                fact.attribute,
                fact.valid_from,
                fact.valid_from,
            ),
        ).fetchone()
        if containing:
            db.execute(
                "update memory_facts set valid_to = ? where fact_id = ?",
                (fact.valid_from, containing["fact_id"]),
            )
            successor_boundary = containing["valid_to"]
        else:
            successor = db.execute(
                """
                select valid_from
                from memory_facts
                where tenant_id = ? and subject = ? and attribute = ? and valid_from > ?
                order by valid_from
                limit 1
                """,
                (fact.tenant_id, fact.subject, fact.attribute, fact.valid_from),
            ).fetchone()
            successor_boundary = successor["valid_from"] if successor else None

        db.execute(
            """
            insert into memory_facts
                (tenant_id, subject, attribute, value, valid_from, valid_to, source_episode_id)
            values (?, ?, ?, ?, ?, ?, ?)
            """,
            (
                fact.tenant_id,
                fact.subject,
                fact.attribute,
                fact.value,
                fact.valid_from,
                successor_boundary,
                fact.source_episode_id,
            ),
        )

def fact_at(db: sqlite3.Connection, timestamp: str) -> sqlite3.Row:
    return db.execute(
        """
        select value, source_episode_id
        from memory_facts
        where tenant_id = ?
          and subject = ?
          and attribute = ?
          and valid_from <= ?
          and (valid_to is null or valid_to > ?)
        limit 1
        """,
        ("acme", "mira", "passport_deadline", timestamp, timestamp),
    ).fetchone()

db = open_db()
replace_fact(
    db,
    MemoryFact("acme", "mira", "passport_deadline", "2026-07-15", "2026-06-01T09:00:00Z", "e1"),
)
replace_fact(
    db,
    MemoryFact("acme", "mira", "passport_deadline", "2026-06-30", "2026-06-03T10:00:00Z", "e2"),
)
current = fact_at(db, "2026-06-04T00:00:00Z")
assert (current["value"], current["source_episode_id"]) == ("2026-06-30", "e2")

historical = fact_at(db, "2026-06-02T00:00:00Z")
assert (historical["value"], historical["source_episode_id"]) == ("2026-07-15", "e1")

# A delayed extraction predates e1. It ends at e1's existing boundary,
# rather than closing e2, which remains current.
replace_fact(
    db,
    MemoryFact("acme", "mira", "passport_deadline", "2026-08-01", "2026-05-30T08:00:00Z", "e0"),
)
delayed = fact_at(db, "2026-05-31T00:00:00Z")
assert (delayed["value"], delayed["source_episode_id"]) == ("2026-08-01", "e0")
current = fact_at(db, "2026-06-04T00:00:00Z")
assert (current["value"], current["source_episode_id"]) == ("2026-06-30", "e2")
intervals = db.execute("select valid_from, valid_to from memory_facts").fetchall()
assert all(row["valid_to"] is None or row["valid_from"] < row["valid_to"] for row in intervals)

episodes = (
    "e1: Mira prefers concise answers. Her passport deadline is 2026-07-15.",
    "e2: Mira corrected the deadline. It is now 2026-06-30.",
)
naive_match = next(episode for episode in episodes if "passport deadline" in episode)
assert naive_match.startswith("e1:")

replace_fact reject eerst een gelijke valid_from: voor dat conflict is application policy nodig, zoals source precedence of een user-confirmed revision, in plaats van een silent overwrite. Vervolgens zoekt het interval dat de incoming timestamp bevat. Als het er één vindt, sluit het die predecessor op de incoming boundary en geeft het de inserted row het eerdere einde van de predecessor. Als de timestamp vóór elk opgeslagen interval ligt, gebruikt het de volgende interval’s valid_from als het einde van de nieuwe row. Zo wordt een delayed fact vóór e1 [2026-05-30, 2026-06-01) en blijven e1 en de current e2 intact. De row factory maakt row["fact_id"] en named result fields geldig op de default connection die hier wordt aangemaakt. De partial unique index is de database guard voor één open row; een multi-writer deployment moet een database- en retry policy kiezen die bij de workload past. DM heeft geen equivalente update step, dus de oude tekst kan de correctie nog steeds overtreffen.

De assertions verifiëren de current e2 row, de historische e1 row, delayed insertion vóór e1, de interval invariant en de eerste matching naive text episode:

Naive text memory:
  returned episode: e1 -> passport deadline is 2026-07-15

SGAM current state:
  mira.passport_deadline = 2026-06-30
  valid_from=2026-06-03T10:00:00Z, source=e2

SGAM point-in-time state:
  on 2026-06-02, mira.passport_deadline = 2026-07-15

Combineer deze transaction in production met structured extraction op de write path. De database transaction werkt temporal validity bij. Het model extraheert een candidate fact, maar beslist niet welke opgeslagen row current blijft.


Storagekeuzes volgen uit het retrieval pattern

Projects gebruiken verschillende namen voor onderdelen van dit pattern: memory stores, context graphs, profiles, long-term stores, graph RAG en stateful agents.

Tool of frameworkBelangrijkste storage layerMechanisme voor temporal stateSchema-mechanismePraktische niche
GraphitiNeo4j, FalkorDB en Amazon Neptune; Kuzu is deprecatedFact validity intervals plus source-episode provenancePydantic entity- en edge-types, temporal edges, provenanceSelf-hosted temporal graph memory
ZepProprietary Context Graph EngineManaged temporal Context Graphs die changing facts behoudenDefault en custom entity- en edge-typesManaged agent memory en governance
LangGraph / LangMemLangGraph stores, Postgres-backed storesApplication-owned timestamps en fields in store recordsJSON stores plus Pydantic profile- of collection extractionAgent-apps die al op LangGraph zijn gebouwd
Mem0Managed stack, Valkey / Redis / vector backends in OSS-setupsMemory updates; temporal policy blijft application-ownedMemory types, custom categories, extraction promptsUser-, agent- en session memory als service
Letta / MemGPTDatabase-backed agent state en memory blocksEditable blocks zonder field-level validity intervalsEditable labeled memory blocksStateful agents met OS-style context management
CogneeGraph plus vector- en relational backendsHistory hangt af van de ontology en de geselecteerde backendOntology-oriented extraction en validationEnterprise knowledge graph memory
LlamaIndex property graphProperty graph stores plus vector storesTime fields hangen af van het graph schema en de storeSchemaLLMPathExtractor met toegestane entities en relationsGraph extraction over documents en traces

Graphiti is een concrete open-source implementation van relational, temporal memory. Het trackt facts terwijl ze veranderen, bewaart pointers naar source episodes en ondersteunt hybrid retrieval. LangGraph scheidt thread checkpoints van cross-thread stores. Mem0 verpakt memory operations als een managed service. Letta gebruikt editable context blocks in plaats van field-level SGAM, maar behandelt agent state nog steeds als persistent data.

Begin met het data model. Als exact fact lookup de belangrijkste operatie is, volstaat meestal een relational table met JSON payloads, validity columns, tenant indexes en een vector sidecar. Voeg een graph toe wanneer relationship traversal onderdeel is van het product, niet omdat de graph demo er indrukwekkend uitziet.


Bouw eerst de write path, daarna de graph

Bepaal eerst wat het product mag onthouden. De keuze tussen graph en vector komt later.

Een support agent kan account tier, open cases en durable contact preferences onthouden. Het moet niet elke gefrustreerde terzijde promoveren tot profile state. Een coding agent kan repo conventions en unresolved tasks onthouden. Het moet een private note niet voor altijd bewaren omdat die note toevallig één keer werd opgehaald.

Begin met de write path en behandel memory als een kleine state mutation:

  1. Geef het memory type, de subject, tenant scope en retention class een naam.
  2. Extraheer candidate records met structured output.
  3. Valideer de payload met Pydantic of de schema layer die je stack al gebruikt.
  4. Resolve conflicts vóór insert, inclusief de vraag of het nieuwe record een oud record supersedes.
  5. Bewaar een source pointer naar de raw episode, tool result, file, ticket of user confirmation die het record heeft opgeleverd.
  6. Schrijf de schema version met elk record weg, in plaats van die alleen in application code te laten staan.

De eerste SGAM store kan een relational table met een JSON column en enkele indexes zijn. Een graph wordt nuttig wanneer het product relationships moet traverseren, zoals customer-to-account, account-to-policy, task-to-artifact of project-to-decision.

Hot path en background writes

Immediate extraction is de moeite waard wanneer de volgende turn afhankelijk is van de nieuwe memory. Als de gebruiker zegt “onthoud dat ik korte antwoorden prefereer”, zou het systeem geen nightly job nodig moeten hebben voordat het zich anders gedraagt.

De meeste turns hebben geen immediate write nodig. Sla de raw episode op met tenant-, session- en tool-metadata en laat daarna een background worker candidates extraheren. Met recurrence-based consolidation buffert de worker weak signals en promoveert hij een fact pas nadat vergelijkbare evidence zich herhaalt of de user die bevestigt. Dit voegt freshness lag toe. Dat is acceptabel voor “de gebruiker vraagt vaak om CSV-exports” en riskant voor “de klant heeft het afleveradres gewijzigd.”

Houd de read path deterministic. Handhaaf tenant scope en validity eerst en gebruik daarna fuzzy retrieval alleen wanneer dat nuttige context kan toevoegen.

  1. Filter op tenant, memory type en validity window.
  2. Haal eerst exacte structured state op, vóór semantic neighbors.
  3. Gebruik vector- of graph-expansion voor supporting evidence, related entities en examples, niet als authority voor current facts.
  4. Stel de kleinste cited context samen die de vraag kan beantwoorden.

Behandel schema migration als een productwijziging, omdat die verandert wat de agent kan ophalen, citeren of verwijderen. Ze kan ook veranderen welke historical facts als current gelden. Plan migration scripts, backfills, dual-read windows en deletion behavior in dezelfde release.


Wanneer SGAM de complexiteit waard is

Gebruik SGAM wanneer facts door de tijd heen kunnen veranderen:

  • user preferences die kunnen worden bijgewerkt of ingetrokken
  • customer- of account-facts met audit requirements
  • task state voor long-running assistants
  • coding-agent project memory
  • multi-agent shared state
  • compliance notes waarbij provenance belangrijk is
  • temporal questions zoals “wat geloofden we vóór de migration?”

SGAM is overkill wanneer memory short-lived, exploratory of goedkoop opnieuw te berekenen is. Als de agent slechts enkele turns aan continuity nodig heeft, zijn een checkpoint en trimmed message history voldoende. Voor static document QA heb je mogelijk alleen RAG nodig. En als het domain zo unsettled is dat het schema dagelijks verandert, zal typed memory het team vertragen.


Evaluation checklist

Evalueer de memory lifecycle én het uiteindelijke antwoord. Een systeem kan een plausibele response produceren nadat het het verkeerde fact heeft geschreven, een stale fact heeft opgehaald of een tenant boundary heeft overschreden.

Ik gebruik dezelfde stage-by-stage split als in mijn RAG evaluation article. Meet de stage waar een failure kan ontstaan, in plaats van evaluation te beperken tot de generated text. De trace discipline uit het agent evaluation article is hier ook van toepassing, omdat een memory bug vaak in de run history zichtbaar wordt voordat die het antwoord bereikt.

Ik zou SGAM met replay testen. Voer een fixed sequence van episodes in de memory writer in en inspecteer de ledger na elke betekenisvolle turn. Stel vervolgens current-state- en point-in-time-vragen aan de resulterende store.

LayerFailure waarnaar je zoektMeasures
Write extractionDe agent miste een fact, verzon er een of produceerde een invalid shapeSchema-valid write rate, extraction precision/recall, source episode coverage
Conflict handlingEen stale fact bleef current of een geldig oud fact werd overschrevenSupersession correctness, duplicate rate, stale-fact invalidation correctness
Isolation en policyMemory lekte tussen users of bleef bestaan na de policy windowTenant isolation failures, deletion correctness, retention compliance
Read retrievalHet juiste record bestaat, maar de reader haalde het niet opCurrent-state accuracy, point-in-time accuracy, recall@k over memory records
Answer groundingHet antwoord gebruikte memory zonder support of citeerde de verkeerde sourceClaim support against source episodes, citation accuracy, conflict-resolution correctness
OperationsDe memory path is te langzaam, te stale of te duurp95 write latency, freshness lag, read latency, cost per query

Benchmarks zoals LoCoMo, LongMemEval en ATM-Bench bieden public test cases. Ze vervangen geen domain test suite. Een coding assistant, customer support bot en compliance copilot hebben verschillende schemas, filters, retention rules en failure tests nodig.


Caveats

SGAM is mijn label voor een pattern, geen standard. Bestaande projecten verdelen het probleem anders. LangGraph memory en LangMem beschrijven short-term en long-term stores, profiles, collections, hot-path writes en background memory managers. Zep Graphiti gebruikt de term temporal Context Graph. Letta persisteert editable memory blocks, terwijl Mem0 een managed memory layer biedt. Microsoft GraphRAG, LlamaIndex property graphs en Cognee benaderen verwante onderdelen van het probleem als knowledge graphs.

Een user profile, episode log, document graph en agent-editable memory block lossen verschillende retrieval- en updateproblemen op. Ik reserveer SGAM voor durable memory die current application state representeert en daarom schema, validity, provenance, conflict handling, retention en migration nodig heeft.

Typed memory kan nog steeds verkeerd zijn. Een schema maakt bad writes eenvoudiger te inspecteren; het maakt ze niet trustworthy. Je hebt nog steeds source trust, user confirmation voor sensitive facts, conflict policy, deletion en monitoring nodig.

Schema migration is werk. Zodra memory state wordt, ben je verantwoordelijk voor versioning, backfills, old records en deletion behavior. Sla je dat werk over, dan overleven old records de semantics of retention policy waardoor ze zijn aangemaakt.


References