LangGraph 生产环境持久化学习总结
核心概念
1. 三种持久化方式对比
| 方式 | 说明 | 适用场景 | 持久化 |
|---|---|---|---|
InMemorySaver |
内存存储 | 测试环境 | ❌ 重启丢失 |
PostgresSaver |
PostgreSQL 存储 | 生产环境推荐 | ✅ 持久化 |
RedisSaver |
Redis 存储 | 高并发场景 | ✅ 持久化 |
2. State(状态)- 工作流中共享的数据结构
python
class customstate(AgentState):
user_name: str # 用户姓名
conversation_count: int = 0 # 对话次数
3. Checkpointer(检查点)- 短期记忆
作用:保存对话历史和工作流状态
- 记录每次对话的状态
- 支持多轮对话
- 提供 Time Travel 功能(状态回溯)
4. Store(存储)- 长期记忆
作用:保存用户画像、知识库等跨会话数据
- 用户信息(姓名、偏好等)
- 知识库元数据
- 跨会话的业务数据
一、PostgreSQL Checkpointer 使用
1.1 数据库准备
sql
-- 创建数据库(如果还没有)
CREATE DATABASE dengmingfang OWNER dengmingfang;
-- 赋予权限
GRANT ALL PRIVILEGES ON DATABASE dengmingfang TO dengmingfang;
1.2 代码实现
python
from langgraph.checkpoint.postgres import PostgresSaver
# 数据库连接字符串
DB_URL = "postgresql://dengmingfang:123456@localhost:5432/dengmingfang"
# 使用上下文管理器
with PostgresSaver.from_conn_string(DB_URL) as checkpointer:
# 第一次使用必须调用 setup() 初始化数据库表
checkpointer.setup()
# 创建 graph,绑定 checkpointer
graph = create_react_agent(
model=llm,
tools=[username, greet_user],
state_schema=customstate,
checkpointer=checkpointer
)
# 配置参数
config = {
"configurable": {
"thread_id": "user_123", # 会话 ID
"username": "张三"
}
}
# 多轮对话(状态自动持久化)
result1 = graph.invoke(
{"messages": [{"role": "user", "content": "第一次对话"}]},
config
)
result2 = graph.invoke(
{"messages": [{"role": "user", "content": "第二次对话"}]},
config # 相同 thread_id,状态会累加
)
1.3 查看状态
python
# 查看当前状态
state_snapshot = graph.get_state(config)
print(f"next: {state_snapshot.next}")
print(f"values: {state_snapshot.values}")
# 查看历史记录
for snapshot in graph.get_state_history(config):
print(f"checkpoint_id: {snapshot.config['configurable']['checkpoint_id']}")
二、Time Travel(时间回溯)
2.1 获取历史状态
python
# 获取所有历史记录
history = list(graph.get_state_history(config))
# 倒数第二条记录
snapshot = history[-2]
2.2 回溯并修改状态
python
# 从历史记录恢复
new_config = graph.update_state(
snapshot.config,
{"messages": ["这是人工修改的消息"]}
)
# 从修改后的状态继续
result = graph.invoke(
{"messages": [{"role": "user", "content": "继续执行"}]},
new_config
)
2.3 应用场景
- 调试:回溯到某个节点重新执行
- 错误回滚:撤销错误的工具调用
- 流程优化:对比不同执行路径的结果
三、Store(长期记忆)
3.1 保存用户信息
python
from langgraph.store.postgres import PostgresStore
with PostgresStore.from_conn_string(DB_URL) as store:
# 初始化表
store.setup()
# 保存用户画像
store.put(
namespace=("profile",), # 命名空间
key="user_123",
value={
"name": "邓",
"age": 26,
"preferences": ["技术", "阅读"]
}
)
3.2 读取用户信息
python
# 读取用户数据
user_profile = store.get(("profile",), "user_123")
if user_profile:
print(user_profile.value)
# 输出:{'name': '邓茗芳', 'age': 27, 'preferences': ['技术', '阅读']}
3.3 更新用户信息
python
# 更新(会覆盖原值)
store.put(
("profile",),
"user_123",
{
**user_profile.value,
"last_login": "2026-01-29",
"login_count": user_profile.value.get("login_count", 0) + 1
}
)
四、完整生产环境架构
4.1 架构图
┌─────────────────────────────────────────────────────────┐
│ LangGraph Application │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ Graph │────────▶│ Checkpointer │ │
│ │ (State) │ │ (PostgreSQL) │ │
│ └─────────────┘ └──────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ Store │ │ Vector Store │ │
│ │ (PostgreSQL)│ │ (FAISS) │ │
│ └─────────────┘ └──────────────┘ │
│ │ │ │
│ └───────────────────────┘ │
│ │ │
│ ▼ │
│ PostgreSQL 数据库 │
└─────────────────────────────────────────────────────────┘
4.2 完整代码示例
python
from langgraph.checkpoint.postgres import PostgresSaver
from langgraph.store.postgres import PostgresStore
from langchain_community.vectorstores import FAISS
from langgraph.prebuilt.chat_agent_executor import create_react_agent
DB_URL = "postgresql://dengmingfang:123456@localhost:5432/dengmingfang"
with PostgresSaver.from_conn_string(DB_URL) as checkpointer, \
PostgresStore.from_conn_string(DB_URL) as store:
# 初始化
checkpointer.setup()
store.setup()
# 加载向量库
vector_store = FAISS.load_local(
"/path/to/faiss_index",
embeddings=embeddings,
allow_dangerous_deserialization=True
)
# 创建 graph
graph = create_react_agent(
model=llm,
tools=[username, greet_user, rag_query],
state_schema=customstate,
checkpointer=checkpointer,
store=store
)
# 执行
result = graph.invoke(
{"messages": [{"role": "user", "content": "查询商品"}]},
{"configurable": {"thread_id": "user_123"}}
)
五、数据库表结构
5.1 Checkpointer 自动创建的表
sql
-- 检查点表
CREATE TABLE checkpoints (
thread_id TEXT,
checkpoint_ns TEXT,
checkpoint_id TEXT,
parent_checkpoint_id TEXT,
type TEXT,
checkpoint JSONB,
metadata JSONB,
PRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id)
);
-- 写入表
CREATE TABLE checkpoint_writes (
thread_id TEXT,
checkpoint_ns TEXT,
checkpoint_id TEXT,
task_id TEXT,
idx INTEGER,
channel TEXT,
type TEXT,
value JSONB,
PRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id, task_id, idx)
);
5.2 Store 自动创建的表
sql
-- 存储表
CREATE TABLE store (
namespace TEXT,
key TEXT,
value JSONB,
created_at TIMESTAMP,
updated_at TIMESTAMP,
PRIMARY KEY (namespace, key)
);
六、最佳实践
6.1 配置优化
python
# 使用连接池
import psycopg2.pool
DB_URL = "postgresql://dengmingfang:123456@localhost:5432/dengmingfang?pool_size=10&max_overflow=20"
# 设置超时
checkpointer = PostgresSaver.from_conn_string(DB_URL, checkpointer_options={
"connection_timeout": 30,
"command_timeout": 60
})
6.2 错误处理
python
from psycopg2 import OperationalError
try:
checkpointer = PostgresSaver.from_conn_string(DB_URL)
checkpointer.setup()
except OperationalError as e:
print(f"数据库连接失败: {e}")
# 使用降级方案(如 InMemorySaver)
checkpointer = InMemorySaver()
6.3 数据备份
bash
# 备份数据库
pg_dump -U dengmingfang dengmingfang > backup.sql
# 恢复数据库
psql -U dengmingfang dengmingfang < backup.sql
七、测试环境 vs 生产环境
7.1 测试环境(InMemorySaver)
python
from langgraph.checkpoint.memory import InMemorySaver
# 简单、快速,但重启后丢失
checkpointer = InMemorySaver()
graph = create_react_agent(model=llm, tools=tools, checkpointer=checkpointer)
7.2 生产环境(PostgresSaver)
python
from langgraph.checkpoint.postgres import PostgresSaver
# 持久化、可靠、支持回溯
checkpointer = PostgresSaver.from_conn_string(DB_URL)
checkpointer.setup()
graph = create_react_agent(model=llm, tools=tools, checkpointer=checkpointer)
八、常见问题
8.1 数据库连接失败
python
# 错误:psycopg2.OperationalError
# 解决:检查数据库服务、用户名密码、网络连接
# 验证连接
import psycopg2
conn = psycopg2.connect(DB_URL)
print("连接成功")
8.2 表已存在错误
python
# 第二次运行时 setup() 会报错
# 解决:捕获异常或先检查
try:
checkpointer.setup()
except Exception as e:
print(f"表可能已存在: {e}")
8.3 状态丢失
python
# 确保 thread_id 一致
config = {"configurable": {"thread_id": "same_id"}}
# 每次都用同一个 config
result1 = graph.invoke({"messages": [...]}, config)
result2 = graph.invoke({"messages": [...]}, config) # 状态会累加
九、性能优化
9.1 批量操作
python
# 批量存储用户数据
for user_id, user_data in user_list:
store.put(("profile",), user_id, user_data)
9.2 定期清理
sql
-- 清理 30 天前的历史记录
DELETE FROM checkpoints WHERE created_at < NOW() - INTERVAL '30 days';
9.3 索引优化
sql
-- 为常用查询创建索引
CREATE INDEX idx_checkpoints_thread_id ON checkpoints(thread_id);
CREATE INDEX idx_store_namespace ON store(namespace);
十、总结
关键要点
-
Checkpointer:短期记忆,保存对话历史
- 生产环境用
PostgresSaver - 测试环境用
InMemorySaver - 必须调用
setup()初始化表
- 生产环境用
-
Store:长期记忆,保存用户画像
- 独立于 checkpointer
- 支持命名空间分类存储
put()/get()/delete()操作
-
Time Travel:状态回溯
get_state_history()获取历史update_state()修改状态- 支持从任意历史节点恢复
-
生产环境:
- PostgreSQL 作为持久化存储
- checkpointer + store 配合使用
- 定期备份数据库
- 配置连接池优化性能
运行完整示例
bash
python /www/learning_langchain/langgraph_state_learining.py
输出示例:
============================================================
PostgreSQL 持久化示例
============================================================
✓ 数据库表初始化完成
第一次对话:
响应: 祝贺你,张三!这是第 1 次对话
第二次对话(状态已持久化):
响应: 祝贺你,张三!这是第 2 次对话
当前状态快照:
- next: ()
- config: {'configurable': {'thread_id': 'user_123', 'username': '张三'}}
- values: {...}