文章目录
-
- [第 1 章:LangGraph 初识与核心概念](#第 1 章:LangGraph 初识与核心概念)
-
- [1.1 本章目标](#1.1 本章目标)
- [1.2 核心概念](#1.2 核心概念)
-
- [LangGraph 是什么?](#LangGraph 是什么?)
- [LangGraph 在 AI 生态中的位置](#LangGraph 在 AI 生态中的位置)
- [第一个 Graph 的内部结构](#第一个 Graph 的内部结构)
- [1.3 实战:你的第一个 LangGraph 程序](#1.3 实战:你的第一个 LangGraph 程序)
- [1.4 API 速查](#1.4 API 速查)
- [1.5 错误与避坑指南](#1.5 错误与避坑指南)
-
- [坑 1:忘记导入 START 和 END](#坑 1:忘记导入 START 和 END)
- [坑 2:节点函数返回 None 而非 dict](#坑 2:节点函数返回 None 而非 dict)
- [坑 3:返回的 key 不在 State 中](#坑 3:返回的 key 不在 State 中)
- [坑 4:混淆 invoke() 的参数](#坑 4:混淆 invoke() 的参数)
- [1.6 最佳实践总结](#1.6 最佳实践总结)
第 1 章:LangGraph 初识与核心概念

1.1 本章目标
学完本章你将能够:
- 理解 LangGraph 在 AI 开发生态中的定位
- 掌握 State、Node、Edge、Graph 四大核心概念
- 独立编写并运行第一个 LangGraph 程序
1.2 核心概念
LangGraph 是什么?
在计算机科学中,图(Graph)由节点(Node)和边(Edge)组成。节点是执行任务的单元,边是连接节点的线,决定了任务执行的先后顺序。就像地铁线路图------每个站点是节点,连接站点的轨道是边。
LangGraph 是一个有状态的多步骤 AI 应用编排框架。你可以把它想象成一个智能工厂的流水线:
| 概念 | 比喻(工厂流水线) | 技术定义 |
|---|---|---|
| Graph(图) | 整个工厂的布局图 | 定义了所有节点和边的有向图结构 |
| State(状态) | 在流水线上流转的零件 | 在节点间共享的数据结构,每个节点可以读取和修改 |
| Node(节点) | 每个工位 | 执行具体操作的函数(LLM 调用、工具执行、数据处理) |
| Edge(边) | 连接工位的传送带 | 定义节点间的执行顺序和条件 |
核心公式 :Nodes 做工作,Edges 决定流程,State 是纽带
LangGraph 在 AI 生态中的位置
#mermaid-svg-kamBW7feidFCXmzY{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-kamBW7feidFCXmzY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-kamBW7feidFCXmzY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-kamBW7feidFCXmzY .error-icon{fill:#552222;}#mermaid-svg-kamBW7feidFCXmzY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-kamBW7feidFCXmzY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-kamBW7feidFCXmzY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-kamBW7feidFCXmzY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-kamBW7feidFCXmzY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-kamBW7feidFCXmzY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-kamBW7feidFCXmzY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-kamBW7feidFCXmzY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-kamBW7feidFCXmzY .marker.cross{stroke:#333333;}#mermaid-svg-kamBW7feidFCXmzY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-kamBW7feidFCXmzY p{margin:0;}#mermaid-svg-kamBW7feidFCXmzY .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-kamBW7feidFCXmzY .cluster-label text{fill:#333;}#mermaid-svg-kamBW7feidFCXmzY .cluster-label span{color:#333;}#mermaid-svg-kamBW7feidFCXmzY .cluster-label span p{background-color:transparent;}#mermaid-svg-kamBW7feidFCXmzY .label text,#mermaid-svg-kamBW7feidFCXmzY span{fill:#333;color:#333;}#mermaid-svg-kamBW7feidFCXmzY .node rect,#mermaid-svg-kamBW7feidFCXmzY .node circle,#mermaid-svg-kamBW7feidFCXmzY .node ellipse,#mermaid-svg-kamBW7feidFCXmzY .node polygon,#mermaid-svg-kamBW7feidFCXmzY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-kamBW7feidFCXmzY .rough-node .label text,#mermaid-svg-kamBW7feidFCXmzY .node .label text,#mermaid-svg-kamBW7feidFCXmzY .image-shape .label,#mermaid-svg-kamBW7feidFCXmzY .icon-shape .label{text-anchor:middle;}#mermaid-svg-kamBW7feidFCXmzY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-kamBW7feidFCXmzY .rough-node .label,#mermaid-svg-kamBW7feidFCXmzY .node .label,#mermaid-svg-kamBW7feidFCXmzY .image-shape .label,#mermaid-svg-kamBW7feidFCXmzY .icon-shape .label{text-align:center;}#mermaid-svg-kamBW7feidFCXmzY .node.clickable{cursor:pointer;}#mermaid-svg-kamBW7feidFCXmzY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-kamBW7feidFCXmzY .arrowheadPath{fill:#333333;}#mermaid-svg-kamBW7feidFCXmzY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-kamBW7feidFCXmzY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-kamBW7feidFCXmzY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kamBW7feidFCXmzY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-kamBW7feidFCXmzY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kamBW7feidFCXmzY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-kamBW7feidFCXmzY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-kamBW7feidFCXmzY .cluster text{fill:#333;}#mermaid-svg-kamBW7feidFCXmzY .cluster span{color:#333;}#mermaid-svg-kamBW7feidFCXmzY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-kamBW7feidFCXmzY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-kamBW7feidFCXmzY rect.text{fill:none;stroke-width:0;}#mermaid-svg-kamBW7feidFCXmzY .icon-shape,#mermaid-svg-kamBW7feidFCXmzY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-kamBW7feidFCXmzY .icon-shape p,#mermaid-svg-kamBW7feidFCXmzY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-kamBW7feidFCXmzY .icon-shape .label rect,#mermaid-svg-kamBW7feidFCXmzY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-kamBW7feidFCXmzY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-kamBW7feidFCXmzY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-kamBW7feidFCXmzY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 基础设施
模型层
编排层
AI 应用层
你的 AI 应用
LangGraph
状态编排 + 流程控制
LangChain
模型调用 + 工具集成 + 提示词
LLM 模型
OpenAI / Claude / DeepSeek / ...
持久化
Checkpoint / Store
外部工具
搜索 / 计算 / API
第一个 Graph 的内部结构
#mermaid-svg-CTCHCFilF4nUaDx4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CTCHCFilF4nUaDx4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CTCHCFilF4nUaDx4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CTCHCFilF4nUaDx4 .error-icon{fill:#552222;}#mermaid-svg-CTCHCFilF4nUaDx4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CTCHCFilF4nUaDx4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CTCHCFilF4nUaDx4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CTCHCFilF4nUaDx4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CTCHCFilF4nUaDx4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CTCHCFilF4nUaDx4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CTCHCFilF4nUaDx4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CTCHCFilF4nUaDx4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CTCHCFilF4nUaDx4 .marker.cross{stroke:#333333;}#mermaid-svg-CTCHCFilF4nUaDx4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CTCHCFilF4nUaDx4 p{margin:0;}#mermaid-svg-CTCHCFilF4nUaDx4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-CTCHCFilF4nUaDx4 .cluster-label text{fill:#333;}#mermaid-svg-CTCHCFilF4nUaDx4 .cluster-label span{color:#333;}#mermaid-svg-CTCHCFilF4nUaDx4 .cluster-label span p{background-color:transparent;}#mermaid-svg-CTCHCFilF4nUaDx4 .label text,#mermaid-svg-CTCHCFilF4nUaDx4 span{fill:#333;color:#333;}#mermaid-svg-CTCHCFilF4nUaDx4 .node rect,#mermaid-svg-CTCHCFilF4nUaDx4 .node circle,#mermaid-svg-CTCHCFilF4nUaDx4 .node ellipse,#mermaid-svg-CTCHCFilF4nUaDx4 .node polygon,#mermaid-svg-CTCHCFilF4nUaDx4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CTCHCFilF4nUaDx4 .rough-node .label text,#mermaid-svg-CTCHCFilF4nUaDx4 .node .label text,#mermaid-svg-CTCHCFilF4nUaDx4 .image-shape .label,#mermaid-svg-CTCHCFilF4nUaDx4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-CTCHCFilF4nUaDx4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-CTCHCFilF4nUaDx4 .rough-node .label,#mermaid-svg-CTCHCFilF4nUaDx4 .node .label,#mermaid-svg-CTCHCFilF4nUaDx4 .image-shape .label,#mermaid-svg-CTCHCFilF4nUaDx4 .icon-shape .label{text-align:center;}#mermaid-svg-CTCHCFilF4nUaDx4 .node.clickable{cursor:pointer;}#mermaid-svg-CTCHCFilF4nUaDx4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-CTCHCFilF4nUaDx4 .arrowheadPath{fill:#333333;}#mermaid-svg-CTCHCFilF4nUaDx4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CTCHCFilF4nUaDx4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CTCHCFilF4nUaDx4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CTCHCFilF4nUaDx4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-CTCHCFilF4nUaDx4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CTCHCFilF4nUaDx4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-CTCHCFilF4nUaDx4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CTCHCFilF4nUaDx4 .cluster text{fill:#333;}#mermaid-svg-CTCHCFilF4nUaDx4 .cluster span{color:#333;}#mermaid-svg-CTCHCFilF4nUaDx4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-CTCHCFilF4nUaDx4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-CTCHCFilF4nUaDx4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-CTCHCFilF4nUaDx4 .icon-shape,#mermaid-svg-CTCHCFilF4nUaDx4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CTCHCFilF4nUaDx4 .icon-shape p,#mermaid-svg-CTCHCFilF4nUaDx4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-CTCHCFilF4nUaDx4 .icon-shape .label rect,#mermaid-svg-CTCHCFilF4nUaDx4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CTCHCFilF4nUaDx4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-CTCHCFilF4nUaDx4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-CTCHCFilF4nUaDx4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 开始
完成
START
greet 节点
生成问候语
END
1.3 实战:你的第一个 LangGraph 程序
让我们从一个最简单的例子开始:输入一个人的名字,输出一句问候语。
python
# ============================================
# 第 1 步:导入必要的模块
# ============================================
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
# ============================================
# 第 2 步:定义 State(状态)------ 图中流转的数据结构
# ============================================
class State(TypedDict):
"""
State 是图中所有节点共享的数据结构。
使用 TypedDict 定义,提供类型安全和 IDE 提示。
这里定义了两个字段:
- name: 用户输入的名字
- greeting: 生成的问候语(初始为空)
"""
name: str
greeting: str
# TypedDict 是 Python 的类型提示工具,它定义了字典中每个键对应的值类型。
# LangGraph 用 TypedDict 来声明 State 的结构,这样 IDE 可以自动补全字段名,
# 也能在编写代码时检查类型错误。
# ============================================
# 第 3 步:定义 Node(节点)------ 执行具体操作的函数
# ============================================
def greet(state: State) -> dict:
"""
节点函数签名规则:
- 参数:接收当前 State 作为输入
- 返回值:返回一个 dict,包含要更新的 State 字段
注意:只需返回要更新的字段,不需要返回完整 State!
LangGraph 会自动将返回值合并到当前 State 中。
"""
print(f" [greet 节点] 收到名字: {state['name']}")
# 从 State 中读取 name,生成问候语,返回更新
return {"greeting": f"你好, {state['name']}!"}
# ============================================
# 第 4 步:构建 Graph(图)------ 把节点和边组合起来
# ============================================
# 创建 StateGraph 构建器,传入 State 类型
builder = StateGraph(State)
# 注册节点:给 greet 函数起名为 "greet"
builder.add_node("greet", greet)
# 添加边(流程控制):
# START → greet → END
# 表示从图入口开始,执行 greet 节点,然后结束
builder.add_edge(START, "greet")
builder.add_edge("greet", END)
# 编译图:将构建器"冻结"为可执行的图对象
graph = builder.compile()
# ============================================
# 第 5 步:运行 Graph
# ============================================
print("=== 执行 Graph ===")
# invoke() 方法传入初始状态,返回最终状态
result = graph.invoke({"name": "小明"})
print(f"=== 结果: {result['greeting']}")
# ============================================
# 运行输出:
# === 执行 Graph ===
# [greet 节点] 收到名字: 小明
# === 结果: 你好, 小明!
# ============================================
代码执行流程解析:
graph.invoke({"name": "小明"})--- 传入初始 State(只有name,greeting为默认值"")- 图从
START出发,找到第一条边START → greet - 执行
greet节点函数,传入当前 State,函数返回{"greeting": "你好, 小明!"} - 图将返回值合并到 State 中,State 变为
{"name": "小明", "greeting": "你好, 小明!"} - 找到下一条边
greet → END,图结束 invoke()返回最终的完整 State
1.4 API 速查
| API | 完整签名 | 入参说明 | 返回值 | 说明 |
|---|---|---|---|---|
StateGraph(state_schema) |
StateGraph(state_schema: Type[StateT]) |
state_schema: State 类型(TypedDict/dataclass/Pydantic) |
StateGraph 构建器对象 |
创建状态图构建器 |
.add_node(name, action) |
add_node(node: str, action: Callable) |
node: 节点名(str); action: 节点函数 |
Self(支持链式调用) |
注册一个节点 |
.add_edge(start, end) |
add_edge(start_key: str, end_key: str) |
start_key: 源节点名; end_key: 目标节点名 |
Self |
添加一条普通边 |
.compile() |
compile(checkpointer, interrupt_before, interrupt_after, ...) |
可选参数见后续章节 | CompiledStateGraph |
编译图使之可执行 |
.invoke(input) |
invoke(input: dict, config: dict = None) |
input: 初始 State 字典; config: 运行配置(可选) |
dict 最终 State |
同步执行图 |
1.5 错误与避坑指南
坑 1:忘记导入 START 和 END
python
# ❌ 错误写法
from langgraph.graph import StateGraph # 只导入了 StateGraph
builder = StateGraph(State)
builder.add_edge(START, "my_node") # NameError: name 'START' is not defined
# ✅ 正确写法
from langgraph.graph import StateGraph, START, END # 同时导入 START 和 END
坑 2:节点函数返回 None 而非 dict
python
# ❌ 错误写法
def bad_node(state: State):
print("处理中...")
# 忘记返回值,隐式返回 None
# → LangGraph 收到 None,无法更新 State,可能报错或静默失败
# ✅ 正确写法
def good_node(state: State) -> dict:
print("处理中...")
return {"some_field": "new_value"} # 必须返回 dict
坑 3:返回的 key 不在 State 中
python
class State(TypedDict):
name: str
greeting: str
# ❌ 错误写法
def bad_node(state: State) -> dict:
return {"message": "hello"} # "message" 不在 State 中定义,运行时报错
# ✅ 正确写法
def good_node(state: State) -> dict:
return {"greeting": "hello"} # "greeting" 在 State 中定义
坑 4:混淆 invoke() 的参数
python
# ❌ 错误写法
graph.invoke("hello") # 传入字符串而非 dict
# ✅ 正确写法
graph.invoke({"name": "小明"}) # 传入 dict,key 对应 State 的字段
1.6 最佳实践总结
- 使用 TypedDict 定义 State:类型安全,IDE 有完整提示,出错时容易定位问题
- 节点函数保持单一职责:一个节点只做一件事(如"搜索"、"生成回复"、"调用工具"),不要在一个节点里做太多事
- 始终从 START 到 END 形成完整路径:确保每个节点都有入口和出口,避免"死胡同"
- 节点返回值只包含变更字段:不需要返回完整 State,LangGraph 自动合并,减少冗余代码
- 先画图再写代码:复杂流程先用 Mermaid 画出图结构,再着手实现,思路更清晰