- Redis — session state, sliding windows, rate counters; sub-millisecond, TTL-native. - PostgreSQL + pgvector — durable facts with semantic search alongside relational data; one store, transactional, easiest to operate. - Neo4j / graph — relationship-heavy memory ("who reports to whom") where traversal beats similarity. - Mem0 / Zep / Letta — managed memory layers that extract, deduplicate, and decay facts for you.
sql
create table memories (
id uuid primary key default gen_random_uuid(),
user_id uuid not null,
kind text not null check (kind in ('preference','fact','task')),
content text not null,
embedding vector(3072) not null,
confidence real not null default 0.6,
last_used_at timestamptz,
created_at timestamptz not null default now()
);
create index memories_vec on memories using hnsw ((embedding::halfvec(3072)) halfvec_cosine_ops);
create index memories_user on memories (user_id, kind);Then govern it: extract candidate facts after a session, deduplicate against existing memories, decay confidence for unused entries, and let the user view and delete anything stored. Unbounded memory becomes contradictory memory, and contradictory memory produces worse answers than none.
Exercise: store preferences after each session, retrieve the top 5 by similarity on the next one, and add a "forget this" action that hard-deletes rows.