LangGraph代理模式
一、LangGraph代理模式总览
(一)围绕State的核心机制
LangGraph集成多种代理模式以适配不同AI agent应用场景,这些代理模式均围绕state状态展开。在前后节点间,中间流程及状态信息依靠state进行传递,state是整个代理模式运作的关键枢纽。
(二)代理架构的控制与类型
随着应用程序需求复杂度的提升,大模型在其中的操作和控制权限也相应增加。LangGraph官方对代理架构的控制程度有清晰界定,从路由代理到全自动接管,大模型介入工作和决策动作逐渐增多。主要的四类代理架构如下:
- 路由代理(Router Agent):控制程度相对较低,其运作方式类似编程中的if - else判断语句,大模型根据预设条件选择执行路径。
- 工具调用代理(Tool - calling Agent ):大模型具备自主决策调用外部工具(如数据库查询、文本编辑、计算工具等)并执行的能力,根据工具返回结果进一步处理任务。
- 自主循环代理(Autonomous Loop Agent ):大模型自主决策并循环执行任务,控制程度较高。它利用预定义步骤(包含执行函数、工具调用等)集合不断循环决策,自主判断任务完成情况,直至输出结果。
- 多代理(Multi - Agent ):由多个单代理相互协作构成,Agent间可相互输入输出,自主循环交互,能够灵活应对复杂场景。这四类代理架构构成了LangGraph构建AI Agent应用的基础框架,开发者可在此基础上进行自主研发扩展,以适配更复杂的任务需求。
二、路由代理(Router Agent)详解
(一)原理与场景
路由代理基于条件边概念工作。在LangGraph中,Start节点负责接收用户输入,大模型借助Router函数,依据输入内容及中间过程进行决策,引导输入走向相应的处理流程。例如,当输入结构化查询请求时,可能导向数据库操作节点;若输入简单问候语,则直接返回响应。每个决策路径最终都指向End节点。
(二)代码实现
- 基础构建:使用
dict
定义图状态,作为共享状态数据类型。添加由函数构成的节点,在函数内部编写具体逻辑。通过add_edge
方法构建节点之间的关联关系,明确数据的流向。例如:
from langgraph.graph import START, StateGraph, END
from langgraph.graph import StateGraph
def node_a(state):
return {"x": state["x"] + 1}
def node_b(state):
return {"x": state["x"] - 2}
builder = StateGraph(dict)
builder.add_node("node_a", node_a)
builder.add_node("node_b", node_b)
builder.add_edge(START, "node_a")
builder.add_edge("node_a", "node_b")
builder.add_edge("node_b", END)
graph = builder.compile()
在这段代码里,首先从langgraph.graph
导入所需对象。接着定义node_a
和node_b
两个节点函数,分别对共享状态中的x
进行加1和减2操作。然后创建StateGraph
对象builder
,利用add_node
方法添加节点,再用add_edge
方法构建从START
经node_a
、node_b
到END
的路径,完成图的基本构建后,通过compile
方法进行编译。
2. 条件边构建:核心是使用Graph
基类中的add_conditional_edges
方法,该方法接收多个重要参数:
source
:指定分支起始节点,确定从哪个节点开始进行分支决策。path
:是一个可调用函数,它接收全局共享状态,返回节点名称或布尔值来决定路由方向。可以是普通函数、异步函数或可运行对象。path_map
(可选):用于节点名称映射。当path
返回的不是直接的节点名称(如布尔值)时,可通过path_map
将其映射到具体的节点名称。then
:用于指定在path
选择的节点之后执行的节点名称。
class Graph:
def __init__(self) -> None:
self.nodes: dict[str, NodeSpec]
self.edges = set[tuple[str, str]]()
self.branches: defaultdict[str, dict[str, Branch]] = defaultdict(dict)
self.support_multiple_edges = False
self.compiled = False
def add_conditional_edges(
self,
source: str,
path: Union[
Callable[..., Union[Hashable, list[Hashable]]],
Callable[..., Awaitable[Union[Hashable, list[Hashable]]]],
Runnable[Any, Union[Hashable, list[Hashable]]],
],
path_map: Optional[Union[dict[Hashable, str], list[str]]] = None,
then: Optional[str] = None,
) -> Self:
pass
- 示例操作:定义路由函数,根据状态值判断返回相应的节点名。添加节点并设置起始节点,使用
add_conditional_edges
方法添加条件边,传入起始节点和路由函数,完成图的构建、编译及可视化。也可以结合path_map
,根据路由函数返回的布尔值映射到不同节点,构建更灵活的路由逻辑。
from langgraph.graph import START, StateGraph, END
from langgraph.graph import StateGraph
from IPython.display import Image, display
def node_a(state):
return {"x": state["x"] + 1}
def node_b(state):
return {"x": state["x"] - 2}
def node_c(state):
return {"x": state["x"] + 1}
def routing_function(state):
if state["x"] == 10:
return "node_b"
else:
return "node_c"
builder = StateGraph(dict)
builder.add_node("node_a", node_a)
builder.add_node("node_b", node_b)
builder.add_node("node_c", node_c)
builder.set_entry_point("node_a")
# 重点关注
builder.add_conditional_edges("node_a", routing_function)
graph = builder.compile()
display(Image(graph.get_graph(xray=True).draw_mermaid_png()))
在该示例中,定义了node_a
、node_b
、node_c
节点函数和routing_function
路由函数。routing_function
根据共享状态中x
的值决定返回node_b
或node_c
。创建StateGraph
对象builder
后,添加节点并设node_a
为起始节点,通过add_conditional_edges
方法添加条件边,编译图后使用display
和Image
展示可视化图结构,直观呈现路由分支效果。
from langgraph.graph import START, StateGraph, END
from langgraph.graph import StateGraph
from IPython.display import Image, display
def node_a(state):
return {"x": state["x"] + 1}
def node_b(state):
return {"x": state["x"] - 2}
def node_c(state):
return {"x": state["x"] + 1}
def routing_function(state):
if state["x"] == 10:
return True
else:
return False
builder = StateGraph(dict)
builder.add_node("node_a", node_a)
builder.add_node("node_b", node_b)
builder.add_node("node_c", node_c)
builder.set_entry_point("node_a")
# 重点关注
builder.add_conditional_edges("node_a", routing_function, {True: "node_b", False: "node_c"})
builder.add_edge("node_b", END)
builder.add_edge("node_c", END)
graph = builder.compile()
display(Image(graph.get_graph(xray=True).draw_mermaid_png()))
此示例进一步展示了结合path_map
的用法。routing_function
返回布尔值,通过add_conditional_edges
的path_map
参数,将True
映射到node_b
,False
映射到node_c
,并添加从node_b
和node_c
到END
的边,构建出更灵活的路由逻辑。
(三)优势与劣势
- 优势:开发者能够基于业务逻辑预先规划整个流程,对中间过程实现高度可控。其逻辑清晰明了,便于理解和维护,在处理简单规则的任务时优势明显。
- 劣势:灵活性方面存在欠缺,面对构建图时未考虑到的边缘情况,难以做出合适的响应。当业务变得复杂时,拓展性受到限制,图结构容易变得复杂,增加维护成本。
(四)应用场景
适用于业务逻辑固定明确的场景。例如在电商系统中,可根据订单类型(普通订单、退换货订单等)进行不同的流程处理;在客服问答系统里,依据用户问题类型(产品信息咨询、售后投诉等)转接至不同的处理模块。
三、构建路由代理的关键要点
(一)优势与局限
在构建图结构时,开发者可以基于业务逻辑和个人需求,对中间过程实现高度可控,预先明确可能出现的问题和分支走向,这使得整个流程具有较好的可管理性。然而,当出现构建图时未考虑到的边缘条件时,路由代理可能无法做出正确响应,其适应性相对较弱。
(二)路由函数设计
构建路由代理的关键在于合理设计router function
。它需要精确判断用户意图,从而确定后续分支路径。在实际业务场景中,判断逻辑往往较为复杂,并非简单的条件判断。例如上述示例中判断“x = 10”的逻辑,在实际应用中会被更复杂的业务逻辑取代,需要开发者根据具体需求进行精细化设计。这一过程依赖大模型结构化输出能力,以识别不同输入模式,做出准确决策。
四、其他代理模式简介
(一)工具调用代理(Tool - calling Agent )
- 原理:大模型能够自主决策调用外部工具(如数据库查询工具、文本编辑工具、计算工具等)并执行操作,然后依据工具返回的结果进一步处理任务,以此来完成更复杂的功能。
- 优势与劣势:借助外部丰富的工具,大大拓展了大模型的能力边界,使其能够灵活应对各种不同类型的任务。然而,该代理模式对工具的稳定性有较强依赖,一旦工具出现故障、接口变更等问题,会影响代理的正常工作。同时,合理选择和组合工具需要精确的判断和规划,否则可能导致资源浪费或任务处理失误。
- 应用场景:广泛应用于需要多种专业工具协同工作的场景。比如科研数据处理,可能需要调用数据采集工具、数据分析工具、绘图工具等;在智能写作场景中,会调用语法检查工具、素材检索工具等辅助创作。
(二)自主循环代理(Autonomous Loop Agent )
- 原理:Start节点接收输入后,大模型利用预定义的步骤(包括执行函数、工具调用等)集合不断进行循环决策。在这个过程中,大模型自主判断任务是否完成,若未完成则持续尝试,直至认为结果能够输出给用户。
- 优势与劣势:自主性极高,无需人工过多干预中间过程,能够充分发挥大模型的智能决策能力,尤其擅长处理复杂、实现路径不清晰的任务。但由于模型自主决策过程复杂,导致结果难以预知,调试和优化工作困难,并且决策过程的可解释性较差,不利于对结果进行合理性验证。
- 应用场景:适用于复杂问题求解场景,如科学研究中的创新算法探索、复杂系统故障诊断等,这些场景需要模型自主尝试多种方法找到解决方案。
(三)多代理(Multi - Agent )
- 原理:基于LangGraph底层图的构建思路,由多个单代理(如路由代理、工具调用代理等)相互协作构成。Agent之间可以相互输入输出,实现自主循环交互,共同完成复杂任务。
- 优势与劣势:不同类型的代理发挥各自优势,协同处理任务,能够显著提升任务处理的效率和效果,并且扩展性良好,可根据任务需求灵活添加或调整代理。但多个代理之间的通信、协作和任务分配需要精细设计和管理,否则容易出现冲突或任务衔接不畅的问题。随着代理数量和交互逻辑的增加,整个系统的复杂度会呈指数级上升,维护和调试成本高昂。
- 应用场景:适用于大型复杂系统和分布式任务场景。如智能城市管理中,涉及交通管理、能源调度、公共服务等多个领域的任务需要多代理协作完成;在大型企业的业务流程管理中,采购、生产、销售等多个环节的协同工作也可借助多代理实现高效运作。