Fun with Learning Technology
LearnCoursesQuestionsTracksToolsNewsExplorePractice
Fun with Learning Technology

A new problem, explained clearly, every day.

Subscribe
Learn
  • Lessons
  • Topics
  • News
  • Tools
  • Courses
  • Career tracks
  • Everything
Site
  • About
  • Contact
  • Support
  • Privacy
  • Terms
Get the daily one

One email per new problem. No spam.

Request a tutorial

Requests shape what gets made next.

© 2026 Fun with Learning TechnologyRSS
Home›Courses›LangChain›Conversation Memory Types

Memory and State

Conversation Memory Types

Conversation memory is the mechanism LangChain uses to persist context across multiple interactions in a stateless environment. By storing and retrieving past exchanges, developers can enable agents to maintain continuity and relevance throughout a multi-turn conversation. Choosing the correct memory type depends on balancing the model's context window constraints against the need for historical depth and specific retrieval strategies.

ConversationBufferMemory: The Foundation of Context

The ConversationBufferMemory is the most straightforward implementation, acting as a raw container that stores the entire history of a chat session as a sequence of messages. Because Large Language Models are inherently stateless, they have no intrinsic way of remembering what was said just moments ago. This memory type solves that by appending the user’s inputs and the model’s outputs into a buffer, which is then injected into the prompt before the next request is sent to the model. While simple to implement, this approach consumes your available context window tokens linearly as the conversation grows. Understanding this is crucial because once the total number of tokens exceeds the model's maximum limit, the application will encounter errors or force a truncation of early interaction history, rendering earlier context inaccessible to the model's attention mechanism.

from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain
from langchain_openai import ChatOpenAI

# Initialize the memory and the chain
memory = ConversationBufferMemory()
llm = ChatOpenAI(model="gpt-4")
chain = ConversationChain(llm=llm, memory=memory)

# The chain automatically handles history storage
chain.predict(input="Hi, my name is Alex.")
chain.predict(input="What is my name?")

ConversationBufferWindowMemory: Managing Context Limits

When dealing with long-running conversations, the BufferWindowMemory provides a vital optimization by only keeping the 'k' most recent interactions in the context window. Unlike the standard buffer, which retains every single message until the session ends, this implementation maintains a rolling window of history. By defining a specific integer value for 'k', you effectively control the token expenditure, ensuring that the model does not attempt to ingest an infinitely growing list of previous exchanges. This design choice is fundamental when you want to ensure the agent remains reactive to recent instructions while preventing it from becoming bogged down by old, irrelevant details. It relies on a first-in, first-out strategy, where the oldest dialogue turn is discarded to make room for the newest, keeping the input prompt size stable and predictable for high-volume service environments.

from langchain.memory import ConversationBufferWindowMemory

# Keep only the last 2 interactions
memory = ConversationBufferWindowMemory(k=2)

# As we add more, the oldest is pushed out automatically
memory.save_context({"input": "First"}, {"output": "One"})
memory.save_context({"input": "Second"}, {"output": "Two"})
memory.save_context({"input": "Third"}, {"output": "Three"})
print(memory.load_memory_variables({}))

ConversationSummaryMemory: Synthesized Context

ConversationSummaryMemory represents a shift from storing raw dialogue to maintaining a running summary of the conversation's intent and findings. Instead of passing every individual turn to the model, this memory type uses an auxiliary language model to compress the dialogue history into a concise paragraph. This is particularly useful when the interaction spans many turns but the specific details of the initial greeting or trivial filler are less important than the overall trajectory of the task. By storing a summary, you vastly reduce the token count, allowing for much deeper conversations that remain within the model's constraints. It operates by performing a 're-summarization' step after each new exchange, effectively distillating the session history into an updated narrative summary that provides the model with the 'big picture' without needing to re-read every previous message.

from langchain.memory import ConversationSummaryMemory
from langchain_openai import ChatOpenAI

# Uses a model to summarize past interactions
llm = ChatOpenAI(model="gpt-4")
memory = ConversationSummaryMemory(llm=llm)

memory.save_context({"input": "We discussed a project proposal."},
                    {"output": "The project looks promising."})
print(memory.load_memory_variables({}))

ConversationSummaryBufferMemory: The Hybrid Approach

The ConversationSummaryBufferMemory is often considered the 'gold standard' for production applications because it combines the benefits of both buffer and summary mechanisms. It works by keeping a rolling buffer of recent messages for immediate context, while simultaneously maintaining a distilled summary of older, historical messages. This hybrid strategy allows the model to respond accurately to fine-grained details during current exchanges while still maintaining a long-term memory of previous phases in the conversation. When the total token count of the buffered messages exceeds a defined threshold, the oldest messages are passed into the summary function, preventing total loss of older information. This balance is critical for applications like customer support bots, where specific account details must be remembered (buffer) but the history of the ticket progress (summary) must also persist throughout the call.

from langchain.memory import ConversationSummaryBufferMemory

# Buffer messages, summarize if they exceed token count
memory = ConversationSummaryBufferMemory(
    llm=ChatOpenAI(), 
    max_token_limit=100
)

memory.save_context({"input": "User needs a refund."},
                    {"output": "I will process that."})
print(memory.load_memory_variables({}))

VectorStoreRetrieverMemory: Persistent Semantic Access

For use cases where information needs to be recalled even after long periods of inactivity, VectorStoreRetrieverMemory is the ideal solution. Unlike the previous memory types that keep state in memory or within a prompt-based summary, this approach uses a vector database to perform semantic searches over the entire history of an interaction. When the user asks a question, the memory component fetches the most relevant historical snippets from the database based on semantic similarity. This essentially turns your conversation into a searchable knowledge base. It is incredibly powerful for applications that handle complex, long-running workflows where users might ask about a detail they mentioned three weeks ago. By leveraging embeddings and vector similarity, the model doesn't just look at the last few messages, but instead retrieves the exact historical context needed to answer the current inquiry accurately.

from langchain.memory import VectorStoreRetrieverMemory
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings

# Setup vector storage for memory
vectorstore = Chroma(embedding_function=OpenAIEmbeddings())
retriever = vectorstore.as_retriever()
memory = VectorStoreRetrieverMemory(retriever=retriever)

# Data is persisted and retrieved semantically
memory.save_context({"input": "My favorite color is blue."},
                    {"output": "Understood."})
print(memory.load_memory_variables({"prompt": "What is my favorite color?"}))

Key points

  • Large language models are inherently stateless and rely on memory components to maintain context across interaction turns.
  • ConversationBufferMemory stores every message, which is simple but risks exceeding the context window limit.
  • The BufferWindowMemory keeps only the most recent 'k' turns to prevent token inflation in long conversations.
  • ConversationSummaryMemory uses a model to distill history, prioritizing essential information over raw message logs.
  • Hybrid memory types like SummaryBufferMemory offer a balance by keeping recent history fresh and older data summarized.
  • VectorStoreRetrieverMemory enables semantic search, allowing models to recall relevant information from long-term history.
  • Token usage optimization is a primary requirement when scaling conversational agents in production environments.
  • Selecting a memory type requires balancing the need for precise recent context against the total historical span required.

Common mistakes

  • Mistake: Choosing BufferMemory for long conversations. Why it's wrong: It passes the entire history to the LLM, leading to token overflow costs and limits. Fix: Use ConversationSummaryMemory or WindowBufferMemory instead.
  • Mistake: Misunderstanding return_messages=True. Why it's wrong: Users assume it returns a raw string, but it actually returns a list of BaseMessage objects. Fix: Ensure your prompt templates or downstream components are configured to handle message objects rather than plain strings.
  • Mistake: Manually managing chat history in the prompt. Why it's wrong: It overrides the structured memory management provided by LangChain classes. Fix: Utilize the memory variable substitution within LangChain's PromptTemplate classes.
  • Mistake: Using memory outside of a Chain or Agent structure. Why it's wrong: LangChain memory objects depend on the input/output keys defined in the chain pipeline. Fix: Inject the memory instance directly into your LLMChain constructor.
  • Mistake: Not setting an output_key. Why it's wrong: When multiple outputs are produced, the memory module won't know which one to store. Fix: Explicitly define 'output_key' in the memory class configuration.

Interview questions

What is the primary purpose of ConversationBufferMemory in LangChain?

ConversationBufferMemory is the most straightforward memory type in LangChain. Its primary purpose is to store every single message exchanged between the user and the AI in a raw, unmodified format. It keeps a running list of the conversation history and passes this entire list as context to the LLM during each subsequent turn. This ensures the model has the complete, perfect context of everything said previously, which is ideal for short conversations where retaining every detail is critical for consistency.

How does ConversationBufferWindowMemory differ from the standard buffer memory?

ConversationBufferWindowMemory adds a layer of control by introducing a 'k' parameter, which defines the number of recent interactions to keep. Instead of storing the entire conversation history, which could quickly exceed the context window of an LLM and increase costs, this memory type acts as a sliding window. By keeping only the last 'k' messages, it prevents the prompt from becoming bloated, ensuring that the model remains focused on recent context while automatically discarding older, less relevant data as the conversation progresses.

Explain the logic behind ConversationSummaryMemory in LangChain.

ConversationSummaryMemory is designed for long-running conversations where the history is too large to fit into the LLM's context window. Instead of storing raw messages, it uses an LLM to condense the conversation history into a running summary. Every time a new message is added, the memory asks the LLM to update the existing summary. This allows the AI to retain a high-level understanding of the conversation's trajectory without needing to store the exact wording of every single previous prompt.

When would you choose to use ConversationSummaryBufferMemory over other memory types?

You would choose ConversationSummaryBufferMemory when you need the precision of a buffer for recent events but the efficiency of a summary for long-term history. It keeps a buffer of recent messages in their raw form to maintain immediate context accuracy while summarizing older interactions that exceed a token limit. This approach is superior because it provides the LLM with both specific, granular details from the current turn and a compressed overview of the entire past interaction history.

Compare ConversationBufferMemory and ConversationSummaryMemory in terms of performance and token usage.

ConversationBufferMemory provides perfect recall but suffers from linear token growth, which eventually consumes the entire context window, leading to high latency and potentially hitting model limits. Conversely, ConversationSummaryMemory consumes a predictable and stable number of tokens because it replaces long conversations with a condensed summary. While the summary might lose some specific details, it significantly lowers operational costs and keeps performance consistent even in very long, multi-turn interactions where raw buffer storage would be technically unfeasible.

How can you implement custom storage for memory in LangChain when default in-memory storage isn't sufficient?

For production applications, you often move beyond in-memory storage by integrating LangChain memory with external databases like Redis or Postgres. You achieve this by configuring the memory class to use a 'ChatMessageHistory' object backed by a database adapter. For example, using `RedisChatMessageHistory`, you define a session ID, and LangChain automatically persists every conversation turn to the database. This is essential for creating stateful applications where a user can disconnect and return later to resume a conversation seamlessly, as the history is fetched from the database upon initialization.

All LangChain interview questions →

Check yourself

1. If you have a very long conversation and want to keep the LLM within its context window without losing all history, which memory type is most effective?

  • A.ConversationBufferMemory
  • B.ConversationSummaryBufferMemory
  • C.ConversationEntityMemory
  • D.ConversationTokenBufferMemory
Show answer

B. ConversationSummaryBufferMemory
ConversationSummaryBufferMemory stores recent messages but summarizes older ones, maintaining context while saving space. BufferMemory risks overflow, EntityMemory is for extracting specific facts, and TokenBuffer simply truncates, losing information.

2. What is the primary function of 'ConversationSummaryMemory' in a LangChain application?

  • A.To encrypt conversation history
  • B.To store every single user prompt as a raw string
  • C.To compress conversation history into a running summary using an LLM
  • D.To fetch history from a SQL database instead of memory
Show answer

C. To compress conversation history into a running summary using an LLM
SummaryMemory uses an LLM to condense history, keeping it brief. The others are incorrect because it does not encrypt, it does not store raw prompts, and it is independent of the persistence layer.

3. Why would you choose 'ConversationSummaryBufferMemory' over 'ConversationBufferMemory'?

  • A.It is faster because it does not use an LLM
  • B.It balances the need for recent exact details with the need for long-term context summaries
  • C.It is mandatory for all LangChain models regardless of the use case
  • D.It saves data to disk automatically while BufferMemory does not
Show answer

B. It balances the need for recent exact details with the need for long-term context summaries
The hybrid approach maintains recent conversational precision while summarizing stale history to avoid token limits. The other options are false as it does use an LLM, is not mandatory, and doesn't handle persistence by default.

4. In a custom chain implementation, how does the memory object know what to save as the 'answer'?

  • A.It randomly selects a string from the input
  • B.It automatically saves all outputs from the chain
  • C.It relies on the 'output_key' parameter to identify which part of the chain output to persist
  • D.It requires a manual function call after every step
Show answer

C. It relies on the 'output_key' parameter to identify which part of the chain output to persist
The memory component maps variables defined in the chain's execution. Without specifying 'output_key', it may fail to identify the target output, unlike the other options which mischaracterize its operation.

5. What is the consequence of setting 'return_messages=True' in a memory component?

  • A.The model ignores the history entirely
  • B.The memory returns a list of chat message objects rather than a single concatenated string
  • C.The history is deleted immediately after the response
  • D.The model stops generating new output
Show answer

B. The memory returns a list of chat message objects rather than a single concatenated string
Setting this to true ensures compatibility with ChatModels by returning structured message objects. This doesn't delete data, stop the model, or cause it to ignore context; it simply changes the data structure.

Take the full LangChain quiz →

← PreviousRunnables and ChainsNext →ConversationBufferMemory

LangChain

24 lessons, free to read.

All lessons →

Track your progress

Sign in to mark lessons done, score quizzes and keep notes.

Open in the app