LangGraph 入门实战(10)--时光回溯

LangGraph 状态回显:查询、回放与分叉

LangGraph 的检查点(Checkpointer)会保存图在每一步执行后的状态。借助它,我们可以查询最新状态、查看历史快照,还可以从某个历史节点重新执行并创建分支。

本文中的 baidu、google 和 safari 是模拟工具,只返回固定文本,不会真正访问搜索引擎。

1. 安装与配置

bash 复制代码
pip install -U langgraph langchain-deepseek
export DEEPSEEK_API_KEY="你的 API Key"
python index.py

2. 构建带状态的工作流

先定义工具并绑定模型。ToolNode 会执行模型生成的工具调用,MessagesState 则负责累积消息。

python 复制代码
from langchain_core.tools import tool
from langchain_deepseek import ChatDeepSeek
from langgraph.graph import END, START, MessagesState, StateGraph
from langgraph.prebuilt import ToolNode


@tool
def baidu(name: str):
    """使用百度搜索"""
    return f"{name} 搜索百度"


@tool
def safari(name: str):
    """使用 Safari 浏览器"""
    return f"{name} 使用Safari浏览器"


tools = [baidu, safari]
tool_node = ToolNode(tools)
model = ChatDeepSeek(model="deepseek-v4-flash", temperature=0).bind_tools(
    tools, parallel_tool_calls=False
)


def call_model(state):
    return {"messages": [model.invoke(state["messages"])]}


def should_continue(state):
    if state["messages"][-1].tool_calls:
        return "continue"
    return "end"


builder = StateGraph(MessagesState)
builder.add_node("call_model", call_model)
builder.add_node("tool_node", tool_node)
builder.add_edge(START, "call_model")
builder.add_conditional_edges(
    "call_model",
    should_continue,
    {"continue": "tool_node", "end": END},
)
builder.add_edge("tool_node", "call_model")

执行路径如下:

text 复制代码
START -> call_model -> tool_node -> call_model -> END

3. 保存并回显状态

编译图时传入 MemorySaver,再通过 thread_id 标识一条独立会话。同一个 thread_id 会继续使用此前保存的状态。

python 复制代码
from langchain_core.messages import HumanMessage
from langchain_core.runnables.config import RunnableConfig
from langgraph.checkpoint.memory import MemorySaver

graph = builder.compile(checkpointer=MemorySaver())
config = RunnableConfig(configurable={"thread_id": "1"})

for chunk in graph.stream(
    {"messages": [HumanMessage(content="搜索中国的首都是哪里?")]},
    config=config,
    stream_mode="values",
):
    chunk["messages"][-1].pretty_print()

# 最新状态
current_state = graph.get_state(config)
print(current_state.values["messages"])

# 历史快照,顺序为从新到旧
history = list(graph.get_state_history(config))
for snapshot in history:
    print(snapshot.next, snapshot.values)

一次运行的关键输出如下(消息 ID 和快照元数据已省略):

text 复制代码
Human Message
搜索中国的首都是哪里?

Ai Message
Tool Calls:
  baidu
  Args: {"name": "中国的首都是哪里?"}

Tool Message
中国的首都是哪里? 搜索百度

Ai Message
中国的首都是北京。

# 历史快照中的待执行节点
()
('call_model',)
('tool_node',)

其中,get_state() 返回线程的最新快照,get_state_history() 返回该线程的全部历史快照。快照中的 next 表示下一步将执行的节点,空元组表示流程已经结束。

4. 从历史状态创建分支

选择模型刚产生工具调用的历史快照,将工具从 baidu 改为 safari,再从该检查点继续执行:

python 复制代码
from copy import deepcopy

replay = history[2]
last_message = deepcopy(replay.values["messages"][-1])
last_message.tool_calls[0]["name"] = "safari"

branch_config = graph.update_state(
    replay.config,
    {"messages": [last_message]},
)

# None 表示不添加新输入,直接从新检查点继续执行
for event in graph.stream(None, branch_config):
    print(event)

分支的关键输出:

text 复制代码
Tool Message
中国的首都是哪里? 使用Safari浏览器

Ai Message
中国的首都是北京。

这里的 update_state() 不会覆盖原执行路径,而是创建一个新的检查点。使用深拷贝修改消息,可以避免意外改变原历史快照。

小结

  • stream(..., stream_mode="values"):实时查看每一步的完整状态。
  • get_state(config):获取当前线程的最新状态。
  • get_state_history(config):按从新到旧的顺序读取历史快照。
  • update_state(snapshot.config, values):基于历史快照创建分支。

MemorySaver 只适合本地演示,程序退出后数据会丢失;生产环境应换成持久化的检查点实现。

相关推荐
Y3815326622 分钟前
SERP API 计费口径:credits_charged、执行失败扣费与退款边界
python·搜索引擎
蒸鱼Yuzheng2 小时前
设备端性能工件可靠导出:断点续传、哈希、manifest 与失败恢复
android·自动化测试·python·adb·数据完整性
BD_Marathon2 小时前
调用DeesSeek官网的DeepSeek模型
langchain
圆圆讲门店2 小时前
挑选同城获客服务机构时需要考量的核心因素都有哪些?
大数据·网络·人工智能·python
傻啦嘿哟3 小时前
Python的默认参数把我坑惨了,原来写[]和写None的区别这么大
开发语言·python·机器学习
微小冷3 小时前
Python凸优化cvxpy初步
python·机器人·凸优化·数学规划·cvxpy
在世修行3 小时前
干货:显式映射 vs 自动判据
python·插件
xzal123 小时前
Python之简单理解栈和队列
python
lupai3 小时前
维修保养记录精准版 API 对接实战指南
数据库·python
水水不水啊4 小时前
告别杂乱的调试窗口:我用 Python + WebView 写了一个现代化串口助手
python·测试工具·嵌入式·嵌入式开发·串口调试·串口助手