LangMemLangMem 0.0.30 · LangGraph 1.2 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
18 small wins to finish your pathNext lesson

An agent that remembers across conversations

Give an agent the memory tools, a store and a checkpointer. A preference saved in one conversation thread can be searched from a new one.

Example
from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver
from langmem import create_manage_memory_tool, create_search_memory_tool

from memory_model import MemoryModel

namespace = ("memories", "{user_id}")
agent = create_agent(
    MemoryModel(),
    tools=[create_manage_memory_tool(namespace=namespace), create_search_memory_tool(namespace=namespace)],
    store=store,
    checkpointer=InMemorySaver(),
)

create_agent from LangChain runs the model in a loop with its tools. The tools were created without a store: inside the agent they use the store passed here. InMemorySaver is the checkpointer, keeping each thread's messages.

Example
first = {"configurable": {"user_id": "asha", "thread_id": "chat-1"}}
result = agent.invoke({"messages": [{"role": "user", "content": "Please email me about refunds."}]}, config=first)
for message in result["messages"]:
    print(f"{message.type:5} {message.content or message.tool_calls[0]['name']}"[:70])

The model called manage_memory, the tool saved the memory, and the model answered. That was thread chat-1.

Example
second = {"configurable": {"user_id": "asha", "thread_id": "chat-2"}}
result = agent.invoke({"messages": [{"role": "user", "content": "How do I like to be contacted?"}]}, config=second)
print(len(result["messages"]))
print(result["messages"][-1].content)

A new thread starts with no messages from the first: four messages here, the question, the search call, its result and the answer. The answer came from search_memory, which read Asha's namespace in the shared store. That is the difference between the checkpointer, per thread, and the store, per user.

Example
other = {"configurable": {"user_id": "ravi", "thread_id": "chat-3"}}
result = agent.invoke({"messages": [{"role": "user", "content": "How do I like to be contacted?"}]}, config=other)
print(result["messages"][-1].content)

Ravi's search returned an empty list, and the answer says so. The memory tools searched ("memories", "ravi"), so Asha's preference could not be found from Ravi's conversation.

Try it yourself
  • Ask Asha's question again in chat-1 and count the messages.
  • Add a system_prompt telling the agent to save contact preferences.
  • Print store.search(("memories", "asha")) after the first call.

Slow is fine. Stopping is the only problem.