LangGraph:add_conditional_edges详解

在 LangGraph 中,add_conditional_edges 是构建动态工作流的关键,用于创建基于条件判断的分支路径;它允许工作流根据当前状态动态决定下一步的执行路径,种模式使 LangGraph 能够处理复杂的、状态驱动的对话流程,特别是在需要工具调用和多次交互的场景中。

示例

    # State Management
    class State(TypedDict):
        messages: Annotated[List[AnyMessage], add_messages]
​
    # Nodes
    def chat_node(state: State) -> State:
        state["messages"] = chat_llm.invoke({"messages": state["messages"]})
        return state
​
    # Building the graph
    graph_builder = StateGraph(State)
    graph_builder.add_node("chat_node", chat_node)
    graph_builder.add_node("tool_node", ToolNode(tools=tools))
    graph_builder.add_edge(START, "chat_node")
    graph_builder.add_conditional_edges("chat_node", tools_condition, {"tools": "tool_node", "__end__": END})
    graph_builder.add_edge("tool_node", "chat_node")
    graph = graph_builder.compile(checkpointer=MemorySaver())
    return graph

解读:

上述示例的执行流程如下:

image

 

细节描述

执行工具节点

class ToolNode:
    def __init__(self, tools):
        self.tools = tools
    
    def __call__(self, state: State) -> State:
        # 执行工具调用
        tool_results = []
        for tool_call in state["messages"][-1].tool_calls:
            tool = self.tools[tool_call["name"]]
            result = tool.invoke(tool_call["args"])
            tool_results.append(result)
        
        return {"messages": tool_results}

状态更新:将工具执行结果作为新消息添加

 

工具节点执行后,通过 graph_builder.add_edge("tool_node", "chat_node") 返回聊天节点继续生成对工具结果的响应

 

重点关注

add_conditional_edges,这个方法包含三个核心参数

image

A、源节点:条件分支的起点
B、条件函数:决定分支路径的函数
C、分支映射:将条件函数返回值映射到目标节点的字典

 

条件函数

条件函数是一个自定义函数,它接收当前状态作为输入,返回一个字符串值,表示下一步应该执行的路径。

在上面示例中,tools_condition 函数可能类似这样:

def tools_condition(state: State) -> str:
    """判断是否需要调用工具"""
    # 获取最后一条消息
    last_message = state["messages"][-1]
    
    # 检查是否是工具调用请求
    if hasattr(last_message, "tool_calls") and last_message.tool_calls:
        return "tools"  # 需要调用工具
    else:
        return "__end__"  # 结束对话

 

tools_condition(LangGraph源码)

image

 

image

 

def tools_condition(
    state: list[AnyMessage] | dict[str, Any] | BaseModel,
    messages_key: str = "messages",
) -> Literal["tools", "__end__"]:
    """Conditional routing function for tool-calling workflows.

    This utility function implements the standard conditional logic for ReAct-style
    agents: if the last `AIMessage` contains tool calls, route to the tool execution
    node; otherwise, end the workflow. This pattern is fundamental to most tool-calling
    agent architectures.

    The function handles multiple state formats commonly used in LangGraph applications,
    making it flexible for different graph designs while maintaining consistent behavior.

    Args:
        state: The current graph state to examine for tool calls. Supported formats:
            - Dictionary containing a messages key (for `StateGraph`)
            - `BaseModel` instance with a messages attribute
        messages_key: The key or attribute name containing the message list in the state.
            This allows customization for graphs using different state schemas.

    Returns:
        Either `'tools'` if tool calls are present in the last `AIMessage`, or `'__end__'`
            to terminate the workflow. These are the standard routing destinations for
            tool-calling conditional edges.

    Raises:
        ValueError: If no messages can be found in the provided state format.

    Example:
        Basic usage in a ReAct agent:

        ```python
        from langgraph.graph import StateGraph
        from langchain.tools import ToolNode
        from langchain.tools.tool_node import tools_condition
        from typing_extensions import TypedDict


        class State(TypedDict):
            messages: list


        graph = StateGraph(State)
        graph.add_node("llm", call_model)
        graph.add_node("tools", ToolNode([my_tool]))
        graph.add_conditional_edges(
            "llm",
            tools_condition,  # Routes to "tools" or "__end__"
            {"tools": "tools", "__end__": "__end__"},
        )
        ```

        Custom messages key:

        ```python
        def custom_condition(state):
            return tools_condition(state, messages_key="chat_history")
        ```

    !!! note
        This function is designed to work seamlessly with `ToolNode` and standard
        LangGraph patterns. It expects the last message to be an `AIMessage` when
        tool calls are present, which is the standard output format for tool-calling
        language models.
    """
    if isinstance(state, list):
        ai_message = state[-1]
    elif (isinstance(state, dict) and (messages := state.get(messages_key, []))) or (
        messages := getattr(state, messages_key, [])
    ):
        ai_message = messages[-1]
    else:
        msg = f"No messages found in input state to tool_edge: {state}"
        raise ValueError(msg)
    if hasattr(ai_message, "tool_calls") and len(ai_message.tool_calls) > 0:
        return "tools"
    return "__end__"

 

分支映射

分支映射是一个字典,将条件函数的返回值映射到具体的节点或特殊端点:

{
    "tools": "tool_node",  # 当条件返回 "tools" 时,跳转到 tool_node
    "__end__": END         # 当条件返回 "__end__" 时,结束工作流
}

 

特殊端点:

  • START:工作流起点
  • END:工作流终点

 

条件分支的高级应用

多分支条件

可以创建包含多个可能路径的条件分支

def advanced_condition(state: State) -> str:
    last_message = state["messages"][-1]
    
    if "help" in last_message.content:
        return "help_flow"
    elif "purchase" in last_message.content:
        return "checkout_flow"
    elif "cancel" in last_message.content:
        return "cancellation_flow"
    else:
        return "__end__"

graph_builder.add_conditional_edges(
    "chat_node",
    advanced_condition,
    {
        "help_flow": "help_node",
        "checkout_flow": "checkout_node",
        "cancellation_flow": "cancellation_node",
        "__end__": END
    }
)

 

嵌套条件分支

# 第一层条件分支
graph_builder.add_conditional_edges(
    "initial_node",
    determine_flow_type,
    {"support": "support_flow", "sales": "sales_flow"}
)

# 支持流中的子分支
graph_builder.add_conditional_edges(
    "support_flow",
    support_condition,
    {"technical": "tech_support_node", "billing": "billing_support_node"}
)

# 销售流中的子分支
graph_builder.add_conditional_edges(
    "sales_flow",
    sales_condition,
    {"new": "new_customer_node", "existing": "existing_customer_node"}
)

 

最佳实践

保持条件函数纯净

只读取状态,不修改状态
避免副作用

明确的返回值

使用描述性的字符串作为返回值
确保返回值在分支映射中有对应项

错误处理

def safe_condition(state: State) -> str:
    try:
        # 业务逻辑
    except Exception as e:
        # 记录错误
        state["errors"].append(str(e))
        return "error_handling"

状态设计

确保状态包含条件判断所需的所有信息
使用清晰的字段命名

posted @ 2025-11-30 13:46  时空穿越者  阅读(0)  评论(0)    收藏  举报