DC娱乐网

Spring AI Alibaba Graph Workflow快速入...

Spring AI Alibaba Graph 是一款面向 Java 开发者的工作流、多智能体框架,用于构建由多个 AI

Spring AI Alibaba Graph 是一款面向 Java 开发者的工作流、多智能体框架,用于构建由多个 AI 模型或步骤组成的复杂应用。

它基于 Spring Boot 生态进行深度集成,提供声明式的 API 来编排工作流,让开发者能将 AI 应用的各个步骤抽象为节点(Node),并通过有向图(Graph)的形式连接这些节点,形成可定制的执行流程。

State (状态) - 工作流的记忆中枢Node (节点) - 工作流的执行单元Edge (边) - 工作流的导航路径编译与执行 - 从蓝图到现实

本文将基于Spring AI Alibaba Graph 组件一步一步创建客户服务工作流(Customer Service Workflow)。

一、工作流图概述

客户服务请求分类如图所示,其中包含了几个核心组件和概念:

端点 (Endpoint):客户请求输入

系统的输入点,通常是一个API接口(如RESTful API),接收来自前端(网站、APP)或外部系统(如邮箱、客服平台)的客户原始请求数据。

处理节点 (Process):反馈分类器(feedback_classifier)

核心AI组件1。这是一个机器学习模型服务(如一个微服务),其功能是进行情感分析或意图识别,将输入初步分类为“积极”或“消极”。

决策节点 (Condition):检查情感状态

业务规则引擎的一部分。根据第一个分类器的结果,执行预定义的业务规则,决定下一步流程的路径。这是一个逻辑路由组件。

处理节点 (Process):具体问题分类器(specific_question_classifier)

核心AI组件2。另一个更细粒度的机器学习模型服务,负责对“消极”反馈进行多标签分类(如产品质量、售后服务等),精确识别具体问题类型。

决策节点 (Condition):检查问题类型

业务规则引擎的另一部分。根据第二个分类器的结果,将请求路由到记录器的不同逻辑通道。在实际系统中,这个路由可能意味着为记录添加不同的类型标签。

处理节点 (Process) :记录器(recorder)

数据持久化组件。是流程的汇聚点,所有路径最终都会到达这里。它将客户请求的元数据(原始内容、分类结果、时间戳等)写入数据库(如MySQL、PostgreSQL)或创建工单到工单系统。

端点 (Endpoint):流程结束

系统的输出点。代表该条请求的自动化预处理流程已完成,记录已成功创建,等待后续的人工处理或自动化响应。

该工作流展示了一个高效的客户请求自动化预处理流程:

两级分类:先判断情感,再细化问题类型,结构清晰,判断准确。路由决策:通过条件节点 (condition1, condition2) 实现动态路由。集中记录:所有请求最终统一由记录器处理,保证了数据的一致性,为后续流程提供了可靠的输入。

简而言之,此流程将一个模糊的“客户请求”逐步精确分类并标记,最终转化为一条结构清晰的“待处理记录”,极大提升了客服系统的处理效率和智能化水平。

1. 第一级分类节点(feedback_classifier),将评论分为 positive 和 negative 两种。如果是 positive 评论则进行系统记录后结束流程;如果是 negative 评论则进行第二级分类

2. 第二级分类节点(specific_feedback_classifier),根据 negative 评论的具体内容识别用户的具体问题,如 “after-sale service”、“product quality”、“transportation” 等,根据具体问题分流到具体的问题处理节点。

3. 最后问题处理节点进行处理并记录后,流程结束。

二、创建节点

在开始创建工作流StateGraph之前,需要先初始化ChatClient 对象,以及创建工作流中的节点对象。

在示例项目中创建一个 Spring Boot 配置类(例如 WorkflowAutoconfiguration),如图所示:

在该配置类中,需要完成以下几个步骤。

1. 初始化 ChatClient

从容器中获取注入的 ChatModel(由上一步配置产生),构建一个 ChatClient 实例并附加必要的 Advisor(如日志记录器),用于后续 LLM 调用。例如:

// 构建 ChatClient:封装大模型调用并加入简单日志 Advisor ChatClient chatClient = ChatClient.builder(chatModel) .defaultAdvisors(new SimpleLoggerAdvisor()) .build();

这里 ChatClient 是 Spring AI 提供的与大模型对话的客户端,可看作对底层 API 的封装。

2. 设置全局状态 OverAllState

定义一个 OverAllStateFactory,用于在每次执行工作流时创建初始的全局状态对象。通过注册若干 Key 及其更新策略来管理上下文数据:

// 定义全局状态工厂:初始化可在节点之间共享 / 传递的数据键及其写入策略 OverAllStateFactory stateFactory = () -> { OverAllState state = new OverAllState(); // 用户原始输入 state.registerKeyAndStrategy("input", new ReplaceStrategy()); // 分类器输出(分类标签) state.registerKeyAndStrategy("classifier_output", new ReplaceStrategy()); // 最终解决方案或回复 state.registerKeyAndStrategy("solution", new ReplaceStrategy()); return state; };

上述代码注册了三个状态键:input(输入文本)、classifier_output(分类结果)和 solution(最终处理结论),均采用 ReplaceStrategy(每次写入替换旧值)。这些键将贯穿整个工作流,用于在节点之间传递数据。

3. 定义节点 (Node)

创建工作流中的核心节点,包括两个文本分类节点和一个记录节点。在本示例中,框架提供了预定义的 QuestionClassifierNode 类用于文本分类任务。利用其构建器指定分类的细分类别及提示语,引入 ChatClient 来调用大模型服务,实现智能分类:

// == 情感/反馈正负分类节点 == // 作用:判断当前输入属于正向还是负向反馈;输出写入 key:ifier_output QuestionClassifierNode feedbackClassifier = QuestionClassifierNode.builder() .chatClient(chatClient) .inputTextKey("input") // 从全局状态读取用户原始输入 .outputKey("classifier_output") // 分类结果写入同一状态 key // 注意:categories 返回值目前是 "positive feedback"/"negative feedback" .categories(List.of("positive feedback", "negative feedback")) .classificationInstructions( List.of("Try to understand the user's feeling when he/she is giving the feedback.") ).build(); // == 负面反馈细分问题分类节点 == // 触发条件:来自上一阶段判定为负面(需要在 dispatcher 中控制) // 输出同样写入ifier_output,后续仅用于路由到 recorder QuestionClassifierNode specificQuestionClassifier = QuestionClassifierNode.builder() .chatClient(chatClient) .inputTextKey("input") .outputKey("classifier_output") .categories(List.of("after-sale service", "transportation", "product quality", "others")) .classificationInstructions(List.of( "What kind of service or help the customer is trying to get from us? " + "Classify the question based on your understanding." )).build();

上面定义了两个节点:feedbackClassifier 将判断反馈是正面(positive feedback)还是负面(negative feedback);specificQuestionClassifier 则对负面反馈进一步归类(如售后服务、运输、产品质量或其他)。两者都使用 ChatClient 调用大模型完成分类,并会把结果写入全局状态的 "classifier_output" 键中(框架内部约定)。此外,也可以按需定义自定义节点。

框架预定义的 QuestionClassifierNode 类用于文本分类任务,QuestionClassifierNode 是一个实现 NodeAction 的分类节点,利用 Spring AI 的 ChatClient 调用大模型,将输入文本归类到给定类别之一,并抽取关键词,再把结果写回流程状态。

QuestionClassifierNode 类的功能大致如下,具体细节可以参考源码:

通过构造函数或 Builder 注入:输入文本在状态中的键 inputTextKey、类别列表categories、分类指令classificationInstructions、输出键 outputKey、ChatClient。从 OverAllState 读取输入文本(inputTextKey 对应的值)。构建 few-shot 示例:手工加入两组 用户/助手 消息,作为分类示例。使用 SystemPromptTemplate 渲染系统提示(包含占位符: inputText、categories、classificationInstructions)。发送对话:chatClient.prompt().system(...).user(inputText).messages(few-shot).call()取模型返回文本,放入 updatedState 的 outputKey。如果原状态里存在 messages 键,则附加当前输出消息对象。返回新的局部状态 Map(供外部合并)。

接下来,自定义的 RecordingNode 节点用于记录和处理最终结果:

// == 结果记录节点 == RecordingNode recorderNode = new RecordingNode();

RecordingNode 实现了 NodeAction 接口,会在流程末尾根据分类结果生成相应的 Solution,并将结果写回OverAllState。

/** * 功能: * 1. 从全局工作流状态中读取上游节点写入的分类结果(键:classifier_output)。 * 2. 依据文本是否包含 "positive" 做简单正/负向判定,仅用于日志区分。 * 3. 将原始结果写入增量状态键 "solution",供后续节点继续使用。 */ public RecordingNode implements NodeAction { private static final Logger logger = LoggerFactory.getLogger(RecordingNode.class); @Override public Map<String, Object> apply(OverAllState state) throws Exception { // 从全局状态中获取分类器的输出结果 String feedback = (String) state.value("classifier_output").get(); // 初始化状态更新映射,用于存储本节点产生的新状态数据 Map<String, Object> updatedState = new HashMap<>(); // 根据反馈内容进行简单的正负向分类判断 if(feedback.contains("positive")) { logger.info("Received positive feedback: {}", feedback); // 将原始反馈作为解决方案存储到状态中 updatedState.put("solution", feedback); } else { // 未检测到正向关键词,按负向反馈处理,记录相应日志 logger.info("Received negative feedback: {}", feedback); // 同样将原始反馈作为解决方案存储(实际业务中可能需要不同处理) updatedState.put("solution", feedback); } // 返回更新后的状态映射给工作流引擎 // 该映射将被合并到全局状态中,供后续节点访问 // 键 "solution" 包含了经过记录节点处理的最终结果 return updatedState; } }

RecordingNode 是一个工作流节点,在AI工作流中充当数据记录和传递的角色。

数据读取:从全局工作流状态中获取上游分类器节点的输出结果简单分类:根据文本内容是否包含 "positive" 进行正负向判断状态更新:将处理结果写入状态,供下游节点使用

这个节点在AI工作流中起到承上启下的作用,将分类器的输出转换为标准化的Solution 格式,为后续节点提供统一的数据接口。

现在,流程图中的三个节点已经定义好了。下一步,将添加节点和边到状态图StateGraph中。