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。

RecordingNode 是一个工作流节点,在AI工作流中充当数据记录和传递的角色。
数据读取:从全局工作流状态中获取上游分类器节点的输出结果简单分类:根据文本内容是否包含 "positive" 进行正负向判断状态更新:将处理结果写入状态,供下游节点使用这个节点在AI工作流中起到承上启下的作用,将分类器的输出转换为标准化的Solution 格式,为后续节点提供统一的数据接口。
现在,流程图中的三个节点已经定义好了。下一步,将添加节点和边到状态图StateGraph中。