LangChain

Adding Memory to LLM Apps

Dealing with Memory

In this tutorial, we’ll enhance our in-memory chat history demo by persisting conversation context in Redis. Externalizing message history enables multi-session, multi-tenant applications that can resume context across restarts and deployments.

1. Base Chain Setup: Prompt + OpenAI Model

Begin by importing the core components and defining a base chain that combines a prompt template with an OpenAI chat model:

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_openai.chat_models import ChatOpenAI

model = ChatOpenAI()
prompt = ChatPromptTemplate.from_messages([
    (
        "system",
        "You’re an assistant skilled in {ability}. Keep responses under 20 words.",
    ),
    MessagesPlaceholder(variable_name="history"),
    ("human", "{input}"),
])
base_chain = prompt | model

2. Persisting Message History with Redis

To support long-term memory, we’ll store each session’s chat history in Redis.

from langchain_community.chat_message_histories import RedisChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory

Define your Redis connection and a helper function to instantiate a RedisChatMessageHistory per session:

REDIS_URL = "redis://localhost:6379/0"

def get_message_history(session_id: str) -> RedisChatMessageHistory:
    return RedisChatMessageHistory(session_id, url=REDIS_URL)

Note

Make sure a Redis server is running at localhost:6379 or update REDIS_URL to match your configuration.

Wrap the base chain in a RunnableWithMessageHistory to automatically load and save chat history:

redis_chain = RunnableWithMessageHistory(
    base_chain,
    get_message_history,
    input_messages_key="input",
    history_messages_key="history",
)

3. Running Conversation Threads

Each thread represents a separate session. Let’s demonstrate with two threads: math and physics.

3.1 Math Thread

# Start math session
redis_chain.invoke(
    {"ability": "math", "input": "What does cosine mean?"},
    config={"configurable": {"session_id": "math-thread1"}},
)
# Follow-up in the same session
redis_chain.invoke(
    {"ability": "math", "input": "Tell me more!"},
    config={"configurable": {"session_id": "math-thread1"}},
)
# → AIMessage: It oscillates between -1 and 1 and is key in wave analysis.

3.2 Physics Thread

# Start physics session
redis_chain.invoke(
    {"ability": "physics", "input": "What is the theory of relativity?"},
    config={"configurable": {"session_id": "phy-thread1"}},
)
# Follow-up in the same session
redis_chain.invoke(
    {"ability": "physics", "input": "Tell me more!"},
    config={"configurable": {"session_id": "phy-thread1"}},
)
# → AIMessage: Einstein’s theory unifies mass–energy equivalence and spacetime curvature.

4. Inspecting Stored Data in Redis

You can explore stored message lists directly within Redis.

# Ensure Redis container is running
docker ps

# Enter the Redis CLI
docker exec -it <container_id> sh
redis-cli

# List all session keys
127.0.0.1:6379> KEYS *
1) "message_store:math-thread1"
2) "message_store:phy-thread1"

View the math thread history:

127.0.0.1:6379> LRANGE message_store:math-thread1 0 -1

View the physics thread:

127.0.0.1:6379> LRANGE message_store:phy-thread1 0 -1

5. Resuming Conversations After Restart

After a restart or in a new notebook, simply re-import and re-create redis_chain. Invocations with existing session IDs will automatically load prior context:

# Resume math thread
redis_chain.invoke(
    {"ability": "math", "input": "Tell me more!"},
    config={"configurable": {"session_id": "math-thread1"}},
)
# Resume physics thread
redis_chain.invoke(
    {"ability": "physics", "input": "Tell me more!"},
    config={"configurable": {"session_id": "phy-thread1"}},
)
# → AIMessage: There are special and general relativity covering inertial and accelerated frames.

Swapping session IDs lets you switch contexts on the fly:

redis_chain.invoke(
    {"ability": "math", "input": "Tell me more!"},
    config={"configurable": {"session_id": "phy-thread1"}},  # loads physics history
)

6. Memory Types Comparison

Memory TypeScopePersistenceUse Case
Short-TermIn-process onlyVolatileSingle-session demos, rapid prototyping
Long-Term (Redis)Multi-sessionPersistent (Redis)Multi-tenant apps, context resumption after restarts

7. Summary

  • Short-term memory: Uses an in-memory list; lost on restart.
  • Long-term memory: Persists chat history externally (Redis) via RunnableWithMessageHistory.
  • Supports multi-session and multi-tenant LLM applications with seamless context resumption.

Next, explore retrieval-augmented generation (RAG) to integrate external documents with LangChain.

Watch Video

Watch video content

Practice Lab

Practice lab

Previous
Exploring Configurable Parameters