LangGraph 原理深度解析:为什么它是目前最适合构建 Agent 的框架

LangGraph 原理深度解析:为什么它是目前最适合构建 Agent 的框架

很多人用 LangGraph 只是跟着教程跑通了 demo,但底层到底发生了什么并不清楚。本文从原理层面拆解 LangGraph 的核心设计,帮你真正理解它,而不只是会用它。


从一个问题出发

假设你要构建一个 AI Agent,它需要:

  1. 接收用户问题
  2. 判断是否需要查资料
  3. 如果需要,调用搜索工具
  4. 把搜索结果交给 LLM 继续推理
  5. 如果还不够,继续搜索;否则输出答案

用最朴素的写法,这是一堆嵌套的 if/elsewhile 循环。逻辑稍微复杂一点,代码就开始腐烂:状态传来传去、循环条件难以维护、加个新步骤要动好几处。

LangGraph 解决的正是这个问题。它把"Agent 的运行过程"抽象成一张有向图,用图的语言描述流程,让复杂的控制逻辑变得可读、可维护、可扩展。


核心抽象:图、状态、节点、边

LangGraph 的整个设计围绕四个概念展开。

State(状态)

State 是贯穿整个图的共享数据结构,用 Python 的 TypedDict 定义:

python 复制代码
from typing import TypedDict, Annotated
import operator

class AgentState(TypedDict):
    messages: Annotated[list, operator.add]  # 对话历史
    current_plan: str                         # 当前计划
    iteration_count: int                      # 已迭代次数

State 有几个关键特性:

不可变更新:节点函数不直接修改 state,而是返回一个"diff"(增量),LangGraph 负责将 diff 合并进当前 state。这和 Redux 的设计思路一致,让状态变更可追踪。

Reducer 机制Annotated[list, operator.add] 这个写法告诉 LangGraph,当多个节点同时更新 messages 字段时,用 operator.add(列表追加)而不是覆盖。这是 LangGraph 处理并发更新冲突的方式------每个字段可以有自己的合并策略。

python 复制代码
# 节点只需返回要更新的字段,不需要返回完整 state
def my_node(state: AgentState) -> dict:
    return {"messages": [new_message]}  # LangGraph 负责 merge

Node(节点)

节点是图中的计算单元,本质上就是一个 Python 函数:

python 复制代码
def call_llm(state: AgentState) -> dict:
    response = model.invoke(state["messages"])
    return {"messages": [response]}

节点可以是任何东西:LLM 调用、工具执行、数据转换、外部 API 请求。LangGraph 对节点内部的实现没有任何约束,你想怎么写就怎么写。

LangGraph 内置了一些常用节点,最常用的是 ToolNode,它自动解析 LLM 输出的 tool_calls,执行对应工具,并把结果包装成 ToolMessage 写回 state:

python 复制代码
from langgraph.prebuilt import ToolNode
tool_node = ToolNode(tools=[search, calculator])

Edge(边)

边定义了节点之间的流转关系,分两种:

固定边:A 执行完永远去 B。

python 复制代码
builder.add_edge("tools", "agent")

条件边:根据当前 state 决定去哪里,这是 LangGraph 实现分支和循环的关键。

python 复制代码
def should_continue(state: AgentState) -> str:
    last_msg = state["messages"][-1]
    if last_msg.tool_calls:
        return "tools"   # 去执行工具
    return END           # 结束

builder.add_conditional_edges("agent", should_continue)

should_continue 函数接收当前 state,返回一个字符串,LangGraph 根据这个字符串决定下一个节点。这个函数就是整个 Agent 的"大脑决策"------它完全由你控制,不依赖任何框架魔法。

Graph(图)

图是上述三个元素的容器,负责编排和执行:

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

builder = StateGraph(AgentState)
builder.add_node("agent", call_llm)
builder.add_node("tools", tool_node)
builder.set_entry_point("agent")
builder.add_conditional_edges("agent", should_continue)
builder.add_edge("tools", "agent")

graph = builder.compile()

compile() 做的事情包括:验证图的合法性(有没有死路、节点是否都定义了)、生成执行计划、挂载 checkpointer。编译后的 graph 对象是不可变的,可以在多线程环境下安全复用。


执行机制:图是怎么跑起来的

调用 graph.invoke(input) 后,LangGraph 的执行流程如下:

perl 复制代码
1. 初始化 state:将 input 合并进初始 state
2. 从 entry_point 节点开始
3. 执行当前节点函数,拿到返回的 diff
4. 将 diff 通过 reducer 合并进 state(生成新 state 快照)
5. 根据出边(固定边或条件边)确定下一个节点
6. 重复 3-5,直到到达 END
7. 返回最终 state

每一步执行后,LangGraph 都会生成一个新的 state 快照。如果配置了 checkpointer,这个快照会被持久化,这是多轮对话和断点恢复的基础。

这个执行模型本质上是一个事件循环 ,每次循环处理一个节点。循环本身(即 Agent 的"思考-行动"循环)是通过图的结构来表达的,而不是通过代码里的 while True


Checkpoint:状态持久化的原理

Checkpoint 是 LangGraph 最被低估的特性之一。它的核心思想是:把每一步执行后的完整 state 快照存下来

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

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

config = {"configurable": {"thread_id": "session_001"}}
graph.invoke({"messages": [HumanMessage("你好")]}, config=config)

thread_id 是会话的唯一标识。每次 invoke 时,LangGraph 会:

  1. thread_id 从 checkpointer 里查找历史快照
  2. 如果有,恢复到上次结束时的 state
  3. 执行完成后,把新的 state 快照存进 checkpointer

这意味着多轮对话的记忆不是靠你手动维护消息列表实现的,而是 checkpointer 自动帮你做的。换 SQLite 做持久化,进程重启后对话历史依然在:

python 复制代码
from langgraph.checkpoint.sqlite import SqliteSaver
memory = SqliteSaver.from_conn_string("./agent.db")

Checkpoint 还支持时间旅行------你可以拿到任意历史快照,从那个时间点重新执行,这对调试复杂 Agent 非常有用。


Human-in-the-Loop:中断与恢复

LangGraph 原生支持在指定节点前暂停,等待人工干预后再继续:

python 复制代码
graph = builder.compile(
    checkpointer=memory,
    interrupt_before=["execute_action"]  # 执行这个节点前暂停
)

# 第一次调用:执行到 execute_action 前暂停
graph.invoke(input, config=config)

# 人工审核,确认后继续执行
graph.invoke(None, config=config)  # 传 None 表示从暂停点继续

实现原理是:到达中断节点时,LangGraph 保存当前 state 快照,然后抛出一个特殊的中断信号。下次 invoke 时,从快照恢复,跳过已执行的节点,从中断点继续。这个机制对需要人工审核的高风险操作场景(比如执行数据库删除、发送邮件)非常关键。


与其他框架的本质区别

很多人问:LangGraph 和 LangChain AgentExecutor、AutoGen 有什么本质区别?

AgentExecutor 是一个封装好的黑盒,它内置了 ReAct 的执行逻辑,你只需要提供工具列表。好处是上手快,坏处是控制权在框架手里------想改循环逻辑、加条件分支、自定义状态,都很别扭。

AutoGen 的核心抽象是"多个 Agent 互相对话",适合角色分工明确的多 Agent 协作场景,但对单 Agent 内部的控制流支持有限。

LangGraph 的定位是控制流引擎 ,它不预设 Agent 应该怎么跑,只提供图的描述能力和执行机制。你来决定流程,它来负责执行。这种设计在简单场景下比 AgentExecutor 啰嗦,但在复杂场景下优势明显------任何你能想到的流程,都可以用图来描述。


总结

LangGraph 的设计哲学可以用一句话概括:把 Agent 的控制流从代码里解放出来,用图来表达。

概念 作用
State 全局共享的不可变数据,reducer 处理并发更新
Node 无副作用的计算单元,只负责处理和返回 diff
Edge 控制流的显式描述,条件边实现分支和循环
Checkpoint 每步快照持久化,支持多轮对话和断点恢复
Interrupt 人工介入的原语,高风险操作不可或缺

理解了这五个东西,LangGraph 就没有黑魔法了------它就是一个带状态管理的图执行引擎,只是这个图刚好特别适合描述 Agent 的行为。


参考资料

相关推荐
孟陬4 小时前
国外技术周刊 #139:LLM 正在杀死程序员的「懒惰美德」
前端·人工智能·后端
Peter·Pan爱编程4 小时前
23. 算法库:用算法代替手写循环
c++·人工智能·算法
Nile4 小时前
Claude Code-Dynamic Workflows:1.为什么用工作流?
人工智能·ai·ai编程·ai-native
狂炫冰美式4 小时前
AI 生成 Draw.io,导入飞书/Lark 画板后可编辑
前端·人工智能·后端
战族狼魂4 小时前
从零构建企业级Hermes-Agent:复杂任务拆解、工具协同与安全落地实践
开发语言·人工智能·python
o561-6o623o7鹿4 小时前
陈,生理实验系统虚实结合型 生理学实验系统 生理学实验系统软件
人工智能
继续商行4 小时前
Go 并发原语深度剖析:Channel 与 Mutex 的性能博弈
人工智能
yaoxiaoganggang4 小时前
克隆 Superpowers 的规则库到你的本地(或者直接作为 Git Submodule)
人工智能·经验分享·git·ai编程
小雨青年4 小时前
GitHub Spark:自然语言能把全栈 AI 应用做到什么程度
人工智能·github