Back to the stack guide
Agent memory

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.