黑白梦黑白梦

  • 文章
  • 专栏
  • 文章
  • 专栏
全部文章

LangGraph 核心基础概览

发布于 2026-08-06约 22 分钟

总结梳理 LangGraph 的基础,涵盖 StateGraph、状态定义 (State Schemas)、节点 (Nodes)、边 (Edges)、Command、Send、Runtime 依赖注入、流式传输 (Streaming) 、工具集成和错误处理。

LangGraph 工作流

LangGraph 将智能体工作流建模为有向图 (directed graphs)。其核心架构由以下关键要素构成:

  • StateGraph:构建有状态图的主类,管理全局状态模式(Schema)。
  • 节点 (Nodes):执行具体逻辑的 Python 函数,接收当前 State 并返回状态增量更新。
  • 边 (Edges):控制执行流走向,分为确定性关系的静态边与动态判定的条件分支边。
  • START / END:图执行的起始点与终止点预定义标识。
  • Reducer:定义增量更新与现有状态如何合并的策略规则(如追加、合并或替换)。

图构建完成后必须调用 builder.compile() 生成可运行对象。


快速入门:端到端示例

以下示例展示智能助手意图路由 (Router Agent Pattern) 工作流。相比于线性链式调用,动态路由与分支跳转(add_conditional_edges)是体现 LangGraph 图编排能力的机制。

核心流转逻辑:

  • 分类判定:初始节点 classify 接收用户输入并判定分类(技术支持 vs 账单服务)。
  • 条件路由:条件路由函数 route_intent 根据状态中的分类字段,动态决定控制流走向 tech_support 还是 billing_support 节点。
  • 流程体现:展示了 LangGraph 中“状态维护 → 条件边判断 → 动态节点分发”的工作流范式。
Python
from typing import TypedDict
from langgraph.constants import START, END
from langgraph.graph import StateGraph

# 1. 定义图状态 (TypedDict)
class AgentState(TypedDict):
    query: str
    category: str
    response: str

# 2. 定义节点函数 (仅返回增量更新字典)
def classify_node(state: AgentState) -> dict:
    category = "technical" if "代码" in state["query"] else "billing"
    return {"category": category}

def tech_node(state: AgentState) -> dict:
    return {"response": f"【技术支持】已处理关于“{state['query']}”的技术咨询。"}

def billing_node(state: AgentState) -> dict:
    return {"response": f"【账单服务】已查询关于“{state['query']}”的账单明细。"}

# 3. 条件路由函数
def route_intent(state: AgentState) -> str:
    return state["category"]

# 4. 构建图与配置动态条件边 (Conditional Edges)
builder = StateGraph(AgentState)

builder.add_node("classify", classify_node)
builder.add_node("tech_support", tech_node)
builder.add_node("billing_support", billing_node)

builder.add_edge(START, "classify")
builder.add_conditional_edges(
    "classify",
    route_intent,
    {
        "technical": "tech_support",
        "billing": "billing_support",
    },
)
builder.add_edge("tech_support", END)
builder.add_edge("billing_support", END)

# 5. 编译与执行
graph = builder.compile()
final_state = graph.invoke({"query": "请问这段 Python 代码报错怎么解决?"})
print(final_state["response"])

状态管理 (State Management)

State 是贯穿整个图生命周期的全局数据容器。

1. 状态定义容器选择

容器类型 特点 适用场景
TypedDict (推荐) 无运行时校验开销,语法轻量,是实战项目中最常采用的方式 绝大多数智能体编排与图流转场景
Pydantic BaseModel 支持运行时数据强校验、字段默认值及自定义 Validator 需要严格校验外部 API 输入输出的场景

TypedDict 示例

Python
from typing import TypedDict, List
from typing_extensions import NotRequired

# 可设置 total=False 允许实例化时只传入部分初始字段
class AgentState(TypedDict, total=False):
    user_query: str
    conversation_history: List[str]
    search_results: NotRequired[List[str]]  # 可选增量字段

Pydantic BaseModel 示例

Python
from pydantic import BaseModel, Field
from typing import Optional

class AgentStateModel(BaseModel):
    user_id: str = Field(description="用户标识")
    query: str = Field(min_length=1, description="用户问题")
    final_answer: Optional[str] = None

2. Reducer 函数:状态合并机制

默认情况下,节点返回同名字段的值会直接覆盖现有状态。如果需要列表追加或特殊合并行为,需使用 Reducer:

合并逻辑 配置方式 说明
覆盖值 (默认) 无 Annotated 声明 直接替换原有键值
列表追加 Annotated[list, operator.add] 将节点返回的列表元素追加至旧列表末尾
消息合并 Annotated[list, add_messages] 内置消息 Reducer,支持按 ID 替换或追加 Message

带有 Reducer 的 State 定义

Python
from typing_extensions import TypedDict, Annotated
import operator
from langgraph.graph import add_messages

class StateWithReducer(TypedDict):
    current_step: str                        # 默认覆盖
    logs: Annotated[list, operator.add]      # 列表追加
    messages: Annotated[list, add_messages]  # 消息自动化合并

3. 必须返回部分更新 (Partial Updates)

节点函数接收当前状态,但必须且仅需返回增量更新字典(Partial Update)。切勿在节点内原地修改全量 state 对象再整体返回,否则易引发并发状态冲突或数据重置。

Python
# 错误做法:直接原地修改并返回整个 state
def wrong_node(state: MyState) -> MyState:
    state["final_answer"] = "done"
    return state

# 正确做法:仅返回变更字段的增量字典
def correct_node(state: MyState) -> dict:
    return {"final_answer": "done"}

节点 (Nodes)

1. 节点签名与依赖注入

节点函数可接收不同的参数签名以满足相应的功能需求:

签名格式 使用场景
def node(state: State) 仅读取和更新图状态的基础节点
def node(state: State, runtime: Runtime[Context]) 需要依赖注入外部服务(数据库连接、底层客户端、仓库实例)的节点

运行时依赖注入模式

在生产级应用中,建议通过 context_schema 定义依赖类型,并在 invoke / astream 时传入服务实例,避免全局变量依赖:

Python
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.runtime import Runtime

# 1. 定义 Context 依赖类型与 State 类型
class AppContext(TypedDict):
    db_service: object

class AppState(TypedDict):
    query: str
    result: str

# 2. 节点中通过 runtime.context 获取注入的服务
def process_node(state: AppState, runtime: Runtime[AppContext]) -> dict:
    db = runtime.context["db_service"]
    # 使用 db 服务进行查询...
    return {"result": "processed"}

# 3. 绑定 state_schema 与 context_schema
builder = StateGraph(state_schema=AppState, context_schema=AppContext)
builder.add_node("process", process_node)
builder.add_edge(START, "process")
builder.add_edge("process", END)

graph = builder.compile()

# 4. 执行时传入 context 实体
res = graph.invoke(
    {"query": "test"},
    context={"db_service": "DatabaseInstance"}
)

2. 特殊节点 (START / END)

  • START:图的唯一入口标识。通过 builder.add_edge(START, "first_node") 配置起跑节点。
  • END:图的终止节点标识。走向 END 即代表该轮图执行完成。

边 (Edges) 与路由控制

1. 静态边 (add_edge)

用于确定性的顺序节点跳转或固定分支并发:

Python
# 顺序执行:node_a -> node_b
builder.add_edge("node_a", "node_b")

# 并行并发:node_a 分发至 node_b 与 node_c
builder.add_edge("node_a", "node_b")
builder.add_edge("node_a", "node_c")

2. 条件边 (add_conditional_edges)

根据运行时状态动态路由至不同节点。

示例 A:分支路由与列表并发分发

Python
from typing import TypedDict
from langgraph.graph import StateGraph, START, END

class RouteState(TypedDict):
    query: str
    need_web_search: bool

def route_decision(state: RouteState):
    if state["need_web_search"]:
        # 返回列表触发并行处理
        return ["rag_node", "web_node"]
    return "rag_node"

builder = StateGraph(RouteState)
builder.add_node("rag_node", lambda s: {"result": "rag"})
builder.add_node("web_node", lambda s: {"result": "web"})

builder.add_conditional_edges(
    START,
    route_decision,
    {
        "rag_node": "rag_node",
        "web_node": "web_node"
    }
)

示例 B:Lambda 路由与状态自愈回环 (Retry/Correction Loop)

在实战(如 SQL 校验与纠错)中,常使用 Lambda 结合回流边构成自动纠错循环:

Python
# 当校验节点失败时流转至纠错节点,纠错完成后重新指向校验节点形成回环
builder.add_conditional_edges(
    "validate_node",
    lambda state: "execute_node" if state.get("error") is None else "correct_node",
    {
        "correct_node": "correct_node",
        "execute_node": "execute_node"
    }
)
# 纠错后重新校验
builder.add_edge("correct_node", "validate_node")
builder.add_edge("execute_node", END)

3. 循环控制与递归限制

当图中包含回环重试(如校验失败重新生成)时,可以通过在执行时传入 recursion_limit 限制最大超级步数(Superstep),防止因逻辑缺陷引发死循环:

Python
# 设置最大执行步数为 10 步
result = graph.invoke(
    {"query": "input"},
    config={"recursion_limit": 10}
)

高级控制流

1. Command API

Command 可以在节点返回值中同时完成状态更新与显式路由跳转:

Python
from langgraph.types import Command
from typing import Literal

def decision_node(state: dict) -> Command[Literal["node_b", "node_c"]]:
    if state.get("score", 0) > 80:
        return Command(update={"status": "passed"}, goto="node_c")
    return Command(update={"status": "failed"}, goto="node_b")

2. Send API

用于 Map-Reduce 模式下的动态分发(Fan-out),针对输入列表为每个元素动态生成并行节点:

Python
from langgraph.types import Send
from typing import Annotated
import operator

class MapReduceState(TypedDict):
    items: list[str]
    results: Annotated[list, operator.add]

def map_dispatcher(state: MapReduceState):
    # 动态为每个 item 生成一个 worker 节点任务
    return [Send("worker_node", {"item": item}) for item in state["items"]]

def worker_node(state: dict) -> dict:
    return {"results": [f"Processed {state['item']}"]}

运行图与流式输出 (Streaming)

1. 同步与异步调用 (invoke / ainvoke)

Python
# 同步调用
final_state = graph.invoke({"query": "hello"})

# 异步调用
final_state = await graph.ainvoke({"query": "hello"})

工程化实践:工作流类封装 (Workflow Wrapper Pattern)

在生产项目中,推荐将编译后的图实例封装在 Workflow 服务类中,对外统一提供 run() 和 stream() 接口:

Python
class KBQueryWorkflow:
    def __init__(self):
        # 初始化并编译图对象
        self.app = create_query_graph()
        
    async def run(self, initial_state: dict):
        return await self.app.ainvoke(initial_state)
        
    async def stream(self, initial_state: dict):
        async for output in self.app.astream(initial_state):
            yield output

2. 异步流式输出 (astream)

LangGraph 支持通过 .astream 获取执行过程中的流式状态事件:

Python
# 1. updates 模式:接收每一步节点产出的状态增量
async for event in graph.astream(initial_state, stream_mode="updates"):
    print(f"Node Update: {event}")

# 2. values 模式:接收每一步执行结束后的全量 State 视图
async for state_snapshot in graph.astream(initial_state, stream_mode="values"):
    print(f"State Snapshot: {state_snapshot}")

# 3. messages 模式:捕获大模型节点的流式 Token 输出
async for message_chunk, metadata in graph.astream(initial_state, stream_mode="messages"):
    if message_chunk.content:
        print(message_chunk.content, end="", flush=True)

工具集成与 ToolNode (Tools in LangGraph)

1. ToolNode 的核心用法

ToolNode 是 LangGraph 内置的标准工具执行节点(位于 langgraph.prebuilt)。其核心职责为:

  • 解析状态 state["messages"] 中最新一条 AIMessage 包含的 tool_calls 参数;
  • 执行对应的工具函数;
  • 将工具执行结果封装为 ToolMessage 并追加写入状态列表中(需在 State 中对 messages 配置 add_messages Reducer)。

配合内置条件边路由 tools_condition,可以构建 ReAct 工具调用循环:

Python
from typing import Annotated
from typing_extensions import TypedDict
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.graph import StateGraph, START, END, add_messages
from langgraph.prebuilt import ToolNode, tools_condition

# 1. 定义工具
@tool
def multiply(a: int, b: int) -> int:
    """计算两个整数的乘积。"""
    return a * b

tools = [multiply]

# 2. 定义状态模式
class State(TypedDict):
    messages: Annotated[list, add_messages]

# 3. 绑定工具到模型
llm = ChatOpenAI(model="gpt-4o-mini").bind_tools(tools)

def chatbot_node(state: State) -> dict:
    return {"messages": [llm.invoke(state["messages"])]}

# 4. 构建图结构
builder = StateGraph(State)
builder.add_node("chatbot", chatbot_node)
builder.add_node("tools", ToolNode(tools))  # 实例化 ToolNode 节点

builder.add_edge(START, "chatbot")

# 结合 tools_condition 动态判断:若模型产生 tool_calls 则转向 "tools" 节点,否则终止转向 END
builder.add_conditional_edges(
    "chatbot",
    tools_condition,
    {
        "tools": "tools",
        "__end__": END
    }
)
builder.add_edge("tools", "chatbot")  # 工具执行完成后返回 chatbot 节点

graph = builder.compile()

2. ToolNode 与 create_agent 的对比

维度 LangChain create_agent (传统 API) LangGraph StateGraph + ToolNode (图架构)
底层架构 基于链式 (Chain) / AgentExecutor 循环 基于有向图 (StateGraph),天然支持复杂图拓扑与并行分支
封装粒度 高(内部封装完整的 Model 与 Tool 执行流程) 低(自由控制节点、边、路由条件及状态更新规则)
状态管理 依赖 AgentAction / AgentFinish 传输,状态字段难以自定义扩展 自定义 State(支持 TypedDict/Pydantic 及 Reducer 增量合并)
控制流拓展 受限(难以在工具执行前后插入自定义计算节点或多路分支) 极高(可任意添加并行节点、人机协同断点、复杂条件分支与子图)
适用场景 快速原型验证、单 Agent 简单工具调用场景 生产级复杂工作流、多 Agent 协同系统与复杂业务逻辑编排

3. 在 LangGraph 中使用 Tool 的典型场景

  1. 标准 ReAct 循环
    LLM 生成工具调用指令 -> ToolNode 执行工具 -> 返回结果 -> LLM 根据工具输出继续推理并给出最终回答。
  2. 人机协同与安全审核 (Human-in-the-loop)
    在执行高风险工具(如数据库写操作、资金转账)之前,通过断点设置(如 interrupt_before=["tools"])暂停图的执行,等待人工审批确认后再推进 ToolNode 运行。
  3. 工具异常捕获与自我修复 (Error Handling)
    当外部 API 报错或输入参数不符合要求时,ToolNode(handle_tool_errors=True) 可以捕获错误并生成包含报错信息的 ToolMessage。LLM 收到报错信息后可进行自我修正重试,提升系统稳定性。
  4. 多 Agent 专项分工 (Multi-Agent Subgraphs)
    在多 Agent 系统中,不同的专家 Agent(如 SearchAgent、CodeAgent)拥有各自独立的 ToolNode,主控制图依据意图识别动态分派任务至不同的工具节点。

错误处理 (Error Handling)

1. 瞬时错误重试策略 (RetryPolicy)

针对网络连接中断、速率限制等网络或瞬时错误,可以在注册节点时配置 RetryPolicy:

Python
from langgraph.types import RetryPolicy

builder.add_node(
    "search_node",
    search_node_func,
    retry_policy=RetryPolicy(
        max_attempts=3,
        initial_interval=1.0,
        retry_on=(ConnectionError, TimeoutError)
    )
)

2. 工具调用错误捕获 (ToolNode)

在包含工具调用的 Agent 架构中,推荐使用 ToolNode 捕获工具内部产生的运行时错误并将其封装为 ToolMessage,使模型能够感知错误并自我修正:

Python
from langgraph.prebuilt import ToolNode

# handle_tool_errors=True 会自动将工具执行报错转化为 ToolMessage 节点输出
tool_node = ToolNode(tools=[fetch_user_data], handle_tool_errors=True)
builder.add_node("tools", tool_node)
目录
LangGraph 工作流快速入门:端到端示例状态管理 (State Management)1. 状态定义容器选择TypedDict 示例Pydantic BaseModel 示例2. Reducer 函数:状态合并机制带有 Reducer 的 State 定义3. 必须返回部分更新 (Partial Updates)节点 (Nodes)1. 节点签名与依赖注入运行时依赖注入模式2. 特殊节点 (START / END)边 (Edges) 与路由控制1. 静态边 (add_edge)2. 条件边 (add_conditional_edges)示例 A:分支路由与列表并发分发示例 B:Lambda 路由与状态自愈回环 (Retry/Correction Loop)3. 循环控制与递归限制高级控制流1. Command API2. Send API运行图与流式输出 (Streaming)1. 同步与异步调用 (invoke / ainvoke)工程化实践:工作流类封装 (Workflow Wrapper Pattern)2. 异步流式输出 (astream)工具集成与 ToolNode (Tools in LangGraph)1. ToolNode 的核心用法2. ToolNode 与 create_agent 的对比3. 在 LangGraph 中使用 Tool 的典型场景错误处理 (Error Handling)1. 瞬时错误重试策略 (RetryPolicy)2. 工具调用错误捕获 (ToolNode)

本文收录于专栏

AI 应用开发笔记

沉淀大模型智能体等 AI 应用的开发与落地笔记

0 篇文章更新于 2026-08-23
上一篇LangChain 核心基础概念详解下一篇Matt Skills:把模糊需求走成一条可控的 AI 编程流水线

©2015-2026 黑白梦 粤ICP备15018165号

联系: heibaimeng@foxmail.com