核心概念 #

概述 #

LangGraph 的核心是将 Agent 工作流建模为**图(Graph)**结构。通过组合节点(Nodes)和边(Edges),你可以创建复杂的有状态、可循环的工作流。

text
┌─────────────────────────────────────────────────────────────┐
│                    LangGraph 核心架构                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│                      ┌─────────┐                            │
│                      │  State  │                            │
│                      │  状态   │                            │
│                      └────┬────┘                            │
│                           │                                 │
│              ┌────────────┼────────────┐                    │
│              │            │            │                    │
│              ▼            ▼            ▼                    │
│         ┌────────┐   ┌────────┐   ┌────────┐               │
│         │  Node  │   │  Node  │   │  Node  │               │
│         │  节点  │   │  节点  │   │  节点  │               │
│         └────┬───┘   └────┬───┘   └────┬───┘               │
│              │            │            │                    │
│              └────────────┼────────────┘                    │
│                           │                                 │
│                      ┌────┴────┐                            │
│                      │  Edge   │                            │
│                      │  边     │                            │
│                      └─────────┘                            │
│                                                             │
└─────────────────────────────────────────────────────────────┘

三大核心组件 #

LangGraph 使用三个关键组件来定义 Agent 的行为:

1. State(状态) #

状态是一个共享的数据结构,代表应用程序的当前快照。它可以在图的节点之间传递和更新。

python
from typing import TypedDict, Annotated
from langgraph.graph.message import add_messages

class State(TypedDict):
    messages: Annotated[list, add_messages]
    documents: list
    current_step: str

2. Nodes(节点) #

节点是编码 Agent 逻辑的函数。它们接收当前状态作为输入,执行计算或副作用,然后返回更新后的状态。

python
def agent_node(state: State):
    response = llm.invoke(state["messages"])
    return {"messages": [response]}

3. Edges(边) #

边是根据当前状态确定下一个执行节点的函数。它们可以是条件分支或固定转换。

python
def should_continue(state: State):
    if state["messages"][-1].tool_calls:
        return "tools"
    return END

图(Graph) #

StateGraph #

StateGraph 是 LangGraph 的主要图类,它以用户定义的状态对象为参数。

python
from langgraph.graph import StateGraph

class State(TypedDict):
    messages: list
    count: int

graph = StateGraph(State)

图的编译 #

编译图是一个重要步骤,它会:

  • 验证图结构(检查孤立节点等)
  • 配置运行时参数(如检查点、断点)
python
app = graph.compile()

编译选项 #

python
from langgraph.checkpoint.memory import MemorySaver

app = graph.compile(
    checkpointer=MemorySaver(),  # 添加持久化
    interrupt_before=["sensitive_node"],  # 在特定节点前中断
    interrupt_after=["review_node"],  # 在特定节点后中断
)

状态(State)详解 #

状态 Schema #

状态 Schema 定义了图的数据结构,可以使用 TypedDict 或 Pydantic 模型。

python
from typing import TypedDict, Annotated
from operator import add
from pydantic import BaseModel

class TypedState(TypedDict):
    messages: Annotated[list, add]
    count: int

class PydanticState(BaseModel):
    messages: list
    count: int = 0

Reducer 函数 #

Reducer 定义了如何将节点的更新应用到状态上。

text
┌─────────────────────────────────────────────────────────────┐
│                    Reducer 工作原理                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  默认 Reducer(覆盖):                                      │
│  state = {"count": 1}                                       │
│  update = {"count": 2}                                      │
│  result = {"count": 2}  # 直接覆盖                          │
│                                                             │
│  自定义 Reducer(如 add):                                  │
│  state = {"items": [1, 2]}                                  │
│  update = {"items": [3]}                                    │
│  result = {"items": [1, 2, 3]}  # 合并                      │
│                                                             │
└─────────────────────────────────────────────────────────────┘

内置 Reducer #

python
from typing import Annotated
from operator import add

class State(TypedDict):
    items: Annotated[list, add]
    messages: Annotated[list, add_messages]

自定义 Reducer #

python
def custom_reducer(left: list, right: list) -> list:
    return left + [x for x in right if x not in left]

class State(TypedDict):
    unique_items: Annotated[list, custom_reducer]

多 Schema 支持 #

LangGraph 支持为图定义不同的输入、输出和内部 Schema。

python
from typing import TypedDict

class InputState(TypedDict):
    user_input: str

class OutputState(TypedDict):
    graph_output: str

class OverallState(TypedDict):
    user_input: str
    internal_data: str
    graph_output: str

graph = StateGraph(
    OverallState,
    input_schema=InputState,
    output_schema=OutputState
)

节点(Nodes)详解 #

节点函数签名 #

节点是 Python 函数,可以接收以下参数:

python
from langchain_core.runnables import RunnableConfig
from langgraph.runtime import Runtime

def node_function(
    state: State,                    # 必需:当前状态
    config: RunnableConfig,          # 可选:配置信息
    runtime: Runtime,                # 可选:运行时上下文
):
    return {"key": "value"}  # 返回状态更新

添加节点 #

python
graph.add_node("agent", agent_node)

graph.add_node("tools", ToolNode(tools))

graph.add_node(lambda state: {"count": state["count"] + 1})

特殊节点 #

text
┌─────────────────────────────────────────────────────────────┐
│                    特殊节点                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  START 节点:                                                │
│  - 虚拟节点,表示图的入口                                    │
│  - 用于定义第一个执行的节点                                  │
│                                                             │
│  END 节点:                                                  │
│  - 虚拟节点,表示图的出口                                    │
│  - 当流程到达 END 时,图执行结束                             │
│                                                             │
│  使用示例:                                                  │
│  graph.add_edge(START, "first_node")                        │
│  graph.add_edge("last_node", END)                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

节点缓存 #

LangGraph 支持节点级别的缓存,避免重复计算。

python
from langgraph.types import CachePolicy
from langgraph.cache.memory import InMemoryCache

def expensive_node(state: State):
    import time
    time.sleep(2)
    return {"result": state["input"] * 2}

graph.add_node("expensive", expensive_node, cache_policy=CachePolicy(ttl=60))
app = graph.compile(cache=InMemoryCache())

边(Edges)详解 #

普通边 #

普通边表示固定的转换,从一个节点直接到另一个节点。

python
from langgraph.graph import START, END

graph.add_edge(START, "agent")
graph.add_edge("agent", "tools")
graph.add_edge("tools", END)

条件边 #

条件边根据状态动态决定下一个节点。

python
def route(state: State):
    if state["needs_tools"]:
        return "tools"
    return END

graph.add_conditional_edges(
    "agent",
    route,
    ["tools", END]  # 可能的目标节点
)

条件边映射 #

可以使用字典映射返回值到节点名称:

python
def route(state: State):
    if state["type"] == "math":
        return "math_agent"
    elif state["type"] == "code":
        return "code_agent"
    return "general_agent"

graph.add_conditional_edges(
    "router",
    route,
    {
        "math_agent": "math_agent",
        "code_agent": "code_agent",
        "general_agent": "general_agent"
    }
)

入口点 #

入口点定义图的起始节点。

python
from langgraph.graph import START

graph.add_edge(START, "first_node")

graph.set_entry_point("first_node")

条件入口点 #

python
from langgraph.graph import START

def route_entry(state: State):
    if state["urgent"]:
        return "priority_handler"
    return "normal_handler"

graph.add_conditional_edges(START, route_entry)

执行模型 #

Super-step(超步) #

LangGraph 基于 Pregel 模型,使用"超步"概念:

text
┌─────────────────────────────────────────────────────────────┐
│                    Super-step 执行模型                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Super-step 1:                                              │
│  ┌─────────┐                                                │
│  │ Node A  │ ───> 执行并产生消息                            │
│  └─────────┘                                                │
│                                                             │
│  Super-step 2:                                              │
│  ┌─────────┐   ┌─────────┐                                  │
│  │ Node B  │   │ Node C  │ ───> 并行执行                    │
│  └─────────┘   └─────────┘                                  │
│                                                             │
│  Super-step 3:                                              │
│  ┌─────────┐                                                │
│  │ Node D  │ ───> 合并 B 和 C 的结果                        │
│  └─────────┘                                                │
│                                                             │
│  规则:                                                     │
│  - 同一超步内的节点并行执行                                 │
│  - 不同超步的节点顺序执行                                   │
│  - 所有节点完成且无消息传递时结束                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

并行执行 #

当一个节点有多个出边时,目标节点会并行执行:

python
graph.add_edge("splitter", "worker_1")
graph.add_edge("splitter", "worker_2")
graph.add_edge("splitter", "worker_3")

worker_1, worker_2, worker_3 会并行执行

递归限制 #

防止无限循环:

python
result = app.invoke(
    {"messages": [...]},
    config={"recursion_limit": 25}
)

Command 对象 #

Command 是一个多功能原语,用于控制图的执行。

python
from langgraph.types import Command

def my_node(state: State) -> Command:
    return Command(
        update={"foo": "bar"},  # 状态更新
        goto="next_node"        # 控制流
    )

Command 用途 #

text
┌─────────────────────────────────────────────────────────────┐
│                    Command 用途                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 从节点返回:                                             │
│     - update: 更新状态                                      │
│     - goto: 跳转到指定节点                                  │
│                                                             │
│  2. 输入到 invoke/stream:                                   │
│     - resume: 在中断后恢复执行                              │
│                                                             │
│  3. 从工具返回:                                             │
│     - 结合状态更新和控制流                                   │
│                                                             │
│  4. 子图导航:                                               │
│     - graph=Command.PARENT 跳转到父图                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Send 对象 #

Send 用于动态创建边,常用于 Map-Reduce 模式。

python
from langgraph.types import Send

def map_node(state: State):
    return [
        Send("process", {"item": item})
        for item in state["items"]
    ]

graph.add_conditional_edges("mapper", map_node)

Map-Reduce 示例 #

python
from langgraph.types import Send

def generate_topics(state: State):
    return [Send("generate_joke", {"topic": t}) for t in state["topics"]]

def generate_joke(state: State):
    return {"jokes": [llm.invoke(f"joke about {state['topic']}")]}

def combine_jokes(state: State):
    return {"result": "\n".join(state["jokes"])}

graph = StateGraph(State)
graph.add_node("generate_topics", generate_topics)
graph.add_node("generate_joke", generate_joke)
graph.add_node("combine_jokes", combine_jokes)

graph.add_edge(START, "generate_topics")
graph.add_conditional_edges("generate_topics", generate_topics)
graph.add_edge("generate_joke", "combine_jokes")
graph.add_edge("combine_jokes", END)

运行时上下文 #

配置(Config) #

python
from langchain_core.runnables import RunnableConfig

def my_node(state: State, config: RunnableConfig):
    thread_id = config["configurable"]["thread_id"]
    return {"thread_id": thread_id}

result = app.invoke(
    {"messages": [...]},
    config={"configurable": {"thread_id": "123"}}
)

运行时上下文(Runtime) #

python
from dataclasses import dataclass
from langgraph.runtime import Runtime

@dataclass
class Context:
    user_id: str
    db_connection: any

graph = StateGraph(State, context_schema=Context)

def my_node(state: State, runtime: Runtime[Context]):
    user_id = runtime.context.user_id
    return {"user_id": user_id}

result = app.invoke(
    {"messages": [...]},
    context=Context(user_id="user-123", db_connection=db)
)

图迁移 #

LangGraph 支持图定义的迁移,即使使用了检查点。

text
┌─────────────────────────────────────────────────────────────┐
│                    图迁移支持                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  已完成的线程:                                              │
│  ✅ 可以完全改变拓扑结构                                    │
│  ✅ 添加/删除/重命名节点和边                                │
│                                                             │
│  中断中的线程:                                              │
│  ✅ 可以添加节点和边                                        │
│  ⚠️ 不能重命名/删除节点(可能正在等待)                     │
│                                                             │
│  状态修改:                                                  │
│  ✅ 添加/删除状态键                                         │
│  ⚠️ 重命名状态键会丢失历史数据                              │
│  ⚠️ 类型不兼容可能导致问题                                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

下一步 #

现在你已经理解了 LangGraph 的核心概念,接下来学习 状态管理,深入了解如何设计和使用状态!

最后更新:2026-03-30