Mem0
Per-user chat memory that consolidates conversations into facts — isolated by user, injected sparingly, and never a hard dependency.
Memory as another retrieval leg
The chat tutor attaches a Mem0-backed memory per user (via
llama_index.memory.mem0): conversations are distilled into persistent facts,
and each turn retrieves only the relevant ones — capped by a search limit —
instead of replaying transcripts into the prompt. Architecturally it's just
another retrieval leg next to the corpus: user-scoped facts,
fetched per turn, subject to the same grounding discipline.
Why Mem0
What Mem0 adds over a message buffer is the part that's genuinely hard to roll yourself: consolidation — dedupe, update-vs-add decisions, forgetting. The store is the easy 20%; the memory lifecycle is the product. And because it ships as a LlamaIndex memory integration, it drops into the existing chat engine as a component, not a parallel system — the same reason the rest of the pipeline leans on framework seams. (For what short-term/working memory looks like on the other side of that boundary, see the short-term memory deep dive.)
Local-first: the engine runs in-process
Memory is a mode, not a cloud dependency. MEM0_MODE=local (the localhost
default) runs the open-source mem0 engine inside the RAG service itself: fact
extraction and consolidation on the same DeepSeek credentials the service
already holds, embeddings from the in-process FastEmbed model it already
loaded, storage in a service-owned collection inside the shared embedded
Qdrant, and a SQLite history log — no Mem0 account, no memory API key, no
telemetry egress. cloud keeps the hosted Mem0 Platform for the deployed
worker; the wire contract is identical either way. Beyond the chat lane, the
same engine seasons the memorize tutor, the grounded /query path, and raw
completions: remembered learner facts join the prompt as tone and difficulty
guidance — explicitly fenced off from being treated as evidence, so the
grounding gates keep their authority.
Never a hard dependency
Memory off, or the engine fails at init? The chat engine falls back to a memoryless default buffer — logged, not raised. Chat never breaks because memory is down, and a mid-turn consolidation failure degrades the same way (the answer still ships; only the remembering is skipped). That fallback also keeps the platform honest about coupling: memory is an enhancement, not a load-bearing wall.
Isolation is the design requirement
Memory is keyed by user identity from the constructor down — not filtered after the fact. Cross-user leakage is the one unrecoverable failure mode of a memory system, so isolation isn't a query parameter that could be forgotten; it's the shape of the API.
The case-study system pushes this further: long-term memory on Mem0 Cloud with per-contact isolation and source-trust tiers — a fact a contact stated in their own email carries different weight than one an agent inferred. Memory without provenance becomes confident hearsay.
What gets remembered
Learner preferences and progress context on the chat and tutor lanes (a practice card only enters memory once it passes the mnemonic gate); verified contact facts with provenance on the case-study lane. The rule of thumb: nothing enters memory that the user didn't say or that wasn't verified — memory is curated state, not a transcript dump.
The invariants
- Per-turn retrieval is capped by a search limit — relevant facts, never replayed transcripts.
- Memory failure degrades, never breaks: no key or an outage at init falls back to a memoryless buffer, logged not raised.
- Isolation is keyed by user identity from the constructor down — not a filter that could be forgotten.
- Every remembered fact carries provenance; inferred and stated facts are never the same trust tier.