如果你正在经历一段格外艰难的人生,请允许我祝福你可以从今天开始,邂逅最棒的一年。
——莉兹·克里莫
本文将使用 langgraph-checkpoint-postgres
库,将 Postgres
作为后端来持久化 checkpoint
状态。温馨提示:本文搭配 jupyter-lab
食用更佳。
需求背景
如果您正在使用 LangGraph API,则无需手动实现 checkpointer。API 会自动为您处理 checkpointing。本指南适用于您在自己的自定义服务器中实现 LangGraph 的情况。
1、Checkpointer持久化的核心作用
LangChain
框架中Checkpointer
持久化的核心价值在于保存和恢复复杂任务的状态。大语言模型(LLM)应用常涉及多步骤链式调用或长时间运行的任务,中断后重新执行成本高昂。
from langchain.checkpoint import FileCheckpointer
checkpointer = FileCheckpointer(file_path="./chat_state.json")
2、中断恢复与连续性保障
对话应用或长期运行流程需要保持上下文一致性。Checkpointer
记录链式调用中间状态,在系统崩溃或人工暂停后,可从最后记录点继续执行而非重新开始。典型场景包括:
- 多轮对话历史保存
- 分阶段文档处理进度
- API调用失败后的重试基准点
# 保存状态示例
agent.run("开始分析报告", callbacks=[checkpointer])# 恢复状态示例
loaded_state = checkpointer.load()
agent.resume(loaded_state)
3、实验与调试支持
开发过程中,Checkpointer
允许从特定检查点反复测试流程分支。相比每次从头运行,能快速验证特定环节的修改效果,显著提升迭代效率。
# 调试时加载特定检查点
test_state = checkpointer.load_at_step(step=3)
debug_agent(test_state)
4、分布式系统协同
微服务架构中,不同组件可能在不同节点执行。Checkpointer
提供的序列化状态可实现:
- 工作负载重新分配
- 故障节点任务转移
- 多个worker协同处理
// 典型检查点数据结构
{"step_id": "analyze_chapter3","artifacts": {"extracted_text": "...","embeddings": [...]},"metadata": {"timestamp": "2023-07-15T08:30:00","version": "llm-v2.3"}
}
5、版本控制与审计追踪
持久化检查点形成不可变的任务历史记录,可用于:
- 回滚到先前版本
- 比较不同参数的效果
- 合规性审计跟踪
# 检查点版本管理
checkpointer.list_versions() # 返回所有保存的版本
checkpointer.revert(version="20230715_v1")
6、性能优化手段
选择性持久化能避免重复计算。对于资源密集型操作(如大型文档嵌入),Checkpointer
存储中间结果后,后续运行可直接复用。
# 条件性检查点保存
if not checkpointer.exists("doc_embedding"):embeddings = compute_embeddings(text)checkpointer.save("doc_embedding", embeddings)
else:embeddings = checkpointer.load("doc_embedding")
```### Checkpointer持久化的核心作用LangChain框架中Checkpointer持久化的核心价值在于保存和恢复复杂任务的状态。大语言模型(LLM)应用常涉及多步骤链式调用或长时间运行的任务,中断后重新执行成本高昂。```python
from langchain.checkpoint import FileCheckpointer
checkpointer = FileCheckpointer(file_path="./chat_state.json")
7、中断恢复与连续性保障
对话应用或长期运行流程需要保持上下文一致性。Checkpointer
记录链式调用中间状态,在系统崩溃或人工暂停后,可从最后记录点继续执行而非重新开始。典型场景包括:
- 多轮对话历史保存
- 分阶段文档处理进度
- API调用失败后的重试基准点
# 保存状态示例
agent.run("开始分析报告", callbacks=[checkpointer])# 恢复状态示例
loaded_state = checkpointer.load()
agent.resume(loaded_state)
8、实验与调试支持
开发过程中,Checkpointer
允许从特定检查点反复测试流程分支。相比每次从头运行,能快速验证特定环节的修改效果,显著提升迭代效率。
# 调试时加载特定检查点
test_state = checkpointer.load_at_step(step=3)
debug_agent(test_state)
9、分布式系统协同
微服务架构中,不同组件可能在不同节点执行。Checkpointer
提供的序列化状态可实现:
- 工作负载重新分配
- 故障节点任务转移
- 多个worker协同处理
// 典型检查点数据结构
{"step_id": "analyze_chapter3","artifacts": {"extracted_text": "...","embeddings": [...]},"metadata": {"timestamp": "2023-07-15T08:30:00","version": "llm-v2.3"}
}
10、版本控制与审计追踪
持久化检查点形成不可变的任务历史记录,可用于:
- 回滚到先前版本
- 比较不同参数的效果
- 合规性审计跟踪
# 检查点版本管理
checkpointer.list_versions() # 返回所有保存的版本
checkpointer.revert(version="20230715_v1")
11、性能优化手段
选择性持久化能避免重复计算。对于资源密集型操作(如大型文档嵌入),Checkpointer
存储中间结果后,后续运行可直接复用。
# 条件性检查点保存
if not checkpointer.exists("doc_embedding"):embeddings = compute_embeddings(text)checkpointer.save("doc_embedding", embeddings)
else:embeddings = checkpointer.load("doc_embedding")
一、Docker安装PostgreSQL数据库
# 拉取镜像
sudo docker pull postgres:15
# 创建本地卷
sudo docker volume create pgdata
数据卷可以在容器之间共享和重用,默认会一直存在,即使容器被删除(docker volume inspect pgdata
可查看数据卷的本地位置)。
# 运行一个PostgreSQL数据库实例
sudo docker run --name pgsql -p 5432:5432 -e POSTGRES_PASSWORD=abc123 -v pgdata:/home/sam/postgresql/data --restart=always -d postgres:15
二、pgAdmin访问
https://www.pgadmin.org/download/
#
# Setup the repository
## Install the public key for the repository (if not done previously):
curl -fsS https://www.pgadmin.org/static/packages_pgadmin_org.pub | sudo gpg --dearmor -o /usr/share/keyrings/packages-pgadmin-org.gpg# Create the repository configuration file:
sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/packages-pgadmin-org.gpg] https://ftp.postgresql.org/pub/pgadmin/pgadmin4/apt/$(lsb_release -cs) pgadmin4 main" > /etc/apt/sources.list.d/pgadmin4.list && apt update'#
# Install pgAdmin
## Install for both desktop and web modes:
sudo apt install pgadmin4# Install for desktop mode only:
sudo apt install pgadmin4-desktop# Install for web mode only:
sudo apt install pgadmin4-web # Configure the webserver, if you installed pgadmin4-web:
sudo /usr/pgadmin4/bin/setup-web.sh
三、安装依赖
pip install -U psycopg psycopg-pool langgraph langgraph-checkpoint-postgres
四、为图定义模型和工具
from pydantic import SecretStr
import osos.environ["OPENAI_BASE_URL"] = "https://api.siliconflow.cn/v1/"
os.environ["OPENAI_API_KEY"] = "sk-xxx"from langchain.chat_models import init_chat_modelmodel = init_chat_model("Qwen/Qwen3-8B", model_provider="openai")
from typing import Literalfrom langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.postgres import PostgresSaver
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver@tool
def get_weather(city: Literal["北京", "上海"]):"""使用该工具获取城市天气信息"""if city == "北京":return "晴天"elif city == "上海":return "多云"else:raise AssertionError("未知的城市")tools = [get_weather]
五、使用同步连接
这将设置一个到数据库的同步连接。同步连接以阻塞方式执行操作,这意味着每个操作都会等待完成,然后才进行下一个操作。DB_URI
是数据库连接 URI,包含连接 PostgreSQL 数据库使用的协议、身份验证以及数据库运行的主机。connection_kwargs
字典定义了数据库连接的附加参数。
DB_URI = "postgresql://postgres:abc123@localhost:5432/postgres?sslmode=disable"
connection_kwargs = {"autocommit": True,"prepare_threshold": 0,
}
1、使用连接池
这管理着一个可重用数据库连接池:
- 优点:高效利用资源,提高频繁连接的性能
- 适用于:具有许多短暂数据库操作的应用程序
from psycopg_pool import ConnectionPoolwith ConnectionPool(# Example configurationconninfo=DB_URI,max_size=20,kwargs=connection_kwargs,
) as pool:checkpointer = PostgresSaver(pool)# NOTE: you need to call .setup() the first time you're using your checkpointercheckpointer.setup()graph = create_react_agent(model, tools=tools, checkpointer=checkpointer)config = {"configurable": {"thread_id": "1"}}res = graph.invoke({"messages": [("human", "今天北京天气如何?")]}, config)# 读取历史信息checkpoint = checkpointer.get(config)
res
{'messages': [HumanMessage(content='今天北京天气如何?', additional_kwargs={}, response_metadata={}, id='e5ea0799-173e-4e1b-8940-91e5a164bc64'),AIMessage(content='\n\n', additional_kwargs={'tool_calls': [{'id': '0196d7134c393b91618a7d1b142a4e26', 'function': {'arguments': ' {"city": "北京"}', 'name': 'get_weather'}, 'type': 'function', 'index': 0}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 96, 'prompt_tokens': 165, 'total_tokens': 261, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 88, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_name': 'Qwen/Qwen3-8B', 'system_fingerprint': '', 'id': '0196d71344be98b7bf1742796c139083', 'service_tier': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run--29759721-c1c2-4e6f-a8b3-e920b91d763b-0', tool_calls=[{'name': 'get_weather', 'args': {'city': '北京'}, 'id': '0196d7134c393b91618a7d1b142a4e26', 'type': 'tool_call'}], usage_metadata={'input_tokens': 165, 'output_tokens': 96, 'total_tokens': 261, 'input_token_details': {}, 'output_token_details': {'reasoning': 88}}),ToolMessage(content='晴天', name='get_weather', id='974cabfa-8742-4257-b836-460dbd17b657', tool_call_id='0196d7134c393b91618a7d1b142a4e26'),AIMessage(content='\n\n今天北京的天气是晴天,阳光明媚,适合外出活动。记得做好防晒措施哦!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 172, 'prompt_tokens': 208, 'total_tokens': 380, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 150, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_name': 'Qwen/Qwen3-8B', 'system_fingerprint': '', 'id': '0196d7134dc1d2ed7c8e61f6e72ce537', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None}, id='run--835d7789-bdc8-4fa2-96f4-59d4f44c4fd6-0', usage_metadata={'input_tokens': 208, 'output_tokens': 172, 'total_tokens': 380, 'input_token_details': {}, 'output_token_details': {'reasoning': 150}})]}
checkpoint
{'v': 3,'id': '1f032037-78cc-615b-8003-a6736ebdf047','ts': '2025-05-16T03:11:32.048918+00:00','pending_sends': [],'versions_seen': {'agent': {'branch:to:agent': '00000000000000000000000000000004.0.2739958167978239'},'tools': {'branch:to:tools': '00000000000000000000000000000003.0.603242543748743'},'__input__': {},'__start__': {'__start__': '00000000000000000000000000000001.0.013718584308971438'}},'channel_versions': {'messages': '00000000000000000000000000000005.0.11823643751462909','__start__': '00000000000000000000000000000002.0.8037870172415423','branch:to:agent': '00000000000000000000000000000005.0.3650025119425234','branch:to:tools': '00000000000000000000000000000004.0.5015268184742752'},'channel_values': {'messages': [HumanMessage(content='今天北京天气如何?', additional_kwargs={}, response_metadata={}, id='e5ea0799-173e-4e1b-8940-91e5a164bc64'),AIMessage(content='\n\n', additional_kwargs={'tool_calls': [{'id': '0196d7134c393b91618a7d1b142a4e26', 'function': {'arguments': ' {"city": "北京"}', 'name': 'get_weather'}, 'type': 'function', 'index': 0}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 96, 'prompt_tokens': 165, 'total_tokens': 261, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 88, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_name': 'Qwen/Qwen3-8B', 'system_fingerprint': '', 'id': '0196d71344be98b7bf1742796c139083', 'service_tier': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run--29759721-c1c2-4e6f-a8b3-e920b91d763b-0', tool_calls=[{'name': 'get_weather', 'args': {'city': '北京'}, 'id': '0196d7134c393b91618a7d1b142a4e26', 'type': 'tool_call'}], usage_metadata={'input_tokens': 165, 'output_tokens': 96, 'total_tokens': 261, 'input_token_details': {}, 'output_token_details': {'reasoning': 88}}),ToolMessage(content='晴天', name='get_weather', id='974cabfa-8742-4257-b836-460dbd17b657', tool_call_id='0196d7134c393b91618a7d1b142a4e26'),AIMessage(content='\n\n今天北京的天气是晴天,阳光明媚,适合外出活动。记得做好防晒措施哦!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 172, 'prompt_tokens': 208, 'total_tokens': 380, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 150, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_name': 'Qwen/Qwen3-8B', 'system_fingerprint': '', 'id': '0196d7134dc1d2ed7c8e61f6e72ce537', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None}, id='run--835d7789-bdc8-4fa2-96f4-59d4f44c4fd6-0', usage_metadata={'input_tokens': 208, 'output_tokens': 172, 'total_tokens': 380, 'input_token_details': {}, 'output_token_details': {'reasoning': 150}})]}}
2、使用单个连接
这创建了一个到数据库的单个专用连接:
- 优点:使用简单,适用于较长的事务
- 适用于:具有较少、较长数据库操作的应用程序
from psycopg import Connectionwith Connection.connect(DB_URI, **connection_kwargs) as conn:checkpointer = PostgresSaver(conn)# NOTE: you need to call .setup() the first time you're using your checkpointer# checkpointer.setup()graph = create_react_agent(model, tools=tools, checkpointer=checkpointer)config = {"configurable": {"thread_id": "2"}}res = graph.invoke({"messages": [("human", "今天上海天气如何")]}, config)checkpoint_tuple = checkpointer.get_tuple(config)
checkpoint_tuple
CheckpointTuple(config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1f03203d-ba45-60fc-8003-ef82a83d5b66'}}, checkpoint={'v': 3, 'id': '1f03203d-ba45-60fc-8003-ef82a83d5b66', 'ts': '2025-05-16T03:14:19.975490+00:00', 'pending_sends': [], 'versions_seen': {'agent': {'branch:to:agent': '00000000000000000000000000000004.0.3111923409346694'}, 'tools': {'branch:to:tools': '00000000000000000000000000000003.0.6987713872806675'}, '__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0.9943878685247373'}}, 'channel_versions': {'messages': '00000000000000000000000000000005.0.7602821276570259', '__start__': '00000000000000000000000000000002.0.293618470215541', 'branch:to:agent': '00000000000000000000000000000005.0.5778995140285749', 'branch:to:tools': '00000000000000000000000000000004.0.3416019952246956'}, 'channel_values': {'messages': [HumanMessage(content='今天上海天气如何', additional_kwargs={}, response_metadata={}, id='7eadd00c-00ce-49b3-8349-37cf445305e0'), AIMessage(content='\n\n', additional_kwargs={'tool_calls': [{'id': '0196d715ce404add2415fd6212a8973c', 'function': {'arguments': ' {"city": "上海"}', 'name': 'get_weather'}, 'type': 'function', 'index': 0}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 94, 'prompt_tokens': 164, 'total_tokens': 258, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 86, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_name': 'Qwen/Qwen3-8B', 'system_fingerprint': '', 'id': '0196d715bb9372d38c8a60da334c7fc8', 'service_tier': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run--94765d3d-8b2c-49e3-a006-56b37116bf78-0', tool_calls=[{'name': 'get_weather', 'args': {'city': '上海'}, 'id': '0196d715ce404add2415fd6212a8973c', 'type': 'tool_call'}], usage_metadata={'input_tokens': 164, 'output_tokens': 94, 'total_tokens': 258, 'input_token_details': {}, 'output_token_details': {'reasoning': 86}}), ToolMessage(content='多云', name='get_weather', id='5b8d14c1-dbbf-4a0f-891c-9541d42f9cbc', tool_call_id='0196d715ce404add2415fd6212a8973c'), AIMessage(content='\n\n上海今天天气多云,建议出门可以准备一把小伞,或者看看是否需要搭配外套哦~', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 157, 'prompt_tokens': 208, 'total_tokens': 365, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 134, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_name': 'Qwen/Qwen3-8B', 'system_fingerprint': '', 'id': '0196d715d09ee98c6f98d1ac52cd503a', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None}, id='run--f0893e0b-f74c-4c7a-98d6-140e974b5454-0', usage_metadata={'input_tokens': 208, 'output_tokens': 157, 'total_tokens': 365, 'input_token_details': {}, 'output_token_details': {'reasoning': 134}})]}}, metadata={'step': 3, 'source': 'loop', 'writes': {'agent': {'messages': [AIMessage(content='\n\n上海今天天气多云,建议出门可以准备一把小伞,或者看看是否需要搭配外套哦~', additional_kwargs={'refusal': None}, response_metadata={'id': '0196d715d09ee98c6f98d1ac52cd503a', 'logprobs': None, 'model_name': 'Qwen/Qwen3-8B', 'token_usage': {'total_tokens': 365, 'prompt_tokens': 208, 'completion_tokens': 157, 'prompt_tokens_details': None, 'completion_tokens_details': {'audio_tokens': None, 'reasoning_tokens': 134, 'accepted_prediction_tokens': None, 'rejected_prediction_tokens': None}}, 'service_tier': None, 'finish_reason': 'stop', 'system_fingerprint': ''}, id='run--f0893e0b-f74c-4c7a-98d6-140e974b5454-0', usage_metadata={'input_tokens': 208, 'output_tokens': 157, 'total_tokens': 365, 'input_token_details': {}, 'output_token_details': {'reasoning': 134}})]}}, 'parents': {}, 'thread_id': '2'}, parent_config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1f03203d-7a6e-6d79-8002-e176fcb372de'}}, pending_writes=[])
3、使用连接字符串
这基于连接字符串创建一个连接:
- 优点:简单性,封装连接详细信息
- 适用于:快速设置或连接详细信息以字符串形式提供时
with PostgresSaver.from_conn_string(DB_URI) as checkpointer:graph = create_react_agent(model, tools=tools, checkpointer=checkpointer)config = {"configurable": {"thread_id": "3"}}res = graph.invoke({"messages": [("human", "明天北京天气如何")]}, config)checkpoint_tuples = list(checkpointer.list(config))
checkpoint_tuples
[CheckpointTuple(config={'configurable': {'thread_id': '3', 'checkpoint_ns': '', 'checkpoint_id': '1f032041-deaa-6466-8003-c6fab3893072'}}, checkpoint={'v': 3, 'id': '1f032041-deaa-6466-8003-c6fab3893072', 'ts': '2025-05-16T03:16:11.166003+00:00', 'pending_sends': [], 'versions_seen': {'agent': {'branch:to:agent': '00000000000000000000000000000004.0.5008888481496694'}, 'tools': {'branch:to:tools': '00000000000000000000000000000003.0.2442059679188554'}, '__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0.2637731363043043'}}, 'channel_versions': {'messages': '00000000000000000000000000000005.0.8936397767083367', '__start__': '00000000000000000000000000000002.0.7662491731519978', 'branch:to:agent': '00000000000000000000000000000005.0.38094316679119766', 'branch:to:tools': '00000000000000000000000000000004.0.19293298057002828'}, 'channel_values': {'messages': [HumanMessage(content='明天北京天气如何', additional_kwargs={}, response_metadata={}, id='23e2b3c9-22d9-4dc1-a89f-97f72edb7def'), AIMessage(content='\n\n', additional_kwargs={'tool_calls': [{'id': '0196d7177d081ad977161456336fdbac', 'function': {'arguments': ' {"city": "北京"}', 'name': 'get_weather'}, 'type': 'function', 'index': 0}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 158, 'prompt_tokens': 164, 'total_tokens': 322, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 150, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_name': 'Qwen/Qwen3-8B', 'system_fingerprint': '', 'id': '0196d71774145483ac5bbcd15d13a722', 'service_tier': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run--c3798487-5ba2-4f72-8fed-6cc5c134c28e-0', tool_calls=[{'name': 'get_weather', 'args': {'city': '北京'}, 'id': '0196d7177d081ad977161456336fdbac', 'type': 'tool_call'}], usage_metadata={'input_tokens': 164, 'output_tokens': 158, 'total_tokens': 322, 'input_token_details': {}, 'output_token_details': {'reasoning': 150}}), ToolMessage(content='晴天', name='get_weather', id='689f2cc4-6f78-4802-abe2-cc3ccbec04dc', tool_call_id='0196d7177d081ad977161456336fdbac'), AIMessage(content='\n\n明天北京的天气是晴天,阳光明媚,适合外出活动。记得做好防晒措施哦!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 144, 'prompt_tokens': 207, 'total_tokens': 351, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 122, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_name': 'Qwen/Qwen3-8B', 'system_fingerprint': '', 'id': '0196d7177e3b7ef7c19e1f3341951fa1', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None}, id='run--45a35256-995f-437d-84ae-8bac88fecc5b-0', usage_metadata={'input_tokens': 207, 'output_tokens': 144, 'total_tokens': 351, 'input_token_details': {}, 'output_token_details': {'reasoning': 122}})]}}, metadata={'step': 3, 'source': 'loop', 'writes': {'agent': {'messages': [AIMessage(content='\n\n明天北京的天气是晴天,阳光明媚,适合外出活动。记得做好防晒措施哦!', additional_kwargs={'refusal': None}, response_metadata={'id': '0196d7177e3b7ef7c19e1f3341951fa1', 'logprobs': None, 'model_name': 'Qwen/Qwen3-8B', 'token_usage': {'total_tokens': 351, 'prompt_tokens': 207, 'completion_tokens': 144, 'prompt_tokens_details': None, 'completion_tokens_details': {'audio_tokens': None, 'reasoning_tokens': 122, 'accepted_prediction_tokens': None, 'rejected_prediction_tokens': None}}, 'service_tier': None, 'finish_reason': 'stop', 'system_fingerprint': ''}, id='run--45a35256-995f-437d-84ae-8bac88fecc5b-0', usage_metadata={'input_tokens': 207, 'output_tokens': 144, 'total_tokens': 351, 'input_token_details': {}, 'output_token_details': {'reasoning': 122}})]}}, 'parents': {}, 'thread_id': '3'}, parent_config={'configurable': {'thread_id': '3', 'checkpoint_ns': '', 'checkpoint_id': '1f032041-92c4-67f1-8002-baf2b9717c21'}}, pending_writes=[]),CheckpointTuple(config={'configurable': {'thread_id': '3', 'checkpoint_ns': '', 'checkpoint_id': '1f032041-92c4-67f1-8002-baf2b9717c21'}}, checkpoint={'v': 3, 'id': '1f032041-92c4-67f1-8002-baf2b9717c21', 'ts': '2025-05-16T03:16:03.207567+00:00', 'pending_sends': [], 'versions_seen': {'agent': {'branch:to:agent': '00000000000000000000000000000002.0.9220065296348962'}, 'tools': {'branch:to:tools': '00000000000000000000000000000003.0.2442059679188554'}, '__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0.2637731363043043'}}, 'channel_versions': {'messages': '00000000000000000000000000000004.0.3418660141913067', '__start__': '00000000000000000000000000000002.0.7662491731519978', 'branch:to:agent': '00000000000000000000000000000004.0.5008888481496694', 'branch:to:tools': '00000000000000000000000000000004.0.19293298057002828'}, 'channel_values': {'messages': [HumanMessage(content='明天北京天气如何', additional_kwargs={}, response_metadata={}, id='23e2b3c9-22d9-4dc1-a89f-97f72edb7def'), AIMessage(content='\n\n', additional_kwargs={'tool_calls': [{'id': '0196d7177d081ad977161456336fdbac', 'function': {'arguments': ' {"city": "北京"}', 'name': 'get_weather'}, 'type': 'function', 'index': 0}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 158, 'prompt_tokens': 164, 'total_tokens': 322, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 150, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_name': 'Qwen/Qwen3-8B', 'system_fingerprint': '', 'id': '0196d71774145483ac5bbcd15d13a722', 'service_tier': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run--c3798487-5ba2-4f72-8fed-6cc5c134c28e-0', tool_calls=[{'name': 'get_weather', 'args': {'city': '北京'}, 'id': '0196d7177d081ad977161456336fdbac', 'type': 'tool_call'}], usage_metadata={'input_tokens': 164, 'output_tokens': 158, 'total_tokens': 322, 'input_token_details': {}, 'output_token_details': {'reasoning': 150}}), ToolMessage(content='晴天', name='get_weather', id='689f2cc4-6f78-4802-abe2-cc3ccbec04dc', tool_call_id='0196d7177d081ad977161456336fdbac')], 'branch:to:agent': None}}, metadata={'step': 2, 'source': 'loop', 'writes': {'tools': {'messages': [ToolMessage(content='晴天', name='get_weather', id='689f2cc4-6f78-4802-abe2-cc3ccbec04dc', tool_call_id='0196d7177d081ad977161456336fdbac')]}}, 'parents': {}, 'thread_id': '3'}, parent_config={'configurable': {'thread_id': '3', 'checkpoint_ns': '', 'checkpoint_id': '1f032041-92c0-6615-8001-6e9be51e90b6'}}, pending_writes=[('7d8bc83b-13ee-3cc6-b8bc-f563a07a74ac', 'messages', [AIMessage(content='\n\n明天北京的天气是晴天,阳光明媚,适合外出活动。记得做好防晒措施哦!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 144, 'prompt_tokens': 207, 'total_tokens': 351, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 122, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_name': 'Qwen/Qwen3-8B', 'system_fingerprint': '', 'id': '0196d7177e3b7ef7c19e1f3341951fa1', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None}, id='run--45a35256-995f-437d-84ae-8bac88fecc5b-0', usage_metadata={'input_tokens': 207, 'output_tokens': 144, 'total_tokens': 351, 'input_token_details': {}, 'output_token_details': {'reasoning': 122}})])]),CheckpointTuple(config={'configurable': {'thread_id': '3', 'checkpoint_ns': '', 'checkpoint_id': '1f032041-92c0-6615-8001-6e9be51e90b6'}}, checkpoint={'v': 3, 'id': '1f032041-92c0-6615-8001-6e9be51e90b6', 'ts': '2025-05-16T03:16:03.205879+00:00', 'pending_sends': [], 'versions_seen': {'agent': {'branch:to:agent': '00000000000000000000000000000002.0.9220065296348962'}, '__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0.2637731363043043'}}, 'channel_versions': {'messages': '00000000000000000000000000000003.0.6752645854463857', '__start__': '00000000000000000000000000000002.0.7662491731519978', 'branch:to:agent': '00000000000000000000000000000003.0.14624747432252805', 'branch:to:tools': '00000000000000000000000000000003.0.2442059679188554'}, 'channel_values': {'messages': [HumanMessage(content='明天北京天气如何', additional_kwargs={}, response_metadata={}, id='23e2b3c9-22d9-4dc1-a89f-97f72edb7def'), AIMessage(content='\n\n', additional_kwargs={'tool_calls': [{'id': '0196d7177d081ad977161456336fdbac', 'function': {'arguments': ' {"city": "北京"}', 'name': 'get_weather'}, 'type': 'function', 'index': 0}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 158, 'prompt_tokens': 164, 'total_tokens': 322, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 150, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_name': 'Qwen/Qwen3-8B', 'system_fingerprint': '', 'id': '0196d71774145483ac5bbcd15d13a722', 'service_tier': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run--c3798487-5ba2-4f72-8fed-6cc5c134c28e-0', tool_calls=[{'name': 'get_weather', 'args': {'city': '北京'}, 'id': '0196d7177d081ad977161456336fdbac', 'type': 'tool_call'}], usage_metadata={'input_tokens': 164, 'output_tokens': 158, 'total_tokens': 322, 'input_token_details': {}, 'output_token_details': {'reasoning': 150}})], 'branch:to:tools': None}}, metadata={'step': 1, 'source': 'loop', 'writes': {'agent': {'messages': [AIMessage(content='\n\n', additional_kwargs={'refusal': None, 'tool_calls': [{'id': '0196d7177d081ad977161456336fdbac', 'type': 'function', 'index': 0, 'function': {'name': 'get_weather', 'arguments': ' {"city": "北京"}'}}]}, response_metadata={'id': '0196d71774145483ac5bbcd15d13a722', 'logprobs': None, 'model_name': 'Qwen/Qwen3-8B', 'token_usage': {'total_tokens': 322, 'prompt_tokens': 164, 'completion_tokens': 158, 'prompt_tokens_details': None, 'completion_tokens_details': {'audio_tokens': None, 'reasoning_tokens': 150, 'accepted_prediction_tokens': None, 'rejected_prediction_tokens': None}}, 'service_tier': None, 'finish_reason': 'tool_calls', 'system_fingerprint': ''}, id='run--c3798487-5ba2-4f72-8fed-6cc5c134c28e-0', tool_calls=[{'name': 'get_weather', 'args': {'city': '北京'}, 'id': '0196d7177d081ad977161456336fdbac', 'type': 'tool_call'}], usage_metadata={'input_tokens': 164, 'output_tokens': 158, 'total_tokens': 322, 'input_token_details': {}, 'output_token_details': {'reasoning': 150}})]}}, 'parents': {}, 'thread_id': '3'}, parent_config={'configurable': {'thread_id': '3', 'checkpoint_ns': '', 'checkpoint_id': '1f032041-7991-60fc-8000-030f778771d9'}}, pending_writes=[('159b69a7-5acb-ab28-29ce-4091542a3089', 'messages', [ToolMessage(content='晴天', name='get_weather', id='689f2cc4-6f78-4802-abe2-cc3ccbec04dc', tool_call_id='0196d7177d081ad977161456336fdbac')]), ('159b69a7-5acb-ab28-29ce-4091542a3089', 'branch:to:agent', None)]),CheckpointTuple(config={'configurable': {'thread_id': '3', 'checkpoint_ns': '', 'checkpoint_id': '1f032041-7991-60fc-8000-030f778771d9'}}, checkpoint={'v': 3, 'id': '1f032041-7991-60fc-8000-030f778771d9', 'ts': '2025-05-16T03:16:00.565062+00:00', 'pending_sends': [], 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0.2637731363043043'}}, 'channel_versions': {'messages': '00000000000000000000000000000002.0.27439344645254793', '__start__': '00000000000000000000000000000002.0.7662491731519978', 'branch:to:agent': '00000000000000000000000000000002.0.9220065296348962'}, 'channel_values': {'messages': [HumanMessage(content='明天北京天气如何', additional_kwargs={}, response_metadata={}, id='23e2b3c9-22d9-4dc1-a89f-97f72edb7def')], 'branch:to:agent': None}}, metadata={'step': 0, 'source': 'loop', 'writes': None, 'parents': {}, 'thread_id': '3'}, parent_config={'configurable': {'thread_id': '3', 'checkpoint_ns': '', 'checkpoint_id': '1f032041-798f-689c-bfff-9180c905a847'}}, pending_writes=[('b7ff270f-dacb-945c-3ecd-20ba6dec52a4', 'messages', [AIMessage(content='\n\n', additional_kwargs={'tool_calls': [{'id': '0196d7177d081ad977161456336fdbac', 'function': {'arguments': ' {"city": "北京"}', 'name': 'get_weather'}, 'type': 'function', 'index': 0}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 158, 'prompt_tokens': 164, 'total_tokens': 322, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 150, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_name': 'Qwen/Qwen3-8B', 'system_fingerprint': '', 'id': '0196d71774145483ac5bbcd15d13a722', 'service_tier': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run--c3798487-5ba2-4f72-8fed-6cc5c134c28e-0', tool_calls=[{'name': 'get_weather', 'args': {'city': '北京'}, 'id': '0196d7177d081ad977161456336fdbac', 'type': 'tool_call'}], usage_metadata={'input_tokens': 164, 'output_tokens': 158, 'total_tokens': 322, 'input_token_details': {}, 'output_token_details': {'reasoning': 150}})]), ('b7ff270f-dacb-945c-3ecd-20ba6dec52a4', 'branch:to:tools', None)]),CheckpointTuple(config={'configurable': {'thread_id': '3', 'checkpoint_ns': '', 'checkpoint_id': '1f032041-798f-689c-bfff-9180c905a847'}}, checkpoint={'v': 3, 'id': '1f032041-798f-689c-bfff-9180c905a847', 'ts': '2025-05-16T03:16:00.564439+00:00', 'pending_sends': [], 'versions_seen': {'__input__': {}}, 'channel_versions': {'__start__': '00000000000000000000000000000001.0.2637731363043043'}, 'channel_values': {'__start__': {'messages': [['human', '明天北京天气如何']]}}}, metadata={'step': -1, 'source': 'input', 'writes': {'__start__': {'messages': [['human', '明天北京天气如何']]}}, 'parents': {}, 'thread_id': '3'}, parent_config=None, pending_writes=[('8b412bef-d87d-76d2-05d1-bf7f5a97378c', 'messages', [['human', '明天北京天气如何']]), ('8b412bef-d87d-76d2-05d1-bf7f5a97378c', 'branch:to:agent', None)])]
六、使用异步连接
这将设置一个到数据库的异步连接。异步连接允许非阻塞数据库操作。这意味着应用程序的其他部分可以在等待数据库操作完成的同时继续运行。这在并发场景较高或处理 I/O 密集型操作时特别有用。
1、使用连接池
from psycopg_pool import AsyncConnectionPoolasync with AsyncConnectionPool(# Example configurationconninfo=DB_URI,max_size=20,kwargs=connection_kwargs,
) as pool:checkpointer = AsyncPostgresSaver(pool)# NOTE: you need to call .setup() the first time you're using your checkpointerawait checkpointer.setup()graph = create_react_agent(model, tools=tools, checkpointer=checkpointer)config = {"configurable": {"thread_id": "4"}}res = await graph.ainvoke({"messages": [("human", "明天上海天气如何")]}, config)checkpoint = await checkpointer.aget(config)
checkpoint
{'v': 3,'id': '1f032048-191d-60c4-8003-450932a97415','ts': '2025-05-16T03:18:58.356030+00:00','pending_sends': [],'versions_seen': {'agent': {'branch:to:agent': '00000000000000000000000000000004.0.9476460076898559'},'tools': {'branch:to:tools': '00000000000000000000000000000003.0.5075539263137369'},'__input__': {},'__start__': {'__start__': '00000000000000000000000000000001.0.9870325191514127'}},'channel_versions': {'messages': '00000000000000000000000000000005.0.31782154529391415','__start__': '00000000000000000000000000000002.0.35708852446726413','branch:to:agent': '00000000000000000000000000000005.0.9121909450060119','branch:to:tools': '00000000000000000000000000000004.0.7808599098083274'},'channel_values': {'messages': [HumanMessage(content='明天上海天气如何', additional_kwargs={}, response_metadata={}, id='b2535639-0388-467c-92ad-0c1c2ecde59d'),AIMessage(content='\n\n', additional_kwargs={'tool_calls': [{'id': '0196d719fcb95724c34629d42cfe99e2', 'function': {'arguments': ' {"city": "上海"}', 'name': 'get_weather'}, 'type': 'function', 'index': 0}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 122, 'prompt_tokens': 164, 'total_tokens': 286, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 114, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_name': 'Qwen/Qwen3-8B', 'system_fingerprint': '', 'id': '0196d719f72bd0bb64ed95e8a578ff06', 'service_tier': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run--a1e1efc4-4634-4b2b-bd15-83586b77de21-0', tool_calls=[{'name': 'get_weather', 'args': {'city': '上海'}, 'id': '0196d719fcb95724c34629d42cfe99e2', 'type': 'tool_call'}], usage_metadata={'input_tokens': 164, 'output_tokens': 122, 'total_tokens': 286, 'input_token_details': {}, 'output_token_details': {'reasoning': 114}}),ToolMessage(content='多云', name='get_weather', id='9b137c50-5685-4d83-8d8a-ae96dc240959', tool_call_id='0196d719fcb95724c34629d42cfe99e2'),AIMessage(content='\n\n明天上海的天气为多云,建议出门可以准备伞具以防突然降雨,并注意防晒。如需了解更详细的天气信息,可以随时告知我!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 284, 'prompt_tokens': 208, 'total_tokens': 492, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 249, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_name': 'Qwen/Qwen3-8B', 'system_fingerprint': '', 'id': '0196d719fd7b229416116b372cfc23ec', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None}, id='run--dbe5ac72-383f-4fd9-8b08-bb7016649334-0', usage_metadata={'input_tokens': 208, 'output_tokens': 284, 'total_tokens': 492, 'input_token_details': {}, 'output_token_details': {'reasoning': 249}})]}}
2、使用单个连接
from psycopg import AsyncConnectionasync with await AsyncConnection.connect(DB_URI, **connection_kwargs) as conn:checkpointer = AsyncPostgresSaver(conn)graph = create_react_agent(model, tools=tools, checkpointer=checkpointer)config = {"configurable": {"thread_id": "5"}}res = await graph.ainvoke({"messages": [("human", "后天北京天气如何")]}, config)checkpoint_tuple = await checkpointer.aget_tuple(config)
checkpoint_tuple
CheckpointTuple(config={'configurable': {'thread_id': '5', 'checkpoint_ns': '', 'checkpoint_id': '1f03204b-f7ba-617b-8003-8ba829ed9c2d'}}, checkpoint={'v': 3, 'id': '1f03204b-f7ba-617b-8003-8ba829ed9c2d', 'ts': '2025-05-16T03:20:42.229378+00:00', 'pending_sends': [], 'versions_seen': {'agent': {'branch:to:agent': '00000000000000000000000000000004.0.4841987625771813'}, 'tools': {'branch:to:tools': '00000000000000000000000000000003.0.8898034330376885'}, '__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0.4325236474012414'}}, 'channel_versions': {'messages': '00000000000000000000000000000005.0.36731613104976735', '__start__': '00000000000000000000000000000002.0.865284452352145', 'branch:to:agent': '00000000000000000000000000000005.0.7688631247355521', 'branch:to:tools': '00000000000000000000000000000004.0.22510220545092896'}, 'channel_values': {'messages': [HumanMessage(content='后天北京天气如何', additional_kwargs={}, response_metadata={}, id='339339d5-2c8d-4f0c-8e39-667f4196c555'), AIMessage(content='\n\n', additional_kwargs={'tool_calls': [{'id': '0196d71bb51b6733bd79c1ee1f261b33', 'function': {'arguments': ' {"city": "北京"}', 'name': 'get_weather'}, 'type': 'function', 'index': 0}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 275, 'prompt_tokens': 165, 'total_tokens': 440, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 267, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_name': 'Qwen/Qwen3-8B', 'system_fingerprint': '', 'id': '0196d71b77acc177b59cbc50667c0580', 'service_tier': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run--1090c017-5901-41f8-9191-00dee1a7fb9b-0', tool_calls=[{'name': 'get_weather', 'args': {'city': '北京'}, 'id': '0196d71bb51b6733bd79c1ee1f261b33', 'type': 'tool_call'}], usage_metadata={'input_tokens': 165, 'output_tokens': 275, 'total_tokens': 440, 'input_token_details': {}, 'output_token_details': {'reasoning': 267}}), ToolMessage(content='晴天', name='get_weather', id='37a3f432-b07e-4891-9b87-d176b5b5ff75', tool_call_id='0196d71bb51b6733bd79c1ee1f261b33'), AIMessage(content='\n\n北京后天的天气是晴天,适合外出活动,记得做好防晒哦!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 166, 'prompt_tokens': 208, 'total_tokens': 374, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 147, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_name': 'Qwen/Qwen3-8B', 'system_fingerprint': '', 'id': '0196d71bb7b501e087b3ef82469a46df', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None}, id='run--d4d8be11-920c-430b-8f35-a9da47af3335-0', usage_metadata={'input_tokens': 208, 'output_tokens': 166, 'total_tokens': 374, 'input_token_details': {}, 'output_token_details': {'reasoning': 147}})]}}, metadata={'step': 3, 'source': 'loop', 'writes': {'agent': {'messages': [AIMessage(content='\n\n北京后天的天气是晴天,适合外出活动,记得做好防晒哦!', additional_kwargs={'refusal': None}, response_metadata={'id': '0196d71bb7b501e087b3ef82469a46df', 'logprobs': None, 'model_name': 'Qwen/Qwen3-8B', 'token_usage': {'total_tokens': 374, 'prompt_tokens': 208, 'completion_tokens': 166, 'prompt_tokens_details': None, 'completion_tokens_details': {'audio_tokens': None, 'reasoning_tokens': 147, 'accepted_prediction_tokens': None, 'rejected_prediction_tokens': None}}, 'service_tier': None, 'finish_reason': 'stop', 'system_fingerprint': ''}, id='run--d4d8be11-920c-430b-8f35-a9da47af3335-0', usage_metadata={'input_tokens': 208, 'output_tokens': 166, 'total_tokens': 374, 'input_token_details': {}, 'output_token_details': {'reasoning': 147}})]}}, 'parents': {}, 'thread_id': '5'}, parent_config={'configurable': {'thread_id': '5', 'checkpoint_ns': '', 'checkpoint_id': '1f03204b-e387-6790-8002-719fde470558'}}, pending_writes=[])
3、使用连接字符串
async with AsyncPostgresSaver.from_conn_string(DB_URI) as checkpointer:graph = create_react_agent(model, tools=tools, checkpointer=checkpointer)config = {"configurable": {"thread_id": "6"}}res = await graph.ainvoke({"messages": [("human", "后天上海天气如何")]}, config)checkpoint_tuples = [c async for c in checkpointer.alist(config)]
checkpoint_tuples
[CheckpointTuple(config={'configurable': {'thread_id': '6', 'checkpoint_ns': '', 'checkpoint_id': '1f032050-b6c5-65e0-8001-601198051338'}}, checkpoint={'v': 3, 'id': '1f032050-b6c5-65e0-8001-601198051338', 'ts': '2025-05-16T03:22:49.635980+00:00', 'pending_sends': [], 'versions_seen': {'agent': {'branch:to:agent': '00000000000000000000000000000002.0.8929341257310782'}, '__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0.6643697680485742'}}, 'channel_versions': {'messages': '00000000000000000000000000000003.0.721638363372932', '__start__': '00000000000000000000000000000002.0.11953722026997815', 'branch:to:agent': '00000000000000000000000000000003.0.08189810500536276'}, 'channel_values': {'messages': [HumanMessage(content='后天上海天气如何', additional_kwargs={}, response_metadata={}, id='37425ee0-faa6-4c1d-9b7b-a898d52ecc65'), AIMessage(content='\n\n当前工具仅支持查询当前天气情况,无法获取后天天气信息。请问您是否需要了解上海当前的天气状况?或者是否有其他可以协助您的地方?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 185, 'prompt_tokens': 165, 'total_tokens': 350, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 149, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_name': 'Qwen/Qwen3-8B', 'system_fingerprint': '', 'id': '0196d71d96afa5548e5dfd9b7fe02261', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None}, id='run--edad30f3-8032-480f-8303-e339ac63dfa0-0', usage_metadata={'input_tokens': 165, 'output_tokens': 185, 'total_tokens': 350, 'input_token_details': {}, 'output_token_details': {'reasoning': 149}})]}}, metadata={'step': 1, 'source': 'loop', 'writes': {'agent': {'messages': [AIMessage(content='\n\n当前工具仅支持查询当前天气情况,无法获取后天天气信息。请问您是否需要了解上海当前的天气状况?或者是否有其他可以协助您的地方?', additional_kwargs={'refusal': None}, response_metadata={'id': '0196d71d96afa5548e5dfd9b7fe02261', 'logprobs': None, 'model_name': 'Qwen/Qwen3-8B', 'token_usage': {'total_tokens': 350, 'prompt_tokens': 165, 'completion_tokens': 185, 'prompt_tokens_details': None, 'completion_tokens_details': {'audio_tokens': None, 'reasoning_tokens': 149, 'accepted_prediction_tokens': None, 'rejected_prediction_tokens': None}}, 'service_tier': None, 'finish_reason': 'stop', 'system_fingerprint': ''}, id='run--edad30f3-8032-480f-8303-e339ac63dfa0-0', usage_metadata={'input_tokens': 165, 'output_tokens': 185, 'total_tokens': 350, 'input_token_details': {}, 'output_token_details': {'reasoning': 149}})]}}, 'parents': {}, 'thread_id': '6'}, parent_config={'configurable': {'thread_id': '6', 'checkpoint_ns': '', 'checkpoint_id': '1f032050-7351-6c98-8000-f62e8b117b4f'}}, pending_writes=[]),CheckpointTuple(config={'configurable': {'thread_id': '6', 'checkpoint_ns': '', 'checkpoint_id': '1f032050-7351-6c98-8000-f62e8b117b4f'}}, checkpoint={'v': 3, 'id': '1f032050-7351-6c98-8000-f62e8b117b4f', 'ts': '2025-05-16T03:22:42.563181+00:00', 'pending_sends': [], 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0.6643697680485742'}}, 'channel_versions': {'messages': '00000000000000000000000000000002.0.6541960891137211', '__start__': '00000000000000000000000000000002.0.11953722026997815', 'branch:to:agent': '00000000000000000000000000000002.0.8929341257310782'}, 'channel_values': {'messages': [HumanMessage(content='后天上海天气如何', additional_kwargs={}, response_metadata={}, id='37425ee0-faa6-4c1d-9b7b-a898d52ecc65')], 'branch:to:agent': None}}, metadata={'step': 0, 'source': 'loop', 'writes': None, 'parents': {}, 'thread_id': '6'}, parent_config={'configurable': {'thread_id': '6', 'checkpoint_ns': '', 'checkpoint_id': '1f032050-7350-6dcc-bfff-46d64947994f'}}, pending_writes=[('6ea05cff-f255-2cd4-0e99-0f0637eb2a63', 'messages', [AIMessage(content='\n\n当前工具仅支持查询当前天气情况,无法获取后天天气信息。请问您是否需要了解上海当前的天气状况?或者是否有其他可以协助您的地方?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 185, 'prompt_tokens': 165, 'total_tokens': 350, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 149, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': None}, 'model_name': 'Qwen/Qwen3-8B', 'system_fingerprint': '', 'id': '0196d71d96afa5548e5dfd9b7fe02261', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None}, id='run--edad30f3-8032-480f-8303-e339ac63dfa0-0', usage_metadata={'input_tokens': 165, 'output_tokens': 185, 'total_tokens': 350, 'input_token_details': {}, 'output_token_details': {'reasoning': 149}})])]),CheckpointTuple(config={'configurable': {'thread_id': '6', 'checkpoint_ns': '', 'checkpoint_id': '1f032050-7350-6dcc-bfff-46d64947994f'}}, checkpoint={'v': 3, 'id': '1f032050-7350-6dcc-bfff-46d64947994f', 'ts': '2025-05-16T03:22:42.562806+00:00', 'pending_sends': [], 'versions_seen': {'__input__': {}}, 'channel_versions': {'__start__': '00000000000000000000000000000001.0.6643697680485742'}, 'channel_values': {'__start__': {'messages': [['human', '后天上海天气如何']]}}}, metadata={'step': -1, 'source': 'input', 'writes': {'__start__': {'messages': [['human', '后天上海天气如何']]}}, 'parents': {}, 'thread_id': '6'}, parent_config=None, pending_writes=[('225c6741-b759-049f-51cd-496b6230b72d', 'messages', [['human', '后天上海天气如何']]), ('225c6741-b759-049f-51cd-496b6230b72d', 'branch:to:agent', None)])]
七、数据表
从数据库中可以看到 checkpointer 创建的 4 张表
参考文档
- https://github.langchain.ac.cn/langgraph/how-tos/persistence_postgres/