Initial commit
This commit is contained in:
224
skills/langgraph-master/03_memory_management_checkpointer.md
Normal file
224
skills/langgraph-master/03_memory_management_checkpointer.md
Normal file
@@ -0,0 +1,224 @@
|
||||
# Checkpointer
|
||||
|
||||
Implementation details for saving and restoring state.
|
||||
|
||||
## Overview
|
||||
|
||||
Checkpointer implements the `BaseCheckpointSaver` interface and is responsible for state persistence.
|
||||
|
||||
## Checkpointer Implementations
|
||||
|
||||
### 1. MemorySaver (For Experimentation & Testing)
|
||||
|
||||
Saves checkpoints in memory:
|
||||
|
||||
```python
|
||||
from langgraph.checkpoint.memory import MemorySaver
|
||||
|
||||
checkpointer = MemorySaver()
|
||||
graph = builder.compile(checkpointer=checkpointer)
|
||||
|
||||
# All data is lost when the process terminates
|
||||
```
|
||||
|
||||
**Use Case**: Local testing, prototyping
|
||||
|
||||
### 2. SqliteSaver (For Local Development)
|
||||
|
||||
Saves to SQLite database:
|
||||
|
||||
```python
|
||||
from langgraph.checkpoint.sqlite import SqliteSaver
|
||||
|
||||
# File-based
|
||||
checkpointer = SqliteSaver.from_conn_string("checkpoints.db")
|
||||
|
||||
# Or from connection object
|
||||
import sqlite3
|
||||
conn = sqlite3.connect("checkpoints.db")
|
||||
checkpointer = SqliteSaver(conn)
|
||||
|
||||
graph = builder.compile(checkpointer=checkpointer)
|
||||
```
|
||||
|
||||
**Use Case**: Local development, single-user applications
|
||||
|
||||
### 3. PostgresSaver (For Production)
|
||||
|
||||
Saves to PostgreSQL database:
|
||||
|
||||
```python
|
||||
from langgraph.checkpoint.postgres import PostgresSaver
|
||||
from psycopg_pool import ConnectionPool
|
||||
|
||||
# Connection pool
|
||||
pool = ConnectionPool(
|
||||
conninfo="postgresql://user:password@localhost:5432/db"
|
||||
)
|
||||
|
||||
checkpointer = PostgresSaver(pool)
|
||||
graph = builder.compile(checkpointer=checkpointer)
|
||||
```
|
||||
|
||||
**Use Case**: Production environments, multi-user applications
|
||||
|
||||
## BaseCheckpointSaver Interface
|
||||
|
||||
All checkpointers implement the following methods:
|
||||
|
||||
```python
|
||||
class BaseCheckpointSaver:
|
||||
def put(
|
||||
self,
|
||||
config: RunnableConfig,
|
||||
checkpoint: Checkpoint,
|
||||
metadata: dict
|
||||
) -> RunnableConfig:
|
||||
"""Save a checkpoint"""
|
||||
|
||||
def get_tuple(
|
||||
self,
|
||||
config: RunnableConfig
|
||||
) -> CheckpointTuple | None:
|
||||
"""Retrieve a checkpoint"""
|
||||
|
||||
def list(
|
||||
self,
|
||||
config: RunnableConfig,
|
||||
*,
|
||||
before: RunnableConfig | None = None,
|
||||
limit: int | None = None
|
||||
) -> Iterator[CheckpointTuple]:
|
||||
"""Get list of checkpoints"""
|
||||
```
|
||||
|
||||
## Custom Checkpointer
|
||||
|
||||
Implement your own persistence logic:
|
||||
|
||||
```python
|
||||
from langgraph.checkpoint.base import BaseCheckpointSaver
|
||||
|
||||
class RedisCheckpointer(BaseCheckpointSaver):
|
||||
def __init__(self, redis_client):
|
||||
self.redis = redis_client
|
||||
|
||||
def put(self, config, checkpoint, metadata):
|
||||
thread_id = config["configurable"]["thread_id"]
|
||||
checkpoint_id = checkpoint["id"]
|
||||
|
||||
key = f"checkpoint:{thread_id}:{checkpoint_id}"
|
||||
self.redis.set(key, serialize(checkpoint))
|
||||
|
||||
return config
|
||||
|
||||
def get_tuple(self, config):
|
||||
thread_id = config["configurable"]["thread_id"]
|
||||
# Retrieve the latest checkpoint
|
||||
# ...
|
||||
|
||||
def list(self, config, before=None, limit=None):
|
||||
# Return list of checkpoints
|
||||
# ...
|
||||
```
|
||||
|
||||
## Checkpointer Configuration
|
||||
|
||||
### Namespaces
|
||||
|
||||
Share the same checkpointer across multiple graphs:
|
||||
|
||||
```python
|
||||
checkpointer = MemorySaver()
|
||||
|
||||
graph1 = builder1.compile(
|
||||
checkpointer=checkpointer,
|
||||
name="graph1" # Namespace
|
||||
)
|
||||
|
||||
graph2 = builder2.compile(
|
||||
checkpointer=checkpointer,
|
||||
name="graph2" # Different namespace
|
||||
)
|
||||
```
|
||||
|
||||
### Automatic Propagation
|
||||
|
||||
Parent graph's checkpointer automatically propagates to subgraphs:
|
||||
|
||||
```python
|
||||
# Set only on parent graph
|
||||
parent_graph = parent_builder.compile(checkpointer=checkpointer)
|
||||
|
||||
# Automatically propagates to child graphs
|
||||
```
|
||||
|
||||
## Checkpoint Management
|
||||
|
||||
### Deleting Old Checkpoints
|
||||
|
||||
```python
|
||||
# Delete after a certain period (implementation-dependent)
|
||||
import datetime
|
||||
|
||||
cutoff = datetime.datetime.now() - datetime.timedelta(days=30)
|
||||
|
||||
# Implementation example (SQLite)
|
||||
checkpointer.conn.execute(
|
||||
"DELETE FROM checkpoints WHERE created_at < ?",
|
||||
(cutoff,)
|
||||
)
|
||||
```
|
||||
|
||||
### Optimizing Checkpoint Size
|
||||
|
||||
```python
|
||||
class State(TypedDict):
|
||||
# Avoid large data
|
||||
messages: Annotated[list, add_messages]
|
||||
|
||||
# Store references only
|
||||
large_data_id: str # Actual data in separate storage
|
||||
|
||||
def node(state: State):
|
||||
# Retrieve large data from external source
|
||||
large_data = fetch_from_storage(state["large_data_id"])
|
||||
# ...
|
||||
```
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Connection Pool (PostgreSQL)
|
||||
|
||||
```python
|
||||
from psycopg_pool import ConnectionPool
|
||||
|
||||
pool = ConnectionPool(
|
||||
conninfo=conn_string,
|
||||
min_size=5,
|
||||
max_size=20
|
||||
)
|
||||
|
||||
checkpointer = PostgresSaver(pool)
|
||||
```
|
||||
|
||||
### Async Checkpointer
|
||||
|
||||
```python
|
||||
from langgraph.checkpoint.postgres import AsyncPostgresSaver
|
||||
|
||||
async_checkpointer = AsyncPostgresSaver(async_pool)
|
||||
|
||||
# Async execution
|
||||
async for chunk in graph.astream(input, config):
|
||||
print(chunk)
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
Checkpointer determines how state is persisted. It's important to choose the appropriate implementation for your use case.
|
||||
|
||||
## Related Pages
|
||||
|
||||
- [03_memory_management_persistence.md](03_memory_management_persistence.md) - How to use persistence
|
||||
- [03_memory_management_store.md](03_memory_management_store.md) - Differences from long-term memory
|
||||
Reference in New Issue
Block a user