LangChainLangChain 1.4 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
46 small wins to finish your pathNext lesson →

Memory that outlives the conversation

A store is a saver for facts that outlive any one conversation, filed as JSON documents under a namespace and a key.

Last updated: 27 Sep, 2026 · LangChain 1.4

Ravi told the shop once to leave parcels at the back door. That belongs to Ravi, not to any one conversation, so a new thread next week should still know it.

Where an agent keeps things
One thread, saved by the checkpointerThe store, across all threadsmessagesthe conversationyour own keysstate_schemacontextpassed per callthe agentcreate_agentcustomers/ravidelivery notecustomers/meiher own documents
Hover or tap a piece to see what it is and which lesson built it.
What survives

Pick one to watch it run, step by step.

The InMemoryStore API

python
from langgraph.store.memory import InMemoryStore

store = InMemoryStore()
store.put(("customers", "ravi"), "delivery", {"note": "..."})  # namespace, key, value
item = store.get(("customers", "ravi"), "delivery")            # an item, or None

Putting and getting

Save a note under a folder for Ravi, then read it back. Asking a folder that has nothing under that key returns None.

python
from langgraph.store.memory import InMemoryStore

store = InMemoryStore()
store.put(("customers", "ravi"), "delivery", {"note": "leave it at the back door"})

item = store.get(("customers", "ravi"), "delivery")   # read Ravi's note
print(item.key, item.value)
print(store.get(("customers", "mei"), "delivery"))    # nothing there -> None
Example
from langgraph.store.memory import InMemoryStore

store = InMemoryStore()
store.put(("customers", "ravi"), "delivery", {"note": "leave it at the back door"})

item = store.get(("customers", "ravi"), "delivery")
print(item.key, item.value)
print(store.get(("customers", "mei"), "delivery"))

The customer and the orders

A tool can reach the store through its runtime. Start with the customer type and the order data.

python
from dataclasses import dataclass

@dataclass
class Customer:            # who is asking, passed as context
    name: str

ORDERS = {"A17": "shipped on 3 March", "C40": "waiting for stock"}

A tool that uses the store

The tool reads Ravi's delivery note into its answer and writes down which order he asked about last. runtime.store is the store the agent was given.

python
from langchain.tools import ToolRuntime, tool

@tool
def lookup_order(order_id: str, runtime: ToolRuntime[Customer]) -> str:
    """Look up an order's shipping status by its id, such as A17."""
    folder = ("customers", runtime.context.name)                     # this customer
    runtime.store.put(folder, "last_order", {"order_id": order_id})  # write
    note = runtime.store.get(folder, "delivery")                    # read note
    status = f"{order_id} {ORDERS.get(order_id, 'is not an order we have')}."
    return f"{status} Delivery note: {note.value['note']}." if note else status

The agent with a store

Give the agent the store, the context type, and a checkpointer. Seed the store with Ravi's note first.

python
from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.store.memory import InMemoryStore
from shop_model import ShopModel
from tools import Customer, lookup_order

store = InMemoryStore()
store.put(("customers", "ravi"), "delivery", {"note": "leave it at the back door"})
agent = create_agent(ShopModel(), tools=[lookup_order], context_schema=Customer,
                     checkpointer=InMemorySaver(), store=store)

Looking up A17 with a saved note

Ask as Ravi. The delivery note comes out of the store, not the conversation.

Example
ravi = Customer("ravi")
result = agent.invoke({"messages": [{"role": "user", "content": "Where is A17?"}]},
                      {"configurable": {"thread_id": "monday"}}, context=ravi)
print(result["messages"][-1].text)

A new thread, the same customer

A different thread_id starts a fresh conversation, but the store is shared. Ravi's note is still there, and the last order is now C40.

Example
result = agent.invoke({"messages": [{"role": "user", "content": "And C40?"}]},
                      {"configurable": {"thread_id": "friday"}}, context=ravi)

print(len(result["messages"]))
print(store.get(("customers", "ravi"), "last_order").value)

What the store kept across threads

  • The namespace is a tuple that works like a folder path, here one folder per customer; the key names a document, and the value is a dictionary.
  • A missing document returns None, so Mei's folder gives None for a note only Ravi set.
  • The delivery note in Ravi's answer came out of the store, and the tool wrote A17 down as the order he asked about last.
  • The Friday thread starts with four messages, none from Monday: the checkpointer keeps threads apart. The store does not, so the note stays and the last order is now C40.

Thread vs store

Thread (checkpointer)Store
HoldsOne conversationFacts across all conversations
Keyed bythread_idnamespace + key
A new threadStarts emptyStill has the facts
Read withget_statestore.get

Where long-term memory fits

  • Remembering a customer's preferences from one visit to the next.
  • Any fact that belongs to a user or account rather than a single chat.
Watch out. Create the agent without store= and a tool that calls runtime.store raises at run time. The store has to be handed to the agent before a tool can read or write it.
Try it yourself
  • Invoke as Mei and check that the answer has no delivery note.
  • Print [i.key for i in store.search(("customers", "ravi"))].
  • Create the agent without store= and read the error the tool raises.

Little by little, you're building something great.