【大模型实战笔记 8】深入理解 LangGraph:构建可持久化、多智能体的 LLM 工作流

《深入理解 LangGraph:构建可持久化、多智能体的 LLM 工作流》

摘要:本文系统解析 LangGraph 框架的核心设计理念与工程实践,详解其图式架构、状态管理机制及高级应用场景,包括持久化内存、人机协同、多智能体系统与规划执行模式,助你构建复杂可靠的 LLM 应用。

  • [《深入理解 LangGraph:构建可持久化、多智能体的 LLM 工作流》](#《深入理解 LangGraph:构建可持久化、多智能体的 LLM 工作流》)
    • [一、引言:LangGraph 的诞生背景与工程价值](#一、引言:LangGraph 的诞生背景与工程价值)
    • [二、LangGraph 核心组件:图、状态、节点与边](#二、LangGraph 核心组件:图、状态、节点与边)
      • [2.1 Graph(图):工作流的骨架与执行引擎](#2.1 Graph(图):工作流的骨架与执行引擎)
      • [2.2 State(状态):工作流的记忆与上下文载体](#2.2 State(状态):工作流的记忆与上下文载体)
        • [2.2.1 模式(Schema)定义](#2.2.1 模式(Schema)定义)
        • [2.2.2 归约器(Reducers)机制](#2.2.2 归约器(Reducers)机制)
      • [2.3 Nodes(节点):工作流的执行单元](#2.3 Nodes(节点):工作流的执行单元)
      • [2.4 Edges(边):工作流的控制流](#2.4 Edges(边):工作流的控制流)
    • [三、持久化与人机交互:构建生产级 LLM 应用](#三、持久化与人机交互:构建生产级 LLM 应用)
      • [3.1 Persistence(持久化):跨会话记忆与错误恢复](#3.1 Persistence(持久化):跨会话记忆与错误恢复)
        • [3.1.1 检查点实现原理](#3.1.1 检查点实现原理)
        • [3.1.2 线程(Thread)概念](#3.1.2 线程(Thread)概念)
        • [3.1.3 完整示例:带持久记忆的天气查询代理](#3.1.3 完整示例:带持久记忆的天气查询代理)
      • [3.2 Human-in-the-loop(人机交互):关键决策的人工审核](#3.2 Human-in-the-loop(人机交互):关键决策的人工审核)
        • [3.2.1 断点机制原理](#3.2.1 断点机制原理)
        • [3.2.2 交互流程详解](#3.2.2 交互流程详解)
    • 四、高级应用场景:多智能体系统与规划执行
      • [4.1 Multi-Agent Systems(多智能体系统)](#4.1 Multi-Agent Systems(多智能体系统))
        • [4.1.1 案例:研究者与图表生成器协作](#4.1.1 案例:研究者与图表生成器协作)
      • [4.2 Plan-and-Execute(规划与执行)模式](#4.2 Plan-and-Execute(规划与执行)模式)
        • [4.2.1 状态设计](#4.2.1 状态设计)
        • [4.2.2 规划与重规划机制](#4.2.2 规划与重规划机制)
    • 五、总结与工程实践
      • [5.1 核心价值与定位](#5.1 核心价值与定位)
      • [5.2 最佳工程实践](#5.2 最佳工程实践)
      • [5.3 未来演进方向](#5.3 未来演进方向)

一、引言:LangGraph 的诞生背景与工程价值

在 LLM 应用开发领域,传统框架如 LangChain 的 AgentExecutor 面对复杂场景时往往力不从心:缺乏循环能力、状态管理粗糙、难以实现多角色协作。当我们的应用需要跨多轮保持对话上下文在循环中调用工具在关键操作前等待人工审核 ,或多个专业 Agent 协作解决复杂问题时,线性链式结构很快会变得难以维护和调试。

LangGraph 的出现并非偶然,它由 LangChain Inc(LangChain 创建者)打造,设计灵感源自 Google Pregel (图计算模型)与 Apache Beam (数据流系统),同时在接口设计上借鉴了 NetworkX 的图论 API。这种设计哲学使 LangGraph 成为一个"底层但强大"的框架,如官方文档所述:

"LangGraph 允许您定义涉及循环的流程,这对于大多数代理架构至关重要。作为一种非常底层的框架,它提供了对应用程序的流程和状态的精细控制,这对创建可靠的代理至关重要。此外,LangGraph 包含内置的持久性,可以实现高级的'人机交互'和内存功能。"

本文将从工程视角,结合官方设计文档与实战经验,系统剖析 LangGraph 的架构精髓与应用场景,助你跨越从"简单 Agent"到"工程级智能系统"的关键门槛。

二、LangGraph 核心组件:图、状态、节点与边

LangGraph 将智能体工作流建模为一个有状态的图 ,其能力构建于四个核心抽象之上:Graph、State、Node、Edge 。理解这些组件是掌握 LangGraph 的基础。

2.1 Graph(图):工作流的骨架与执行引擎

在 LangGraph 中,StateGraph 是最核心的图类型,它由用户定义的状态对象参数化,负责协调节点执行和状态流转。一个典型的构建流程如下:

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

# 定义状态模式
class MyState(TypedDict):
    messages: list
    data: dict

# 创建状态图构建器
builder = StateGraph(MyState)

# 添加节点和边
builder.add_node("step_1", step_1_function)
builder.add_edge(START, "step_1")
builder.add_edge("step_1", END)

# 编译图(关键步骤!)
graph = builder.compile()

编译过程是 LangGraph 的重要环节,它:

  • 验证图结构完整性(无孤立节点、有明确入口/出口)
  • 构建内部消息通道(channels)网络
  • 注册节点和边的执行逻辑
  • 准备检查点和断点机制
  • 将图转换为 LangChain Runnable,支持标准调用接口(.invoke().stream().batch()

编译后的图对象包含复杂的内部结构,例如:

复制代码
nodes={
    '__start__': PregelNode(...),
    'my_node': PregelNode(...)
}
channels={
    '__root__': <LastValue object>,
    '__start__': <EphemeralValue object>,
    'my_node': <EphemeralValue object>,
    'start:my_node': <EphemeralValue object>
}

这一结构使 LangGraph 能够高效管理节点执行顺序和状态流转,为复杂工作流提供底层支持。

2.2 State(状态):工作流的记忆与上下文载体

状态是 LangGraph 中最核心的概念,它表示应用程序在任何给定时刻的完整快照。每次图执行都会创建一个状态,该状态在节点间传递,每个节点执行后使用其返回值更新此内部状态。

2.2.1 模式(Schema)定义

LangGraph 支持两种主要的状态模式定义方式:

TypedDict 方式(推荐)

python 复制代码
from typing import Annotated, TypedDict
from langgraph.graph.message import add_messages
from langchain_core.messages import BaseMessage

class State(TypedDict):
    messages: Annotated[list[BaseMessage], add_messages]
    sender: str
    context: dict

Pydantic BaseModel 方式(支持默认值和验证)

python 复制代码
from pydantic import BaseModel, Field

class State(BaseModel):
    messages: list[BaseMessage] = Field(default_factory=list)
    sender: str = ""
    context: dict = Field(default_factory=dict)
2.2.2 归约器(Reducers)机制

归约器是理解状态更新的关键。每个状态键可指定独立的归约函数,决定如何将新值与旧值合并。LangGraph 提供多层次的归约策略。

默认归约器:简单覆盖

python 复制代码
# 初始状态
state = {"foo": 1, "bar": ["hi"]}

# 节点1返回更新
node1_update = {"foo": 2}  # 应用后: {"foo": 2, "bar": ["hi"]}

# 节点2返回更新
node2_update = {"bar": ["bye"]}  # 应用后: {"foo": 2, "bar": ["bye"]}

自定义归约器 :如 add_messages 用于消息列表

python 复制代码
class State(TypedDict):
    messages: Annotated[list[BaseMessage], add_messages]

当节点返回 {"messages": [new_message]} 时,add_messages 会将新消息追加到现有列表,而非覆盖整个列表。这种设计使对话上下文得以持续积累,是构建多轮对话系统的基础。

2.3 Nodes(节点):工作流的执行单元

节点是执行具体工作的 Python 函数,接收状态为输入,返回更新后的状态。在 LangGraph 中,有两种特殊节点:

START 节点:虚拟入口点

python 复制代码
from langgraph.graph import START
graph.add_edge(START, "my_first_node")

END 节点:虚拟终端节点

python 复制代码
from langgraph.graph import END
graph.add_edge("last_node", END)

节点函数遵循特定签名,可接收当前状态和配置参数:

python 复制代码
from langchain_core.runnables import RunnableConfig

def my_node(state: dict, config: RunnableConfig):
    # 从配置中获取可定制参数
    user_id = config["configurable"]["user_id"]
    print(f"Processing for user: {user_id}")
    
    # 更新状态
    return {
        "results": f"Hello, {state['input']}!",
        "processed_by": "my_node"
    }

在底层,LangGraph 将普通函数转换为 RunnableLambda,自动添加批处理、异步支持、跟踪和调试能力,大幅提升开发体验。

2.4 Edges(边):工作流的控制流

边定义了节点间的执行顺序和条件分支,是工作流控制逻辑的核心。LangGraph 支持四种主要类型的边:

普通边:直接从一个节点到另一个节点

python 复制代码
graph.add_edge("node_a", "node_b")

条件边:基于函数返回值决定下一个节点

python 复制代码
def routing_function(state) -> Literal["node_b", "node_c"]:
    return "node_b" if state["flag"] else "node_c"

graph.add_conditional_edges("node_a", routing_function)

条件映射:将路由函数输出映射到节点名称

python 复制代码
graph.add_conditional_edges(
    "node_a", 
    routing_function,
    {True: "node_b", False: "node_c"}
)

入口点与条件入口点:定义工作流起点

python 复制代码
# 固定入口点
graph.add_edge(START, "first_node")

# 条件入口点
def entry_router(state):
    return "research_node" if "data" in state["query"] else "chart_node"

graph.add_conditional_edges(START, entry_router)

并行执行机制

当一个节点有多个输出边时,目标节点将在下一个超级步骤(superstep)中并行执行:

python 复制代码
# 此设置将使node_b和node_c并行执行
graph.add_conditional_edges("node_a", lambda s: ["node_b", "node_c"])

超级步骤(Superstep)概念

LangGraph 的执行模型基于"超级步骤"概念,受 Google 的 Pregel 系统启发:

  • 每个超级步骤包含一组可以并行执行的节点
  • 节点执行完毕后,根据输出决定下一超级步骤的节点
  • 当没有活跃节点且无消息传输时,执行终止

三、持久化与人机交互:构建生产级 LLM 应用

3.1 Persistence(持久化):跨会话记忆与错误恢复

检查点机制是 LangGraph 区别于其他框架的核心特性,通过在每个超级步骤后保存状态,实现一系列高级功能。

3.1.1 检查点实现原理

LangGraph 提供 MemorySaver 作为默认的内存中检查点实现:

python 复制代码
from langgraph.checkpoint.memory import MemorySaver

memory = MemorySaver()
graph = workflow.compile(checkpointer=memory)

当启用检查点时,LangGraph 在每个节点执行后:

  1. 捕获当前完整状态
  2. 为状态生成唯一标识(thread_id)
  3. 将状态存储在检查点存储中
  4. 记录执行历史和元数据
3.1.2 线程(Thread)概念

线程是持久化的关键抽象,表示一个会话或工作流实例:

python 复制代码
config = {"configurable": {"thread_id": "42"}}

相同 thread_id 的调用共享相同状态历史,实现跨请求记忆。不同 thread_id 则启动全新会话。

3.1.3 完整示例:带持久记忆的天气查询代理
python 复制代码
# 定义状态类
class State(TypedDict):
    messages: Annotated[list, add_messages]

# 初始化工具
@tool
def search(query: str):
    """模拟一个搜索工具"""
    if "上海" in query.lower() or "Shanghai" in query.lower():
        return "现在30度,有雾."
    return "现在是35度,阳光明媚。"

# 创建工具节点
tool_node = ToolNode([search])

# 初始化模型
model = ChatOpenAI(model="gpt-4o", temperature=0).bind_tools([search])

# 定义节点函数
def call_model(state: State):
    response = model.invoke(state["messages"])
    return {"messages": [response]}

# 路由逻辑
def should_continue(state: State) -> Literal["tools", END]:
    last_message = state["messages"][-1]
    if last_message.tool_calls:
        return "tools"
    return END

# 构建工作流
workflow = StateGraph(State)
workflow.add_node("agent", call_model)
workflow.add_node("tools", tool_node)
workflow.set_entry_point("agent")
workflow.add_conditional_edges("agent", should_continue)
workflow.add_edge("tools", "agent")

# 添加持久化
memory = MemorySaver()
app = workflow.compile(checkpointer=memory)

# 交互示例
config = {"configurable": {"thread_id": "42"}}
response1 = app.invoke({"messages": [HumanMessage(content="上海的天气怎么样?")]}, config)
response2 = app.invoke({"messages": [HumanMessage(content="我问的那个城市?")]}, config)

print(response1["messages"][-1].content)  # "上海现在的天气是30度,有雾。"
print(response2["messages"][-1].content)  # "你问的是上海的天气。上海现在的天气是30度,有雾。"

通过共享相同的 thread_id,系统在两次查询间保留完整对话上下文,实现真正连贯的多轮对话。这一机制使 LangGraph 成为构建对话型 Agent 的理想选择。

3.2 Human-in-the-loop(人机交互):关键决策的人工审核

在许多场景中,LLM 的决策需要人类审核,特别是在处理敏感操作时。LangGraph 通过断点机制实现了无缝的人机交互。

3.2.1 断点机制原理

断点允许在特定节点执行前或后暂停工作流,等待人工干预:

python 复制代码
graph = builder.compile(
    checkpointer=memory,
    interrupt_before=["critical_action"]  # 在执行前中断
)
3.2.2 交互流程详解
  1. 初始执行:图执行直到断点
  2. 人工审核:检查当前状态,决定是否继续
  3. 恢复执行 :传入 None 继续流程
  4. 状态修改:在恢复前修改状态

完整断点示例

python 复制代码
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)

# 设置断点
memory = MemorySaver()
graph = builder.compile(checkpointer=memory, interrupt_before=["step_3"])

# 初始执行
initial_input = {"input": "hello world"}
thread = {"configurable": {"thread_id": "1"}}
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":
    # 恢复执行
    for event in graph.stream(None, thread, stream_mode="values"):
        print(event)
else:
    print("Operation cancelled by user.")

这种能力在金融交易审批、医疗诊断辅助、法律文档生成等高风险场景中至关重要,为 LLM 应用提供了必要的安全网。

四、高级应用场景:多智能体系统与规划执行

4.1 Multi-Agent Systems(多智能体系统)

单一 Agent 在面对复杂任务时往往力不从心,而多 Agent 协作可以将问题分解,各司其职,大幅提升解决复杂问题的能力。

4.1.1 案例:研究者与图表生成器协作
python 复制代码
class AgentState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], operator.add]
    sender: str

# 创建专用 Agent
research_agent = create_agent(
    llm, 
    [tavily_tool], 
    system_message="你应该提供准确的数据供chart_generator使用,确保数据完整且格式正确。"
)
chart_agent = create_agent(
    llm,
    [python_repl],
    system_message="你负责根据提供的数据生成Python代码绘制图表,任何展示的图表都将对用户可见。"
)

# 创建 Agent 节点
research_node = functools.partial(agent_node, agent=research_agent, name="Researcher")
chart_node = functools.partial(agent_node, agent=chart_agent, name="chart_generator")

# 路由逻辑
def router(state) -> Literal["call_tool", "__end__", "continue"]:
    last_message = state["messages"][-1]
    if last_message.tool_calls:
        return "call_tool"
    if "FINAL ANSWER" in last_message.content:
        return "__end__"
    return "continue"

# 构建协作图
workflow = StateGraph(AgentState)
workflow.add_node("Researcher", research_node)
workflow.add_node("chart_generator", chart_node)
workflow.add_node("call_tool", tool_node)

# 添加条件边
workflow.add_conditional_edges(
    "Researcher",
    router, 
    {"continue": "chart_generator", "call_tool": "call_tool", "__end__": END}
)
workflow.add_conditional_edges(
    "chart_generator", 
    router, 
    {"continue": "Researcher", "call_tool": "call_tool", "__end__": END}
)

# 工具调用路由
workflow.add_conditional_edges(
    "call_tool",
    lambda x: x["sender"],
    {"Researcher": "Researcher", "chart_generator": "chart_generator"}
)

# 设置入口点
workflow.add_edge(START, "Researcher")
graph = workflow.compile()

# 调用示例
events = graph.stream({
    "messages": [HumanMessage(
        content="获取过去5年AI软件市场规模,然后绘制一条折线图。一旦你编写好代码,完成任务。"
    )],
}, {"recursion_limit": 150})

for s in events:
    print(s)
    print("----")

通信机制详解

  1. 用户输入首先路由给 Researcher
  2. Researcher 搜集数据,通过消息传递给 chart_generator
  3. chart_generator 生成图表代码,可能需要调用工具
  4. 工具结果路由回原始调用者
  5. 任一 Agent 可在消息中包含 "FINAL ANSWER" 标记结束流程

这种架构使系统能够处理需要多专业知识的任务,如市场分析与数据可视化,大幅提升解决复杂问题的能力。

4.2 Plan-and-Execute(规划与执行)模式

传统 ReAct 模式一次只思考一步,而规划执行模式先制定完整计划,再逐步执行,更适合复杂任务。

4.2.1 状态设计
python 复制代码
class PlanExecute(TypedDict):
    input: str                      # 用户原始输入
    plan: List[str]                 # 待执行步骤列表
    past_steps: Annotated[List[Tuple], operator.add]  # (步骤, 结果)元组列表
    response: str                   # 最终响应
4.2.2 规划与重规划机制

规划步骤

python 复制代码
class Plan(BaseModel):
    """未来要执行的计划"""
    steps: List[str] = Field(description="需要执行的不同步骤,应该按顺序排列")

planner_prompt = ChatPromptTemplate.from_messages([
    ("system", """对于给定的目标,提出一个简单的逐步计划。这个计划应该包含独立的任务,如果正确执行将得出正确的答案。不要添加任何多余的步骤。最后一步的结果应该是最终答案。确保每一步都有所有必要的信息-不要跳过步骤。"""),
    ("placeholder", "{messages}"),
])

planner = planner_prompt | ChatOpenAI(model="gpt-4o", temperature=0).with_structured_output(Plan)

完整工作流构建

python 复制代码
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,  # 决定是否结束或继续
    {"agent": "agent", "__end__": END}
)

app = workflow.compile()

# 调用示例
inputs = {"input": "2024年巴黎奥运会100米自由泳决赛冠军的家乡是哪里?请用中文答复"}
async for event in app.astream(inputs, config={"recursion_limit": 50}):
    for k, v in event.items():
        if k != "__end__":
            print(v)

执行流程

  1. 规划器生成计划:["查找2024年巴黎奥运会100米自由泳决赛冠军的名字", "查找该冠军的家乡"]
  2. 执行器执行第一步,返回"潘展乐"
  3. 重规划器更新计划:["查找潘展乐的家乡"]
  4. 执行器执行第二步,返回"浙江温州"
  5. 重规划器判断任务完成,返回最终响应

五、总结与工程实践

5.1 核心价值与定位

LangGraph 代表了 LLM 应用开发范式的重大演进,其核心价值在于提供工程级控制能力,解决了传统 Agent 框架的固有局限:

  • 状态驱动架构:通过精细的状态管理与归约机制,实现复杂工作流的精确控制
  • 图式执行模型:支持循环、分支与并行执行,突破线性链式结构的局限
  • 生产级特性:内置持久化与人机协同能力,满足企业级应用的可靠性要求

不同于高层抽象框架,LangGraph 作为底层基础设施,提供了构建可靠、复杂 LLM 应用所需的原语与保障,使开发者能够将 Agent 系统从"原型"提升至"生产系统"。

5.2 最佳工程实践

在 LangGraph 项目实施中,遵循以下关键原则可显著提升系统可靠性与可维护性:

状态与节点设计

  • 保持状态最小化,仅保留必要上下文;为每个状态字段明确定义归约策略
  • 遵循单一职责原则设计节点,确保每个节点具有清晰的输入/输出契约
  • 优先使用纯函数实现节点逻辑,减少副作用,增强可测试性

生产环境部署

  • 启用检查点机制实现错误恢复与审计追踪,为关键操作配置断点
  • 采用分层线程ID策略(如 user_id:session_id),支持灵活的会话管理
  • 集成 LangSmith 进行全链路监控,捕获执行轨迹与性能指标

5.3 未来演进方向

随着 LLM 应用复杂度持续提升,LangGraph 生态将向以下方向演进:

  1. 工程化增强:可视化工作流设计器、分布式执行引擎、状态版本控制
  2. 自适应能力:基于执行反馈动态优化图结构,实现真正意义上的自适应工作流
  3. 企业级集成:与现有业务系统深度集成,支持事务性操作与合规性要求

LangGraph 不仅是一个技术框架,更是一种系统化思考复杂 AI 应用的新范式。它将 LLM 从"一次性推理引擎"转变为"持续演化的智能系统",为构建下一代企业级 AI 应用奠定了坚实基础。正如分布式系统通过状态机复制实现可靠性,LangGraph 通过有状态的图式执行,为 LLM 应用带来了工程化所需的确定性与可预测性。

工程箴言:在 LangGraph 中,复杂性不在于框架本身,而在于如何将业务问题分解为状态转换图。从最小可行工作流开始,逐步演进,让图结构成为你表达业务逻辑的清晰语言,而非复杂性的来源。

相关推荐
小二·2 小时前
AI工程化实战《二》:RAG 高级优化全解——从 HyDE 到 Self-RAG,打造高精度企业问答系统
人工智能·microsoft·机器学习
波比:)2 小时前
(概率)波利亚的罐子
笔记·数学
yuhaiqun19892 小时前
学AI Agent:从React模式到Plan框架,3条路径一次学透
人工智能·经验分享·笔记·react.js·机器学习·ai·aigc
智者知已应修善业2 小时前
【字符串提取3个整数求和】2024-2-11
c语言·c++·经验分享·笔记·算法
zhonghua8810162 小时前
spring ai alibab agent之ReactAgent深度解读
java·人工智能·spring
大模型教程.2 小时前
收藏级教程:ReAct模式详解,让大模型从回答问题到解决问题
前端·人工智能·机器学习·前端框架·大模型·产品经理·react
飞凌嵌入式2 小时前
AIoT出海背景下,嵌入式主控的国际认证之路与价值思考
大数据·人工智能·嵌入式硬件·区块链·嵌入式
Robot侠2 小时前
多模态大语言模型(Multimodal LLM)技术实践指南
人工智能·语言模型·自然语言处理·transformer·rag·多模态大模型
进阶的猪2 小时前
stm32 GPIO输出-使用固件库点亮LED灯 Q&A
c语言·笔记·stm32·单片机