Redis implementation of the LangGraph agent checkpoint saver and store.
Project description
LangGraph Redis
This repository contains Redis implementations for LangGraph, providing both Checkpoint Savers and Stores functionality.
Overview
The project consists of two main components:
- Redis Checkpoint Savers: Implementations for storing and managing checkpoints using Redis
- Redis Stores: Redis-backed key-value stores with optional vector search capabilities
Dependencies
Python Dependencies
The project requires the following main Python dependencies:
redis>=5.2.1redisvl>=0.5.1langgraph-checkpoint>=2.0.24
Redis Modules Requirements
IMPORTANT: This library requires Redis with the following modules:
- RedisJSON - For storing and manipulating JSON data
- RediSearch - For search and indexing capabilities
Redis 8.0+
If you're using Redis 8.0 or higher, both RedisJSON and RediSearch modules are included by default as part of the core Redis distribution. No additional installation is required.
Redis < 8.0
If you're using a Redis version lower than 8.0, you'll need to ensure these modules are installed:
- Use Redis Stack, which bundles Redis with these modules
- Or install the modules separately in your Redis instance
Failure to have these modules available will result in errors during index creation and checkpoint operations.
Azure Cache for Redis / Redis Enterprise Configuration
If you're using Azure Cache for Redis (especially Enterprise tier) or Redis Enterprise, there are important configuration considerations:
Client Configuration
Azure Cache for Redis and Redis Enterprise use a proxy layer that makes the cluster appear as a single endpoint. This requires using a standard Redis client, not a cluster-aware client:
from redis import Redis
from langgraph.checkpoint.test_redis import RedisSaver
# ✅ CORRECT: Use standard Redis client for Azure/Enterprise
client = Redis(
host="your-cache.redis.cache.windows.net", # or your Redis Enterprise endpoint
port=6379, # or 10000 for Azure Enterprise with TLS
password="your-access-key",
ssl=True, # Azure/Enterprise typically requires SSL
ssl_cert_reqs="required", # or "none" for self-signed certs
decode_responses=False # RedisSaver expects bytes
)
# Pass the configured client to RedisSaver
saver = RedisSaver(redis_client=client)
saver.setup()
# ❌ WRONG: Don't use RedisCluster client with Azure/Enterprise
# from redis.cluster import RedisCluster
# cluster_client = RedisCluster(...) # This will fail with proxy-based deployments
Why This Matters
- Proxy Architecture: Azure Cache for Redis and Redis Enterprise use a proxy layer that handles cluster operations internally
- Automatic Detection: RedisSaver will correctly detect this as non-cluster mode when using the standard client
- No Cross-Slot Errors: The proxy handles key distribution, avoiding cross-slot errors
Azure Cache for Redis Specific Settings
For Azure Cache for Redis Enterprise tier:
- Port: Use port
10000for Enterprise tier with TLS, or6379for standard - Modules: Enterprise tier includes RediSearch and RedisJSON by default
- SSL/TLS: Always enabled, minimum TLS 1.2 for Enterprise
Example for Azure Cache for Redis Enterprise:
client = Redis(
host="your-cache.redisenterprise.cache.azure.net",
port=10000, # Enterprise TLS port
password="your-access-key",
ssl=True,
ssl_cert_reqs="required",
decode_responses=False
)
Installation
Install the library using pip:
pip install test-langgraph-checkpoint-redis
Redis Checkpoint Savers
Important Notes
[!IMPORTANT] When using Redis checkpointers for the first time, make sure to call
.setup()method on them to create required indices. See examples below.
Standard Implementation
from langgraph.checkpoint.test_redis import RedisSaver
write_config = {"configurable": {"thread_id": "1", "checkpoint_ns": ""}}
read_config = {"configurable": {"thread_id": "1"}}
with RedisSaver.from_conn_string("redis://localhost:6379") as checkpointer:
# Call setup to initialize indices
checkpointer.setup()
checkpoint = {
"v": 1,
"ts": "2024-07-31T20:14:19.804150+00:00",
"id": "1ef4f797-8335-6428-8001-8a1503f9b875",
"channel_values": {
"my_key": "meow",
"node": "node"
},
"channel_versions": {
"__start__": 2,
"my_key": 3,
"start:node": 3,
"node": 3
},
"versions_seen": {
"__input__": {},
"__start__": {
"__start__": 1
},
"node": {
"start:node": 2
}
},
"pending_sends": [],
}
# Store checkpoint
checkpointer.put(write_config, checkpoint, {}, {})
# Retrieve checkpoint
loaded_checkpoint = checkpointer.get(read_config)
# List all checkpoints
checkpoints = list(checkpointer.list(read_config))
Async Implementation
from langgraph.checkpoint.test_redis.aio import AsyncRedisSaver
async def main():
write_config = {"configurable": {"thread_id": "1", "checkpoint_ns": ""}}
read_config = {"configurable": {"thread_id": "1"}}
async with AsyncRedisSaver.from_conn_string("redis://localhost:6379") as checkpointer:
# Call setup to initialize indices
await checkpointer.asetup()
checkpoint = {
"v": 1,
"ts": "2024-07-31T20:14:19.804150+00:00",
"id": "1ef4f797-8335-6428-8001-8a1503f9b875",
"channel_values": {
"my_key": "meow",
"node": "node"
},
"channel_versions": {
"__start__": 2,
"my_key": 3,
"start:node": 3,
"node": 3
},
"versions_seen": {
"__input__": {},
"__start__": {
"__start__": 1
},
"node": {
"start:node": 2
}
},
"pending_sends": [],
}
# Store checkpoint
await checkpointer.aput(write_config, checkpoint, {}, {})
# Retrieve checkpoint
loaded_checkpoint = await checkpointer.aget(read_config)
# List all checkpoints
checkpoints = [c async for c in checkpointer.alist(read_config)]
# Run the async main function
import asyncio
asyncio.run(main())
Shallow Implementations
Shallow Redis checkpoint savers store only the latest checkpoint in Redis. These implementations are useful when retaining a complete checkpoint history is unnecessary.
from langgraph.checkpoint.test_redis.shallow import ShallowRedisSaver
# For async version: from langgraph.checkpoint.test_redis.ashallow import AsyncShallowRedisSaver
write_config = {"configurable": {"thread_id": "1", "checkpoint_ns": ""}}
read_config = {"configurable": {"thread_id": "1"}}
with ShallowRedisSaver.from_conn_string("redis://localhost:6379") as checkpointer:
checkpointer.setup()
# ... rest of the implementation follows similar pattern
Redis Checkpoint TTL Support
Both Redis checkpoint savers and stores support automatic expiration using Redis TTL:
# Configure automatic expiration
ttl_config = {
"default_ttl": 60, # Expire checkpoints after 60 minutes
"refresh_on_read": True, # Reset expiration time when reading checkpoints
}
with RedisSaver.from_conn_string("redis://localhost:6379", ttl=ttl_config) as saver:
saver.setup()
# Checkpoints will expire after 60 minutes of inactivity
When no TTL is configured, checkpoints are persistent (never expire automatically).
Removing TTL (Pinning Threads)
You can make specific checkpoints persistent by removing their TTL. This is useful for "pinning" important threads that should never expire:
from langgraph.checkpoint.test_redis import RedisSaver
# Create saver with default TTL
saver = RedisSaver.from_conn_string("redis://localhost:6379", ttl={"default_ttl": 60})
saver.setup()
# Save a checkpoint
config = {"configurable": {"thread_id": "important-thread", "checkpoint_ns": ""}}
saved_config = saver.put(config, checkpoint, metadata, {})
# Remove TTL from the checkpoint to make it persistent
checkpoint_id = saved_config["configurable"]["checkpoint_id"]
checkpoint_key = f"checkpoint:important-thread:__empty__:{checkpoint_id}"
saver._apply_ttl_to_keys(checkpoint_key, ttl_minutes=-1)
# The checkpoint is now persistent and won't expire
When no TTL configuration is provided, checkpoints are persistent by default (no expiration).
This makes it easy to manage storage and ensure ephemeral data is automatically cleaned up while keeping important data persistent.
Redis Stores
Redis Stores provide a persistent key-value store with optional vector search capabilities.
Synchronous Implementation
from langgraph.store.redis import RedisStore
# Basic usage
with RedisStore.from_conn_string("redis://localhost:6379") as store:
store.setup()
# Use the store...
# With vector search configuration
index_config = {
"dims": 1536, # Vector dimensions
"distance_type": "cosine", # Distance metric
"fields": ["text"], # Fields to index
}
# With TTL configuration
ttl_config = {
"default_ttl": 60, # Default TTL in minutes
"refresh_on_read": True, # Refresh TTL when store entries are read
}
with RedisStore.from_conn_string(
"redis://localhost:6379",
index=index_config,
ttl=ttl_config
) as store:
store.setup()
# Use the store with vector search and TTL capabilities...
Async Implementation
from langgraph.store.redis.aio import AsyncRedisStore
async def main():
# TTL also works with async implementations
ttl_config = {
"default_ttl": 60, # Default TTL in minutes
"refresh_on_read": True, # Refresh TTL when store entries are read
}
async with AsyncRedisStore.from_conn_string(
"redis://localhost:6379",
ttl=ttl_config
) as store:
await store.setup()
# Use the store asynchronously...
asyncio.run(main())
Examples
The examples directory contains Jupyter notebooks demonstrating the usage of Redis with LangGraph:
persistence_redis.ipynb: Demonstrates the usage of Redis checkpoint savers with LangGraphcreate-react-agent-memory.ipynb: Shows how to create an agent with persistent memory using Rediscross-thread-persistence.ipynb: Demonstrates cross-thread persistence capabilitiespersistence-functional.ipynb: Shows functional persistence patterns with Redis
Running Example Notebooks
To run the example notebooks with Docker:
-
Navigate to the examples directory:
cd examples
-
Start the Docker containers:
docker compose up
-
Open the URL shown in the console (typically http://127.0.0.1:8888/tree) in your browser to access Jupyter.
-
When finished, stop the containers:
docker compose down
Implementation Details
Redis Module Usage
This implementation relies on specific Redis modules:
- RedisJSON: Used for storing structured JSON data as native Redis objects
- RediSearch: Used for creating and querying indices on JSON data
Indexing
The Redis implementation creates these main indices using RediSearch:
- Checkpoints Index: Stores checkpoint metadata and versioning
- Channel Values Index: Stores channel-specific data
- Writes Index: Tracks pending writes and intermediate states
For Redis Stores with vector search:
- Store Index: Main key-value store
- Vector Index: Optional vector embeddings for similarity search
TTL Implementation
Both Redis checkpoint savers and stores leverage Redis's native key expiration:
- Native Redis TTL: Uses Redis's built-in
EXPIREcommand for setting TTL - TTL Removal: Uses Redis's
PERSISTcommand to remove TTL (withttl_minutes=-1) - Automatic Cleanup: Redis automatically removes expired keys
- Configurable Default TTL: Set a default TTL for all keys in minutes
- TTL Refresh on Read: Optionally refresh TTL when keys are accessed
- Applied to All Related Keys: TTL is applied to all related keys (checkpoint, blobs, writes)
- Persistent by Default: When no TTL is configured, keys are persistent (no expiration)
Contributing
We welcome contributions! Here's how you can help:
Development Setup
-
Clone the repository:
git clone https://github.com/redis-developer/langgraph-redis cd langgraph-redis
-
Install dependencies:
uv pip install -e ".[dev]"
Available Commands
The project includes several make commands for development:
-
Testing:
make test # Run all tests make test-all # Run all tests including API tests
-
Linting and Formatting:
make format # Format all files with Black and isort make lint # Run formatting, type checking, and other linters make check-types # Run mypy type checking
-
Code Quality:
make test-coverage # Run tests with coverage reporting make coverage-report # Generate coverage report without running tests make coverage-html # Generate HTML coverage report (opens in htmlcov/) make find-dead-code # Find unused code with vulture
-
Redis for Development/Testing:
make redis-start # Start Redis Stack in Docker (includes RedisJSON and RediSearch modules) make redis-stop # Stop Redis container
Contribution Guidelines
- Create a new branch for your changes
- Write tests for new functionality
- Ensure all tests pass:
make test - Format your code:
make format - Run linting checks:
make lint - Submit a pull request with a clear description of your changes
- Follow Conventional Commits for commit messages
License
This project is licensed under the MIT License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file test_langgraph_checkpoint_redis-0.3.2.tar.gz.
File metadata
- Download URL: test_langgraph_checkpoint_redis-0.3.2.tar.gz
- Upload date:
- Size: 802.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a2bf2316444aa61fe81f137567c08091ec47eb0513ff5f86bee4d4fdedad9d8c
|
|
| MD5 |
308a16997ebbfe0a8b731996905963b1
|
|
| BLAKE2b-256 |
c467f049c1c2fa4f3f7e62227302a5e87cd7a9b312f38764c1f8aa071f69f7b3
|
File details
Details for the file test_langgraph_checkpoint_redis-0.3.2-py3-none-any.whl.
File metadata
- Download URL: test_langgraph_checkpoint_redis-0.3.2-py3-none-any.whl
- Upload date:
- Size: 93.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a4326b667d219caad6781ba3348e82e21c8458fde7787d8f98f1268d609c01cb
|
|
| MD5 |
2d6cbd43f1df2b9421d817e048c402f3
|
|
| BLAKE2b-256 |
dad42f1530e0b35f2de8f33fa7b5cf484b42b0ff3f06e409c67992237beccf96
|