LangChain (YT style)LangChain 1.4 · Python 3.12+
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 →

Short-term memory with a checkpointer

A checkpointer is a saver that stores the agent's conversation after each step, so a later call on the same thread continues where the last one left off.

Last updated: 27 Sep, 2026 · LangChain 1.4

Adding memory with a checkpointer · from the Agentic AI With LangGraph And MCP Crash Course, Part 1 · 86:55 to 93:17

Remembering a name across two calls

A model on its own remembers nothing between calls. The video shows it first: the chatbot is told "Hello my name is Krish" and replies "Nice to meet you", and asked "What is my name" right after, it does not know, because nothing from the earlier call is kept. LangGraph's answer is a checkpointer. MemorySaver is an in-memory checkpoint saver: it stores a checkpoint in a Python dictionary as each node runs, so a later call can read the earlier conversation back. The checkpointer is passed when the graph is compiled.

Each conversation also needs a thread id, passed in a config as {"configurable": {"thread_id": ...}}. It must be unique, one per session or user, and in a full application the session keeps it. With the checkpointer in place, the bot is told "Hi my name is Krish" and answers "Nice to meet you, Krish!". A second call with the same config asks "Hey what is my name", and the bot answers "Your name is Krish." Nothing in the second question mentions the name; it came from the saved thread. The video builds this chatbot by hand as a LangGraph graph; LangGraph is the library create_agent runs on. With create_agent it takes three changes: import InMemorySaver (the current name of MemorySaver), pass checkpointer=, and pass a config with a thread_id:

ExampleAPI key
from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver

agent = create_agent("groq:openai/gpt-oss-120b", checkpointer=InMemorySaver())
config = {"configurable": {"thread_id": "1"}}

agent.invoke({"messages": "Hi my name is Krish"}, config)
response = agent.invoke({"messages": "Hey what is my name"}, config)
print(response["messages"][-1].text)

One agent can hold many conversations at once, one per thread. The shop version below shows it.

Now the shop. First see what goes wrong without a checkpointer: Ravi asks about one order, then another.

Each call starts fresh

Use the shop agent in agent.py from create_agent: the agent loop (not the weather agent at the top of that lesson), which has no checkpointer. Two invokes: each returns its own four messages, and the second never saw A17.

ExampleAPI key
first = agent.invoke({"messages": [{"role": "user", "content": "Where is A17?"}]})
second = agent.invoke({"messages": [{"role": "user", "content": "And C40?"}]})

print(len(first["messages"]), len(second["messages"]))
print([m.text for m in second["messages"] if m.type == "human"])

The InMemorySaver checkpointer

python
from langgraph.checkpoint.memory import InMemorySaver

# save state per thread
agent = create_agent(model, tools=[...], checkpointer=InMemorySaver())
config = {"configurable": {"thread_id": "ravi-1"}}   # name the conversation
agent.invoke({"messages": [...]}, config)            # continues that thread

Adding a checkpointer

This lesson's agent answers order questions with lookup_order, the tool built in Tools: a function the model can call. Start the file with it.

python
from langchain.tools import tool

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


@tool
def lookup_order(order_id: str) -> str:
    """Look up an order's shipping status by its id, such as A17."""
    status = ORDERS.get(order_id)
    return f"{order_id} {status}." if status else f"{order_id} is not an order we have."

Give the same agent a checkpointer. InMemorySaver keeps the saved state in a Python dictionary and reads it back at the start of the next call.

python
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langgraph.checkpoint.memory import InMemorySaver

agent = create_agent(init_chat_model("groq:openai/gpt-oss-120b", temperature=0), tools=[lookup_order],  # uses your GROQ_API_KEY
                     system_prompt="You are the support assistant for a small online shop. Answer in one or two short sentences, using only what the tools returned.",
                     checkpointer=InMemorySaver())   # save after every step

Two calls on one thread

Name the conversation with a thread_id in the config; every call that passes this config shares one saved history. Ask two questions on that thread. The second call passes one new message, and everything saved under the id comes back with it: eight messages, not four.

ExampleAPI key
ravi = {"configurable": {"thread_id": "ravi-1"}}

agent.invoke({"messages": [{"role": "user", "content": "Where is A17?"}]}, ravi)
result = agent.invoke({"messages": [{"role": "user", "content": "And C40?"}]}, ravi)

print(len(result["messages"]))
print([m.text for m in result["messages"] if m.type == "human"])

Reading a thread without running it

get_state reads what the checkpointer saved for a thread without running the agent. Its values are the state.

ExampleAPI key
state = agent.get_state(ravi)
print(len(state.values["messages"]))
print(state.values["messages"][-1].text)

Another thread starts empty

A second thread_id in the same checkpointer holds only its own messages. Mei's thread starts empty even though Ravi's is saved alongside it.

ExampleAPI key
mei = {"configurable": {"thread_id": "mei-1"}}
result = agent.invoke({"messages": [{"role": "user", "content": "Hello"}]}, mei)

print(len(result["messages"]))

What the checkpointer saved

  • With a checkpointer and one thread_id the second call passed one new message and got eight back: the saved history plus the new question and answer.
  • get_state reads what a thread saved without running the agent; here it is the eight messages, ending with the C40 answer.
  • A second thread_id starts empty. Mei's thread holds only her two messages even though Ravi's is in the same checkpointer; each thread's history is kept apart.

Passing history yourself vs a checkpointer

No checkpointerCheckpointer + thread_id
What the agent seesOnly the messages you passThe saved thread plus the new message
Across callsStarts fresh each timeContinues the same conversation
Telling conversations apartYou keep each list yourselfthread_id keys each one
Where it livesNowhere after the callThe saver: memory, or a database

When to use a checkpointer

  • A chat assistant that must remember earlier turns in the same session.
  • Any multi-turn flow where the user refers back to something said before.
Watch out. InMemorySaver is gone when the program ends. For anything that must survive a restart, use a checkpointer backed by a database: langgraph-checkpoint-sqlite or langgraph-checkpoint-postgres, each a separate package with the same interface.
Try it yourself
  • Invoke the checkpointed agent without the config and read the error.
  • Print agent.get_state(mei).values["messages"] after Mei's call.
  • Ask a third question in Ravi's thread and predict the message count before you run it.

This is what real progress feels like.