LangGraph 资深开发者完全指南

2 阅读29分钟

版本参考:LangGraph v0.3.x(2026年4月)
适用读者:有 Python 经验、理解 DAG/状态机概念、希望构建生产级 AI Agent 的资深工程师 当前github地址:github.com/langchain-a…


目录

  1. 框架概述与设计哲学
  2. 仓库结构与包架构
  3. 核心执行引擎:Pregel 模型
  4. Graph API:StateGraph 深度解析
  5. Functional API:@entrypoint 与 @task
  6. 状态管理与 Reducers
  7. 持久化与 Checkpointing 系统
  8. Human-in-the-Loop 工作流
  9. 流式输出(Streaming)
  10. 高级控制流:Send / Command / 条件边
  11. 多 Agent 系统深度指南
    • 11.1 架构模式全景(决策树)
    • 11.2 Supervisor 集中调度模式
    • 11.3 Hierarchical 层级树模式
    • 11.4 Swarm 蜂群去中心化模式
    • 11.5 Reflection 反思质检模式
    • 11.6 Debate 对抗辩论模式
    • 11.7 子图状态映射机制(共享键 vs 包装器)
    • 11.8 跨 Agent 共享内存:BaseStore
    • 11.9 生产并发控制、Double-Texting、可观测性
  12. 预构建组件:ReAct Agent & 工具调用
  13. 部署:langgraph-cli 与 LangGraph Platform
  14. 生产最佳实践
  15. 调试与可观测性
  16. API 快速参考

1. 框架概述与设计哲学

1.1 LangGraph 是什么

LangGraph 是 LangChain Inc. 推出的低级 Agent 编排框架,核心使命是:

将 AI Agent 的执行流程建模为有状态的有向图(Stateful Directed Graph),并提供持久化、容错、人工干预等生产级基础设施。

它不是 RAG 框架,不是 LLM 封装层,而是专注于Agent 的编排与生命周期管理

1.2 设计哲学

设计原则说明
低级可控不隐藏执行细节,开发者完全掌控节点、边、状态
图即状态机每个 superstep 都是一次状态快照,支持时间旅行
持久性优先Checkpointing 是一等公民,而非事后加的功能
框架无关不强依赖 LangChain,可独立使用任何 LLM SDK
可组合性图可以嵌套为子图,两套 API 可以混用

1.3 适合 LangGraph 的场景

  • 多步骤 Agent 工作流(ReAct、Plan-and-Execute、反思循环)
  • 需要人工审批/干预的半自动化流程
  • 需要跨会话记忆的长期运行 Agent
  • 多 Agent 协作系统(supervisor + workers)
  • 需要故障恢复、状态回放的关键业务流程

2. 仓库结构与包架构

2.1 Monorepo 组织

LangGraph 采用 Monorepo 结构,所有包位于 libs/ 目录下,各包独立版本发布到 PyPI:

langchain-ai/langgraph/
├── libs/
│   ├── langgraph/              # 核心包:执行引擎 + Graph API
│   ├── langgraph-checkpoint/   # 基础 Checkpointer 接口 + 序列化
│   ├── langgraph-prebuilt/     # ReAct Agent、ToolNode 等预构建组件
│   ├── langgraph-sdk/          # Python & JS 客户端 SDK
│   ├── langgraph-cli/          # CLI 工具:dev server、部署
│   ├── checkpoint-sqlite/      # SQLite Checkpointer 实现
│   └── checkpoint-postgres/    # PostgreSQL Checkpointer 实现
├── docs/
└── examples/

2.2 包职责与依赖关系

langgraph-cli
    └── depends on → langgraph-sdk
langgraph
    ├── depends on → langgraph-checkpoint (基础接口)
    └── depends on → langgraph-prebuilt>=1.0.2,<1.1.0
langgraph-checkpoint
    └── 提供 BaseCheckpointSaver、JsonPlusSerializer

2.3 命名空间包设计(重要!)

langgraphlanggraph-checkpoint 使用同一顶级命名空间,通过 Python 命名空间包机制合并:

langgraph/
├── graph/          ← 来自 langgraph 包
├── pregel/         ← 来自 langgraph 包(执行引擎)
├── prebuilt/       ← 来自 langgraph-prebuilt 包
├── checkpoint/     ← 来自 langgraph-checkpoint 包
│   ├── base.py     (BaseCheckpointSaver 抽象类)
│   ├── memory.py   (MemorySaver)
│   └── serde/      (JsonPlusSerializer)
└── store/          ← 来自 langgraph-checkpoint 包(跨线程存储)

注意:安装时务必同时安装所需的 checkpointer 包,否则只有内存版 MemorySaver


3. 核心执行引擎:Pregel 模型

3.1 BSP 执行模型

LangGraph 的底层执行引擎基于 Google Pregel 论文的 Bulk Synchronous Parallel(BSP)模型,其执行循环为:

┌─────────────────────────────────────────┐
│           Pregel Execution Loop          │
│                                          │
│  1. PLAN    → 确定本 superstep 要运行的节点  │
│  2. EXECUTE → 并行执行所有节点              │
│  3. UPDATE  → 通过 reducer 合并写入到 channel│
│  4. CHECKPOINT → 持久化当前状态快照          │
│  5. 检查终止条件 → 若未结束,回到步骤 1        │
└─────────────────────────────────────────┘

3.2 Superstep 概念

Superstep 是 Pregel 的基本执行单位:

  • 一个 superstep 内所有被调度的节点并行执行
  • 每个 superstep 结束时保存一个 checkpoint
  • 对于线性图 START → A → B → END,有 3 个 superstep(input, A, B),产生 3 个 checkpoint
# 理解 superstep 对时间旅行调试至关重要
# 只能从 checkpoint 边界恢复执行,不能从节点内部恢复

3.3 Channel 系统

状态的每个字段对应一个 Channel,Channel 决定如何处理并发写入:

Channel 类型行为典型用途
LastValue后写覆盖前写单值状态字段
Topic (Append)累加到列表消息历史、日志
EphemeralValue每个 superstep 后清空临时传递数据

4. Graph API:StateGraph 深度解析

4.1 基础构建流程

from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.graph.message import add_messages
from langchain_core.messages import BaseMessage

# Step 1: 定义 State Schema
class AgentState(TypedDict):
    messages: Annotated[list[BaseMessage], add_messages]  # reducer
    next_step: str                                          # last-value
    iteration: int

# Step 2: 定义节点(纯函数:State -> Partial State)
def llm_node(state: AgentState) -> dict:
    # 只返回需要更新的字段
    response = llm.invoke(state["messages"])
    return {"messages": [response]}

def router(state: AgentState) -> str:
    # 条件边的路由函数,返回节点名称字符串
    last_msg = state["messages"][-1]
    if last_msg.tool_calls:
        return "tools"
    return END

# Step 3: 构建图
builder = StateGraph(AgentState)
builder.add_node("llm", llm_node)
builder.add_node("tools", tool_node)

# Step 4: 定义边
builder.add_edge(START, "llm")
builder.add_conditional_edges("llm", router, ["tools", END])
builder.add_edge("tools", "llm")  # 工具执行后回到 LLM

# Step 5: 编译(可选传入 checkpointer)
from langgraph.checkpoint.memory import MemorySaver
graph = builder.compile(checkpointer=MemorySaver())

4.2 节点设计规范

节点是纯函数,遵循以下契约:

# 输入:完整的 State 快照(只读)
# 输出:Partial State(只包含需要修改的字段)
def node_function(state: MyState) -> dict:
    ...
    return {"field_to_update": new_value}

# 异步节点(推荐用于 I/O 密集型操作)
async def async_node(state: MyState) -> dict:
    result = await some_async_operation()
    return {"result": result}

关键约束:节点不应有副作用(除了调用外部服务),不应直接修改 state 对象。

4.3 条件边(Conditional Edges)的三种模式

# 模式 1:简单路由函数(返回节点名字符串)
def simple_router(state: State) -> str:
    return "node_a" if condition else "node_b"

graph.add_conditional_edges("source", simple_router)

# 模式 2:带映射的路由(枚举值 -> 节点名)
def enum_router(state: State) -> Literal["continue", "end"]:
    return "continue" if state["should_continue"] else "end"

graph.add_conditional_edges(
    "source",
    enum_router,
    {"continue": "node_a", "end": END}
)

# 模式 3:从 START 设置条件入口
graph.add_conditional_edges(START, initial_router)

4.4 图编译选项

graph = builder.compile(
    checkpointer=checkpointer,      # 持久化后端
    interrupt_before=["tool_node"], # 在该节点前自动中断
    interrupt_after=["llm_node"],   # 在该节点后自动中断
    debug=True,                     # 开启详细日志
)

5. Functional API:@entrypoint 与 @task

5.1 设计动机

Functional API 允许用标准 Python 控制流(if/for/while)编写工作流,无需将逻辑拆分为显式节点和边,适合将现有代码快速接入 LangGraph 的持久化与 HIL 能力。

from langgraph.func import entrypoint, task
from langgraph.checkpoint.memory import MemorySaver

# @task:可异步执行的离散工作单元
@task
def fetch_data(query: str) -> dict:
    return expensive_api_call(query)

@task
def process_data(data: dict) -> str:
    return llm.invoke(str(data)).content

# @entrypoint:工作流入口,等价于一个可持久化的函数
@entrypoint(checkpointer=MemorySaver())
def my_workflow(inputs: dict, *, previous=None) -> str:
    # previous:同一 thread_id 上次执行的返回值
    
    # 并行派发两个 task(返回 future)
    fut1 = fetch_data("query_1")
    fut2 = fetch_data("query_2")
    
    # 等待结果
    data1 = fut1.result()
    data2 = fut2.result()
    
    # 使用标准 Python 控制流
    if data1["score"] > data2["score"]:
        return process_data(data1).result()
    else:
        return process_data(data2).result()

5.2 Functional API vs StateGraph 选型矩阵

维度Functional APIStateGraph
控制流表达标准 Python(if/for/while)显式节点 + 条件边
状态可见性隐式(局部变量)显式 State 类
代码量较少较多(结构化)
可视化调试不支持图形化LangGraph Studio 全支持
时间旅行调试⚠️ 有限支持✅ 完全支持
并行执行@task futures同一 superstep 多节点
与现有代码集成✅ 极易需要重构
推荐场景快速原型、过程式逻辑复杂分支、生产级 Agent

5.3 entrypoint.final:控制 checkpoint 保存内容

from langgraph.func import entrypoint
from langgraph.types import Command

@entrypoint(checkpointer=checkpointer)
def workflow(inputs: dict) -> entrypoint.final:
    result = do_work(inputs)
    # 返回给调用者的值 vs 存入 checkpoint 的值可以不同
    return entrypoint.final(
        value=result["output"],      # 调用者拿到的
        save=result["checkpoint_data"]  # 下次 previous 看到的
    )

6. 状态管理与 Reducers

6.1 State Schema 定义方式

LangGraph 支持三种 Schema 定义方式:

# 方式 1:TypedDict(推荐,轻量)
from typing import Annotated
from typing_extensions import TypedDict

class State(TypedDict):
    messages: Annotated[list, add_messages]
    counter: int  # 无 annotation = LastValue reducer

# 方式 2:Pydantic BaseModel(运行时验证)
from pydantic import BaseModel, Field

class State(BaseModel):
    messages: list = Field(default_factory=list)
    user_id: str

# 方式 3:dataclass
from dataclasses import dataclass, field

@dataclass
class State:
    messages: list = field(default_factory=list)
    step: int = 0

6.2 Reducer 详解

Reducer 定义了当多个节点在同一 superstep 写入同一字段时如何合并:

from langgraph.graph.message import add_messages
import operator

# 内置 reducer:追加消息(自动去重、处理 tool messages)
messages: Annotated[list[BaseMessage], add_messages]

# 内置 reducer:使用 operator.add(列表追加)
items: Annotated[list[str], operator.add]

# 自定义 reducer
def merge_dicts(left: dict, right: dict) -> dict:
    return {**left, **right}

metadata: Annotated[dict, merge_dicts]

# 使用 reducer 类(支持类型注解)
from langgraph.graph import add_messages

6.3 MessagesState 内置 State

from langgraph.graph import MessagesState

# 等价于:
class MessagesState(TypedDict):
    messages: Annotated[list[AnyMessage], add_messages]

# add_messages reducer 特性:
# - 自动追加新消息
# - 通过 message.id 去重(相同 id 的消息会被覆盖,用于更新)
# - 正确处理 ToolMessage 与 AIMessage 的 tool_call_id 关联

7. 持久化与 Checkpointing 系统

7.1 架构概览

Pregel Loop
    │
    ├── 每个 superstep 结束 ──→ BaseCheckpointSaver.put(checkpoint)
    │
    └── 恢复执行时 ──────────→ BaseCheckpointSaver.get_tuple(config)

BaseCheckpointSaver(抽象接口)
    ├── MemorySaver          # 开发用,进程内存
    ├── SqliteSaver          # 单机持久化(langgraph-checkpoint-sqlite)
    └── PostgresSaver        # 生产用,分布式(langgraph-checkpoint-postgres)

7.2 Checkpoint 数据模型

# checkpoint 的核心数据结构
@dataclass
class Checkpoint:
    id: str            # UUID v6(嵌入时间戳,可按时间排序)
    v: int             # 版本号
    ts: str            # ISO 时间戳
    channel_values: dict   # 当前所有 channel 的值(即完整 state)
    channel_versions: dict # 每个 channel 的版本号
    versions_seen: dict    # 已处理的写入版本(用于幂等性)
    pending_sends: list    # 待处理的 Send 消息

@dataclass 
class CheckpointMetadata:
    source: Literal["input", "loop", "update", "fork"]
    step: int          # superstep 编号(-1 为 input checkpoint)
    writes: dict       # 本 superstep 的写入记录
    parents: dict      # 父 checkpoint 引用

7.3 Thread 与 Checkpoint 管理

from langgraph.checkpoint.postgres import PostgresSaver
from psycopg import Connection

# 初始化 PostgreSQL checkpointer
conn = Connection.connect("postgresql://user:pass@host/db")
checkpointer = PostgresSaver(conn)
checkpointer.setup()  # 创建必要的表结构

graph = builder.compile(checkpointer=checkpointer)

# 每次调用必须传入 thread_id(隔离不同会话)
config = {"configurable": {"thread_id": "user_123_session_456"}}
result = graph.invoke({"messages": [HumanMessage("Hello")]}, config)

# 获取当前状态快照
snapshot = graph.get_state(config)
print(snapshot.values)      # 当前 state 值
print(snapshot.next)        # 下一个要执行的节点
print(snapshot.metadata)    # step、source 等元数据

# 列出所有历史 checkpoint(时间旅行调试)
history = list(graph.get_state_history(config))
for state in history:
    print(f"Step {state.metadata['step']}: {state.values}")

7.4 跨线程记忆:BaseStore

Checkpointer 是线程(thread)级别的持久化,若需要跨线程共享信息(如用户偏好),使用 BaseStore

from langgraph.store.memory import InMemoryStore
from langgraph.store.postgres import PostgresStore

store = InMemoryStore()  # 或 PostgresStore(...)

graph = builder.compile(
    checkpointer=checkpointer,
    store=store,  # 跨线程共享存储
)

# 在节点中访问 store
def personalized_node(state: State, *, store: BaseStore) -> dict:
    # 读取用户长期记忆
    user_prefs = store.get(("users", state["user_id"]), "preferences")
    
    # 写入
    store.put(
        ("users", state["user_id"]),  # namespace
        "preferences",                 # key
        {"language": "zh-CN"}          # value
    )
    return {}

7.5 时间旅行(Time Travel)

# 回滚到某个历史 checkpoint 并从那里重新执行
history = list(graph.get_state_history(config))
target_checkpoint = history[2]  # 选择某个历史状态

# 从该 checkpoint 分叉执行(不影响原来的 thread)
fork_config = graph.update_state(
    target_checkpoint.config,
    {"messages": [HumanMessage("用不同的方式重试")]},
)
new_result = graph.invoke(None, fork_config)

8. Human-in-the-Loop 工作流

8.1 静态中断(Static Interrupts)

在编译时指定中断点,适用于调试和固定审批流程:

# 在 tool_node 执行前自动暂停
graph = builder.compile(
    checkpointer=checkpointer,
    interrupt_before=["tool_node"],
)

config = {"configurable": {"thread_id": "t1"}}

# 第一次调用:执行到 interrupt_before 节点前暂停
result = graph.invoke(input_data, config)
print("Graph paused. Current state:")
print(graph.get_state(config).values)

# 人工审查后,以 None 输入恢复执行
final_result = graph.invoke(None, config)

8.2 动态中断(Dynamic Interrupts)— 生产推荐

使用 interrupt() 函数在节点内部按条件中断,更灵活:

from langgraph.types import interrupt, Command

def review_node(state: AgentState) -> dict:
    tool_call = state["messages"][-1].tool_calls[0]
    
    # 暂停并向用户展示信息,等待回应
    # interrupt() 会保存当前状态,抛出中断信号
    user_decision = interrupt({
        "action": tool_call["name"],
        "args": tool_call["args"],
        "message": "是否允许执行此工具调用?",
    })
    
    if user_decision["approved"]:
        return {"approved": True}
    else:
        return Command(goto=END)  # 拒绝则终止

# 恢复执行时传入用户决策
graph.invoke(
    Command(resume={"approved": True}),
    config
)

8.3 状态修改后恢复

# 中断后,可以修改状态再继续
graph.update_state(
    config,
    {"messages": [AIMessage("修改后的响应")]},
    as_node="llm_node"  # 假装是从该节点写入的
)

# 继续执行
graph.invoke(None, config)

9. 流式输出(Streaming)

9.1 流式模式对比

模式触发时机数据内容适用场景
values每个 superstep 后完整 state 快照状态追踪
updates每个节点完成后节点输出的 delta仪表板、进度显示
messages每个 LLM token(message_chunk, metadata)聊天 UI
debug各执行阶段详细调试信息开发调试
custom手动推送任意自定义数据特殊业务需求

9.2 使用示例

# 模式 1:values - 每步完整状态
for chunk in graph.stream(inputs, config, stream_mode="values"):
    print(chunk)  # 完整 state dict

# 模式 2:updates - 增量更新(推荐生产)
for node_name, updates in graph.stream(inputs, config, stream_mode="updates"):
    print(f"Node '{node_name}' output: {updates}")

# 模式 3:messages - token 级流式(聊天应用)
for msg_chunk, metadata in graph.stream(inputs, config, stream_mode="messages"):
    if hasattr(msg_chunk, "content"):
        print(msg_chunk.content, end="", flush=True)

# 混合模式(同时获取多种)
for stream_type, data in graph.stream(
    inputs, config, stream_mode=["updates", "messages"]
):
    if stream_type == "messages":
        token, meta = data
        print(token.content, end="")
    elif stream_type == "updates":
        print(f"\n[Node: {list(data.keys())[0]}]")

# 自定义流(在节点内 push 自定义数据)
from langgraph.types import StreamWriter

def my_node(state: State, writer: StreamWriter) -> dict:
    writer({"progress": "Starting step 1..."})
    # do work
    writer({"progress": "Step 1 done"})
    return {}

9.3 异步流式(生产推荐)

import asyncio

async def stream_agent():
    async for chunk in graph.astream(inputs, config, stream_mode="updates"):
        node_name, data = list(chunk.items())[0]
        yield f"data: {json.dumps({'node': node_name, 'data': data})}\n\n"

# 在 FastAPI 中使用 Server-Sent Events
from fastapi import FastAPI
from fastapi.responses import StreamingResponse

app = FastAPI()

@app.post("/chat")
async def chat(request: ChatRequest):
    return StreamingResponse(
        stream_agent(),
        media_type="text/event-stream"
    )

10. 高级控制流:Send / Command / 条件边

10.1 Send API:动态并行(Map-Reduce 模式)

当需要在运行时动态生成可变数量的并行任务时,使用 Send

from langgraph.types import Send

# 场景:对用户提交的 N 个文档并行处理
def dispatch_documents(state: State) -> list[Send]:
    # 从条件边返回 Send 列表,动态创建节点实例
    return [
        Send("process_document", {"doc_id": doc_id, "content": content})
        for doc_id, content in state["documents"].items()
    ]

def process_document(state: dict) -> dict:
    # 每个 Send 实例独立的 state
    result = summarize(state["content"])
    return {"summaries": [result]}

builder.add_conditional_edges("router", dispatch_documents, ["process_document"])
builder.add_node("process_document", process_document)
builder.add_edge("process_document", "aggregate")

10.2 Command 对象:状态更新 + 路由合一

Command 允许节点同时更新状态和决定下一跳,消除对条件边的依赖:

from langgraph.types import Command
from typing import Literal

def smart_node(state: State) -> Command[Literal["node_a", "node_b", "__end__"]]:
    result = process(state)
    
    # 同时更新状态 + 路由
    if result["confidence"] > 0.9:
        return Command(
            update={"result": result["value"], "status": "done"},
            goto=END
        )
    elif result["need_tools"]:
        return Command(
            update={"pending_tool": result["tool_call"]},
            goto="tool_executor"
        )
    else:
        return Command(goto="retry_node")

# 在子图中导航到父图
def subgraph_node(state: SubState) -> Command:
    return Command(
        update={"sub_result": "done"},
        goto="parent_node",
        graph=Command.PARENT  # 关键:导航到父图
    )

陷阱Command.goto叠加的,不是替代。若同时存在 add_edge("node", "next"),两个目标节点都会执行。

10.3 条件边高级用法

# 带类型提示的路由(IDE 友好,运行时检查)
from typing import Literal

def router(state: State) -> Literal["tools", "respond", "__end__"]:
    last = state["messages"][-1]
    if hasattr(last, "tool_calls") and last.tool_calls:
        return "tools"
    elif state["iteration"] >= 5:
        return "__end__"
    else:
        return "respond"

# 使用字符串 "__end__" 等价于 END 常量
graph.add_conditional_edges("llm", router)

11. 多 Agent 系统深度指南

11.1 架构模式全景

LangGraph 原生支持 7 种多 Agent 架构模式,选型决策树如下:

任务是否可分解为独立子域?
├── 否 → 单 Agent + 工具调用
└── 是 → 子域间关系如何?
        ├── 严格顺序依赖 → Pipeline(流水线)模式
        ├── 有中央调度需求 → Supervisor(监督者)模式
        ├── 需要多层级管理 → Hierarchical(层级树)模式
        ├── Agent 自主协商 → Swarm(蜂群)模式
        ├── 点对点通信 → Network(网络)模式
        ├── 需要质量自检 → Reflection(反思)模式
        └── 需要对抗验证 → Debate(辩论)模式

11.2 Supervisor 模式(集中调度)

适用场景:结构化任务、需要统一审查、worker 不能直接回复用户。

from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.prebuilt import create_react_agent
from langgraph.types import Command
from typing import Literal

# 创建专职 Worker Agent
researcher = create_react_agent(llm, tools=[web_search, read_docs], name="researcher")
coder = create_react_agent(llm, tools=[write_code, run_tests], name="coder")

class SupervisorState(MessagesState):
    next_agent: str

SYSTEM_PROMPT = """你是一个任务协调员。根据当前任务决定派发给:
- researcher:需要搜索信息时
- coder:需要编写或执行代码时
- FINISH:任务已完成时
只输出一个词:researcher / coder / FINISH"""

def supervisor_node(state: SupervisorState) -> Command[Literal["researcher", "coder", "__end__"]]:
    messages = [{"role": "system", "content": SYSTEM_PROMPT}] + state["messages"]
    response = supervisor_llm.invoke(messages)
    decision = response.content.strip().lower()

    if decision == "finish":
        return Command(goto=END)
    return Command(goto=decision, update={"next_agent": decision})

builder = StateGraph(SupervisorState)
builder.add_node("supervisor", supervisor_node)
builder.add_node("researcher", researcher)
builder.add_node("coder", coder)
builder.add_edge(START, "supervisor")
# worker 完成后都回到 supervisor
builder.add_edge("researcher", "supervisor")
builder.add_edge("coder", "supervisor")

graph = builder.compile(checkpointer=checkpointer)

Token 成本注意:Supervisor 模式因存在"翻译层"(所有 worker 输出必须经过 supervisor 二次处理),Token 消耗显著高于 Swarm 模式。


11.3 Hierarchical 层级树模式

适用于大规模系统(百级 Agent),将 Agent 组织为多层级团队:

总 Supervisor
├── 研究团队 Supervisor
│   ├── Web 搜索 Agent
│   ├── 文献检索 Agent
│   └── 数据分析 Agent
└── 工程团队 Supervisor
    ├── 代码编写 Agent
    ├── 测试 Agent
    └── 部署 Agent
from langgraph_supervisor import create_supervisor

# 安装:pip install langgraph-supervisor

# 构建子团队 Supervisor
research_team = create_supervisor(
    agents=[web_search_agent, literature_agent, data_analyst_agent],
    model=llm,
    prompt="你是研究团队主管,协调信息收集与分析工作。",
).compile()

engineering_team = create_supervisor(
    agents=[coder_agent, tester_agent, deployer_agent],
    model=llm,
    prompt="你是工程团队主管,协调代码开发与部署工作。",
).compile()

# 顶层总 Supervisor(子团队作为节点)
top_supervisor = create_supervisor(
    agents=[research_team, engineering_team],
    model=llm,
    prompt="你是总协调员,根据任务类型派发给研究团队或工程团队。",
).compile(checkpointer=checkpointer)

11.4 Swarm 蜂群模式(去中心化)

适用场景:探索性任务、Agent 自主判断移交、减少 Token 消耗。

pip install langgraph-swarm
from langgraph_swarm import create_swarm, create_handoff_tool
from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.memory import InMemorySaver

# 每个 Agent 配备"移交工具",自主决定何时将控制权传递给谁
researcher = create_react_agent(
    llm,
    tools=[
        web_search,
        create_handoff_tool(
            agent_name="coder",
            description="当需要编写或执行代码时,移交给 coder"
        ),
    ],
    prompt="你是研究专家,负责信息收集和分析。",
    name="researcher",
)

coder = create_react_agent(
    llm,
    tools=[
        write_code,
        run_tests,
        create_handoff_tool(
            agent_name="researcher",
            description="当需要更多背景信息时,移交给 researcher"
        ),
    ],
    prompt="你是代码专家,负责编写和测试代码。",
    name="coder",
)

# 编译 Swarm(系统会记住最后活跃的 Agent)
swarm = create_swarm(
    agents=[researcher, coder],
    default_active_agent="researcher",  # 默认入口 Agent
).compile(checkpointer=InMemorySaver())

config = {"configurable": {"thread_id": "session_001"}}
result = swarm.invoke(
    {"messages": [HumanMessage("帮我研究 LangGraph 并写一个示例")]},
    config
)

Supervisor vs Swarm 核心对比

维度SupervisorSwarm
协调方式集中式(中央 LLM 决策)去中心化(Agent 自主移交)
Token 消耗高(翻译层开销)低(直接移交)
可控性强(审计清晰)弱(行为涌现)
适合任务结构化、合规敏感探索性、流体任务
用户可见只有 Supervisor 回复当前 Agent 直接回复

11.5 Reflection 反思模式(质量自检循环)

from langgraph.graph import StateGraph, START, END
from typing import Annotated
from operator import add

class ReflectionState(TypedDict):
    task: str
    draft: str
    critiques: Annotated[list[str], add]
    iteration: int
    final_output: str

def generate_node(state: ReflectionState) -> dict:
    """生成或改进草稿"""
    if state.get("critiques"):
        prompt = f"原草稿:{state['draft']}\n批评意见:{state['critiques'][-1]}\n请改进:"
    else:
        prompt = f"任务:{state['task']}\n请生成初稿:"
    result = llm.invoke(prompt)
    return {"draft": result.content}

def reflect_node(state: ReflectionState) -> dict:
    """批评并提出改进意见"""
    prompt = f"请严格审查以下内容并指出问题:\n{state['draft']}"
    critique = llm.invoke(prompt)
    return {"critiques": [critique.content], "iteration": state.get("iteration", 0) + 1}

def should_continue(state: ReflectionState) -> str:
    """质量门控:超过3轮或质量达标则结束"""
    if state.get("iteration", 0) >= 3:
        return "finalize"
    if "无明显问题" in (state.get("critiques") or [""])[-1]:
        return "finalize"
    return "reflect"

builder = StateGraph(ReflectionState)
builder.add_node("generate", generate_node)
builder.add_node("reflect", reflect_node)
builder.add_node("finalize", lambda s: {"final_output": s["draft"]})
builder.add_edge(START, "generate")
builder.add_conditional_edges("generate", should_continue, ["reflect", "finalize"])
builder.add_edge("reflect", "generate")  # 反思后重新生成
builder.add_edge("finalize", END)

11.6 Debate 辩论模式(对抗验证)

研究表明,对抗式多 Agent 辩论可将事实准确率提升约 23%。

class DebateState(TypedDict):
    topic: str
    messages: Annotated[list[BaseMessage], add_messages]
    round: int
    verdict: str

def advocate_node(state: DebateState) -> dict:
    """支持方:论证正面观点"""
    last_msg = state["messages"][-1].content if state["messages"] else ""
    prompt = f"议题:{state['topic']}\n对方论点:{last_msg}\n请提出有力的支持论据:"
    response = advocate_llm.invoke(prompt)
    return {"messages": [AIMessage(content=response.content, name="advocate")]}

def critic_node(state: DebateState) -> dict:
    """反对方:质疑并反驳"""
    last_msg = state["messages"][-1].content
    prompt = f"议题:{state['topic']}\n对方论点:{last_msg}\n请提出有力的反驳意见:"
    response = critic_llm.invoke(prompt)
    return {
        "messages": [AIMessage(content=response.content, name="critic")],
        "round": state.get("round", 0) + 1,
    }

def judge_node(state: DebateState) -> dict:
    """裁判:总结辩论并得出结论"""
    debate_text = "\n".join([f"{m.name}: {m.content}" for m in state["messages"]])
    prompt = f"以下是关于「{state['topic']}」的辩论记录:\n{debate_text}\n请总结并给出结论:"
    verdict = judge_llm.invoke(prompt)
    return {"verdict": verdict.content}

def debate_router(state: DebateState) -> str:
    return "judge" if state.get("round", 0) >= 3 else "critic"

builder = StateGraph(DebateState)
builder.add_node("advocate", advocate_node)
builder.add_node("critic", critic_node)
builder.add_node("judge", judge_node)
builder.add_edge(START, "advocate")
builder.add_conditional_edges("critic", debate_router, ["advocate", "judge"])
builder.add_edge("advocate", "critic")
builder.add_edge("judge", END)

11.7 子图状态映射机制(深度解析)

策略 A:共享状态键(直接挂载)

当父图与子图存在相同的状态字段时,LangGraph 自动同步这些共享键:

class ParentState(TypedDict):
    messages: Annotated[list, add_messages]
    task: str          # 共享键
    result: str        # 共享键

class SubgraphState(TypedDict):
    messages: Annotated[list, add_messages]
    task: str          # 与父图相同 → 自动同步
    result: str        # 与父图相同 → 自动同步
    internal_memo: str  # 子图内部键 → 不会泄漏到父图

sub_graph = builder_sub.compile()

# 直接挂载:LangGraph 自动处理共享键的双向同步
parent_builder.add_node("worker", sub_graph)

策略 B:不同 Schema(包装器函数转换)

当父子图 Schema 完全不兼容时,必须使用包装函数手动转换:

class ParentState(TypedDict):
    user_query: str
    final_answer: str

class SubgraphState(TypedDict):
    input_text: str     # 与父图无重叠键
    output_text: str
    confidence: float

sub_graph = sub_builder.compile()

# 包装函数:纯适配器,只做转换不含业务逻辑
def call_subgraph(state: ParentState) -> dict:
    # Step 1:父图 State → 子图 State
    sub_input = SubgraphState(
        input_text=state["user_query"],
        output_text="",
        confidence=0.0,
    )
    # Step 2:调用子图
    sub_result = sub_graph.invoke(sub_input)
    # Step 3:子图 State → 父图 State
    return {
        "final_answer": sub_result["output_text"],
    }

parent_builder.add_node("worker", call_subgraph)

关键规则

  • 无共享键时不能直接挂载,LangGraph 会抛出运行时错误
  • 包装函数只应做转换,不应包含业务逻辑(保持适配器纯粹性)
  • 子图的内部键(如 internal_memo不会自动泄漏到父图

三层嵌套(祖父 → 父 → 子)

# 每层都需要独立的状态转换
def call_child_graph(parent_state: ParentState) -> dict:
    child_input = transform_to_child(parent_state)
    
    # child 内部会再调用 grandchild
    child_result = child_graph.invoke(child_input)
    
    return transform_from_child(child_result)

# child 内部的节点:
def call_grandchild_graph(child_state: ChildState) -> dict:
    grandchild_input = transform_to_grandchild(child_state)
    grandchild_result = grandchild_graph.invoke(grandchild_input)
    return transform_from_grandchild(grandchild_result)

子图持久化配置

# 重要:checkpointer 只需在父图编译时传入
# 子图会自动继承父图的持久化能力
parent_graph = parent_builder.compile(checkpointer=PostgresSaver(conn))

# 访问子图的状态历史(使用父图 config + 子图命名空间)
parent_config = {"configurable": {"thread_id": "t1"}}
# 子图的 checkpoint 以 (thread_id, subgraph_name) 为命名空间存储

11.8 跨 Agent 共享内存:BaseStore

Checkpointer 只在单个 thread_id 内持久化。若要在多个 Agent、多个会话间共享信息,使用 BaseStore

核心概念:Namespace 体系

BaseStore
└── namespace: ("users", "alice")
    ├── key: "preferences"   → {"language": "zh-CN", "style": "concise"}
    ├── key: "history"       → {"topics": ["LangGraph", "Python"]}
    └── ...
└── namespace: ("agent_instructions",)
    ├── key: "researcher"    → {"instructions": "优先使用学术来源"}
    └── key: "coder"         → {"instructions": "代码需包含类型注解"}
└── namespace: ("shared_context", "project_001")
    └── key: "brief"         → {"goal": "...", "constraints": [...]}

基本 CRUD 操作

from langgraph.store.memory import InMemoryStore
from langgraph.store.postgres import PostgresStore  # 生产用
import uuid

store = InMemoryStore()  # 或 PostgresStore(conn_string)

# 在节点中注入 store(LangGraph 自动注入)
def personalized_agent(state: AgentState, *, store: BaseStore) -> dict:
    user_id = state["user_id"]
    namespace = ("users", user_id)

    # 读取用户偏好
    pref_item = store.get(namespace, "preferences")
    prefs = pref_item.value if pref_item else {}

    # 基于偏好构造系统提示
    system = f"用户偏好语言:{prefs.get('language', 'zh-CN')}"
    response = llm.invoke([SystemMessage(system)] + state["messages"])

    # 更新用户交互记录
    store.put(namespace, "last_interaction", {
        "timestamp": datetime.now().isoformat(),
        "topic": extract_topic(response.content),
    })
    return {"messages": [response]}

# 编译时传入 store
graph = builder.compile(checkpointer=checkpointer, store=store)

语义搜索(向量检索)

# 使用支持向量搜索的后端(如 Redis、MongoDB)
from langgraph.store.redis import RedisStore

store = RedisStore(redis_url="redis://localhost:6379", embedding=embeddings_model)

def memory_aware_agent(state: AgentState, *, store: BaseStore) -> dict:
    user_id = state["user_id"]
    query = state["messages"][-1].content

    # 语义搜索:找出与当前问题最相关的历史记忆
    relevant_memories = store.search(
        namespace_prefix=("users", user_id),
        query=query,        # 向量相似度搜索
        limit=5,
    )
    
    memory_context = "\n".join([
        f"- {item.value['content']}" for item in relevant_memories
    ])
    
    system = f"以下是用户的相关历史信息:\n{memory_context}"
    response = llm.invoke([SystemMessage(system)] + state["messages"])

    # 将新信息存入记忆
    store.put(
        ("users", user_id, "memories"),
        str(uuid.uuid4()),
        {"content": response.content, "timestamp": datetime.now().isoformat()},
    )
    return {"messages": [response]}

多 Agent 共享指令(Procedural Memory)

# Agent 团队共享操作规范,可在运行时动态更新
def update_agent_instructions(agent_name: str, instructions: str, store: BaseStore):
    store.put(
        ("agent_instructions",),
        agent_name,
        {"instructions": instructions, "updated_at": datetime.now().isoformat()},
    )

def agent_with_shared_instructions(state: State, *, store: BaseStore) -> dict:
    # 读取团队共享的操作规范
    instr_item = store.get(("agent_instructions",), "researcher")
    instructions = instr_item.value["instructions"] if instr_item else ""
    
    system = f"操作规范:{instructions}"
    response = llm.invoke([SystemMessage(system)] + state["messages"])
    return {"messages": [response]}

11.9 生产级多 Agent 系统:并发控制与可观测性

并发隔离原则

# 多租户:thread_id 必须包含租户标识,防止状态污染
def make_thread_id(tenant_id: str, user_id: str, session_id: str) -> str:
    return f"t:{tenant_id}:u:{user_id}:s:{session_id}"

# store 的 namespace 同样需要租户隔离
def get_user_namespace(tenant_id: str, user_id: str) -> tuple:
    return ("tenants", tenant_id, "users", user_id)

Double-Texting 防护(LangGraph Platform 特性)

当用户在 Agent 仍在运行时再次发送消息(double-texting),可能导致状态冲突。LangGraph Platform 提供四种处理策略:

策略行为适用场景
reject拒绝新请求,返回错误严格单路对话
enqueue排队等待当前运行完成顺序处理
interrupt中断当前运行,处理新消息聊天机器人
rollback回滚到上一个 checkpoint 再处理需要干净状态
# 通过 SDK 指定策略
result = await client.runs.create(
    thread_id=thread_id,
    assistant_id="agent",
    input={"messages": [...]},
    multitask_strategy="interrupt",  # 指定 double-texting 策略
)

后台运行(Background Runs)

# 创建异步后台运行(不阻塞客户端)
run = await client.runs.create(
    thread_id=thread_id,
    assistant_id="agent",
    input={"messages": [...]},
    # 不传 stream_mode,即为后台运行
)
run_id = run["run_id"]

# 客户端稍后轮询或通过 webhook 获取结果
run_status = await client.runs.get(thread_id, run_id)
if run_status["status"] == "success":
    final_state = await client.threads.get_state(thread_id)

可观测性:关键指标与追踪

import os

# LangSmith 全链路追踪(节点级别)
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "your_key"
os.environ["LANGCHAIN_PROJECT"] = "multi-agent-prod"

# 在节点中添加自定义 metadata(便于后续筛选)
from langchain_core.callbacks import get_callback_manager

def instrumented_node(state: State) -> dict:
    # LangSmith 自动捕获输入/输出、延迟、Token 消耗
    with tracing_context(tags=["agent:researcher", f"user:{state['user_id']}"]):
        result = llm.invoke(state["messages"])
    return {"messages": [result]}

生产监控核心指标

指标说明告警阈值参考
task_success_rate任务完成率< 95% 告警
avg_token_per_run平均 Token 消耗超预算 120% 告警
p95_latencyP95 延迟> 30s 告警(长任务除外)
handoff_rateSwarm 中 Agent 移交频率异常高说明 Agent 能力边界不清
human_escalation_rate人工干预触发率> 10% 需重新评估 Agent 能力
checkpoint_failure_rateCheckpoint 写入失败率> 0.1% 立即告警

生产就绪检查清单

多 Agent 系统上线前检查:
□ State Schema 使用 Pydantic 做运行时验证
□ 所有 Agent 节点配置 RetryPolicy(网络错误重试)
□ thread_id 包含租户隔离标识
□ BaseStore namespace 按租户分区
□ LangSmith 追踪已启用,关键节点打 tag
□ PostgresSaver 已配置连接池(推荐 psycopg3 async pool)
□ 实现 double-texting 防护策略
□ 长任务使用 background runs + webhook 回调
□ 已对 20+ 并发 ainvoke 做过压测
□ 旧 checkpoint 清理策略已配置(防止 DB 膨胀)
□ 敏感字段(PII)在写入 checkpoint 前已脱敏

12. 预构建组件:ReAct Agent & 工具调用

12.1 create_react_agent

from langgraph.prebuilt import create_react_agent
from langchain_anthropic import ChatAnthropic
from langchain_core.tools import tool

@tool
def search(query: str) -> str:
    """搜索互联网"""
    return search_api(query)

@tool
def calculate(expression: str) -> float:
    """计算数学表达式"""
    return eval(expression)  # 注意:生产环境需沙箱

llm = ChatAnthropic(model="claude-opus-4-7")

# 最简用法
agent = create_react_agent(llm, tools=[search, calculate])

# 高级配置
agent = create_react_agent(
    llm,
    tools=[search, calculate],
    state_schema=CustomState,              # 自定义 state schema
    checkpointer=PostgresSaver(conn),      # 持久化
    state_modifier="你是一个专业助手...",   # 系统提示(注入到每轮消息)
    interrupt_before=["tools"],            # HIL
)

result = agent.invoke({
    "messages": [HumanMessage("今天的天气如何,以及 25 * 4 等于多少?")]
})

12.2 ToolNode

from langgraph.prebuilt import ToolNode

# ToolNode 自动处理工具调用结果
tool_node = ToolNode([search, calculate])

# ToolNode 内部逻辑:
# 1. 读取最后一条 AIMessage 的 tool_calls
# 2. 并行执行所有工具
# 3. 将结果包装成 ToolMessage 写回 state

12.3 工具错误处理

# ToolNode 默认会捕获工具异常并写入 ToolMessage
tool_node = ToolNode(
    tools=[search],
    handle_tool_errors=True,  # 默认 True:将异常转为 ToolMessage
)

# 自定义错误处理
def handle_error(error: Exception, tool_call: dict) -> str:
    return f"工具调用失败: {error}. 请换一种方式尝试。"

tool_node = ToolNode(tools, handle_tool_errors=handle_error)

13. 部署:langgraph-cli 与 LangGraph Platform

13.1 项目文件结构

my_agent/
├── langgraph.json      # LangGraph 项目配置(必需)
├── .env                # 环境变量(API keys 等)
├── requirements.txt
└── src/
    └── agent.py        # 图定义

langgraph.json 配置示例:

{
  "dependencies": ["."],
  "graphs": {
    "agent": "./src/agent.py:graph",
    "researcher": "./src/researcher.py:researcher_graph"
  },
  "env": ".env",
  "python_version": "3.11",
  "pip_config_file": "pyproject.toml"
}

13.2 本地开发服务器

# 安装 CLI
pip install langgraph-cli

# 启动本地开发服务器(in-memory 模式)
langgraph dev

# 指定端口和配置
langgraph dev --port 2024 --config langgraph.json

# 输出:
# 🚀 API: http://localhost:2024
# 🎨 Studio: https://smith.langchain.com/studio/?baseUrl=http://localhost:2024

13.3 REST API 调用

LangGraph Server 暴露标准 REST API:

# 创建 assistant(基于已定义的 graph)
curl -X POST http://localhost:2024/assistants \
  -H "Content-Type: application/json" \
  -d '{"graph_id": "agent", "config": {}}'

# 创建 thread
curl -X POST http://localhost:2024/threads \
  -H "Content-Type: application/json" \
  -d '{}'

# 流式运行
curl -X POST http://localhost:2024/threads/{thread_id}/runs/stream \
  -H "Content-Type: application/json" \
  -d '{
    "assistant_id": "agent",
    "input": {"messages": [{"role": "human", "content": "Hello"}]},
    "stream_mode": "messages-tuple"
  }'

13.4 Python SDK 客户端

from langgraph_sdk import get_client

client = get_client(url="http://localhost:2024")

# 创建 thread 并运行
thread = await client.threads.create()

async for chunk in client.runs.stream(
    thread["thread_id"],
    "agent",
    input={"messages": [{"role": "human", "content": "Hello"}]},
    stream_mode="messages",
):
    if chunk.event == "messages/partial":
        print(chunk.data[0]["content"], end="")

13.5 部署选项对比

方案适用场景持久化扩展性
langgraph dev本地开发内存(重启丢失)单进程
LangGraph Cloud (LangSmith)生产托管,一键部署自动管理自动扩缩容
自托管 + PostgresSaver私有部署,数据合规PostgreSQL手动水平扩展
BentoML/BentoCloud开源模型部署自定义容器化

14. 生产最佳实践

14.1 状态设计原则

# ✅ 好的实践:最小化、明确类型、合理使用 Reducer
class AgentState(TypedDict):
    messages: Annotated[list[BaseMessage], add_messages]  # 明确 reducer
    task_id: str                                            # 不可变 ID
    status: Literal["running", "done", "failed"]           # 枚举值

# ❌ 避免:在 state 中存储临时变量或大型二进制数据
class BadState(TypedDict):
    messages: list
    temp_result: Any          # 应该通过函数作用域传递
    raw_pdf_bytes: bytes      # 不应存在 state 中
    everything: dict          # 避免无结构的大 dict

14.2 节点设计规范

# ✅ 节点应该是幂等的(相同输入产生相同输出)
# ✅ 节点应该是纯函数(输出只依赖输入 state)
# ✅ 适当的超时和重试

from langgraph.types import RetryPolicy

# 为节点配置重试策略(网络错误、rate limit 等)
builder.add_node(
    "llm_call",
    llm_node,
    retry=RetryPolicy(
        max_attempts=3,
        initial_interval=1.0,
        backoff_factor=2.0,
        jitter=True,
    )
)

14.3 并发与隔离

# 多租户部署:用 user_id + session_id 组合作为 thread_id
def get_thread_id(user_id: str, session_id: str) -> str:
    return f"user_{user_id}::session_{session_id}"

# 避免 thread_id 碰撞导致状态污染
config = {
    "configurable": {
        "thread_id": get_thread_id(user_id, session_id),
        "user_id": user_id,  # 可用于 store 的 namespace
    }
}

14.4 Checkpoint 管理

# 定期清理旧 checkpoint,避免数据库膨胀
# PostgresSaver 示例:按时间策略清理

# 生产环境建议配置 checkpoint TTL(在数据库层面)
# 或实现定时清理任务:
async def cleanup_old_threads():
    cutoff = datetime.now() - timedelta(days=30)
    await checkpointer.delete_thread(
        config={"configurable": {"thread_id": old_thread_id}}
    )

14.5 错误处理与容错

# LangGraph 故障恢复机制:
# - 某节点失败时,已完成节点的 checkpoint 不会丢失
# - 重新调用 invoke/stream 时,从失败前的最后 checkpoint 恢复

# 自定义错误处理节点
def error_handler_node(state: State) -> dict:
    error = state.get("error")
    if error:
        # 记录错误、通知用户、决定是否重试
        log_error(error)
        return {"status": "failed", "error_message": str(error)}
    return {}

# 在图中添加错误路由
builder.add_conditional_edges(
    "risky_node",
    lambda s: "error_handler" if s.get("error") else "next_node"
)

14.6 安全规范

# 工具调用安全:使用白名单而非通配符
ALLOWED_TOOLS = {"web_search", "calculate", "read_file"}

def secure_tool_router(state: State) -> str:
    tool_name = state["messages"][-1].tool_calls[0]["name"]
    if tool_name not in ALLOWED_TOOLS:
        raise ValueError(f"未授权的工具调用: {tool_name}")
    return "tool_node"

# 状态中的 PII 处理:在写入 checkpoint 前脱敏
def sanitize_state(state: State) -> State:
    # 脱敏敏感字段后再存储
    ...

15. 调试与可观测性

15.1 LangSmith 集成

# 设置环境变量
export LANGCHAIN_TRACING_V2=true
export LANGCHAIN_API_KEY=your_api_key
export LANGCHAIN_PROJECT=my_langgraph_project
# 所有 graph.invoke/stream 调用自动上报到 LangSmith
# 包含完整的节点执行树、state 变化、LLM 调用详情
result = graph.invoke(inputs, config)
# → 在 LangSmith UI 中可查看完整执行轨迹

15.2 本地调试技巧

# 方式 1:开启 debug 模式
graph = builder.compile(debug=True)
# 输出每个 superstep 的详细信息

# 方式 2:遍历执行历史
config = {"configurable": {"thread_id": "debug_001"}}
result = graph.invoke(inputs, config)

for state in graph.get_state_history(config):
    print(f"Step {state.metadata['step']} ({state.metadata['source']})")
    print(f"  Messages: {len(state.values.get('messages', []))}")
    print(f"  Next: {state.next}")
    print("---")

# 方式 3:stream with debug mode
for event in graph.stream(inputs, config, stream_mode="debug"):
    print(event)

15.3 LangGraph Studio

访问本地 Studio(需先运行 langgraph dev):

https://smith.langchain.com/studio/?baseUrl=http://localhost:2024

功能:

  • 图形化执行流程:实时可视化节点执行路径
  • 状态检查器:每个 superstep 查看完整 state
  • 时间旅行:选择任意历史 checkpoint 重新执行
  • 人工干预:在中断点直接修改 state

16. API 快速参考

16.1 核心导入

# 图构建
from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.graph.message import add_messages

# 控制流
from langgraph.types import Send, Command, interrupt, StreamWriter
from langgraph.types import RetryPolicy, CachePolicy, Durability

# Checkpointing
from langgraph.checkpoint.memory import MemorySaver
from langgraph.checkpoint.sqlite import SqliteSaver
from langgraph.checkpoint.postgres import PostgresSaver

# 跨线程存储
from langgraph.store.memory import InMemoryStore

# 预构建组件
from langgraph.prebuilt import create_react_agent, ToolNode

# Functional API
from langgraph.func import entrypoint, task

16.2 StateGraph 方法速查

方法说明
add_node(name, fn, retry=...)添加节点
add_edge(from, to)添加固定边
add_conditional_edges(from, fn, mapping?)添加条件边
set_entry_point(node)等价于 add_edge(START, node)
set_finish_point(node)等价于 add_edge(node, END)
compile(checkpointer?, interrupt_before?, ...)编译为可执行图

16.3 CompiledGraph 方法速查

方法说明
invoke(input, config?)同步执行
ainvoke(input, config?)异步执行
stream(input, config?, stream_mode?)同步流式
astream(input, config?, stream_mode?)异步流式
get_state(config)获取当前状态快照
get_state_history(config)获取历史快照列表
update_state(config, values, as_node?)修改状态(HIL)

16.4 关键类型定义

# 运行配置
config = {
    "configurable": {
        "thread_id": "unique_thread_id",   # 必需(有 checkpointer 时)
        "checkpoint_id": "specific_ckpt",  # 可选:指定恢复点
    },
    "recursion_limit": 25,                 # 最大递归深度(默认 25)
    "tags": ["production", "user_123"],    # LangSmith 标签
    "metadata": {"user_id": "123"},        # 自定义元数据
}

# 流式模式类型
stream_mode: Literal["values", "updates", "messages", "debug", "custom"]

参考资源