核心组件详解

边的路由逻辑

详解各类边的实现,包括条件边、动态路由及循环控制

📚 学习目标

学完这篇文章后,你将能够:

  • 区分普通边与条件边
  • 编写条件路由函数实现动态分支
  • 使用映射对象解耦路由逻辑与节点名称
  • 理解图中的循环结构及其在 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_nodedata_validator,需要修改:

  1. 节点定义处 addNode('validator_node', ...)addNode('data_validator', ...)
  2. 路由函数内部的返回值 'validator_node''data_validator'
  3. 所有其他引用该节点名称的边定义

使用 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、多代理系统等。

登录以继续阅读

解锁完整文档、代码示例及更多高级功能。

立即登录

On this page