Managing Conversational Memory and Persistence
To build interactive chatbots, your application must store previous message exchanges. Let us explore how LangChain manages history memory and integrates with Redis for database persistence.
1. Using ChatMessageHistory In-Memory
For simple applications or testing, keep messages in server RAM memory:
import { ChatMessageHistory } from "langchain/stores/message/in_memory";
const historyStore = new ChatMessageHistory();
// Append messages
await historyStore.addUserMessage("Hi, I am Mike.");
await historyStore.addAIChatMessage("Hello Mike! How can I help you?");
// Retrieve all messages
const messagesHistoryList = await historyStore.getMessages();2. Persisting Session History in Redis
In production server environments, server instances are stateless, meaning memory is cleared between requests. To maintain state, save histories in a Redis database store:
First, install the Redis adapter dependency:
# Install the redis integration store package
npm install @langchain/communityInitialize your Redis connection and bind it to LangChain:
// src/services/redisHistory.ts
import { RedisChatMessageHistory } from "@langchain/community/stores/message/redis";
import { ChatOpenAI } from "@langchain/openai";
import { ChatPromptTemplate, MessagePlaceholder } from "@langchain/core/prompts";
import { RunnableWithMessageHistory } from "@langchain/core/runnables";
const model = new ChatOpenAI({ modelName: "gpt-4o-mini" });
const prompt = ChatPromptTemplate.fromMessages([
["system", "You are an AI assistant."],
new MessagePlaceholder("chatHistory"),
["user", "{userInput}"]
]);
const baseChain = prompt.pipe(model);
// Wrap the chain with message history handlers
export const sessionChain = new RunnableWithMessageHistory({
runnable: baseChain,
// 1. Tell LangChain how to lookup the message store based on sessionId
getMessageHistory: async (sessionId: string) => {
return new RedisChatMessageHistory({
sessionId: sessionId,
sessionTTL: 3600, // Expire session after 1 hour of inactivity
config: {
url: process.env.REDIS_URL || "redis://localhost:6379",
},
});
},
// Define prompt configuration matching variables keys
inputMessagesKey: "userInput",
historyMessagesKey: "chatHistory",
});
export async function continueChatSession(userMessage: string, userSessionId: string) {
const result = await sessionChain.invoke(
{ userInput: userMessage },
// 2. Supply the session identifier inside the config block
{ configurable: { sessionId: userSessionId } }
);
return result.content;
}3. Storage Cleanup Strategy
- Always Set TTLs: Memory sessions in Redis should always include a Time-To-Live (TTL) expiration value to prevent database storage exhaustion.
- Pruning Messages: For long sessions, create a custom helper to prune older messages from Redis, leaving only the most recent messages to fit within context limits.
Published on Last updated: