LangChain Chat History and Memory
LangChain memory is how a chatbot remembers earlier turns. Models are stateless, so "memory" really means storing the chat history and sending the relevant part of it with each new request. This lesson shows a manual approach, how to trim history, and the modern approach with checkpointers.
Manual Chat History
The simplest memory is a list you keep yourself:
from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage, AIMessage
llm = ChatOllama(model="llama3.2", temperature=0)
prompt = ChatPromptTemplate.from_messages([
("system", "You are a concise assistant."),
MessagesPlaceholder("history"),
("human", "{input}"),
])
chain = prompt | llm
history = []
def chat(text):
reply = chain.invoke({"history": history, "input": text})
history.extend([HumanMessage(text), AIMessage(reply.content)])
return reply.content
chat("I live in Karachi.")
print(chat("Which country is my city in?"))Sample output: Karachi is in Pakistan.
Trimming Long Conversations
Context windows are limited and long histories are slow. trim_messages keeps only the most recent messages that fit a budget:
from langchain_core.messages import trim_messages
trimmer = trim_messages(
max_tokens=6, # here: count messages, not tokens
token_counter=len,
strategy="last",
start_on="human",
include_system=True,
)
short_history = trimmer.invoke(history)
print(len(short_history))2
With token_counter=len every message counts as one. In real apps pass the model itself (token_counter=llm) or an approximate counter so the limit is in tokens.
Memory with Checkpointers
In LangChain 1.x the recommended memory for agents is a LangGraph checkpointer. It saves the conversation state per thread_id automatically:
from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver
agent = create_agent(
"ollama:llama3.2",
tools=[],
system_prompt="You are a friendly assistant.",
checkpointer=InMemorySaver(),
)
cfg = {"configurable": {"thread_id": "user-42"}}
agent.invoke({"messages": [{"role": "user", "content": "Hi, I'm Hina."}]}, cfg)
out = agent.invoke({"messages": [{"role": "user", "content": "What's my name?"}]}, cfg)
print(out["messages"][-1].content)Sample output: Your name is Hina.
Each thread_id is a separate conversation. Use a different ID per user or chat session. InMemorySaver loses data when the program stops; for production use a persistent checkpointer such as langgraph-checkpoint-sqlite or langgraph-checkpoint-postgres.
Memory Strategies
- Full history: simplest, but grows without limit.
- Sliding window: keep the last N messages or tokens.
- Summary: periodically ask the model to summarize older turns into one message.
- Long-term memory: store facts about the user in a database or LangGraph store and retrieve them when relevant.
Frequently asked questions
Is ConversationBufferMemory deprecated?
Yes. The old memory classes were moved to the langchain-classic package. New code should use message lists, RunnableWithMessageHistory or LangGraph checkpointers.
How do I give each user their own chat history?
Use a unique thread_id per user or session in the config when calling an agent with a checkpointer.
How do I save LangChain memory to a database?
Use a persistent checkpointer such as SqliteSaver or PostgresSaver from the LangGraph checkpoint packages instead of InMemorySaver.