LangGraph Edge 边

本文最后更新于 2026年8月11日

更新中

1.概述

langgraph的边,定义了逻辑如何路由以及流程怎样结束,是智能体不同节点彼此通信的重要组成部分。langgraph有几种类型的边:

  • 普通边(Normal Edges) 直接从一个节点进入下一个节点
  • 条件边(Conditional Edges) 调用一个函数决定去往哪些节点
  • 入口点(Entry Point) 用户输入到达时首先调用的节点
  • 条件入口点(Conditional Entry Point) 调用一个函数决定用户输入到达时首先调用哪些节点

一个节点有多个出边,如果一个节点有多个出边,那么所有目标节点都作为下一步并行执行。

2.普通边

langgraph两个节点之间就是一条边,两节点通过add_edge相连形成边,自带头节点START和尾节点END,也可以通过set_entry_point()graph.set_finish_point()指定头尾节点

langgraph没有下游边的最后节点走完就自动结束,也可以不指向尾节点,但是建议“有始有终”

例:通过add_edge()相连,就是最简单的普通边

from typing import TypedDict

from langgraph.graph import StateGraph
from langgraph.constants import START
from langgraph.constants import END

# 状态
class DemoState(TypedDict):
    name: str

# 节点
def node1(state: DemoState) -> dict:
    return state

# 节点
def node2(state: DemoState) -> dict:
    return state

def node3(state: DemoState) -> dict:
    return state

def node4(state: DemoState) -> dict:
    return state


if __name__ == "__main__":
    graph = StateGraph(DemoState)
    graph.add_node('node1', node1)
    graph.add_node('node2', node2)
    graph.add_node('node3', node3)
    graph.add_node('node4', node4)

    graph.add_edge(START, 'node1')
    graph.add_edge('node1', 'node2')
    graph.add_edge('node2', 'node3')
    graph.add_edge('node3', 'node4')
    graph.add_edge('node4', END)

    #graph.set_entry_point('node1')
    #graph.set_finish_point('node4')

    app = graph.compile()

    app.get_graph().print_ascii()
+-----------+  
| __start__ |  
+-----------+  
      *        
      *        
      *        
  +-------+    
  | node1 |    
  +-------+    
      *        
      *        
      *        
  +-------+    
  | node2 |    
  +-------+    
      *        
      *        
      *        
  +-------+    
  | node3 |    
  +-------+    
      *        
      *        
      *        
  +-------+    
  | node4 |    
  +-------+    
      *        
      *        
      *        
 +---------+   
 | __end__ |   
 +---------+  

3.条件边

在实际场景中,工作流下个节点可能不是固定的,要根据当前执行状态去确定下一个路由的节点,条件边就可以动态的控制执行的流程,langgraph可以使用路由函数来选择具体要执行的节点。

例:add_conditional_edges()就是添加条件边,使用add_conditional_edges(当前节点,决策函数,路由条件映射)方式调用,将check节点跳到下个节点的决策权交给is_even()方法,根据方法返回值决定跳到even节点还是odd节点

from typing import TypedDict

from langgraph.graph import StateGraph
from langgraph.constants import START
from langgraph.constants import END

# 状态
class DemoState(TypedDict):
    num: int

# 节点
def check(state: DemoState) -> dict:
    return state

def is_even(state: DemoState):
    return state['num'] % 2 == 0

# 节点
def even(state: DemoState) -> dict:
    print('even')
    return state

def odd(state: DemoState) -> dict:
    print('odd')
    return state

if __name__ == "__main__":
    graph = StateGraph(DemoState)
    graph.add_node('check', check)
    graph.add_node('even', even)
    graph.add_node('odd', odd)

    graph.add_edge(START, 'check')
    graph.add_conditional_edges('check', is_even, {
            True: 'even',
            False: 'odd'
        }
    )
    graph.add_edge('odd', END)
    graph.add_edge('even', END)

    app = graph.compile()

    app.get_graph().print_ascii()
     +-----------+      
     | __start__ |      
     +-----------+      
           *            
           *            
           *            
       +-------+        
       | check |        
       +-------+        
       ..     ..        
      .         .       
     .           .      
+------+       +-----+  
| even |       | odd |  
+------+       +-----+  
       **     **        
         *   *          
          * *           
      +---------+       
      | __end__ |       
      +---------+    

传值调用

res = app.invoke(DemoState(num=121))
print(res)
res = app.invoke(DemoState(num=12))
print(res)
odd
{'num': 121}
even
{'num': 12}

条件边构造循环结构

有时,会出现两个节点之间不断循环的情况,例如REACT模式下,大模型调用工具,工具返回后,大模型再次调用工具,直到工具返回正确的结果构成了一个循环,这种场景就可以使用条件边构建条件循环

例:

from typing import TypedDict, Literal

from langgraph.errors import GraphRecursionError
from langgraph.graph import StateGraph
from langgraph.constants import START
from langgraph.constants import END

# 状态
class DemoState(TypedDict):
    num: int
    total_loop: int
    max: int

# 节点
def node_a(state: DemoState) -> dict:
    return {
        'num': state["num"] + 1,
        'total_loop': state['total_loop'] + 1
    }

def node_b(state: DemoState) -> dict:
    return {
        'total_loop': state['total_loop'] + 1
    }


def my_loop(state: DemoState) -> Literal['node_b', END]:
    if state['total_loop'] >= state['max']:
        return END
    else:
        return 'node_b'



if __name__ == "__main__":
    graph = StateGraph(DemoState)
    graph.add_node('node_a', node_a)
    graph.add_node('node_b', node_b)

    graph.add_edge(START, 'node_a')
    graph.add_conditional_edges('node_a', my_loop)
    graph.add_edge('node_b', 'node_a')

    app = graph.compile()

    res = app.invoke(input=DemoState(num=0, total_loop=0, max=300))
    print(res)
{'num': 151, 'total_loop': 301, 'max': 300}

为防止构成死循环,langgraph支持使用config={'recursion_limit': 200}配置,从底层控制循环次数,这个配置在LangGraph定义节点(Node)就用过

try:
    res = app.invoke(
        input=DemoState(num=0, total_loop=0, max=300),
        config={'recursion_limit': 50}
    )
    print(res)
except GraphRecursionError as e:
    print(e)
Recursion limit of 200 reached without hitting a stop condition. You can increase the limit by setting the `recursion_limit` config key.
For troubleshooting, visit: https://docs.langchain.com/oss/python/langgraph/errors/GRAPH_RECURSION_LIMIT

Process finished with exit code 0

例:模拟ReAct风格智能体

import os
from typing import TypedDict, Annotated

from langchain.chat_models import init_chat_model
from langchain_core.messages import SystemMessage
from langchain_core.tools import tool
from langgraph.constants import START, END
from langgraph.graph import StateGraph, add_messages
from langgraph.prebuilt import ToolNode
from pydantic import Field, BaseModel


class AgentState(TypedDict):
    messages: Annotated[list, add_messages]


llm = init_chat_model(
    model = 'deepseek-chat',
    model_provider = 'openai',
    api_key = os.getenv('DSKEY'),
    base_url = 'https://api.deepseek.com'
)


class FiledInfo(BaseModel):
    """
    定义参数信息
    """
    city: str = Field(description='城市')


@tool(args_schema=FiledInfo, description='根据城市名称获取温度')
def tp_tool(city: str):
    print('=======tp_tool=======')
    if city == '北京':
        return 12
    elif city == '武汉':
        return 23
    elif city == '沈阳':
        return -10
    elif city == '泉州':
        return 27
    else:
        return None

tools = [tp_tool]

llm_with_tool = llm.bind_tools(tools)

SYSTEM_PROMPT = SystemMessage(content='你是一个智能助手,能调用工具和回答问题')


def chat_node(state: AgentState) -> dict:
    res = llm_with_tool.invoke( [SYSTEM_PROMPT] + state['messages'] )

    return {
        'messages': [res]
    }



tools_node = ToolNode(tools=tools)


def route_after_chat(state: AgentState):
    last_message = state['messages'][-1]

    if hasattr(last_message, 'tool_calls') and last_message.tool_calls:
        return 'tools_node'

    return END





if __name__ == '__main__':
    graph = StateGraph(AgentState)

    graph.add_node('chat_node', chat_node)
    graph.add_node('tools_node', tools_node)

    graph.add_edge(START, 'chat_node')
    graph.add_conditional_edges('chat_node', route_after_chat, ['tools_node', END])
    graph.add_edge('tools_node', 'chat_node')

    app = graph.compile()

    app.get_graph().print_ascii()

    resp = app.invoke({"messages": '在吗?沈阳的温度是?'})

    #这样也可:resp = app.invoke({"messages": [HumanMessage(content='武汉多少度?')]})

    for e in resp['messages']:
        print(e)

           +-----------+              
           | __start__ |              
           +-----------+              
                 *                    
                 *                    
                 *                    
           +-----------+              
           | chat_node |              
           +-----------+              
          ...         ...             
         .               .            
       ..                 ..          
+---------+           +------------+  
| __end__ |           | tools_node |  
+---------+           +------------+  
=======tp_tool=======
content='在吗?沈阳的温度是?' additional_kwargs={} response_metadata={} id='69998b70-c1f5-4111-8717-548e8ce5d01a'
content='在的!我来帮你查一下沈阳的温度。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 53, 'prompt_tokens': 296, 'total_tokens': 349, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 256}, 'prompt_cache_hit_tokens': 256, 'prompt_cache_miss_tokens': 40}, 'model_provider': 'openai', 'model_name': 'deepseek-v4-flash', 'system_fingerprint': 'fp_8b330d02d0_prod0820_fp8_kvcache_20260402', 'id': 'bafe5bee-2ac9-45a0-9e16-5b52243bfeb4', 'finish_reason': 'tool_calls', 'logprobs': None} id='lc_run--019fa3f5-1393-7142-9d36-f20a157924d2-0' tool_calls=[{'name': 'tp_tool', 'args': {'city': '沈阳'}, 'id': 'call_00_9DxFdFrhliSRF515rmHe7902', 'type': 'tool_call'}] invalid_tool_calls=[] usage_metadata={'input_tokens': 296, 'output_tokens': 53, 'total_tokens': 349, 'input_token_details': {'cache_read': 256}, 'output_token_details': {}}
content='-10' name='tp_tool' id='f53bbf6b-3ad7-40e9-b7c0-3930eb53e58d' tool_call_id='call_00_9DxFdFrhliSRF515rmHe7902'
content='沈阳目前的温度是 **-10℃** 🥶,天气比较冷,出门记得注意保暖哦!' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 23, 'prompt_tokens': 362, 'total_tokens': 385, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 256}, 'prompt_cache_hit_tokens': 256, 'prompt_cache_miss_tokens': 106}, 'model_provider': 'openai', 'model_name': 'deepseek-v4-flash', 'system_fingerprint': 'fp_8b330d02d0_prod0820_fp8_kvcache_20260402', 'id': 'dbf2d398-acbe-41e0-bee8-9756f932b649', 'finish_reason': 'stop', 'logprobs': None} id='lc_run--019fa3f5-18a9-7b92-a933-a61772087c40-0' tool_calls=[] invalid_tool_calls=[] usage_metadata={'input_tokens': 362, 'output_tokens': 23, 'total_tokens': 385, 'input_token_details': {'cache_read': 256}, 'output_token_details': {}}

条件边构造条件入口点

前面例子的添加第一个节点add_edge(START, )set_entry_point(),就是工作流的入口点,有时需要根据输入动态判断走某个入口,一个流程设置多个入口按需进入,这就是条件入口点,用户输入抵达,执行函数判断进入哪个入口点。

langgraph同样使用条件边add_conditional_edges(START,决策函数,路由条件映射)实现条件入口点,使用方式和普通条件边完全相同。

例:

from typing import TypedDict, Literal

from langgraph.constants import START, END
from langgraph.graph import StateGraph


class DemoState(TypedDict):
    num: int

def node1(state: DemoState):
    print('node1')
    return state

def node2(state: DemoState):
    print('node2')
    return state

def node3(state: DemoState):
    print('node3')
    return state

def check(state: DemoState) -> Literal['n1', 'n2', 'n3', END]:
    if state['num'] == 1:
        return 'n1'
    if state['num'] == 2:
        return 'n2'
    if state['num'] == 3:
        return 'n3'
    else:
        return END


if __name__ == '__main__':
    graph = StateGraph(DemoState)
    graph.add_node('node1', node1)
    graph.add_node('node2', node2)
    graph.add_node('node3', node3)

    graph.add_conditional_edges(START, check, {
        'n1': 'node1',
        'n2': 'node2',
        'n3': 'node3',
    })

    graph.add_edge('node1', END)
    graph.add_edge('node2', END)
    graph.add_edge('node3', END)

    app = graph.compile()
    app.get_graph().print_ascii()

    res = app.invoke( DemoState(num=2) )
    print(res)
                +-----------+                  
                | __start__ |                  
                +-----------+..                
             ...      .        ...             
          ...         .           ...          
        ..            .              ..        
+-------+         +-------+         +-------+  
| node1 |*        | node2 |         | node3 |  
+-------+ ***     +-------+       **+-------+  
             ***      *        ***             
                ***   *     ***                
                   ** *   **                   
                 +---------+                   
                 | __end__ |                   
                 +---------+                   
node2
{'num': 2}

"如果文章对您有帮助,可以请作者喝杯咖啡吗?"

微信二维码

微信支付

支付宝二维码

支付宝


LangGraph Edge 边
https://blog.liuzijian.com/post/2026/07/05/langgraph-edge/
作者
Liu Zijian
发布于
2026年7月5日
更新于
2026年8月11日
许可协议