Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 83

Building Short-Term Conversational Memory

Recommended resources

Introduction

In our last lesson, we built a sophisticated multi-agent system using LangGraph. You learned how to orchestrate a "supervisor" agent that delegates sub-tasks to specialized "worker" agents, enabling the system to handle a complex request within a single, powerful execution. However, a critical limitation remains: once that execution finishes, the agent forgets everything. If you ask a follow-up question, it has no memory of the previous interaction. This statelessness is a fundamental challenge of working with LLMs.

Today, we will address this directly by tackling this lesson's learning outcome: Implement short-term conversational memory to maintain context within an agentic session. You will learn how to make your agents stateful across multiple interactions with a user, transforming them from one-shot problem solvers into conversational partners. We will leverage the state management and persistence features built into LangGraph, specifically a mechanism called "checkpointers," to give our agents a memory.


What is Conversational Memory?

At their core, LLM API calls are stateless. Each call is an independent event with no inherent memory of past calls. To create a conversational experience, we must build a memory system at the application layer. The most fundamental type is short-term memory, often called working memory.

This system's job is to:

  1. Keep track of the back-and-forth messages in a conversation.
  2. Provide this history as context for the next turn.

Conceptually, this is as simple as maintaining a list of messages and feeding it back to the LLM with each new user query.

Building Brain-Like Memory for AI | LLM Agent Memory Systems

To start, let's solidify our conceptual understanding of working memory. This video provides a clear analogy to human memory and shows a very simple, framework-agnostic implementation.

Watch the video from the beginning to 08:32. Focus on: The explanation of why stateless LLMs need memory systems (00:00 - 03:20). The definition of 'working memory' as the immediate conversational context (03:20 - 05:56). The simple code demonstration showing how a list of messages is appended to and re-ingested by the model to maintain context (05:56 - 08:32).

This simple approach works, but it's not robust. As you build complex agents with multiple steps and tool calls, you need a more structured way to manage and persist the entire state of the agent, not just the messages.

This is where short-term memory (for the current conversation) fits into the broader picture, as distinct from long-term memory (for recalling facts across many conversations).

LLM Memory Types: Short-term vs. Long-term
This diagram shows the distinction between short-term conversational memory, managed by a 'Checkpointer' for a single thread, and long-term memory, which involves a more permanent 'Store'. In this lesson, we are focused entirely on implementing the short-term Checkpointer mechanism.

The LangGraph Solution: Checkpointers and Threads

In the last lesson, you worked extensively with the State object in LangGraph. This object held the messages, tool outputs, and other data needed for a single execution run. The key to conversational memory is persisting this state between invoke calls.

LangGraph provides a clean, powerful abstraction for this: Checkpointers.

A Checkpointer is a component that automatically saves the entire state of your graph at specified intervals (e.g., after every step). When you later invoke the graph for the same conversation, the checkpointer loads the last saved state, allowing the agent to pick up exactly where it left off.

To distinguish between different conversations, you provide a unique identifier for each one, typically called a thread_id. All invoke calls sharing the same thread_id will share the same persisted state and thus belong to the same conversation.

Short-term memory - LangChain Docs

The official LangChain documentation provides a concise overview of this concept. It explains how checkpointers enable thread-level persistence, which is the technical term for short-term conversational memory.

Read the 'Overview' and 'Usage' sections. Pay close attention to the role of the checkpointer argument when creating an agent and the configurable dictionary containing the thread_id in the invoke call. Notice the different types of savers, like InMemorySaver (for testing) and PostgresSaver (for production).


Implementing Persistent Memory with Redis

Now, let's put this into practice. While InMemorySaver is useful for quick tests, a real application requires a durable backend like a database to store the conversation state. This ensures that conversations can be resumed even if your application restarts. Redis, being a fast in-memory data store, is an excellent choice for this.

The following video provides a complete, practical walkthrough of integrating RedisSaver into a LangGraph agent to give it short-term memory.

Short-Term Memory with LangGraph

This video from Redis demonstrates exactly how to implement persistent short-term memory using LangGraph and a Redis backend. It clearly shows the 'before' and 'after'—an agent that forgets, and then an agent that remembers.

Please watch these two key segments: Setup and Integration (03:32 - 06:09): Observe how the RedisSaver is instantiated and passed as the checkpointer when creating the graph. This is the single most important step for enabling persistence. Execution and Verification (07:31 - 12:20): This is the core of the lesson. Notice how a thread_id is used to initiate a conversation. After the first question is answered, a follow-up question is asked without repeating the context (New York City). The agent remembers because the checkpointer, keyed by the thread_id, reloaded the previous state. The video also shows you the data being stored in Redis, proving the persistence.

By adding just two key pieces—the checkpointer object at graph creation and the thread_id at invocation—you've made your agent conversational.


Under the Hood: The Importance of Reducers

You've now seen how to implement memory, but for deep mastery, it's crucial to understand why it works so efficiently. Why doesn't LangGraph just overwrite the messages list in the state with each new update?

The answer lies in reducers.

As you may recall from your computer science background, a reducer is a function that takes an accumulated value and a new value and returns a new accumulated value (e.g., reduce(accumulator, new_value) -> new_accumulator).

In LangGraph, you can associate a reducer with each field in your state definition.

  • By default, the reducer is overwrite.
  • For conversational history, you need an append or add behavior.

LangGraph provides a special, highly optimized reducer called add_messages. When a node returns a new message, this reducer intelligently appends it to the existing list of messages in the state, even handling complex cases like updating tool calls. This is far more efficient than loading the entire state object, modifying a list in Python, and writing the whole object back.

The Architecture of Agent Memory: How LangGraph Really Works

This article provides an excellent deep dive into the mechanics of LangGraph's state management. It explains the role of reducers and why they are fundamental to building correct and efficient agent memory.

Please read the following sections from the article: 'What Are Reducers and Why They Matter': This explains the core concept and the default 'overwrite' behavior. 'The Built-in add_messages Reducer': This is the key. Understand why this specific reducer is designed for conversation history and how it's smarter than a simple list concatenation. 'Short-Term vs Long-Term Memory': This section reinforces the concepts we've discussed and provides a simple code example showing how a reducer accumulates conversation history in the state.

Understanding reducers is what separates a user of the framework from an architect who can design robust, efficient, and custom stateful agents.

Test your understanding!

You are building an agent to track a package. Your AgentState needs to maintain two pieces of information across a conversation:

  1. messages: The full conversation history.
  2. package_status: The most recent status of the package (e.g., "in_transit", "delivered"). This should always be the latest value, not a list of all historical statuses.

Using TypedDict and Annotated from Python's typing module, how would you define your AgentState to ensure messages are appended and package_status is overwritten?

Show answer

You would use the add_messages reducer for the messages field and no reducer for the package_status field, which makes it default to the overwrite behavior.

from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph import add_messages
from langchain_core.messages import BaseMessage

class PackageTrackerState(TypedDict):
    # The 'messages' field will use the add_messages reducer to append.
    messages: Annotated[list[BaseMessage], add_messages]
    
    # The 'package_status' field has no reducer, so it will be overwritten
    # with each update.
    package_status: str

Conclusion

In this lesson, you have equipped your agent with one of the most critical capabilities for practical use: memory. You've moved beyond single-shot executions and can now build agents that sustain context over an entire conversational session.

Key Takeaways:

  • Memory is an Application-Layer Construct: LLMs are inherently stateless; we must build memory systems around them. Short-term memory maintains context within a single conversation.
  • Checkpointers are the Key to Persistence: In LangGraph, checkpointers (like RedisSaver or PostgresSaver) are the mechanism for automatically saving and loading an agent's state.
  • Threads Define Conversations: A thread_id passed during invocation tells the checkpointer which conversation's state to load, enabling you to manage multiple concurrent conversations.
  • Reducers Enable Efficient State Updates: The add_messages reducer is the low-level mechanism that ensures conversational history is appended correctly and efficiently, rather than being overwritten.

What's Next?

Now that your agents can conduct complex, multi-step tasks and remember the context of a conversation, we can focus on making their reasoning process even more sophisticated. In our next lesson, "Design an agentic workflow that includes a planning step to decompose a complex user request into a sequence of sub-goals," we will dive deeper into the logic of the "supervisor" agent. You will learn how to prompt the agent to explicitly break down a user's request into a structured plan before execution, leading to more reliable and transparent agentic systems.