【langgraph+postgres】用于生产环境的langgraph短期记忆的存取(postgreSQL替代InMemorySaver)

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);

十、总结

关键要点

  1. Checkpointer:短期记忆,保存对话历史

    • 生产环境用 PostgresSaver
    • 测试环境用 InMemorySaver
    • 必须调用 setup() 初始化表
  2. Store:长期记忆,保存用户画像

    • 独立于 checkpointer
    • 支持命名空间分类存储
    • put() / get() / delete() 操作
  3. Time Travel:状态回溯

    • get_state_history() 获取历史
    • update_state() 修改状态
    • 支持从任意历史节点恢复
  4. 生产环境

    • PostgreSQL 作为持久化存储
    • checkpointer + store 配合使用
    • 定期备份数据库
    • 配置连接池优化性能

运行完整示例

bash 复制代码
python /www/learning_langchain/langgraph_state_learining.py

输出示例:

复制代码
============================================================
PostgreSQL 持久化示例
============================================================
✓ 数据库表初始化完成

第一次对话:
响应: 祝贺你,张三!这是第 1 次对话

第二次对话(状态已持久化):
响应: 祝贺你,张三!这是第 2 次对话

当前状态快照:
  - next: ()
  - config: {'configurable': {'thread_id': 'user_123', 'username': '张三'}}
  - values: {...}
相关推荐
木辰風2 小时前
PLSQL自定义自动替换(AutoReplace)
java·数据库·sql
无限码力3 小时前
华为OD技术面真题 - 数据库MySQL - 3
数据库·mysql·华为od·八股文·华为od技术面八股文
heartbeat..3 小时前
Redis 中的锁:核心实现、类型与最佳实践
java·数据库·redis·缓存·并发
Prince-Peng3 小时前
技术架构系列 - 详解Redis
数据结构·数据库·redis·分布式·缓存·中间件·架构
虾说羊3 小时前
redis中的哨兵机制
数据库·redis·缓存
_F_y3 小时前
MySQL视图
数据库·mysql
2301_790300963 小时前
Python单元测试(unittest)实战指南
jvm·数据库·python
九章-3 小时前
一库平替,融合致胜:国产数据库的“统型”范式革命
数据库·融合数据库
2401_838472514 小时前
使用Scikit-learn构建你的第一个机器学习模型
jvm·数据库·python
u0109272714 小时前
使用Python进行网络设备自动配置
jvm·数据库·python