{"slug": "i-built-a-memory-layer-for-llm-agents-that-knows-which-facts-go-stale", "title": "I Built a Memory Layer for LLM Agents That Knows Which Facts Go Stale", "summary": "A developer built VoltMem, a memory layer for LLM agents that distinguishes between volatile and stable facts to avoid stale or corrupted knowledge. Unlike existing systems like Mem0, VoltMem assigns domain-aware protection weights and down-ranks stale volatile memories at retrieval time. In scripted scenarios, it correctly updated a location change from Berlin to Paris, resisted a blip contradicting a stable preference, and updated a mood shift, achieving 0% stale@1 retrieval versus 20% for cosine-only ranking.", "body_md": "VoltMem didn't start because I kept hitting bugs in production agents.\n\nIt started with a conversation about how memory actually works — why some beliefs stick for decades while others evaporate in hours, and what triggers the audit when an old calibration stops matching present reality. That led to continual-learning research on the stability–plasticity tradeoff, and then to a structural parallel in agent memory: most layers treat every fact the same at write and search time.\n\nYour AI assistant knows you live in Berlin. You moved to Paris three months ago. It still thinks you live in Berlin. Meanwhile, the fact that you prefer concise answers — stable for years — gets the same grip as \"currently working on a database migration,\" which you finished last week.\n\nEverything is stored the same way. Everything decays (or doesn't) at the same rate. There's no concept of *how volatile* a piece of knowledge actually is.\n\nMem0 remembers relevant facts. VoltMem remembers\n\ncurrent truth.\n\nThink about how different types of facts actually behave over time:\n\nAn LLM memory system that treats all of these with the same protection strength makes systematic errors in a predictable direction: it holds volatile facts too long (stale knowledge), or overwrites stable facts on thin evidence (corrupted knowledge). You can't fix both with one dial.\n\nWhat you need is *domain-aware protection* — and, at search time, down-ranking of stale volatile memories even when they're semantically close.\n\n**Protection weight** (per domain):\n\n**Write / audit decision** — escalate (audit + update) when\nEt>θt\n:\n\nWhere:\n\nHigh-volatility domain → low threshold → easy to update.\n\nLow-volatility domain → high threshold → hard to update.\n\n**Retrieval** — down-rank stale volatile memories:\n\nThe practical effect: a confident blip like \"the user seemed extroverted today\" won't overwrite a deeply confirmed \"user is introverted\" — but \"user moved to Paris\" will cleanly supersede \"user lives in Berlin\" because location is a volatile domain where a single explicit statement clears the update bar easily.\n\nOn Split-MNIST, this isn't a free-lunch accuracy booster. It's a validated **control knob**: run the same pipeline with volatility priors shuffled or inverted, and the ordering breaks (REAL > SHUFFLE > SWAP). Pre-arXiv draft: [volatility_ewc_portfolio.pdf](https://github.com/Rouche01/voltmem/blob/main/paper/volatility_ewc_portfolio.pdf). Full reproduction: [docs/RESEARCH.md](https://github.com/Rouche01/voltmem/blob/main/docs/RESEARCH.md).\n\nI compared VoltMem against Mem0 (open-source LLM memory) on three concrete scenarios — a **case study**, not a leaderboard claim:\n\n**Scenario 1: Location update**\n\nUser says they moved from Berlin to Paris.\n\n| Mem0 | VoltMem | |\n|---|---|---|\n| Result | Stale \"Berlin\" stored, 2 conflicting facts | Updated to \"Paris\", 1 clean fact |\n\n**Scenario 2: Stable preference blip**\n\nUser says they \"really like short replies\" in one session, contradicting an established preference for thorough explanations.\n\n| Mem0 | VoltMem | |\n|---|---|---|\n| Result | Adopts the blip | Keeps original (resists weak contradicting evidence) |\n\n**Scenario 3: Volatile mood**\n\nUser's mood shifts from \"great\" to \"stressed\".\n\n| Mem0 | VoltMem | |\n|---|---|---|\n| Result | Stale \"great\" persists | Updates to \"stressed\" |\n\n**VoltMem: 3/3** current top answer on these scripted scenarios. Challenge the scripts:\n\n```\npython experiments/mem0_side_by_side.py\n```\n\n**Retrieval haystack** (same chunks, different ranker): cosine-only returns the stale fact first **20%** of the time; VoltMem **0%** [stale@1](mailto:stale@1).\n\n```\npython experiments/retrieval_haystack_bench.py\n```\n\n**LongMemEval-S (n=60):** **70% answer@5** — **ties cosine, does not beat it.** If your only metric is public benchmark SOTA, this isn't the pitch. The pitch is update policy + retrieval freshness on mixed-volatility personal memory.\n\n```\npython experiments/longmemeval.py --split s --per-type 10\npip install voltmem[embeddings]\n```\n\nCore library: **zero required dependencies**. Embeddings optional (`sentence-transformers`\n\n).\n\n``` python\nfrom voltmem import create_memory\n\nmem = create_memory(\"app.db\", user_id=\"alice\")\n\nmem.add(\"I live in Berlin\")\nmem.add(\"I prefer concise, direct answers\")\nmem.add(\"Actually I moved to Paris last month\")   # updates location, not prefs\n\nhits = mem.search(\"where does the user live?\", limit=3)\nprint(hits[0][\"memory\"])   # \"Actually I moved to Paris last month\"\n```\n\nInject into any LLM system:\n\n```\nmemories = mem.search(user_message, limit=5)\ncontext = \"\\n\".join(f\"- {m['memory']}\" for m in memories)\nsystem = f\"What you know about this user:\\n{context}\"\n```\n\nVoltMem ships with sensible defaults you can override:\n\n| Domain | Volatility | Behavior |\n|---|---|---|\n`personality_trait` |\n0.05 | Strongly protected |\n`core_preference` |\n0.08 | Strongly protected |\n`biographical` |\n0.10 | High protection |\n`professional_context` |\n0.30 | Medium — changes every few years |\n`current_project` |\n0.55 | Updates readily |\n`emotional_context` |\n0.80 | Fast-moving |\n`current_task` |\n0.90 | Minimal protection |\n\nCustom domains:\n\n``` python\nfrom voltmem import create_memory, DomainRegistry\n\ndomains = DomainRegistry()\ndomains.register(\"client_relationship\", 0.35)\ndomains.register(\"active_deal_stage\", 0.70)\n\nmem = create_memory(\"crm.db\", user_id=\"rep_01\", domains=domains)\n```\n\nThe priors are hand-tuned today — that's an open gap, and one of the places I'd most like real-world feedback.\n\n```\npip install voltmem[langchain]\npython\nfrom voltmem.integrations.langchain import VoltMemMemory\n\nmemory = VoltMemMemory(session_id=\"user-42\", db_path=\"app.db\")\nmemory.load_memory_variables({\"input\": \"Where do I live?\"})\nmemory.save_context({\"input\": \"I moved to Paris\"}, {\"output\": \"Noted.\"})\n```\n\nThis grew out of a philosophical conversation about how human minds handle stale beliefs — when to trust an old habit and when to question it.\n\nThe observation: animals mostly rely on impulses and simple reinforcement to build routines. Human minds add a monitoring layer on top — but that layer can go wrong when calibrated by social contexts that no longer apply. An old rule, reinforced enough times in a specific environment, can feel like an unquestionable fact even when the environment has fundamentally changed.\n\nThat maps almost exactly onto the LLM memory problem. A memory system calibrated by early conversation data can become rigid in the same way — protecting old \"truths\" that are now stale because they were confirmed enough times in the past.\n\nThe escalation equations above formalize the same idea: use historical reinforcement as *one* input, but also factor in domain volatility, source reliability, and actual mismatch — rather than letting any one factor dominate. The continual-learning experiments validated that as a causal control knob; VoltMem is the engineering artifact applied to agent context memory.\n\n```\npip install voltmem[embeddings]\npython examples/contradiction_demo.py\npython -m examples.chat_app\n```\n\nIf you're building anything with persistent LLM memory, I'd genuinely like to hear how the stale-knowledge problem shows up in practice — the use cases I haven't thought of are usually the most interesting ones.", "url": "https://wpnews.pro/news/i-built-a-memory-layer-for-llm-agents-that-knows-which-facts-go-stale", "canonical_source": "https://dev.to/rouche01/i-built-a-memory-layer-for-llm-agents-that-knows-which-facts-go-stale-1mg5", "published_at": "2026-07-13 01:42:18+00:00", "updated_at": "2026-07-13 02:14:43.189984+00:00", "lang": "en", "topics": ["artificial-intelligence", "large-language-models", "ai-agents", "ai-research", "machine-learning"], "entities": ["VoltMem", "Mem0", "Split-MNIST", "LongMemEval-S"], "alternates": {"html": "https://wpnews.pro/news/i-built-a-memory-layer-for-llm-agents-that-knows-which-facts-go-stale", "markdown": "https://wpnews.pro/news/i-built-a-memory-layer-for-llm-agents-that-knows-which-facts-go-stale.md", "text": "https://wpnews.pro/news/i-built-a-memory-layer-for-llm-agents-that-knows-which-facts-go-stale.txt", "jsonld": "https://wpnews.pro/news/i-built-a-memory-layer-for-llm-agents-that-knows-which-facts-go-stale.jsonld"}}