随着大语言模型技术的快速演进,AI 应用早已从简单的单轮问答走向了复杂的自动化代理工作流。从链式调用的 LangChain 到自主决策的 ReAct 代理,开发者始终在追求更强的流程可控性、更灵活的状态管理与更可靠的循环逻辑。LangGraph 正是在这一背景下诞生的核心框架,它以图结构为基础,为构建有状态、可循环、支持人机协同的智能代理提供了一套底层、精细且高度可扩展的解决方案。
官方文档地址:https://langchain-ai.github.io/langgraph/
一、LangGraph 核心设计与四大基础组件
LangGraph 的核心思想是将代理的完整工作流抽象为一张有向图:节点负责执行具体业务逻辑,边负责控制流程的跳转方向,状态在节点间传递并持续迭代。这套设计借鉴了 Google Pregel 的消息传递模型与 NetworkX 的图操作接口,同时继承了 Apache Beam 统一数据处理的工程思想,最终实现了循环、可控性、持久性三大核心优势。
环境安装:
bash
pip install -U langchain langchain-openai langsmith pandas langchain_experimental matplotlib langgraph langchain-community tavily-python
1. 图(Graph):代理工作流的结构化载体
图是 LangGraph 的顶层抽象,它定义了代理所有可能的执行路径。与传统线性链式框架不同,图天然支持循环、分支、并行等复杂逻辑,这也是代理架构的核心需求。
底层执行原理:超级步骤与消息传递
LangGraph 的执行引擎基于离散的超级步骤(Superstep) 运行:
- 图启动时所有节点处于非激活状态,入口节点接收初始状态后被激活;
- 激活节点执行自身逻辑,生成状态更新,并通过边向下游节点传递消息;
- 每一轮超级步骤结束后,没有收到新消息的节点投票终止;
- 当所有节点均处于非激活状态且无消息传输时,图执行终止。
这种设计让多节点并行、循环迭代、动态分支都有了统一的执行模型,逻辑清晰且可预测。
StateGraph:最常用的图类
StateGraph 是 LangGraph 的核心图实现,它以用户自定义的状态对象为参数,所有节点通过读取和写入共享状态完成通信。每个节点的输入是完整状态,输出仅为状态的部分更新,最终由状态的归约逻辑完成合并。
python
from langgraph.graph import StateGraph, START
from typing_extensions import TypedDict
class MyState(TypedDict):
x: int
y: int
def my_node(state):
return {"x": state["x"] + 1, "y": state["y"] + 2}
# 构建图
builder = StateGraph(MyState)
builder.add_node(my_node)
builder.add_edge(START, "my_node")
# 编译图
graph = builder.compile()
print(graph.invoke({"x": 1, "y": 2}))
# 输出: {'x': 2, 'y': 4}
编译是图构建的最后一步,它会完成结构校验、通道初始化、检查点挂载等工作,最终生成可执行的 LangChain Runnable 对象,支持 invoke、stream、batch 等标准调用方式。
2. 状态(State):共享数据的生命周期管理
状态是 LangGraph 的全局内存,所有节点的输入输出都围绕状态展开。它不仅定义了数据结构,还定义了多节点更新时的合并规则。
模式(Schema):定义数据结构
状态的结构支持两种定义方式:
TypedDict:轻量快捷,适合大多数场景;Pydantic BaseModel:支持默认值、数据校验,适合对数据严谨性要求高的场景。
默认情况下所有节点共享全局状态,也支持创建私有状态通道用于节点间内部通信,实现逻辑隔离。
归约器(Reducers):定义更新规则
归约器是状态管理的核心,它决定了当多个节点对同一个状态键产生更新时,如何合并结果。
- 默认归约器:直接覆盖原值,适用于单一写入者的字段;
- 自定义归约器 :比如消息列表常用的
add_messages,会将新消息追加到列表中,而不是覆盖历史记录。
python
from typing import Annotated, TypedDict
from langgraph.graph.message import add_messages
class State(TypedDict):
# 使用 add_messages 归约器,消息会自动追加
messages: Annotated[list, add_messages]
这种设计让状态更新既灵活又安全:节点只需返回自己关心的字段更新,无需感知全局状态的完整结构,降低了耦合度。
3. 节点(Nodes):业务逻辑的执行单元
节点是代理逻辑的实际载体,本质上就是接收状态、返回状态更新的 Python 函数,支持同步与异步两种形式。
节点的标准结构
一个标准节点函数接收两个参数:
state:当前图的完整状态;config(可选):运行时配置,比如thread_id、自定义参数等。
函数返回一个字典,包含对状态的部分更新。在底层,函数会被包装为 RunnableLambda,自动获得批处理、异步、追踪调试等能力。
python
from langchain_core.runnables import RunnableConfig
from langgraph.graph import StateGraph, START
from langgraph.graph import END
# 初始化 StateGraph,状态类型为字典
graph = StateGraph(dict)
# 定义节点
def my_node(state: dict, config: RunnableConfig):
print("In node: ", config["configurable"]["user_id"])
return {"results": f"Hello, {state['input']}!"}
def my_other_node(state: dict):
return state
# 将节点添加到图中
graph.add_node("my_node", my_node)
graph.add_node("other_node", my_other_node)
# 连接节点以确保它们是可达的
graph.add_edge(START, "my_node")
graph.add_edge("my_node", "other_node")
graph.add_edge("other_node", END)
# 编译图
print(graph.compile())
特殊节点
START:虚拟入口节点,代表图的执行起点,用于指定第一个实际执行的节点;
python
from langgraph.graph import START
graph.add_edge(START, "my_node")
graph.add_edge("my_node", "other_node")
END:虚拟终点节点,代表图执行终止;
python
from langgraph.graph import END
graph.add_edge("other_node", END)
ToolNode:预构建工具节点,自动处理 LLM 的工具调用请求,执行对应工具函数并返回结果。
4. 边(Edges):工作流的路由规则
边决定了图的执行顺序与分支逻辑,是实现条件判断、循环、并行的关键。
| 边类型 | 作用 | 适用场景 |
|---|---|---|
| 普通边 | 固定从一个节点跳转到下一个节点 | 线性顺序执行的步骤 |
| 条件边 | 根据路由函数的返回值动态选择下一个节点 | 分支判断、循环终止条件 |
| 入口点 | 从 START 到首个节点的固定路径 | 单一入口的工作流 |
| 条件入口点 | 根据状态动态选择起始节点 | 不同输入走不同初始化逻辑 |
条件边是实现代理循环的核心。以最经典的 ReAct 代理为例:
python
from typing import Literal
def should_continue(state) -> Literal["tools", END]:
last_message = state["messages"][-1]
if last_message.tool_calls:
return "tools" # 需要调用工具,继续循环
return END # 无需工具,结束执行
当一个节点有多个输出边时,所有目标节点会在下一个超级步骤中并行执行,天然支持多任务并发处理。
二、进阶能力:持久化与人机交互
如果说图 + 状态 + 节点 + 边构成了代理的骨架,那么持久化与人机交互则让 LangGraph 具备了企业级应用的落地能力。
1. 持久化(Persistence):基于检查点的状态记忆
LangGraph 内置了检查点(Checkpoint)持久化层,在每个超级步骤结束后自动保存完整的状态快照。
核心能力
- 对话记忆 :通过
thread_id隔离不同会话,多次调用共享同一份状态,实现多轮对话上下文保留; - 错误恢复:执行中断后可从最近检查点继续,无需从头开始;
- 时间旅行:支持回溯到历史任意步骤,重放或修改后续执行路径。
最简单的持久化实现是使用内存检查点 MemorySaver:
python
from langgraph.checkpoint.memory import MemorySaver
memory = MemorySaver()
app = workflow.compile(checkpointer=memory)
# 相同 thread_id 会复用历史状态
config = {"configurable": {"thread_id": "conv-001"}}
app.invoke({"messages": [("user", "你好,我叫小明")]}, config)
app.invoke({"messages": [("user", "我叫什么名字?")]}, config)
生产环境中可以替换为 SQLite、PostgreSQL 等持久化存储,实现状态的跨进程、跨服务共享。
2. 人机交互(Human-in-the-Loop):断点与人工干预
在敏感业务场景中,代理的关键操作需要人工审核确认。LangGraph 通过断点(Breakpoints)机制原生支持这一模式。

断点的使用
在编译图时通过 interrupt_before 或 interrupt_after 指定断点节点,图执行到对应位置时会自动暂停,等待人工介入:
python
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import MemorySaver
from IPython.display import Image, display
class State(TypedDict):
input: str
def step_1(state):
print("---Step 1---")
pass
def step_2(state):
print("---Step 2---")
pass
def step_3(state):
print("---Step 3---")
pass
builder = StateGraph(State)
builder.add_node("step_1", step_1)
builder.add_node("step_2", step_2)
builder.add_node("step_3", step_3)
builder.add_edge(START, "step_1")
builder.add_edge("step_1", "step_2")
builder.add_edge("step_2", "step_3")
builder.add_edge("step_3", END)
# Set up memory
memory = MemorySaver()
# Add
graph = builder.compile(checkpointer=memory, interrupt_before=["step_3"])
# 将生成的图片保存到文件
graph_png = graph.get_graph().draw_mermaid_png()
with open("breakpoints_case.png", "wb") as f:
f.write(graph_png)
# Input
initial_input = {"input": "hello world"}
# Thread
thread = {"configurable": {"thread_id": "1"}}
# 运行graph,直到第一次中断
for event in graph.stream(initial_input, thread, stream_mode="values"):
print(event)
user_approval = input("Do you want to go to Step 3? (yes/no): ")
if user_approval.lower() == "yes":
# If approved, continue the graph execution
for event in graph.stream(None, thread, stream_mode="values"):
print(event)
else:
print("Operation cancelled by user.")
断点完全构建在检查点之上,暂停时状态已完整保存,恢复时从断点处继续,非常适合审批流程、敏感操作确认、代理行为纠偏等场景。

{'input': 'hello world'}
---Step 1---
---Step 2---
三、典型代理架构实战
基于 LangGraph 的基础能力,我们可以构建多种经典的代理架构,应对不同复杂度的业务需求。
1. 多代理协作系统:分而治之解决复杂任务
单个代理的工具承载能力与领域专业性有限,面对跨领域复杂任务时,分而治之的多代理协作是更优方案。

架构设计
以 "数据调研 + 图表生成" 场景为例:
- 研究代理(Researcher):配备搜索工具,负责检索数据、整理事实信息;
- 图表生成代理(Chart Generator):配备 Python 执行工具,负责将数据可视化为图表;
- 工具节点:统一处理所有工具调用,执行完成后返回给发起代理;
- 路由逻辑 :代理调用工具则走工具节点,输出
FINAL ANSWER则终止,否则流转到下一个代理继续协作。
状态中除了消息列表,还会记录 sender 字段,确保工具执行结果能准确返回给对应的发起代理。
这种模式的优势在于:每个代理只专注于自己的领域,系统提示更聚焦,工具集更精简,准确率与执行效率都高于全能型单代理。
python
# ====================== 导入全部依赖 ======================
import operator
import functools
from typing import Annotated, Sequence, TypedDict, Literal
from langchain_core.messages import (
BaseMessage,
HumanMessage,
AIMessage,
ToolMessage,
)
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.graph import END, StateGraph, START
from langgraph.prebuilt import ToolNode
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_experimental.utilities import PythonREPL
# ====================== 1. 定义工具 ======================
# 全网搜索工具
tavily_tool = TavilySearchResults(max_results=5)
# Python代码执行工具(绘图专用,注意本地代码执行风险)
repl = PythonREPL()
@tool
def python_repl(
code: Annotated[str, "用于生成图表的Python绘图代码,需要print输出结果"]
):
"""执行Python代码绘制可视化图表,生成折线/柱状图等,输出会展示给用户"""
try:
result = repl.run(code)
except BaseException as e:
return f"代码执行失败,错误信息:{repr(e)}"
result_str = f"代码执行成功:\n```python\n{code}\n```\n运行输出:{result}"
return result_str + "\n\n任务完成请输出 FINAL ANSWER"
# 工具集合
tools = [tavily_tool, python_repl]
# ====================== 2. 通用代理创建工厂函数 ======================
def create_agent(llm, tools, system_message: str):
"""
创建专家代理,返回可绑定工具的Runnable
:param llm: 大模型实例
:param tools: 代理可用工具列表
:param system_message: 代理专属角色提示词
:return: 绑定工具的提示链
"""
prompt = ChatPromptTemplate.from_messages([
(
"system",
"你是多代理协作系统中的AI专家,和其他助手分工协作完成复杂任务。"
"优先使用提供工具获取真实数据,无法独立完成就交给其他专家。"
"最终完整结果前必须添加【FINAL ANSWER】标识,系统识别后终止流程。"
"可用工具列表:{tool_names}\n额外角色要求:{system_message}",
),
MessagesPlaceholder(variable_name="messages"),
])
prompt = prompt.partial(system_message=system_message)
prompt = prompt.partial(tool_names=", ".join([tool.name for tool in tools]))
return prompt | llm.bind_tools(tools)
# ====================== 3. 定义全局状态 ======================
class AgentState(TypedDict):
# 全局消息列表,使用operator.add实现追加合并
messages: Annotated[Sequence[BaseMessage], operator.add]
# 记录上一个代理名称,工具执行后原路返回对应专家
sender: str
# ====================== 4. 封装代理节点函数 ======================
def agent_node(state, agent, name):
"""
封装代理执行逻辑,统一格式化输出消息并记录发送者
"""
result = agent.invoke(state)
# 工具消息无需修改,LLM输出包装为带代理名称的AIMessage
if isinstance(result, ToolMessage):
pass
else:
result = AIMessage(**result.dict(exclude={"type", "name"}), name=name)
return {
"messages": [result],
"sender": name,
}
# ====================== 5. 初始化大模型、创建专家代理 ======================
llm = ChatOpenAI(model="gpt-4o", temperature=0)
# 研究员代理:负责搜索行业市场真实数据
research_agent = create_agent(
llm,
[tavily_tool],
system_message="你是行业数据研究员,只负责搜索全球行业市场规模、年度统计数据,收集完整年份数值,不要绘图。",
)
research_node = functools.partial(agent_node, agent=research_agent, name="Researcher")
# 图表生成代理:接收数据,编写matplotlib绘图代码
chart_agent = create_agent(
llm,
[python_repl],
system_message="你是数据可视化工程师,仅接收整理好的年度数据,编写完整matplotlib代码生成折线图,不要搜索数据。",
)
chart_node = functools.partial(agent_node, agent=chart_generator)
# 统一工具执行节点
tool_node = ToolNode(tools)
# ====================== 6. 路由逻辑 ======================
def router(state) -> Literal["call_tool", "__end__", "continue"]:
"""
全局路由函数,控制图流转逻辑:
1. LLM调用工具 → 进入工具执行节点
2. 输出包含FINAL ANSWER → 直接结束流程
3. 无工具调用、未完成 → 切换另一个专家代理
"""
last_msg = state["messages"][-1]
# 判断是否需要调用工具
if last_msg.tool_calls:
return "call_tool"
# 判断任务是否完成
if "FINAL ANSWER" in last_msg.content:
return "__end__"
# 切换协作代理
return "continue"
# ====================== 7. 构建状态图、配置所有节点与边 ======================
# 初始化状态图
workflow = StateGraph(Agent)
# 添加两个专家节点 + 工具节点
workflow.add_node("Researcher", research_node)
workflow.add_node("chart_generator", chart_node)
workflow.add_node("call_tool", tool_node)
# 研究员节点条件分支
workflow.add_conditional_edges(
source="Researcher",
path=router,
path_map={
"continue": "chart_generator",
"call_tool": "call_tool",
"__end__": END
}
)
# 绘图专家节点条件分支
workflow.add_conditional_edges(
source="chart_generator",
path=router,
path_map={
"continue": "Researcher",
"call_tool": "call_tool",
"__end__": END
}
)
# 工具执行完成后,原路返回调用它的代理
workflow.add_conditional_edges(
source="call_tool",
path=lambda state: state["sender"],
path_map={
"Researcher": "Researcher",
"chart_generator": "chart_generator"
}
)
# 设置图入口:先启动研究员
workflow.add_edge(START, "Researcher")
# 编译可执行图
graph = workflow.compile()
# (可选)导出流程图图片
# graph_png = graph.get_graph().draw_mermaid_png()
# with open("multi_agent_workflow.png", "wb") as f:
# f.write(graph_png)
# ====================== 8. 运行多代理协作任务 ======================
if __name__ == "__main__":
# 用户需求:获取全球AI软件市场数据并绘制折线图
user_query = HumanMessage(
content="查询2018-2022全球AI软件市场规模完整数据,整理后生成年度增长折线图,完成后给出FINAL ANSWER"
)
# 执行图流,限制最大递归步数防止无限循环
stream_events = graph.stream(
{"messages": [user_query]},
{"recursion_limit": 150}
)
# 逐步骤打印协作日志
for event in stream_events:
print("=" * 60)
print(event)
print("=" * 60 + "\n")

2. 计划执行代理:先规划后执行的长任务范式
ReAct 风格的代理采用 "思考 - 行动" 一步一迭代的模式,适合简单任务,但面对长链路、多步骤的复杂目标时容易迷失方向。Plan-and-Execute 模式则先做全局规划,再分步执行,并根据执行结果动态调整计划。

核心节点与工作流
- 规划器(Planner):接收用户目标,生成结构化的多步骤执行计划;
- 执行器(Agent):按顺序执行计划中的每一步,调用工具完成具体任务;
- 重规划器(Replanner):根据已完成步骤的结果,评估剩余计划是否合理,调整计划或直接输出最终答案。
整个流程形成 "规划 → 执行 → 重规划 → 再执行" 的闭环,直到任务完成。
与 ReAct 相比,Plan-and-Execute 的优势非常明显:
- 具备明确的长期规划能力,不会在执行中偏离目标;
- 可以分层使用模型:规划用大模型保证质量,执行用小模型降低成本;
- 执行过程可解释性强,用户能清晰看到当前进度与后续步骤。
python
# ====================== 全部依赖导入 ======================
import operator
from typing import Annotated, List, Tuple, TypedDict, Union, Literal
from langchain import hub
from langchain_openai import ChatOpenAI
from langchain_community.tools.tavily_search import TavilySearchResults
from langgraph.prebuilt import create_react_agent
from langgraph.graph import StateGraph, START, END
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.messages import HumanMessage
# ====================== 1. 初始化搜索工具 ======================
# 全网搜索工具,用于子任务查询
tools = [TavilySearchResults(max_results=1)]
# ====================== 2. 创建底层ReAct执行代理 ======================
# 拉取官方ReAct提示词模板
prompt = hub.pull("wfh/react-agent-executor")
# 初始化大模型
llm = ChatOpenAI(model="gpt-4o", temperature=0)
# 创建ReAct执行器:负责执行单一步骤子任务
agent_executor = create_react_agent(llm, tools, messages_modifier=prompt)
# 测试ReAct代理
# test_res = agent_executor.invoke({"messages": [HumanMessage("2023美网男单冠军是谁?")]})
# print(test_res["messages"][-1].content)
# ====================== 3. 定义全局状态结构 ======================
class PlanExecute(TypedDict):
input: str # 用户原始问题
plan: List[str] # 分步任务计划
past_steps: Annotated[List[Tuple], operator.add] # 已完成步骤+结果
response: str # 最终答案
# ====================== 4. Pydantic结构化输出模型 ======================
# 规划输出:分步任务列表
class Plan(BaseModel):
"""拆解后的分步执行计划"""
steps: List[str] = Field(description="有序独立子任务,无多余步骤,包含全部必要信息")
# 重规划输出:要么返回答案,要么更新计划
class Response(BaseModel):
"""任务完成后的最终回答"""
response: str
class Act(BaseModel):
"""重规划动作:输出最终答案 / 新计划"""
action: Union[Response, Plan] = Field(
description="任务完成返回Response;仍需查询则返回新Plan"
)
# ====================== 5. 规划器 & 重规划器 ======================
# 初始规划Prompt:接收用户问题生成完整分步计划
planner_prompt = ChatPromptTemplate.from_messages([
("system", """针对用户目标生成极简分步计划,仅保留必要任务,每一步信息完整无遗漏,最后一步输出最终答案。"""),
("placeholder", "{messages}"),
])
planner = planner_prompt | llm.with_structured_output(Plan)
# 动态重规划Prompt:结合历史步骤更新剩余任务
replanner_prompt = ChatPromptTemplate.from_template("""
用户原始目标:{input}
当前原始计划:{plan}
已完成步骤及结果:{past_steps}
根据已完成内容更新计划:
1. 若信息充足可直接回答,返回最终Response;
2. 信息不足仅保留未完成新任务,不要重复已执行步骤。
""")
replanner = replanner_prompt | llm.with_structured_output(Act)
# ====================== 6. 图节点定义 ======================
def plan_step(state: PlanExecute):
"""节点1:初始生成任务计划"""
plan_res = planner.invoke({"messages": [HumanMessage(state["input"])]})
return {"plan": plan.steps}
def execute_step(state: PlanExecute):
"""节点2:执行当前计划第一步子任务"""
plan = state["plan"]
current_task = plan[0]
task_prompt = f"执行以下计划第一步任务:{current_task}"
# 调用ReAct代理执行子任务
agent_out = agent_executor.invoke({"messages": [HumanMessage(task_prompt)]})
task_result = agent_out["messages"][-1].content
# 将当前任务+结果存入历史步骤
return {"past_steps": [(current_task, task_result)]}
def replan_step(state: PlanExecute):
"""节点3:执行完子任务后,重新评估、更新计划"""
act_out = replanner.invoke(state)
if isinstance(act.action, Response):
# 可直接输出最终答案
return {"response": act.action.response}
else:
# 更新剩余待执行计划
return {"plan": act.action.steps}
def should_end(state: PlanExecute) -> Literal["agent", END]:
"""路由判断:存在最终response则结束,否则继续执行子任务"""
if state.get("response"):
return END
return "agent"
# ====================== 7. 构建、编译状态图 ======================
# 初始化图
workflow = StateGraph(PlanExecute)
# 添加全部业务节点
workflow.add_node("planner", plan_step)
workflow.add_node("agent", execute_step)
workflow.add_node("replan", replan_step)
# 固定流程边
workflow.add_edge(START, "planner")
workflow.add_edge("planner", "agent")
workflow.add_edge("agent", "replan")
# 条件路由:重规划后判断是否结束
workflow.add_conditional_edges("replan", should_end)
# 编译生成可运行图
app = workflow.compile()
# 导出流程图(可选,需安装mermaid依赖)
# with open("plan_graph.png", "wb") as f:
# f.write(app.get_graph().draw_mermaid_png())
# ====================== 8. 运行入口 ======================
if __name__ == "__main__":
# 任务配置:限制最大循环防止死循环
run_config = {"recursion_limit": 50}
# 用户提问
user_query = {
"input": "2024巴黎奥运会男子100米自由泳冠军是谁?他的家乡在哪里?用中文完整回答"
}
# 流式打印每一步执行日志
for event in app.stream(user_query, config=run_config):
print("=" * 70)
print(event)
print("=" * 70 + "\n")
四、总结与展望
LangGraph 的出现,标志着大模型应用开发从提示词工程驱动进入了流程编排驱动的新阶段。它没有停留在对代理行为的黑盒封装,而是提供了一套底层、透明、可精细控制的图编程范式,让开发者可以像搭积木一样构建任意复杂度的代理系统。
从核心价值来看,LangGraph 解决了代理开发的三个核心痛点:
- 循环支持:天然的图结构让 "思考 - 行动" 循环、多轮迭代成为一等公民;
- 可控性:状态与流程完全白盒,每一步执行都可追溯、可干预;
- 持久性:内置检查点机制,轻松实现对话记忆、断点续跑、人机协同。
无论是构建单工具智能助手、复杂业务工作流,还是多角色协作的智能体系统,LangGraph 都提供了坚实的架构基础。随着大模型能力的持续提升,基于图结构的智能代理必将成为企业级 AI 应用的主流形态,而 LangGraph 正是这条技术路径上不可或缺的核心工具。