LangChain LangGraph
Module 1 Module 2 Module 3 Module 4 Module 5 Module 6
Module 1 · 基础入门
1 1-1 Simple Graph
2 1-2 Chain
3 1-3 Router
4 1-4 Agent
5 1-5 Agent Memory
6 1-6 Deployment
SUM Module Summary
HomeLangGraphModule 1 · 基础入门1-1 Simple Graph
📓 Notebook 📖 Explained
LANGGRAPH MODULE 1 · LESSON 1

从零理解 LangGraph
State · Node · Edge · StateGraph

你学过 LangChain,现在来搞懂 LangGraph 的灵魂架构。
为什么要"构建图"?这和 Agent、LLM 又有什么关系?

1 LangChain vs LangGraph:你已知道什么,还缺什么

你学过 LangChain,已经知道怎么调用 LLM、拼接 Chain、使用 Tool。LangChain 的核心模型是"流水线":输入 → 处理步骤 A → 处理步骤 B → 输出,线性地往下走。

维度 LangChain (Chain) LangGraph (Graph)
执行流程 线性 / 顺序 图结构,可以分支、循环、回退
状态管理 靠开发者手动传递变量 内置 State 对象,自动流转
条件判断 需要在代码里手写 if/else Conditional Edge,图结构原生支持
循环 / 迭代 实现复杂,易出 bug 图天然支持环(loop),Agent 循环是第一等公民
适合场景 简单问答、RAG、固定步骤任务 复杂 Agent、多步推理、人机协作、有记忆的对话
核心洞察

LangGraph 是 LangChain 的"超集":它不替代 LangChain,而是在 LangChain 上层提供了一个可控的、有状态的执行引擎。你在 LangGraph 的 Node 里仍然可以调用 LangChain 的 Chain、LLM、Tool。

LangChain 解决了"怎么调用 LLM"的问题,LangGraph 解决了"LLM 调用的流程控制状态管理"的问题。当你的 AI 应用需要"根据上一步结果决定下一步做什么",你就需要 LangGraph。

2 LangGraph 的核心思想:用"图"来描述 AI 的执行流程

什么是"图"?在计算机科学中,图(Graph)由节点(Node)边(Edge)组成。LangGraph 借用了这个概念:

想象你在规划一段旅程:

现实类比:一个简单决策旅程

出发
START
查天气
node_1
条件判断:今天天气怎样?
去海边
node_2(晴天)
去博物馆
node_3(雨天)
结束
END

这就是 Module 1 那个 notebook 的完整逻辑:node_1 执行后,根据某个条件(随机/天气/用户输入),决定走 node_2 还是 node_3,最终都到达 END。

为什么用"图"而不是普通 if/else?

当你的 Agent 需要循环调用工具(搜索 → 判断是否够 → 再搜索)、并行执行(同时查多个数据源)、或者人工介入中断(Human-in-the-loop),用 if/else 写代码会迅速变成意大利面条。图结构让这些复杂流程可视化、可测试、可维护

3 State(状态)——图的"记忆"

State 是什么?

State 是一个 Python 字典(TypedDict),它在整张图的执行过程中一直存在,从 START 到 END,每个 Node 都可以读取它、修改它。你可以把它理解为节点之间传递的"便签纸"或"共享白板"。

from typing_extensions import TypedDict

# 定义 State 的"模板":图里有哪些共享数据
class State(TypedDict):
    graph_state: str  # 这张图只有一个字段:graph_state

在这个最简单的例子里,State 只有一个字段 graph_state,类型是字符串。但在真实 Agent 里,State 可以包含:

State 如何流转?

每个 Node 接收当前 State,做完处理后返回一个部分更新的字典,LangGraph 会自动把这个更新合并进 State:

graph_state: "Hi, this is Lance."
初始 State(你传入的输入)
graph_state: "Hi, this is Lance. I am"
经过 node_1 后
graph_state: "Hi, this is Lance. I am"
node_1 输出
graph_state: "Hi, this is Lance. I am sad!"
经过 node_3 后的最终 State
重要细节:默认行为是"覆盖"

默认情况下,Node 返回的值会覆盖掉 State 中对应字段的旧值。如果你想要追加(比如 messages 列表),需要使用 Reducer。这会在后面的 Module 2 讲到。

在真实 Agent 中,State 长什么样?

from langchain_core.messages import BaseMessage
from typing import Annotated, List
from langgraph.graph.message import add_messages

class AgentState(TypedDict):
    # Annotated + add_messages 表示"追加"而不是"覆盖"
    messages: Annotated[List[BaseMessage], add_messages]
    # 其他字段可以根据需要添加
    user_query: str
    search_results: list
    iteration_count: int

4 Node(节点)——图的"工作单元"

Node 就是普通 Python 函数

这是 LangGraph 最优雅的设计之一:Node 就是一个普通的 Python 函数,没有任何魔法。它只有一个约定:

# 这就是一个完整的 Node!
def node_1(state):
    print("---Node 1---")
    # 读取 State 中的值
    current = state['graph_state']
    # 返回要更新的字段
    return {"graph_state": current + " I am"}

def node_2(state):
    print("---Node 2---")
    return {"graph_state": state['graph_state'] + " happy!"}

def node_3(state):
    print("---Node 3---")
    return {"graph_state": state['graph_state'] + " sad!"}

在真实 Agent 中,Node 里会做什么?

🤖 调用 LLM 的 Node

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4o-mini")

def call_llm(state):
    # 从 State 里取消息历史
    messages = state["messages"]
    # 调用 LLM(这里就用到了 LangChain!)
    response = llm.invoke(messages)
    # 把 LLM 回复追加到 messages
    return {"messages": [response]}

🔧 调用工具的 Node

from langchain_community.tools import TavilySearchResults

search_tool = TavilySearchResults()

def search_web(state):
    query = state["user_query"]
    results = search_tool.invoke(query)
    return {"search_results": results}
关键理解

Node 是"纯粹的业务逻辑",它不知道自己是图的一部分,也不知道下一步去哪儿。它只管读 State、做事、更新 State。谁去哪儿,是 Edge 决定的。

5 Edge(边)——图的"决策路线"

Edge 连接 Node,告诉图"执行完这个节点之后,下一步去哪儿"。LangGraph 有两种 Edge:

普通 Edge(Normal Edge)

始终从 A 走到 B,没有条件判断。

# 总是从 node_2 走到 END
builder.add_edge("node_2", END)
builder.add_edge("node_3", END)

# 总是从 START 走到 node_1
builder.add_edge(START, "node_1")

条件 Edge(Conditional Edge)

根据一个路由函数的返回值,决定下一步去哪个 Node。路由函数接受 State,返回下一个 Node 的名字。

import random
from typing import Literal

# 路由函数:根据 State 决定下一步
def decide_mood(state) -> Literal["node_2", "node_3"]:
    # 可以根据 state 里的任何信息来决定
    if random.random() < 0.5:
        return "node_2"   # 走 happy 路线
    return "node_3"       # 走 sad 路线

# 把路由函数挂到 node_1 之后
builder.add_conditional_edges("node_1", decide_mood)

在真实 Agent 中,条件 Edge 决定"是否继续循环"

🔄 真实 Agent 的路由逻辑

def should_continue(state) -> Literal["tools", "__end__"]:
    messages = state["messages"]
    last_message = messages[-1]
    # 如果 LLM 要调用工具 → 去 tools 节点
    if last_message.tool_calls:
        return "tools"
    # 否则 LLM 已经给出最终答案 → 结束
    return "__end__"

# 这就构成了 Agent 的"思考→工具→思考→工具→…→结束"循环
builder.add_conditional_edges("agent", should_continue)
这就是 ReAct Agent 的本质!

你在 LangChain 里用过的 AgentExecutor,其底层就是这样一个循环:LLM 节点 → 条件判断(要不要调用工具)→ 工具节点(如果要)→ 回到 LLM 节点。LangGraph 让这个循环透明、可控、可定制

6 StateGraph Class——把所有零件组装成图

StateGraph 是 LangGraph 的核心类,它是一个"图的构建器"(Builder Pattern)。你把所有 Node 和 Edge 的定义"告诉"它,最后 compile() 生成一个可以运行的图。

完整的构建流程

START 和 END 是什么?

STARTEND 是 LangGraph 内置的两个特殊节点:

7 逐行读懂那段构建代码

现在来逐行分析 notebook 里那段你"完全摸不着头脑"的代码:

from IPython.display import Image, display
from langgraph.graph import StateGraph, START, END

# ① 创建一个图的"蓝图",使用 State 作为共享数据结构
builder = StateGraph(State)

# ② 注册三个节点("标识符名" → Python函数)
builder.add_node("node_1", node_1)   # node_1 函数处理第一步
builder.add_node("node_2", node_2)   # node_2 = happy 路线
builder.add_node("node_3", node_3)   # node_3 = sad 路线

# ③ 定义固定边:START → node_1(图从 node_1 开始)
builder.add_edge(START, "node_1")

# ④ 定义条件边:node_1 执行完后,调用 decide_mood() 决定去 node_2 还是 node_3
builder.add_conditional_edges("node_1", decide_mood)

# ⑤ 定义固定边:无论走哪条路,最终都到 END
builder.add_edge("node_2", END)
builder.add_edge("node_3", END)

# ⑥ 编译:校验图的结构,生成可执行的 CompiledGraph
graph = builder.compile()

# ⑦ 可视化(仅用于学习/调试,生产代码里不需要)
display(Image(graph.get_graph().draw_mermaid_png()))

执行这段代码后,图的形状如下:

图的可视化结构

__start__
node_1
拼接 "I am"
decide_mood() 路由
50%
node_2
拼接 "happy!"
50%
node_3
拼接 "sad!"
__end__

调用图并观察状态流转

# 传入初始 State,运行图
result = graph.invoke({"graph_state": "Hi, this is Lance."})

# 可能的输出 1(走 node_2):
# ---Node 1---
# ---Node 2---
# {'graph_state': 'Hi, this is Lance. I am happy!'}

# 可能的输出 2(走 node_3):
# ---Node 1---
# ---Node 3---
# {'graph_state': 'Hi, this is Lance. I am sad!'}

完整的 State 演变过程:

阶段graph_state 的值发生了什么
invoke 调用时"Hi, this is Lance."你传入的初始 State
node_1 执行后"Hi, this is Lance. I am"node_1 追加了 " I am"
decide_mood 路由(不修改 State)返回 "node_3"(假设这次随机到了 sad)
node_3 执行后"Hi, this is Lance. I am sad!"node_3 追加了 " sad!"
到达 END"Hi, this is Lance. I am sad!"图执行完毕,返回最终 State

8 这只是示例吗?以后会经常用吗?

直接回答你的问题

这不只是示例。StateGraph + Node + Edge 这套模式就是 LangGraph 的全部基础。从最简单的 chatbot 到最复杂的多 Agent 系统,都是用这套模式搭建的。

Module 1 用"随机选择 happy/sad"只是为了屏蔽 LLM 的复杂性,让你先理解图的流程控制机制。在后续 Module 里,你会看到:

Module在图里加入了什么对应场景
Module 1 LLM 作为 Node;Tool 作为 Node;条件 Edge 判断是否调用工具 完整的 ReAct Agent
Module 2 State 里加 messages 列表;Reducer 做追加而非覆盖 有记忆的对话 chatbot
Module 3 图执行中途暂停,等待人工审批 Human-in-the-loop
Module 4 多个 Node 并行执行;子图(Sub-graph) 研究助手,同时查多个数据源
Module 5 图连接外部记忆存储(Memory Store) 跨对话的长期记忆 Agent
这套模式在工业界真实使用

LangGraph 的 StateGraph 模式被 LinkedIn、Elastic、Uber 等公司的 AI 团队用于生产系统中。这个入门示例教你的,是这些生产系统的共同骨架

9 真实 Agent 场景:LangGraph 如何接管 LLM 调用

现在把 Module 1 的简单示例,升级成一个真正调用 LLM 和工具的 Agent,你会发现结构完全相同

from langchain_openai import ChatOpenAI
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_core.messages import HumanMessage
from langgraph.graph import StateGraph, START, END
from langgraph.prebuilt import ToolNode
from typing_extensions import TypedDict, Annotated
from langgraph.graph.message import add_messages
from typing import Literal

# ─── Step 1: 定义 State(比 Module 1 更丰富)───
class AgentState(TypedDict):
    messages: Annotated[list, add_messages]  # 追加而非覆盖

# ─── Step 2: 准备 LLM 和工具 ───
tools = [TavilySearchResults(max_results=2)]
llm = ChatOpenAI(model="gpt-4o-mini")
llm_with_tools = llm.bind_tools(tools)  # 告诉 LLM 有哪些工具可用

# ─── Step 3: 定义 Nodes(和 Module 1 结构完全一样!)───
def call_llm(state: AgentState):
    # Node:调用 LLM,LLM 会决定是直接回答还是调用工具
    response = llm_with_tools.invoke(state["messages"])
    return {"messages": [response]}

# ─── Step 4: 定义路由函数(就是 Module 1 的 decide_mood)───
def should_continue(state: AgentState) -> Literal["tools", END]:
    last_msg = state["messages"][-1]
    if last_msg.tool_calls:  # LLM 决定要调用工具
        return "tools"
    return END              # LLM 给出了最终答案

# ─── Step 5: 构建图(和 Module 1 完全一样的模式!)───
builder = StateGraph(AgentState)

builder.add_node("agent", call_llm)
builder.add_node("tools", ToolNode(tools))  # 内置的工具执行节点

builder.add_edge(START, "agent")
builder.add_conditional_edges("agent", should_continue)
builder.add_edge("tools", "agent")   # 工具执行完回到 LLM!这就是循环

agent = builder.compile()

# ─── Step 6: 运行 ───
result = agent.invoke({
    "messages": [HumanMessage(content="2024年奥运会在哪里举行?")]
})

这个真实 Agent 的图结构

START
agent (LLM)
调用 LLM 思考
should_continue() 路由
需要工具
tools
执行搜索/计算
↑ 回到 agent
有最终答案
END

注意 add_edge("tools", "agent") 这一行:它把 tools 节点的输出连回了 agent 节点,形成了一个循环。这就是 Agent 反复"思考→工具→思考→工具"直到得出答案的机制。LangChain 的 AgentExecutor 在底层就是这个图,只是以前你看不到它。

10 思维导图:一张图总结所有概念

LangGraph 核心概念
State(状态)
  • • TypedDict 定义结构
  • • 图里所有节点共享
  • • 默认行为:覆盖字段
  • • 可配置 Reducer 改为追加
Node(节点)
  • • 就是普通 Python 函数
  • • 输入:当前 State
  • • 输出:更新的字段字典
  • • 可调用 LLM、工具、API
Edge(边)
  • • 普通 Edge:固定跳转
  • • 条件 Edge:函数返回目标
  • • 可以形成循环
  • • START/END 是特殊节点
StateGraph(图)
  • • Builder Pattern 构建
  • • compile() 生成可执行图
  • • invoke() 运行并返回 State
  • • 实现 Runnable 接口(同 LangChain)
和 LangChain 的关系
LangGraph 的 Node 里调用 LangChain 的 LLM/Chain/Tool → LangGraph 负责"控制流",LangChain 负责"AI 能力" → 两者互补,不是替代关系

学习路线建议

Module 1 的学习重点不是代码细节,而是建立这个心智模型:

第一步 理解 State 是"共享白板",Node 是"处理函数",Edge 是"路由规则"
第二步 把 Module 1 的随机节点换成真实 LLM 调用,理解 Agent Loop
第三步 Module 2:学习 messages 的 Reducer,State 管理更复杂的对话历史
第四步 Module 3:在图执行中途插入人工审批(Breakpoint),实现 Human-in-the-loop
第五步 Module 4-6:并行、子图、长期记忆,逐步构建生产级 Agent
最终结论

Module 1 的这张"简单图"就是你以后所有 LangGraph 代码的骨架。无论多复杂的 Agent,都不过是:定义 State → 写 Node 函数 → 用 Edge 连起来 → compile → invoke。理解了这个模式,你就理解了 LangGraph 的全部基础。