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

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

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

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

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

相关推荐
今天AI了吗41 分钟前
Agent & AI 名词大扫盲
数据库·人工智能·python·sql·rust
张张123y1 小时前
Hermes Agent 是什么?它能做什么,以及如何部署到飞书
人工智能·python·飞书
拾年2751 小时前
让 AI 自己卷自己:50 行代码实现「LLM 当评委 + 多选一」的 Harness 工程
langchain·llm
SamChan901 小时前
用Playwright端到端测试PDF翻译功能:Web自动化测试实战
前端·python·ai·pdf·wpf
袁袁袁袁满1 小时前
Python爬虫实战:利用巨量IP获取跨境电商数据
爬虫·python·网络爬虫·爬虫实战·跨境电商·电商爬虫
jufeng13071 小时前
【系列:TDengine 工业物联网实战:从零搭起可运行系统 · 第 4 篇】
python·时序数据库·tdengine·asyncio
努力搬砖的咸鱼1 小时前
意图理解:让Agent从需求描述自动生成Pytest测试策略
人工智能·python·ai·单元测试·pytest·agent
2601_956319882 小时前
2026年下半年,量化学习要把交易认知和技术实现接起来
人工智能·python
EW Frontier2 小时前
【雷达信号处理】5 个阵元追平 16 个阵元:稀疏阵列 STAP 的实测报告【附python+matlab代码】
python·matlab·信号处理·雷达·mimo·稀疏阵列·stap