> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Resuming a Conversation With Persistent Memory

> Demonstrates using LangGraph checkpointing to persist and resume conversation state across sessions using a thread identifier and a simple in memory checkpointer

In this lesson we demonstrate how to implement persistent conversational memory with LangGraph. Real-world assistants must often resume conversations across sessions: users close an app and return hours or days later expecting the assistant to remember earlier context. LangGraph addresses this with checkpointing — saving the graph state after each interaction so a conversation can be resumed later by loading that saved state.

What you'll learn

* How to model a minimal conversation state for LangGraph
* How to implement a simple chatbot node that updates state
* How to attach a checkpointer (here: `InMemorySaver`) to persist state per conversation thread
* How to resume a conversation using the same `thread_id`

Keywords: LangGraph, persistent memory, checkpointing, stateful workflows, resume conversation, chat history

## Overview of the approach

1. Define a TypedDict for the shared conversation state.
2. Create a node that reads the latest message, produces a reply, and updates state.
3. Build and compile a `StateGraph`, attaching a checkpointer.
4. Invoke the graph with a `thread_id` to save state.
5. Re-invoke with the same `thread_id` to resume the conversation.
6. Inspect saved state via `get_state`.

## Step 0 — Required packages and imports

```python theme={null}
# imports
from typing_extensions import TypedDict
from langgraph.graph import StateGraph
from langgraph.checkpoint.memory import InMemorySaver
from langchain_core.messages import HumanMessage, AIMessage
```

## Step 1 — Define the conversation state

The graph's state is the shared memory between nodes. Keep it minimal for this demo: a `messages` list holding `HumanMessage` and `AIMessage` objects.

```python theme={null}
class ChatState(TypedDict):
    messages: list
```

## Step 2 — Create the chatbot node

This node inspects the latest message in `state["messages"]`, forms a reply (simulated here), appends the reply to the history, and returns the updated state.

```python theme={null}
def chatbot_node(state: ChatState) -> ChatState:
    history = list(state.get("messages", []))
    if not history:
        # No messages yet; nothing to respond to
        return {"messages": history}

    last_message = history[-1]

    if isinstance(last_message, HumanMessage):
        user_text = last_message.content
    else:
        user_text = str(last_message)

    reply = AIMessage(
        content=f"I remember our conversation. You just said: '{user_text}'"
    )

    return {"messages": history + [reply]}
```

## Step 3 — Build and compile the graph with a checkpointer

Create a `StateGraph`, register the node, set entry/finish points, and compile the graph while attaching an `InMemorySaver` checkpointer. The checkpointer persists the graph state after each invocation under a thread identifier.

```python theme={null}
builder = StateGraph(ChatState)
builder.add_node("chatbot", chatbot_node)
builder.set_entry_point("chatbot")
builder.set_finish_point("chatbot")

checkpointer = InMemorySaver()
graph = builder.compile(checkpointer=checkpointer)
```

## Step 4 — Start the first session (create a thread)

Use a `config` including a `thread_id` to uniquely identify this conversation. Invoke the graph with an initial `HumanMessage`. The graph processes input, appends a reply, and the checkpointer saves the resulting state under `thread_id`.

```python theme={null}
config = {"configurable": {"thread_id": "user_123"}}

result_1 = graph.invoke(
    {"messages": [HumanMessage(content="I am planning a trip to Rome next month.")]},
    config=config,
)

for msg in result_1["messages"]:
    print(type(msg).__name__, ":", msg.content)
```

## Step 5 — Simulate the user returning later (resume the thread)

When the user returns, invoke the graph again with the same `thread_id`. LangGraph will load the previously saved state automatically so the assistant "remembers" the prior conversation history.

```python theme={null}
result_2 = graph.invoke(
    {
        "messages": result_1["messages"] + [
            HumanMessage(content="Can you remind me what I told you earlier?")
        ]
    },
    config=config,
)

for msg in result_2["messages"]:
    print(type(msg).__name__, ":", msg.content)
```

Expected console output (example):

```text theme={null}
HumanMessage : I am planning a trip to Rome next month.
AIMessage : I remember our conversation. You just said: 'I am planning a trip to Rome next month.'
HumanMessage : Can you remind me what I told you earlier?
AIMessage : I remember our conversation. You just said: 'Can you remind me what I told you earlier?'
```

## Step 6 — Inspect the saved state

You can verify persistence by calling `get_state` with the same `config` (same `thread_id`). The saved state will include the full conversation history.

```python theme={null}
saved_state = graph.get_state(config)

for i, msg in enumerate(saved_state["messages"], start=1):
    print(f"{i}. {type(msg).__name__}: {msg.content}")
```

This confirms the system stored and restored the conversation memory.

<Callout icon="warning" color="#FF6B6B">
  Avoid using `InMemorySaver` for production: in-memory checkpointers do not survive process restarts or multi-instance deployments. Always choose a durable backing store (see examples below).
</Callout>

<Callout icon="lightbulb" color="#1CB2FE">
  In this lesson we used an in-memory checkpointer for simplicity. For production deployments, replace `InMemorySaver` with a durable checkpoint implementation so conversations persist across restarts and multiple instances.
</Callout>

## Checkpointer options and recommendations

Use a durable store for production — here are common choices:

| Storage Type   | Use Case                                        | Typical implementation                    |
| -------------- | ----------------------------------------------- | ----------------------------------------- |
| Redis          | Fast in-memory with persistence and clustering  | `Redis`-backed checkpointer               |
| Postgres       | Durable relational storage with ACID guarantees | `Postgres`-backed checkpointer            |
| Object storage | Long-term archival for large histories          | `S3` / object storage-backed checkpointer |

For links and references:

* [Redis](https://redis.io/)
* [Postgres](https://www.postgresql.org/)
* [AWS S3](https://aws.amazon.com/s3/)

## Wrap-up

Persistent memory is essential for realistic conversational AI. LangGraph implements this via stateful workflows plus checkpointing:

* Nodes read and update a shared state,
* The checkpointer persists that state under a conversation identifier (e.g., `thread_id`),
* Later invocations with the same identifier restore the saved state so the assistant resumes the conversation seamlessly.

This pattern — shared state, checkpoint after each invocation, and restore by conversation identifier — forms the foundation for assistants that maintain continuity across sessions.

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/langgraph/module/e0cd494a-00a7-4c52-88e9-b3932b03ff9f/lesson/5d61391b-1eed-4ca1-9333-2ef0a43d6d7b" />

  <Card title="Practice Lab" icon="flask-conical" cta="Learn more" href="https://learn.kodekloud.com/user/courses/langgraph/module/e0cd494a-00a7-4c52-88e9-b3932b03ff9f/lesson/7caa0f21-eaee-4ff3-9f8c-291e75424b05" />
</CardGroup>
