Skip to content

Latest commit

 

History

History
232 lines (171 loc) · 6.2 KB

File metadata and controls

232 lines (171 loc) · 6.2 KB

LangGraph 设计改进总结

本文档总结了根据官方 LangGraph 设计思路对当前实现进行的改进。

改进概览

根据计划中的混合方案,我们实现了以下改进:

  1. 支持 Command 对象(可选) - 节点可以选择返回 Command 或字典
  2. 状态分离 - 重构 GraphState 分离业务状态和执行状态
  3. 增强类型安全 - 为路由键添加类型定义和验证
  4. 更新构建器 - 支持处理 Command 对象返回值

1. Command 对象支持

实现方式

节点执行器现在可以选择返回 Command 对象或字典,通过节点配置启用:

# 节点配置
{
  "config": {
    "useCommandMode": true,  # 启用 Command 模式
    "commandGoto": "next_node",  # 指定下一个节点
    "commandErrorGoto": "error_handler"  # 错误处理节点
  }
}

支持的节点类型

  • AgentNodeExecutor: 支持 Command 模式
  • ConditionNodeExecutor: 支持 Command 模式(可配置 true/false 分支的目标节点)
  • RouterNodeExecutor: 支持 Command 模式(可在路由规则中配置 goto)

使用示例

# Agent 节点返回 Command
async def __call__(self, state: GraphState) -> Union[Dict[str, Any], Command]:
    if use_command_mode:
        return Command(
            update={"messages": new_messages},
            goto="next_node"
        )
    return {"messages": new_messages}  # 默认模式

构建器支持

构建器会自动检测 Command 模式,并为 router 节点创建包装函数以处理 Command 对象:

def _create_router_wrapper(router_executor, conditional_map):
    """包装路由函数,处理 Command 对象返回值"""
    async def router_wrapper(state: GraphState) -> str:
        result = await router_executor(state)
        if isinstance(result, Command):
            # 提取 goto 并映射回 route_key
            goto = result.goto
            # ... 映射逻辑
        return result  # 字符串 route_key
    return router_wrapper

2. 状态分离

设计原则

根据官方 LangGraph 设计思路,我们将状态分为两部分:

  • BusinessState: 业务数据(context, messages)
  • ExecutionState: 执行元数据(current_node, route_decision, loop_count 等)

实现方式

class BusinessState(TypedDict, total=False):
    """业务状态:存储工作流的业务数据"""
    context: Dict[str, Any]
    # messages 继承自 MessagesState

class ExecutionState(TypedDict, total=False):
    """执行状态:存储工作流执行的元数据"""
    current_node: Optional[str]
    route_decision: str
    route_history: List[str]
    loop_count: int
    # ... 更多执行元数据

class GraphState(MessagesState, BusinessState, ExecutionState):
    """组合状态:同时包含业务状态和执行状态"""
    # 向后兼容,所有现有代码无需修改

优势

  1. 概念清晰: 业务数据与执行元数据分离
  2. 向后兼容: GraphState 继承两者,现有代码无需修改
  3. 易于理解: 符合官方设计原则

3. 类型安全增强

路由键类型定义

创建了 route_types.py 模块,定义了路由键类型:

RouteKey = Union[
    Literal["true", "false"],
    Literal["continue_loop", "exit_loop"],
    Literal["default"],
    str,  # 允许自定义路由键
]

验证工具

提供了路由键验证函数:

def validate_route_key(route_key: str, allowed_keys: Set[str]) -> bool:
    """验证路由键是否在允许的集合中"""
    return route_key in allowed_keys

def get_standard_route_keys() -> Set[str]:
    """获取标准路由键集合"""
    return {"true", "false", "continue_loop", "exit_loop", "default"}

类型提示更新

节点执行器的返回类型已更新为使用 RouteKey

async def __call__(self, state: GraphState) -> Union[RouteKey, Command]:
    """返回类型安全的路由键或 Command 对象"""
    ...

4. 构建器更新

Command 对象处理

构建器现在能够:

  1. 检测 Command 模式: 检查节点配置中的 useCommandMode
  2. 创建包装函数: 为 router 节点创建包装函数以处理 Command 对象
  3. 路由映射: 将 Command 的 goto 映射回 route_key(用于条件边)

向后兼容

  • 默认行为不变:节点返回字典,使用条件边路由
  • Command 模式是可选的:只有明确配置的节点才会使用
  • 现有图定义无需修改

使用指南

启用 Command 模式

在节点配置中添加:

{
  "config": {
    "useCommandMode": true,
    "commandGoto": "target_node_name"
  }
}

Condition 节点配置

{
  "config": {
    "useCommandMode": true,
    "commandTrueGoto": "true_branch_node",
    "commandFalseGoto": "false_branch_node"
  }
}

Router 节点配置

{
  "config": {
    "useCommandMode": true,
    "routes": [
      {
        "condition": "state.get('score') > 80",
        "targetEdgeKey": "high_score",
        "commandGoto": "high_score_handler"
      }
    ]
  }
}

优势总结

官方方式的优势(现在可用)

  1. 灵活性: 节点可以返回 Command,完全控制路由
  2. 类型安全: 使用类型提示确保路由正确性
  3. 逻辑清晰: 路由决策与状态更新在同一处

当前实现的优势(保留)

  1. 可视化友好: 路由通过边配置,适合拖拽式编辑器
  2. 配置化: 节点行为可通过 JSON 配置
  3. 丰富的元数据: 支持复杂的执行跟踪和调试

混合方案的优势

  1. 最佳实践: 结合两种方式的优点
  2. 向后兼容: 现有代码无需修改
  3. 灵活选择: 根据场景选择使用方式

注意事项

  1. Command 模式是可选的: 默认使用字典返回模式(向后兼容)
  2. 需要 LangGraph 支持: Command 对象需要 langgraph.types.Command 可用
  3. 路由映射: Command 的 goto 需要与节点名称匹配

未来改进

  1. 更智能的路由映射: 自动处理 Command goto 到 route_key 的映射
  2. 状态分离工具: 提供工具函数帮助分离业务状态和执行状态
  3. 类型验证: 在构建时验证路由键的有效性