LangGraph 入门实战(2)

LangGraph 入门实战:用 StateGraph 搭建一条可视化状态流

LangGraph 适合用来描述"多个步骤按照既定关系流转,并在步骤之间共享状态"的程序。它经常被用于 AI Agent、工作流编排和多步骤任务,但理解 LangGraph 并不需要先接入大模型。

本文从一个完全确定、无需 API Key 的线性流程开始,使用 StateGraph 串联三个节点:

text 复制代码
START -> step1 -> step2 -> step3 -> END

程序会依次修改共享状态、返回最终结果,并将图结构保存为 PNG 图片。

1. 运行环境

本文代码的实际运行环境如下:

text 复制代码
Python 3.14.7
LangGraph 1.2.10

建议先为项目创建虚拟环境,避免不同项目的依赖互相影响:

bash 复制代码
python -m venv .venv
source .venv/bin/activate
python -m pip install -U langgraph typing-extensions

在 Windows PowerShell 中,激活命令为:

powershell 复制代码
.venv\Scripts\Activate.ps1

2. 认识 LangGraph 的核心概念

在编写代码之前,先了解示例中使用的几个概念。

概念 作用
State 整个流程共享的数据
Node 接收状态并返回状态更新的处理函数
Edge 指定节点之间的流转关系
START 图的固定入口
END 图的固定出口
compile 将图定义编译为可执行对象
invoke 使用初始状态执行一次完整流程

可以把 State 理解为一份在节点之间传递的数据表。每个节点读取需要的字段,并返回本次需要更新的字段。

3. 定义共享状态

示例使用 TypedDict 定义状态结构:

python 复制代码
from typing_extensions import TypedDict


class State(TypedDict):
    value1: str
    value2: str
    value3: str

这表示流程状态中包含三个字符串字段:value1value2value3

TypedDict 能为编辑器和类型检查工具提供字段提示,但它不是运行时数据校验器。如果需要在运行时校验数据,还可以根据项目需求使用 Pydantic 模型定义状态。

4. 编写三个处理节点

LangGraph 节点可以是普通 Python 函数。函数接收当前状态,并返回需要写回状态的字典。

step1:更新 value1

python 复制代码
def step1(state: State):
    return {"value1": state["value1"] + "这是step1;"}

输入 value1初始值 时,节点返回:

python 复制代码
{"value1": "初始值这是step1;"}

节点只返回了 value1。LangGraph 会把它合并到当前状态中,未返回的 value2value3 会继续保留。

step2:读取 step1 的结果

python 复制代码
def step2(state: State):
    v = state["value1"]
    return {"value2": f"{v}; 这是step2"}

step2 读取的是 step1 更新后的 value1,然后生成 value2。这正是共享状态的价值:后续节点可以直接访问前面节点的执行结果。

step3:组合两个字段

python 复制代码
def step3(state: State):
    v1 = state["value1"]
    v2 = state["value2"]
    return {"value3": f"{v1} : {v2}"}

最后一个节点同时读取 value1value2,将组合结果写入 value3

5. 创建 StateGraph 并注册节点

python 复制代码
from langgraph.graph import START, StateGraph


graph_builder = StateGraph(State)
graph_builder.add_node(step1).add_node(step2).add_node(step3)

StateGraph(State) 告诉 LangGraph,这张图中的所有节点都使用前面定义的 State 作为共享状态结构。

add_node 用于注册节点。没有显式传入名称时,LangGraph 会使用函数名作为节点名,因此这里得到的节点名分别是:

text 复制代码
step1
step2
step3

add_node 会返回当前图构建器,所以可以像示例一样进行链式调用。

6. 使用边定义执行顺序

python 复制代码
graph_builder.add_edge(START, "step1")
graph_builder.add_edge("step1", "step2")
graph_builder.add_edge("step2", "step3")

三条边定义了完整的执行顺序:

  1. START 进入 step1
  2. step1 完成后执行 step2
  3. step2 完成后执行 step3

当前示例中,step3 没有后继节点,因此编译后的图会把它作为流程终点。为了让大型项目中的流程定义更加明确,也可以显式连接 END

python 复制代码
from langgraph.graph import END

graph_builder.add_edge("step3", END)

7. 编译并执行图

图的结构定义完成后,需要先调用 compile()

python 复制代码
graph = graph_builder.compile()

编译会生成一个可执行图。随后通过 invoke() 传入初始状态:

python 复制代码
res = graph.invoke(
    {
        "value1": "初始值",
        "value2": "",
        "value3": "",
    }
)
print("执行结果:", res)

一次 invoke() 会从 START 开始运行,直到流程结束,并返回最终完整状态。

8. 状态是如何变化的

这次执行过程中,状态依次发生如下变化:

阶段 value1 value2 value3
初始状态 初始值 空字符串 空字符串
step1 后 初始值这是step1; 空字符串 空字符串
step2 后 初始值这是step1; 初始值这是step1;; 这是step2 空字符串
step3 后 初始值这是step1; 初始值这是step1;; 这是step2 初始值这是step1; : 初始值这是step1;; 这是step2

这里的两个连续分号 ;; 来自原始代码:step1 的结果末尾已经有一个分号,step2 又在变量后追加了一个分号。这不是 LangGraph 重复执行造成的。如果希望输出更整洁,可以调整节点中的字符串拼接方式。

9. 将图结构导出为 PNG

可执行图可以转换为 Mermaid 图,再渲染为 PNG:

python 复制代码
png_bytes = graph.get_graph().draw_mermaid_png()

with open("langgraph_chain.png", "wb") as f:
    f.write(png_bytes)

代码执行后,会在当前目录生成 langgraph_chain.png

draw_mermaid_png() 默认可能需要访问 Mermaid 渲染服务。如果图片生成阶段出现网络错误,可以先检查网络连接;在对外网络受限的环境中,也可以改用本地 Mermaid 渲染方案。

10. 完整代码

下面是本文实际运行的完整代码:

python 复制代码
from langgraph.graph import START, StateGraph
from typing_extensions import TypedDict


class State(TypedDict):
    value1: str
    value2: str
    value3: str


def step1(state: State):
    return {"value1": state["value1"] + "这是step1;"}


def step2(state: State):
    v = state["value1"]
    return {"value2": f"{v}; 这是step2"}


def step3(state: State):
    v1 = state["value1"]
    v2 = state["value2"]
    return {"value3": f"{v1} : {v2}"}


# 构建流程图
graph_builder = StateGraph(State)
graph_builder.add_node(step1).add_node(step2).add_node(step3)

# 线性边流转
graph_builder.add_edge(START, "step1")
graph_builder.add_edge("step1", "step2")
graph_builder.add_edge("step2", "step3")

# 编译图
graph = graph_builder.compile()

# 绘制结构图
png_bytes = graph.get_graph().draw_mermaid_png()
with open("langgraph_chain.png", "wb") as f:
    f.write(png_bytes)

# 执行流程
res = graph.invoke({"value1": "初始值", "value2": "", "value3": ""})
print("执行结果:", res)

说明:项目当前的 index.py 不需要 IPython.display,因此实际源文件已经移除了对应导入。如果准备在 Jupyter Notebook 中直接展示图片,则可以使用:

python 复制代码
from IPython.display import Image, display

display(Image(png_bytes))

11. 运行代码和真实输出

进入代码所在目录后执行:

bash 复制代码
python index.py

本文在本地实际运行得到的控制台输出为:

text 复制代码
执行结果: 
{'value1': '初始值这是step1;', 
'value2': '初始值这是step1;; 这是step2',
'value3': '初始值这是step1; : 初始值这是step1;; 这是step2'}

同时,目录中会生成:

text 复制代码
langgraph_chain.png

12. 常见问题

12.1 Pylance 提示无法解析 langgraph.graph

通常是 VS Code 选择的 Python 解释器与安装依赖时使用的解释器不一致。先在终端确认:

bash 复制代码
python -c "import sys; print(sys.executable)"
python -m pip show langgraph

然后在 VS Code 中执行 Python: Select Interpreter,选择当前项目的 .venv/bin/python

12.2 为什么节点只返回一个字段,最终结果却包含全部字段

节点返回的是状态更新,不是用新字典替换整个状态。LangGraph 会按照 State 中每个字段对应的更新规则合并结果。在本例中,普通字符串字段会被节点返回的新值覆盖,其他未返回字段保持不变。

12.3 为什么需要 compile

构建阶段只是在描述节点和边。compile() 会检查图结构并生成真正可调用的运行对象。只有编译后的 graph 才能执行 invoke()、生成图结构或接入检查点等运行能力。

12.4 invoke() 和直接调用三个函数有什么区别

对于三个固定步骤,直接依次调用函数当然也能实现相同结果。LangGraph 的价值在流程变复杂后更加明显,例如:

  • 根据状态进行条件分支;
  • 某些步骤循环执行;
  • 并行执行多个节点;
  • 保存检查点并恢复流程;
  • 在人工确认后继续运行;
  • 将大模型、工具调用和业务节点组合成 Agent。

当前这个线性示例建立了最重要的基础:状态、节点、边、编译和执行。掌握这五个概念后,就可以继续学习条件边、持久化和人工介入等能力。

总结

使用 LangGraph 创建一个基础工作流,可以归纳为五步:

  1. 使用 TypedDict 等类型定义共享状态。
  2. 编写接收状态、返回状态更新的节点函数。
  3. 使用 StateGraph 注册节点。
  4. 使用边描述节点之间的流转关系。
  5. 编译图并通过 invoke() 执行。

这个示例虽然简单,但已经完整展示了 LangGraph 的核心运行模型。后续无论是增加条件判断、接入大模型,还是实现可恢复的 Agent,本质上都是在这套"状态 + 节点 + 边"的结构上继续扩展。

相关推荐
ttod_qzstudio2 小时前
Java 常用语法极简通关(五):类与对象——字段、方法、构造器、this 与 static
java·开发语言·python
jufeng13073 小时前
【系列:手搓自主 AI Agent:Hermes 架构原理剖析 · 第 1 篇】
人工智能·python·架构·agent
月光船幽幽4 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
_oP_i6 小时前
python 后缀 mjs文件
开发语言·python
北斗落凡尘6 小时前
如何使用LangGraph(1)
python·langchain
JaydenAI6 小时前
[基于OpenEvals的自动化评估-11]针对Agent对话的评估[下篇]
ai·langchain·agent·evaluation·openevals
Livia要学习7 小时前
Python装饰器
开发语言·python
大模型丫丫8 小时前
LangChain4j:Java 生态的 AI 应用开发利器
java·人工智能·python
circuitsosk8 小时前
向量数据库选型与性能压测:Milvus、Pinecone、Chroma在真实业务下的对比
数据库·python·pinecone·milvus·向量数据库·chroma