Give Your LangGraph Agent a Memory That Survives Restarts
Short-term memory with MongoDBSaver, long-term memory with MongoDBStore and Atlas Vector Search, in one small Python script.
핵심 요약
자동 요약- 1Short-term memory with MongoDBSaver, long-term memory with MongoDBStore and Atlas Vector S…
- 2Most agent demos have the memory of a goldfish.
- 3Restart the process and the conversation is gone.
원문 본문
출처 · dev.toShort-term memory with MongoDBSaver, long-term memory with MongoDBStore and Atlas Vector Search, in one small Python script.
Most agent demos have the memory of a goldfish. Restart the process and the conversation is gone. Open a new chat and the agent has no idea you told it your preferences yesterday.
In LangGraph this is not a model problem, it is a storage problem. The framework already has two clean slots for memory: a checkpointer and a store. You just have to plug something durable into them. In this post I wire both to MongoDB Atlas, so one database holds the conversation state and the facts the agent learns about each user.
Two kinds of memory, one database
LangGraph splits memory into two jobs:
- Short-term memory lives inside a thread (one conversation). The checkpointer saves the full graph state after every step, so a thread can resume after a crash or a redeploy.
MongoDBSaverfromlanggraph-checkpoint-mongodbdoes this. - Long-term memory lives across threads. It is a key-value store organised by namespace, and it can optionally run semantic search.
MongoDBStorefromlanggraph-store-mongodbdoes this, using Atlas Vector Search under the hood.
At work I build multi-agent systems with LangGraph, and the checkpointer is the piece I lean on most. It is what makes human approval gates and crash recovery possible: the graph pauses, the state is saved, and it picks up from the same point later. The store is the newer half of the picture, and it is the one most tutorials skip.
Setup
You need Python 3.10 or later, an Atlas cluster (the free tier is fine for trying this), a Voyage AI key for embeddings, and an API key for your chat model.
pip install -U langchain langchain-anthropic langchain-voyageai \ langgraph-checkpoint-mongodb langgraph-store-mongodb pymongo export MONGODB_ATLAS_URI="mongodb+srv://..." export VOYAGE_API_KEY="..." export ANTHROPIC_API_KEY="..." One nice detail: both from_conn_string context managers create the collections and indexes they need when they open. There is no separate setup() call like the Postgres checkpointer has.
Long-term memory the agent can search
First, tell the store how to embed memories. create_vector_index_config takes an embedding model, the vector size, and the document fields to embed. I use Voyage's voyage-4, which returns 1024-dimension vectors by default. Then I give the agent two tools: one to save a fact, one to search for facts.
import os import uuid from dataclasses import dataclass from langchain.tools import ToolRuntime, tool from langchain_voyageai import VoyageAIEmbeddings from langgraph.store.mongodb import create_vector_index_config URI = os.environ["MONGODB_ATLAS_URI"] index_config = create_vector_index_config( embed=VoyageAIEmbeddings(model="voyage-4"), dims=1024, fields=["text"], ) @dataclass class Context: user_id: str @tool def remember(fact: str, runtime: ToolRuntime[Context]) -> str: """Save a stable fact or preference about the user.""" ns = ("memories", runtime.context.user_id) runtime.store.put(ns, str(uuid.uuid4()), {"text": fact}) return "Saved." @tool def recall(query: str, runtime: ToolRuntime[Context]) -> str: """Search saved facts about the user.""" ns = ("memories", runtime.context.user_id) items = runtime.store.search(ns, query=query, limit=3) texts = [item.value["text"] for item in items] return "\n".join(texts) or "Nothing saved yet." Notice that the tools never take a user ID as an argument. The ID comes from runtime.context, which I pass in when I call the agent. The model cannot read or write another user's namespace, because it never chooses the namespace.
Wiring it together
Now open both the saver and the store, and hand them to create_agent. I run two separate threads to show the difference: the first thread saves a preference, the second thread is a brand-new conversation that still finds it.
from langchain.agents import create_agent from langgraph.checkpoint.mongodb import MongoDBSaver from langgraph.store.mongodb import MongoDBStore PROMPT = ( "Call recall before answering questions about the user. " "Call remember only for stable preferences, not small talk." ) with ( MongoDBSaver.from_conn_string(URI) as saver, MongoDBStore.from_conn_string( URI, index_config=index_config ) as store, ): agent = create_agent( "anthropic:claude-sonnet-4-6", tools=[remember, recall], system_prompt=PROMPT, checkpointer=saver, store=store, context_schema=Context, ) me = Context(user_id="user-42") def ask(thread: str, text: str) -> str: cfg = {"configurable": {"thread_id": thread}} msg = {"messages": [{"role": "user", "content": text}]} out = agent.invoke(msg, cfg, context=me) return out["messages"][-1].content print(ask("chat-1", "I write most of my code in C#.")) print(ask("chat-2", "Show me a hello world in my language.")) Thread chat-1 is checkpointed in one collection. The fact "writes most code in C#" lands in the store, embedded and indexed. When chat-2 starts with an empty history, the agent calls recall, the vector search finds the fact, and the answer comes back in C#. Kill the process between the two calls and it still works, because nothing lives in RAM.
Any chat model that supports tool calling works here. I used the model string from the LangChain docs; swap in your own.
What I would watch in production
The code is the easy part. These are the decisions that matter more.
Scope every namespace to a user. Put the user or tenant ID in the namespace and take it from trusted context, never from model output. This is the single most important line in the whole setup.
Be picky about what gets saved. If the agent saves every sentence, recall turns into noise. The system prompt above restricts saving to stable preferences. In a real system I would also add a review step or a separate summariser node that decides what is worth keeping.
Treat recalled memory as a hint, not a fact. People change their minds. A memory from months ago can be wrong today. Let the agent mention what it remembered so the user can correct it, and give users a way to delete memories.
Plan for forgetting. Old memories cost storage and pollute search. MongoDB's launch post for the store describes support for expiring obsolete memories; whatever you use, decide on an expiry policy early instead of after the collection grows.
Keep secrets and sensitive data out. A memory store is a database of user facts. Apply the same rules you would apply to any user profile table.
Takeaway
Giving a LangGraph agent real memory takes two objects: a MongoDBSaver for the conversation and a MongoDBStore for what it learns. Keeping both in one MongoDB database means one place to back up, secure, and query. Start with strict namespaces and a short list of things worth remembering, and grow from there.
Sources
- LangChain docs: Long-term memory with MongoDB Atlas
- LangChain docs: Short-term memory with MongoDB Atlas
- MongoDB docs: LangGraph integration
- PyPI: langgraph-store-mongodb
- PyPI: langgraph-checkpoint-mongodb
- PyPI: langchain-voyageai
- MongoDB docs: Voyage AI text embedding models
- MongoDB blog: Powering Long-Term Memory for Agents With LangGraph and MongoDB
이 글은 dev.to 의 원문을 정제해 보여드립니다. 저작권은 원저작자에게 있습니다.
전체 내용이 궁금하다면
dev.to 원문에서 이어 읽기




