边的路由逻辑
详解各类边的实现,包括条件边、动态路由及循环控制
📚 学习目标
学完这篇文章后,你将能够:
- 区分普通边与条件边
- 编写条件路由函数实现动态分支
- 使用映射对象解耦路由逻辑与节点名称
- 理解图中的循环结构及其在 Agent 中的应用
前置知识
在开始学习之前,建议先阅读:
你需要了解:
- JavaScript
switch语句或if-else逻辑 - 状态机基本概念
引言
在 LangGraphJS 中,边(Edges) 定义了节点之间的连接关系和执行顺序。如果你熟悉前端开发,可以将边理解为:
- React Router 的路由配置:定义组件之间的导航关系
- Vue Router 的导航守卫:控制路由跳转的条件和逻辑
- 状态机的转换规则:定义状态之间的转换条件
- 工作流的流程控制:决定任务的执行顺序和分支
边是 LangGraph 应用的"交通指挥员",它们决定了数据和控制流如何在节点之间流动。
💡 与前端开发的类比
- 普通边 ≈ React 组件的直接调用关系
- 条件边 ≈ 条件渲染 (
condition ? <ComponentA /> : <ComponentB />) - 入口点 ≈ 应用的根组件或路由入口
- 条件入口点 ≈ 动态路由或权限控制的入口
边的核心特征
🔗 连接性质
- 边连接两个节点,定义执行顺序
- 可以是一对一或一对多的关系
- 支持条件性和无条件连接
⚡ 执行控制
- 决定图的执行路径
- 控制数据在节点间的流动
- 支持动态路由决策
1 边的类型
边连接节点,控制流向。
1. 普通边 (Normal Edge)
最简单的连接,A 做完B 做。
// 执行完 node_a 后,立即执行 node_b
graph.addEdge('node_a', 'node_b');2. 条件边 (Conditional Edge)
根据上一节点的输出(即当前状态),决定下一节点。这是 Agent 自主决策的关键。
// 语法:addConditionalEdges(sourceNode, routingFunction, pathMap?)
graph.addConditionalEdges('check_node', routeLogic);3. 入口与出口
addEdge(START, "first_node"):定义起点addEdge("last_node", END):定义终点addConditionalEdges(START, routeFunction):条件入口点(根据初始条件决定从哪个节点开始)
ℹ️ 条件入口点的应用
条件入口点允许你根据输入数据动态选择开始节点,这在多租户系统、A/B 测试或根据用户权限选择不同处理流程时非常有用。
🎨 可视化说明
下面的图表展示了不同类型边的工作原理:
图表说明:
- 实线箭头:普通边,无条件执行
- 虚线箭头:条件边,根据条件选择路径
- 菱形节点:决策点,包含路由逻辑
- 圆角矩形:START 和 END 特殊节点
2 编写路由函数
路由函数接收当前状态,返回下一个节点的名称。
// 路由逻辑
const routeLogic = (state: typeof StateAnnotation.State) => {
if (state.isHappy) {
return 'happy_path'; // 返回节点名称
} else {
return 'sad_path';
}
};
// 注册
graph.addConditionalEdges('sentiment_analysis', routeLogic);使用 Path Map(推荐)
为了解耦代码,建议使用第三个参数 pathMap。这样路由函数返回逻辑名称(如 "continue"),而不是硬编码的节点名。
const shouldContinue = (state: State) => {
return state.messages.length > 10 ? 'stop' : 'continue';
};
graph.addConditionalEdges('model_node', shouldContinue, {
// 逻辑名称 : 实际节点名称
continue: 'model_node', // 循环!
stop: END,
});ℹ️ Path Map 的优势
使用 Path Map 可以让路由函数专注于业务逻辑(返回逻辑名称),而不是硬编码节点名称。这提高了代码的可维护性和可测试性。
🎯 边的设计模式
1. 线性流程模式
最简单的模式,节点按固定顺序执行。
graph
.addEdge(START, 'validate')
.addEdge('validate', 'process')
.addEdge('process', 'save')
.addEdge('save', END);适用场景:数据处理管道、ETL 流程、简单的工作流
2. 分支决策模式
根据条件选择不同的执行路径。
const routeByUserType = (state) => {
if (state.userType === 'premium') return 'premium';
if (state.userType === 'standard') return 'standard';
return 'free';
};
graph.addConditionalEdges('classify_user', routeByUserType, {
premium: 'premium_service',
standard: 'standard_service',
free: 'free_service',
});适用场景:用户分级处理、内容路由、权限控制
3. 循环重试模式
实现重试逻辑和错误恢复。
const shouldRetry = (state) => {
if (state.error && state.retryCount < 3) return 'retry';
if (state.error) return 'failed';
return 'success';
};
graph.addConditionalEdges('api_call', shouldRetry, {
retry: 'api_call', // 循环回自己
failed: 'error_handler',
success: END,
});适用场景:API 调用重试、网络错误恢复、幂等操作
3 常见路由模式
模式 1:基于工具调用的路由
这是 Tool Calling Agent 的核心模式。
function routeTools(state: typeof ToolStateAnnotation.State) {
const lastMessage = state.messages[state.messages.length - 1];
// 检查最后一条消息是否有工具调用请求
if (lastMessage?.tool_calls?.length) {
return 'tools'; // 路由到工具执行节点
}
return END; // 否则结束
}模式 2:人机交互(HIL)路由
审批流常用模式。
function routeApproval(state: State) {
if (state.approvalStatus === 'approved') {
return 'deploy';
} else if (state.approvalStatus === 'rejected') {
return 'notify_rejection';
}
return 'human_review'; // 默认等待
}4 循环结构
LangGraph 原生支持循环(Graph 中的 Cycle),这在 Agent 中非常常见(例如:思考-行动-观察-思考...)。
[!WARNING] 递归限制:为了防止死循环,LangGraph 设置了默认的递归深度限制(通常是 25)。你可以通过配置修改它:
graph.compile().invoke(inputs, { recursionLimit: 50 })
💡 练习题
1. 分析题
在不使用 Path Map 的情况下,如果我重命名了一个节点,需要修改哪些地方?使用 Path Map 有什么好处?
点击查看答案
不使用 Path Map 时的影响:
// 路由函数直接返回节点名称
const routeLogic = (state) => {
return state.needsValidation ? 'validator_node' : 'processor_node';
};
graph.addConditionalEdges('entry', routeLogic);如果重命名 validator_node → data_validator,需要修改:
- 节点定义处
addNode('validator_node', ...)→addNode('data_validator', ...) - 路由函数内部的返回值
'validator_node'→'data_validator' - 所有其他引用该节点名称的边定义
使用 Path Map 的好处:
// 路由函数返回逻辑名称
const routeLogic = (state) => {
return state.needsValidation ? 'needs_validation' : 'can_process';
};
graph.addConditionalEdges('entry', routeLogic, {
needs_validation: 'validator_node', // 只需修改这里
can_process: 'processor_node',
});如果重命名节点,只需修改 Path Map 映射,路由函数逻辑无需改动。这实现了逻辑与实现的解耦。
2. 设计题
设计一个"多级客服路由",先判断用户等级(VIP/普通),VIP 用户直接转人工,普通用户先经过关键词分类(退款/咨询),再分流到不同节点。
点击查看答案
// 第一层路由:用户等级
const routeByUserLevel = (state) => {
return state.userLevel === 'VIP' ? 'vip' : 'regular';
};
graph.addConditionalEdges(START, routeByUserLevel, {
vip: 'human_agent', // VIP 直接转人工
regular: 'keyword_classifier', // 普通用户分类
});
// 第二层路由:关键词分类
const routeByKeyword = (state) => {
const query = state.userQuery.toLowerCase();
if (query.includes('退款') || query.includes('refund')) {
return 'refund';
} else if (query.includes('咨询') || query.includes('inquiry')) {
return 'inquiry';
}
return 'general'; // 默认
};
graph.addConditionalEdges('keyword_classifier', routeByKeyword, {
refund: 'refund_handler',
inquiry: 'inquiry_handler',
general: 'general_handler',
});
// 图结构示意
graph
.addNode('human_agent', humanAgentNode)
.addNode('keyword_classifier', classifierNode)
.addNode('refund_handler', refundNode)
.addNode('inquiry_handler', inquiryNode)
.addNode('general_handler', generalNode);执行流程:
START
└─ VIP?
├─ Yes → human_agent → END
└─ No → keyword_classifier
├─ 退款 → refund_handler → END
├─ 咨询 → inquiry_handler → END
└─ 其他 → general_handler → END✅ 总结
本章要点:
- 边定义了节点之间的连接关系和执行顺序
- 普通边构建线性流程,条件边构建动态分支逻辑
- 路由函数是 Agent 的"大脑"决策层,决定下一步执行路径
- Path Map 提供了逻辑名称与节点名称的解耦,提高代码可维护性
- 循环结构是构建 Agent 思考-行动循环的关键
最佳实践:
- 优先使用 Path Map 来提高代码的可维护性
- 路由函数应该简洁、清晰,避免复杂的业务逻辑
- 注意递归限制,避免无限循环
- 合理使用边的设计模式(线性、分支、循环)来构建清晰的执行流
下一步:所有核心组件都学完了!在下一章《架构模式》中,我们将把图、状态、节点和边组合起来,构建真正实用的 Agent 架构,如 ReAct、多代理系统等。
登录以继续阅读
解锁完整文档、代码示例及更多高级功能。