AI项目博客
记录 AI 工程实践与大模型应用

Spring AI Alibaba 94|Graph Core · 如何添加子图

子图是在另一个图中用作节点的图,Spring AI Alibaba Graph 支持多种不同的模式来使用子图,不同的使用方式会决定图之间是否共享上下文、。

使用子图的一些原因包括:

  • 构建多智能体系统:每个智能体可以是一个独立的子图
  • 组件复用:当您想在多个图中重用一组节点时,这些节点可能共享某些状态,您可以在子图中定义一次,然后在多个父图中使用它们
  • 团队协作:当您希望不同的团队独立地在图的不同部分上工作时,您可以将每个部分定义为子图,只要遵守子图接口(输入和输出 schema),就可以在不了解子图任何细节的情况下构建父图

有三种方法可以将子图添加到父图中:

1. 直接添加编译的子图作为节点

当父图和子图共享状态时,可以直接将编译的子图作为节点添加到父图中。这是最简单的方式。

import com.alibaba.cloud.ai.graph.CompiledGraph;
import com.alibaba.cloud.ai.graph.KeyStrategy;
import com.alibaba.cloud.ai.graph.KeyStrategyFactory;
import com.alibaba.cloud.ai.graph.StateGraph;
import com.alibaba.cloud.ai.graph.state.strategy.ReplaceStrategy;

import java.util.HashMap;
import java.util.Map;

import static com.alibaba.cloud.ai.graph.StateGraph.END;
import static com.alibaba.cloud.ai.graph.StateGraph.START;
import static com.alibaba.cloud.ai.graph.action.AsyncNodeAction.node_async;

// 创建并编译子图
KeyStrategyFactory subKeyFactory = () -> {
  HashMap<String, KeyStrategy> strategies = new HashMap<>();
  strategies.put("input", new ReplaceStrategy());
  strategies.put("output", new ReplaceStrategy());
  return strategies;
};

StateGraph subGraphDef = new StateGraph(subKeyFactory)
      .addNode("process", node_async(state -> {
          String input = (String) state.value("input").orElse("");
          String output = "Processed: " + input.toUpperCase();
          return Map.of("output", output);
      }))
      .addEdge(START, "process")
      .addEdge("process", END);

CompiledGraph compiledSubGraph = subGraphDef.compile();

// 在父图中直接使用编译的子图作为节点
KeyStrategyFactory parentKeyFactory = () -> {
  HashMap<String, KeyStrategy> strategies = new HashMap<>();
  strategies.put("data", new ReplaceStrategy());
  strategies.put("result", new ReplaceStrategy());
  return strategies;
};

StateGraph parentGraph = new StateGraph(parentKeyFactory)
      .addNode("prepare", node_async(state ->
              Map.of("data", "hello world")))
      .addNode("subgraph", compiledSubGraph)  // 直接使用编译的子图
      .addNode("finalize", node_async(state -> {
          String result = (String) state.value("result").orElse("");
          return Map.of("final", "Done: " + result);
      }))
      .addEdge(START, "prepare")
      .addEdge("prepare", "subgraph")
      .addEdge("subgraph", "finalize")
      .addEdge("finalize", END);

CompiledGraph compiledParent = parentGraph.compile();

2. 在节点操作中调用子图

当父图和子图具有不同的状态 schema,需要在调用子图之前或之后转换状态时,可以在节点操作中手动调用子图。

import com.alibaba.cloud.ai.graph.CompiledGraph;
import com.alibaba.cloud.ai.graph.KeyStrategy;
import com.alibaba.cloud.ai.graph.KeyStrategyFactory;
import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.StateGraph;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import com.alibaba.cloud.ai.graph.state.strategy.ReplaceStrategy;

import java.util.HashMap;
import java.util.Map;

import static com.alibaba.cloud.ai.graph.StateGraph.END;
import static com.alibaba.cloud.ai.graph.StateGraph.START;
import static com.alibaba.cloud.ai.graph.action.AsyncNodeAction.node_async;

// 定义子图
KeyStrategyFactory childKeyFactory = () -> {
  HashMap<String, KeyStrategy> strategies = new HashMap<>();
  strategies.put("input", new ReplaceStrategy());
  strategies.put("result", new ReplaceStrategy());
  return strategies;
};

StateGraph subGraph = new StateGraph(childKeyFactory)
      .addNode("substep1", node_async(state -> {
          String input = (String) state.value("input").orElse("");
          return Map.of("result", "SubStep1:" + input);
      }))
      .addNode("substep2", node_async(state -> {
          String prev = (String) state.value("result").orElse("");
          return Map.of("result", prev + "->SubStep2");
      }))
      .addEdge(START, "substep1")
      .addEdge("substep1", "substep2")
      .addEdge("substep2", END);

CompiledGraph compiledSubGraph = subGraph.compile();

// 将子图包装为 NodeAction
public static class SubGraphNode implements NodeAction {
  private final CompiledGraph subGraph;

  public SubGraphNode(CompiledGraph subGraph) {
      this.subGraph = subGraph;
  }

  @Override
  public Map<String, Object> apply(OverAllState state) {
      // 从父状态提取子图需要的数据
      String input = (String) state.value("data").orElse("");

      // 执行子图
      Map<String, Object> subInput = Map.of("input", input);
      OverAllState subResult = subGraph.invoke(subInput).orElseThrow();

      // 返回结果给父图
      String result = (String) subResult.value("result").orElse("");
      return Map.of("processed", result);
  }
}

// 在父图中使用
KeyStrategyFactory parentKeyFactory = () -> {
  HashMap<String, KeyStrategy> strategies = new HashMap<>();
  strategies.put("data", new ReplaceStrategy());
  strategies.put("processed", new ReplaceStrategy());
  strategies.put("final", new ReplaceStrategy());
  return strategies;
};

SubGraphNode subGraphNode = new SubGraphNode(compiledSubGraph);

StateGraph parentGraph = new StateGraph(parentKeyFactory)
      .addNode("prepare", node_async(state -> {
          return Map.of("data", "Input Data");
      }))
      .addNode("process", node_async(subGraphNode))  // 使用子图作为节点
      .addNode("finalize", node_async(state -> {
          String processed = (String) state.value("processed").orElse("");
          return Map.of("final", "Final:" + processed);
      }))
      .addEdge(START, "prepare")
      .addEdge("prepare", "process")
      .addEdge("process", "finalize")
      .addEdge("finalize", END);

CompiledGraph compiledParent = parentGraph.compile();

3. 直接嵌入 StateGraph

当父图和子图紧密相关,共享状态时,可以直接将 StateGraph 作为节点嵌入到父图中。

import com.alibaba.cloud.ai.graph.CompiledGraph;
import com.alibaba.cloud.ai.graph.KeyStrategy;
import com.alibaba.cloud.ai.graph.KeyStrategyFactory;
import com.alibaba.cloud.ai.graph.StateGraph;
import com.alibaba.cloud.ai.graph.state.strategy.ReplaceStrategy;

import java.util.HashMap;
import java.util.Map;

import static com.alibaba.cloud.ai.graph.StateGraph.END;
import static com.alibaba.cloud.ai.graph.StateGraph.START;
import static com.alibaba.cloud.ai.graph.action.AsyncEdgeAction.edge_async;
import static com.alibaba.cloud.ai.graph.action.AsyncNodeAction.node_async;

// 定义子图(返回 StateGraph)
KeyStrategyFactory keyFactory = () -> {
  HashMap<String, KeyStrategy> strategies = new HashMap<>();
  strategies.put("input", new ReplaceStrategy());
  strategies.put("output", new ReplaceStrategy());
  strategies.put("valid", new ReplaceStrategy());
  return strategies;
};

StateGraph processingSubGraph = new StateGraph(keyFactory)
      .addNode("validate", node_async(state -> {
          String input = (String) state.value("input").orElse("");
          boolean isValid = input != null && !input.isEmpty();
          return Map.of("valid", isValid);
      }))
      .addNode("transform", node_async(state -> {
          String input = (String) state.value("input").orElse("");
          String transformed = input.toUpperCase();
          return Map.of("output", transformed);
      }))
      .addEdge(START, "validate")
      .addConditionalEdges("validate",
              edge_async(state -> {
                  Boolean valid = (Boolean) state.value("valid").orElse(false);
                  return valid ? "valid" : "invalid";
              }),
              Map.of(
                      "valid", "transform",
                      "invalid", END
              ))
      .addEdge("transform", END);

// 在父图中直接嵌入 StateGraph
KeyStrategyFactory parentKeyFactory = () -> {
  HashMap<String, KeyStrategy> strategies = new HashMap<>();
  strategies.put("data", new ReplaceStrategy());
  strategies.put("output", new ReplaceStrategy());
  strategies.put("result", new ReplaceStrategy());
  return strategies;
};

StateGraph parentGraph = new StateGraph(parentKeyFactory)
      .addNode("prepare", node_async(state -> {
          return Map.of("data", "hello world");
      }))
      .addNode("process", processingSubGraph)  // 直接嵌入 StateGraph
      .addNode("finalize", node_async(state -> {
          String output = (String) state.value("output").orElse("");
          return Map.of("result", "Final: " + output);
      }))
      .addEdge(START, "prepare")
      .addEdge("prepare", "process")
      .addEdge("process", "finalize")
      .addEdge("finalize", END);

CompiledGraph compiledParent = parentGraph.compile();

本文整理自 Spring AI Alibaba 官方文档《子图》:https://java2ai.com/docs/frameworks/graph-core/examples/subgraph

赞(0)
未经允许不得转载:AI项目博客 » Spring AI Alibaba 94|Graph Core · 如何添加子图

评论 抢沙发

AI项目博客

专注 AI 工程化落地 —— 覆盖智能体、大模型、Java AI 与 Python 的学习笔记,以及 AI 平台的项目实战记录。

关于本站文章归档

登录

找回密码

注册