SpringAIAlibaba学习使用 ---Graph
本文为学习记录文档,学习参考于三更草堂springAI视频
依旧田甜猫姐镇楼!!!!

Graph概述
为什么要使用Graph?
假设你需要处理一个真实的商业需求:比如自动化审核一份商业合同。拆分:
- 1、理解内容:先请AI通读合同,提炼摘要和关键条款。
- 2、合规检查:再让AI根据公司政策库,判断合同是否有合规风险。
- 3、风险评估:接着,要求AI从法律、财务等多维度给出风险评分。
- 4、人工介入:最后,必须将AI的分析结果提交给法务专家,由专家做出“批准”、“拒绝”或“要求修改”的最终 决定。
- 5、后续动作:系统根据专家的决策,自动进入不同的处理流程(如生成公文、起草拒绝函等)。
你会发现它变成了一个多步骤、有状态、且需要协调AI自动化和人类决策的复杂流程。这就是我们常说 的 AI工作流(AI Workflow)或智能体(AI Agent) 要处理的核心问题。
在没有Graph之前,实现这样的流程会非常麻烦,需要我们写很多硬编码去编排实现。
而 Spring AI Alibaba Graph 就是为了优雅地解决这些问题而生的。它是一个强大的工作流编排引擎,让 你能像画流程图一样,直观地定义和执行复杂的AI应用流程
核心概念
| 定义 | 解释 |
|---|---|
| State【状态】 | 负责在不同步骤间安全地传递和共享数据的容器 |
| Node【节点】 | 代表一个执行单元,可以是一个AI调用、一个数据库操作,或一段业务逻辑 |
| Edge 【边】 | 定义节点之间的连接关系和流转方向。可以是固定的简单边,也可以是能根据State内容决定下一步的条件边。 |
graph创建和调用
目标:创建图
创建新工程后添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-zhipuai</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-graph-core</artifactId>
</dependency>
创建启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GraphApplication {
public static void main(String[] args) {
SpringApplication.run(GraphApplication.class, args);
}
}
定义工具类
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class TimeTools {
@Tool(description = "通过时区id获取当前时间")
public String getTimeByZoneId(@ToolParam(description = "时区id,比如 Asia/ShangHai") String zoneId) {
ZoneId zone = ZoneId.of(zoneId);
ZonedDateTime now = ZonedDateTime.now(zone);
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return now.format(dateTimeFormatter);
}
}
配置文件
server:
port: 8889
servlet:
encoding:
charset: utf-8
enabled: true # 启用流
force: true
spring:
ai:
zhipuai:
api-key: *************************** # 配置 API Key
base-url: "https://open.bigmodel.cn/api/paas" # 配置 模型地址
chat:
options:
model: glm-4.5
http:
client:
read-timeout: 1000000
application:
name: graph
正式代码编写!!!! 【定义状态图(状态,节点,边),编译生成CompiledGraph后注入Spring容器调用】
config文件
import com.alibaba.cloud.ai.graph.CompiledGraph;
import com.alibaba.cloud.ai.graph.KeyStrategy;
import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.StateGraph;
import com.alibaba.cloud.ai.graph.action.AsyncNodeAction;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import com.alibaba.cloud.ai.graph.exception.GraphStateException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
@Configuration
public class GraphConfig {
@Bean("quickStartGraph")
public CompiledGraph quickStartGraph() throws GraphStateException {
/**
* 生成一个 开始->node1->node2->结束节点的图
* 大致步骤为
* 1、生成状态图
* 2、根据状态图生成节点(开始和结束节点已经预设好了)
* 3、节点连边
*/
// 1、生成状态图
StateGraph stateGraph = new StateGraph("quickStartGraph",
() -> Map.of("input1", KeyStrategy.REPLACE, "input2", KeyStrategy.REPLACE));
// 2、生成node1
stateGraph.addNode("node1", AsyncNodeAction.node_async(new NodeAction() {
@Override
public Map<String, Object> apply(OverAllState state) throws Exception {
return Map.of("input1",1,"input2",2);
}
}));
// 3、生成node2
stateGraph.addNode("node2",
AsyncNodeAction.node_async(state -> Map.of("input2",3)));
// 4、连接边 开始节点->node1 node1->node2 node2->结束节点
stateGraph.addEdge(StateGraph.START, "node1");
stateGraph.addEdge("node1", "node2");
stateGraph.addEdge("node2", StateGraph.END);
// 5、编译图并返回
CompiledGraph compile = stateGraph.compile();
return compile;
}
}
调用图 【使用CompiledGraph的call方法调用】
package com.sangeng.controller;
import com.alibaba.cloud.ai.graph.CompiledGraph;
import com.alibaba.cloud.ai.graph.OverAllState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
import java.util.Optional;
@RestController
@RequestMapping("/graph")
public class GraphController {
private final Logger log = LoggerFactory.getLogger(GraphController.class);
private final CompiledGraph compiledGraph;
public GraphController(CompiledGraph compiledGraph) {
this.compiledGraph = compiledGraph;
}
@GetMapping("/quickStartGraph")
public String quickStartGraph() {
Optional<OverAllState> call = compiledGraph.call(Map.of());
log.info("call={}", call);
return "OK";
}
}
配置工具信息到chatClient
private final VectorStore vectorStore;
private final ChatClient chatClient;
public CoffeeController(VectorStore vectorStore, ChatClient.Builder chatClientBuilder, ToolCallbackProvider toolCallbackProvider) {
this.vectorStore = vectorStore;
VectorStoreDocumentRetriever vectorStoreDocumentRetriever = VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStore)
.topK(2)
.similarityThreshold(0.5)
.build();
RetrievalAugmentationAdvisor retrievalAugmentationAdvisor = RetrievalAugmentationAdvisor.builder()
.documentRetriever(vectorStoreDocumentRetriever)
.build();
this.chatClient = chatClientBuilder
.defaultAdvisors(retrievalAugmentationAdvisor)
.defaultToolCallbacks(toolCallbackProvider.getToolCallbacks())
.build();
}
API详解
KeyStrategyFactory
用来定义图中的状态有哪些数据,并且定义这些数据的更新策略是什么。 有三种策略分别是: 替换(ReplaceStrategy),新值替换掉老值 合并(MergeStrategy),适合Map类型的数据,新老Map的数据和合并 追加(AppendStrategy),适合List类型的数据,新List的数据追加到老List中
StateGraph stateGraph = new StateGraph("quickStartGraph", () ->
Map.of("input1", KeyStrategy.REPLACE, // 替换
"input2", KeyStrategy.APPEND, // 追加
"input3", KeyStrategy.MERGE)); // 合并
AsyncNodeAction&NodeAction
NodeAction 是Graph中对节点的抽象。我们只需要实现NodeAction接口,在apply方法中定义节点的 执行逻辑即可。
// 源码
@FunctionalInterface
public interface NodeAction {
Map<String, Object> apply(OverAllState state) throws Exception;
}
AsyncNodeAction 异步节点,提供了一个静态方法可以NodeAction转化成 AsyncNodeAction
// 源码
/*
* Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.ai.graph.action;
import com.alibaba.cloud.ai.graph.OverAllState;
import io.opentelemetry.context.Context;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
/**
* Represents an asynchronous node action that operates on an agent state and returns
* state update.
*
*/
@FunctionalInterface
public interface AsyncNodeAction extends Function<OverAllState, CompletableFuture<Map<String, Object>>> {
/**
* Applies this action to the given agent state.
* @param state the agent state
* @return a CompletableFuture representing the result of the action
*/
CompletableFuture<Map<String, Object>> apply(OverAllState state);
/**
* Creates an asynchronous node action from a synchronous node action.
* @param syncAction the synchronous node action
* @return an asynchronous node action
*/
static AsyncNodeAction node_async(NodeAction syncAction) {
return state -> {
Context context = Context.current();
CompletableFuture<Map<String, Object>> result = new CompletableFuture<>();
try {
result.complete(syncAction.apply(state));
}
catch (Exception e) {
result.completeExceptionally(e);
}
return result;
};
}
}
StateGraph
状态图的抽象,需要配置状态(通过KeyStrategyFactory ),节点,边。 配置好后通过compile方法编译成CompiledGraph后才可以供调用。
import com.alibaba.cloud.ai.graph.CompiledGraph;
import com.alibaba.cloud.ai.graph.KeyStrategy;
import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.StateGraph;
import com.alibaba.cloud.ai.graph.action.AsyncNodeAction;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import com.alibaba.cloud.ai.graph.exception.GraphStateException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
@Configuration
public class GraphConfig {
@Bean("quickStartGraph")
public CompiledGraph quickStartGraph() throws GraphStateException {
/**
* 生成一个 开始->node1->node2->结束节点的图
* 大致步骤为
* 1、生成状态图
* 2、根据状态图生成节点(开始和结束节点已经预设好了)
* 3、节点连边
*/
// 1、生成状态图
StateGraph stateGraph = new StateGraph("quickStartGraph",
() -> Map.of("input1", KeyStrategy.REPLACE, "input2", KeyStrategy.REPLACE));
// 2、生成node1
stateGraph.addNode("node1", AsyncNodeAction.node_async(new NodeAction() {
@Override
public Map<String, Object> apply(OverAllState state) throws Exception {
return Map.of("input1",1,"input2",2);
}
}));
// 3、生成node2
stateGraph.addNode("node2",
AsyncNodeAction.node_async(state -> Map.of("input2",3)));
// 4、连接边 开始节点->node1 node1->node2 node2->结束节点
stateGraph.addEdge(StateGraph.START, "node1");
stateGraph.addEdge("node1", "node2");
stateGraph.addEdge("node2", StateGraph.END);
// 5、编译图并返回
CompiledGraph compile = stateGraph.compile();
return compile;
}
}
CompiledGraph
import com.alibaba.cloud.ai.graph.CompiledGraph;
import com.alibaba.cloud.ai.graph.OverAllState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
import java.util.Optional;
@RestController
@RequestMapping("/graph")
public class GraphController {
private final Logger log = LoggerFactory.getLogger(GraphController.class);
private final CompiledGraph compiledGraph;
public GraphController(CompiledGraph compiledGraph) {
this.compiledGraph = compiledGraph;
}
@GetMapping("/quickStartGraph")
public String quickStartGraph() {
Optional<OverAllState> call = compiledGraph.call(Map.of());
log.info("call={}", call);
return "OK";
}
}