Skip to content

核心概念

StateGraph、节点/边/条件边、状态与 reducer。

Updated View as Markdown
For humans

核心概念

LangGraph 把 agent 流程建模成状态机图:节点是处理步骤,边是流转,状态是节点间传递的数据。面试主线:图怎么建、状态怎么定义、分支怎么走。

图的三个要素

节点 + 边 + 条件边构成图

要素 API 作用
节点 add_node("name", fn) 一个处理步骤,函数接收 state 返回 state 更新
add_edge(a, b) 固定流转
条件边 add_conditional_edges(a, router) 按状态动态路由
入口/出口 START / END 图边界
from langgraph.graph import StateGraph, START, END

builder = StateGraph(AgentState)
builder.add_node("model", call_model)
builder.add_node("tools", call_tools)
builder.add_edge(START, "model")
builder.add_conditional_edges("model", should_continue,  # 路由函数
    {"continue": "tools", "end": END})
builder.add_edge("tools", "model")
graph = builder.compile()

状态与 reducer

状态是 TypedDict(或 Pydantic 模型),reducer 决定字段如何合并更新

from typing import Annotated, TypedDict, operator

class AgentState(TypedDict):
    messages: Annotated[list, operator.add]   # 追加合并
    user_id: str                              # 默认覆盖
    steps: int                                # 计数器
字段定义 合并行为
无 reducer 后写的覆盖先写的
Annotated[list, operator.add] 列表追加(消息历史的标准写法)
自定义 reducer 任意合并逻辑(去重、取最大)

reducer 是考点核心:节点返回的只是“增量”,reducer 决定怎么合并进状态。messages 用 operator.add 才能跨节点累积对话历史,覆盖语义会丢掉历史。

条件边与路由

def should_continue(state: AgentState):
    if state["messages"][-1].tool_calls:
        return "continue"   # 还有工具要调
    return "end"

# 模型输出 → 有 tool_calls 去工具节点, 否则结束

条件边让图有了循环能力:模型节点 → 工具节点 → 模型节点,直到模型不再请求工具。这就是 create_agent 循环的 LangGraph 底层形态(标准 harness 只是这套图的封装)。

与普通代码的区别

维度 普通函数调用 LangGraph
状态 隐式(局部变量) 显式(State 类型)
流转 代码顺序 图结构声明
持久化 可挂 checkpoint(见持久化篇)
可视化/调试 图即文档(LangGraph Studio)

面试话术:LangGraph 的价值不是“图”本身,而是状态显式化 + 可持久化 + 可中断,这是复杂 agent 可靠性的前提。

面试追问

  1. LangGraph 的三个要素? 节点(处理)、边(流转)、状态(数据)。条件边实现分支和循环
  2. reducer 是什么? 字段的合并规则:默认覆盖,operator.add 追加。messages 必须追加才能累积历史
  3. 节点函数返回什么? 状态的增量(部分字段),reducer 合并进完整状态。不是返回整个状态
  4. 循环怎么实现? 条件边:模型节点根据是否还有 tool_calls 路由到工具节点或 END
  5. 为什么用图而不是代码? 状态显式、可持久化、可中断、可可视化。复杂 agent 的可靠性靠这些
Navigation

Type to search…

↑↓ navigate↵ selectEsc close