SpringAIAlibaba学习使用 ---Graph

0 阅读5分钟

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";
    }

}