Agent memory
Agent memory is long-term memory an agent manages itself: LangMem's memory tools plus a store make a preference saved in one conversation thread findable from any later thread for the same user.
Last updated: 30 Sep, 2026 · LangMem 0.0.30
The memory tools become useful inside an agent. LangChain's create_agent runs the model in a loop with tools; with a checkpointer it keeps each thread's messages, and with a store it gives LangMem's tools somewhere to save. A new thread starts with no messages, so anything the agent knows about the customer there came from the store.
Syntax:
agent = create_agent(model, tools=[manage_tool, search_tool], store=store, checkpointer=InMemorySaver())
agent.invoke({"messages": [...]}, config={"configurable": {"user_id": "asha", "thread_id": "chat-1"}})The agent
The tools are created without a store; inside the agent they use the one passed to create_agent. The system prompt says what to save and keeps answers to what the tools returned.
namespace = ("memories", "{user_id}")
agent = create_agent(
model,
tools=[create_manage_memory_tool(namespace=namespace), create_search_memory_tool(namespace=namespace)],
store=store,
checkpointer=InMemorySaver(),
system_prompt=PROMPT,
)A config per thread
user_id picks the namespace; thread_id picks the conversation.
first = {"configurable": {"user_id": "ravi", "thread_id": "chat-1"}}
second = {"configurable": {"user_id": "ravi", "thread_id": "chat-2"}}Saving in one thread, recalling in another
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.store.memory import InMemoryStore
from langmem import create_manage_memory_tool, create_search_memory_tool
PROMPT = "You are a support assistant for an online shop. When the customer tells you a preference, save it with manage_memory as one plain sentence. Before answering a question about the customer, search memory. Answer in one short sentence, using only what the tools returned."
model = init_chat_model("groq:openai/gpt-oss-120b", temperature=0)
store = InMemoryStore(index={"dims": 3072, "embed": "google_genai:gemini-embedding-2"})
namespace = ("memories", "{user_id}")
agent = create_agent(
model,
tools=[create_manage_memory_tool(namespace=namespace), create_search_memory_tool(namespace=namespace)],
store=store,
checkpointer=InMemorySaver(),
system_prompt=PROMPT,
)
def chat(user_id, thread_id, text):
config = {"configurable": {"user_id": user_id, "thread_id": thread_id}}
result = agent.invoke({"messages": [{"role": "user", "content": text}]}, config=config)
print(f"[{user_id} / {thread_id}] {text}")
for message in result["messages"][1:]:
what = message.content or ", ".join(call["name"] for call in message.tool_calls)
print(f" {message.type:5} {what[:90]}")
chat("ravi", "chat-1", "Please call me about refunds, not email.")
chat("ravi", "chat-2", "How do I like to be contacted?")
chat("meera", "chat-3", "How do I like to be contacted?")[ravi / chat-1] Please call me about refunds, not email.
ai manage_memory
tool created memory 4fabe5b0-4b3b-46b3-80f5-2fd61240cc6b
ai Got it—I'll call you about refunds instead of emailing.
[ravi / chat-2] How do I like to be contacted?
ai search_memory
tool [{"namespace":["memories","ravi"],"key":"4fabe5b0-4b3b-46b3-80f5-2fd61240cc6b","value":{"c
ai You prefer to be called about refunds, not emailed.
[meera / chat-3] How do I like to be contacted?
ai search_memory
tool []
ai I have no record of your contact preference.What happened in each thread
- chat-1: the model called
manage_memory, the tool created a memory in Ravi's namespace, and the reply confirmed it. - chat-2, a new thread: the checkpointer gave the agent none of chat-1's messages. It called
search_memory, the tool returned the saved memory, and the answer came from it: call about refunds, not email. - chat-3, Meera: the same question searched Meera's namespace, the tool returned
[], and the agent said it had no record instead of guessing, because the prompt limits answers to what the tools returned.
Checkpointer vs store in an agent
| Checkpointer (InMemorySaver) | Store (InMemoryStore) | |
|---|---|---|
| Keyed by | thread_id | Namespace, here from user_id |
| Holds | Every message of one conversation | Memories the agent chose to save |
| Seen in a new thread | No | Yes, through search_memory |
When an agent should manage its own memory
- A personal assistant that users talk to over weeks, in separate chats.
- Support, where the customer's preferences should follow them to the next ticket.
- Any agent whose users say "remember that...".
search_memory, even though the store has the answer. Say in the prompt when to search.Related
- Previous: Memory tools
- Next: Background memory
- Reference: Hot path quickstart
- Ask Ravi's question again in
chat-1and count the messages that come back. - Remove "Before answering a question about the customer, search memory." from the prompt and ask in a new thread.
- Print
store.search(("memories", "ravi"))after the first chat.
Slow is fine. Stopping is the only problem.