StateGraph 详细分析

StateGraph 详细分析

源码路径:spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/StateGraph.java


1. 类的定位与职责

StateGraph 是整个图引擎的定义层(Definition Layer) ,负责描述一个有状态工作流的拓扑结构。它不负责执行,只负责声明图的结构 ------哪些节点、哪些边、如何连接。真正的执行由 compile() 产生的 CompiledGraph 承担。

scss 复制代码
StateGraph(定义)  ──compile()──▶  CompiledGraph(执行)

2. 核心数据结构

特殊节点常量

常量 说明
START __START__ 图的入口,所有流程必须从此出发
END __END__ 图的出口,表示流程正常结束
ERROR __ERROR__ 错误路由节点,流程异常时跳转
NODE_BEFORE __NODE_BEFORE__ 节点执行前的钩子标识
NODE_AFTER __NODE_AFTER__ 节点执行后的钩子标识

所有常量以 __ 为前缀,与用户自定义节点隔离(Node.PRIVATE_PREFIX = "__")。

Nodes 容器(内部类)

java 复制代码
public static class Nodes {
    public final Set<Node> elements;  // LinkedHashSet,保证去重且保持插入顺序
}
方法 说明
anyMatchById(String id) 判断是否存在指定 id 的节点
onlySubStateGraphNodes() 获取所有未编译子图节点
exceptSubStateGraphNodes() 获取排除子图节点后的普通节点列表

Edges 容器(内部类)

java 复制代码
public static class Edges {
    public final List<Edge> elements;  // LinkedList,便于顺序查找
}
方法 说明
edgeBySourceId(String sourceId) 按源节点 id 查找第一条匹配的边
edgesByTargetId(String targetId) 反向查找所有指向目标节点的边

3. 节点类型体系

addNode 提供 6 个重载,对应 4 种节点类型:

重载签名 实际节点类型 说明
addNode(id, AsyncNodeAction) Node 普通节点,执行业务逻辑并返回状态更新
addNode(id, AsyncNodeActionWithConfig) Node 带编译配置的普通节点
addNode(id, AsyncCommandAction, mappings) Node + 条件边 节点本身是路由决策点(单路由)
addNode(id, AsyncMultiCommandAction, mappings) Node + 并行条件边 节点决定并行路由(多路由)
addNode(id, CompiledGraph) SubCompiledGraphNode 已编译子图(直接内嵌,共享父图状态)
addNode(id, StateGraph) SubStateGraphNode 未编译子图(父图编译时一并编译)

后两种子图节点与父图共享同一份 OverAllState,状态透传无需额外转换。


4. 边类型体系

普通边

java 复制代码
addEdge(sourceId, targetId)               // 1 对 1
addEdge(List<String> sourceIds, targetId) // 多对 1(汇聚)
addEdge(sourceId, List<String> targetIds) // 1 对多(广播)

同一 sourceId 可累积多个 target,形成并行分叉Edge.isParallel() == true)。

条件边(单路由)

java 复制代码
addConditionalEdges(sourceId, AsyncCommandAction, Map<String, String> mappings)
addConditionalEdges(sourceId, AsyncEdgeAction, Map<String, String> mappings)
addConditionalEdges(sourceId, AsyncEdgeActionWithConfig, Map<String, String> mappings)

AsyncCommandAction 在运行时返回一个 Command(包含下一节点 key),通过 mappings 映射到实际节点 ID。

并行条件边(多路由)

java 复制代码
addParallelConditionalEdges(sourceId, AsyncMultiCommandAction, Map<String, String> mappings)

AsyncMultiCommandAction 返回 MultiCommand(包含多个节点 key),可同时路由到多个节点并行执行


5. 序列化机制

java 复制代码
public static final StateSerializer DEFAULT_JACKSON_SERIALIZER =
    new SpringAIJacksonStateSerializer(OverAllState::new, new ObjectMapper());
序列化器 说明
SpringAIJacksonStateSerializer 默认,基于 Jackson JSON
SpringAIStateSerializer 已废弃
PlainTextStateSerializer 已废弃
  • StateSerializer:决定 OverAllState 如何在检查点(checkpoint)中持久化
  • KeyStrategyFactory:控制状态中每个 key 的合并策略(覆盖、追加、自定义聚合)

6. 校验机制(validateGraph()

编译前自动执行,按以下规则检查:

  1. 所有节点自校验(id 不能为空、不能以 __ 开头)
  2. 必须存在从 START 出发的边,否则抛 missingEntryPoint
  3. 所有边的 source/target 节点必须存在于节点集合
  4. 并行边不能有重复 target
  5. 条件边的 mappings 中引用的节点必须存在(END 除外)

7. 编译流程

java 复制代码
// 推荐:带自定义配置(生产环境,注入持久化 Saver)
CompiledGraph compile(CompileConfig config)

// 默认:使用 MemorySaver(开发调试)
CompiledGraph compile()

compile() 默认使用 MemorySaver 作为检查点存储,适合开发调试。生产场景应通过 CompileConfig 注入 JDBC / Redis 等持久化 Saver。


8. 图可视化

java 复制代码
getGraph(GraphRepresentation.Type type, String title, boolean printConditionalEdges)
getGraph(GraphRepresentation.Type type, String title)
getGraph(GraphRepresentation.Type type)

将图结构序列化为可视化代码(如 Mermaid 流程图),供 Studio 调试界面渲染。


9. 设计模式

模式 体现
Builder / Fluent API 所有 addNode / addEdge 返回 this,支持链式调用
工厂方法 KeyStrategyFactoryNode.ActionFactory 延迟到编译时创建实例
定义与执行分离 StateGraph(定义)→ CompiledGraph(执行)
策略模式 StateSerializerKeyStrategy 可替换
模板方法 SubStateGraphNode 延迟到父图编译时才编译子图

10. 典型使用示例

java 复制代码
var graph = new StateGraph(keyStrategyFactory)
    // 普通节点
    .addNode("llm", state ->
        completedFuture(Map.of("result", callLLM(state))))
    // 工具节点
    .addNode("tool", state ->
        completedFuture(Map.of("result", callTool(state))))
    // 入口 → llm
    .addEdge(START, "llm")
    // llm 根据结果决定路由
    .addConditionalEdges("llm",
        (state, cfg) -> completedFuture(
            needTool(state) ? new Command("tool") : new Command("end")),
        Map.of("tool", "tool", "end", END))
    // 工具执行完回到 llm
    .addEdge("tool", "llm");

// 编译(开发调试)
CompiledGraph compiled = graph.compile();

// 编译(生产,使用 JDBC 持久化检查点)
CompiledGraph compiled = graph.compile(
    CompileConfig.builder()
        .saverConfig(SaverConfig.builder().register(jdbcSaver).build())
        .build());

11. 构造器一览

构造器 说明
StateGraph() 无名称,空 key 策略,默认 Jackson 序列化
StateGraph(KeyStrategyFactory) 自定义 key 策略,默认 Jackson 序列化
StateGraph(String, KeyStrategyFactory) 带名称,默认 Jackson 序列化
StateGraph(KeyStrategyFactory, StateSerializer) 自定义 key 策略和序列化器
StateGraph(String, KeyStrategyFactory, StateSerializer) 完整参数(推荐)
相关推荐
JavaGuide3 分钟前
我用 Claude Code/ZCode+GLM-5.3 从零做了一款 Agent 游戏!
前端·后端
程序员清风15 分钟前
专业再升级!程序员专属显示器明基RD280UG上手实测!
java·后端·面试
刘立军1 小时前
RESTful 与契约优先:规范接口定义,统一接口设计范式
后端·架构·ai编程
JavaGuide2 小时前
GitHub 4.5 万+ Star!GitNexus 把代码仓库变成了 Claude Code / Codex 能查询的知识图谱
后端·ai编程
子兮曰2 小时前
DeepSeek Harness 架构深潜:一个把 Agent 运行时做成纯插件树的开源 Harness
前端·后端·deepseek
子兮曰3 小时前
AI Agent 完整入门指南:从 LLM 到生产落地的 30+ 个核心概念
前端·后端·agent
渔夫正在掘金3 小时前
Cordis 插件热插拔能力深度解析
后端·node.js
不爱编程的小九九3 小时前
小九源码-springboot004-springboot智能阅读推荐系统
java·spring boot·后端
码事漫谈4 小时前
为什么调试模式不崩溃,打包后却崩溃了?
后端
智驭未来掌门人4 小时前
利用FFmpeg快速实现一个RTSP推流服务器
后端