Skip to content

Node 与 Edge

Node(节点)和 Edge(边)是 StateGraph 的两个基本构建单元。节点是执行的单元,边定义了执行的顺序和条件。

Node(节点)

基本节点

节点就是一个函数,接收当前的 state,返回 state 的更新:

python
def my_node(state: State) -> dict:
    # 读取 state
    input_value = state["input"]

    # 执行逻辑
    result = f"处理: {input_value}"

    # 返回更新(只返回需要修改的字段)
    return {"output": result}

节点签名

节点函数可以接受以下参数:

python
def my_node(
    state: State,                        # 必需的 state 参数
    config: RunnableConfig,              # 运行配置(可选)
    **kwargs,                            # 其他参数
) -> dict:
    pass

带 Config 的节点

python
from langchain_core.runnables import RunnableConfig

def node_with_config(state: State, config: RunnableConfig):
    thread_id = config["configurable"]["thread_id"]
    print(f"Running on thread: {thread_id}")
    return {"output": f"done on {thread_id}"}

异步节点

python
async def async_node(state: State):
    result = await some_async_function(state["input"])
    return {"output": result}

多返回值

节点可以一次更新多个 state 字段:

python
def multi_output_node(state: State):
    return {
        "intermediate": "处理中...",
        "status": "processing",
        "timestamp": time.time(),
    }

Edge(边)

普通边:无条件流转

python
from langgraph.graph import StateGraph, START, END

builder = StateGraph(State)

# 添加节点
builder.add_node("step1", step1_function)
builder.add_node("step2", step2_function)

# 定义执行顺序
builder.add_edge(START, "step1")   # 入口 → step1
builder.add_edge("step1", "step2") # step1 → step2
builder.add_edge("step2", END)     # step2 → 结束

条件边:根据条件路由

python
from typing import Literal

def router(state: State) -> Literal["tool_node", "respond", END]:
    """根据最后一条消息的内容决定下一步"""
    last_message = state["messages"][-1]

    if last_message.get("tool_calls"):
        return "tool_node"  # 有工具调用 → 执行工具
    elif state.get("need_clarification"):
        return "respond"   # 需要澄清 → 回复用户
    else:
        return END          # 完成 → 结束

builder.add_conditional_edges(
    "llm_node",          # 起始节点
    router,              # 路由函数
    {                    # 路由图
        "tool_node": "tool_node",
        "respond": "respond",
        END: END,
    }
)

也可以简写为列表形式:

python
builder.add_conditional_edges(
    "llm_node",
    router,
    ["tool_node", "respond", END]
)

条件边中 END 的引用方式:

  • 传入 END 常量(已导入):["tool_node", END]
  • 传入字符串 "__end__"["tool_node", "__end__"]
  • 传入字典:{... END: END}{... "__end__": END}

并行边

多个节点可以并行执行,LangGraph 会自动处理:

python
# START 后同时执行 A 和 B
builder.add_edge(START, "node_a")
builder.add_edge(START, "node_b")

# A 和 B 都完成后执行 C
builder.add_edge("node_a", "node_c")
builder.add_edge("node_b", "node_c")

图结构示例

顺序执行

START → A → B → C → END
python
builder.add_edge(START, "A")
builder.add_edge("A", "B")
builder.add_edge("B", "C")
builder.add_edge("C", END)

条件分支

         → tool_node ┐
START → LLM          → END
         → respond  ─┘
python
builder.add_node("LLM", llm_node)
builder.add_node("tool_node", tool_node)
builder.add_node("respond", respond_node)

builder.add_edge(START, "LLM")
builder.add_conditional_edges("LLM", router, ["tool_node", "respond", END])
builder.add_edge("tool_node", "LLM")  # 工具执行完后回到 LLM
builder.add_edge("respond", END)

并行执行

     → A ┐
START     → C → END
     → B ┘
python
builder.add_edge(START, "A")
builder.add_edge(START, "B")
builder.add_edge("A", "C")
builder.add_edge("B", "C")
builder.add_edge("C", END)

节点命名规范

  • 使用小写字母 + 下划线(snake_case)
  • 名称应描述节点的功能:retrieve_docscall_llmparse_output
  • 避免特殊字符
  • 在同一张图中保持名称风格一致

最佳实践

  1. 节点粒度适中:太细(每行代码一个节点)可读性差,太粗(一个大函数一个节点)丧失编排优势
  2. 无副作用:节点函数不应该有副作用(如修改全局变量),所有状态变化通过返回值体现
  3. 幂等性:尽量让节点函数在重复执行时结果一致
  4. 命名清晰:好的节点名胜过注释

参考

本站为非官方中文学习站点,不代表 LangChain 官方。部分内容参考官方文档并重新整理为中文学习笔记。