ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Spring AI Alibaba Graph:构建可控灵活的Java Agent工作流

Spring AI Alibaba Graph:构建可控灵活的Java Agent工作流 开发 Agent 项目时大家很容易陷入一个两难用 Workflow 写固定流程可控性很足但业务一变就要同步改代码灵活性差用纯 Agent 让大模型自由决策灵活是灵活了但输出不稳、行为不可控生产环境不敢轻易放量。Spring AI Alibaba Graph 要解决的就是这个“可控”和“灵活”之间的矛盾。Spring AI Alibaba 是阿里开源的 Spring AI 实现Graph 模块在这个体系里扮演的是 Agent 工作流编排的角色。它把业务流程抽象成一张图每个执行步骤是节点节点之间的跳转关系是边。边可以是固定的也可以由模型或代码按状态动态决定。这样主干流程是可控的分支和决策是灵活的两者不再对立。这篇文章会从工程落地角度拆解这个方案核心能力和概念、环境准备、怎么构建一个可运行的 Graph Workflow、怎么暴露接口、怎么做功能测试、线上怎么排查问题。如果你正在用 Java 做 Agent 项目或者打算把 Agent 落到生产环境这篇文章建议直接收藏。1. Spring AI Alibaba Graph 核心能力速览先看整体规格再决定要不要继续往下读。能力项说明项目定义Spring AI Alibaba 提供的 Graph 工作流编排能力用于构建可控与灵活兼备的 Agent技术栈Java 17、Spring Boot 3.x、Spring AI Alibaba核心能力节点编排、固定边跳转、条件边跳转、状态传递、LLM 节点、SubGraph 扩展模型接入支持 DashScope也可通过 Spring AI 兼容方式接入其他模型服务是否支持 API支持可基于 Spring Boot Controller 暴露 HTTP / SSE 接口是否支持批量任务支持通过并发生成或任务队列实现需要自行控制并发上限与幂等硬件要求不需要本地 GPU普通开发机即可模型调用走 API显存占用不适用本地只运行 Java 服务适用场景客服、工单流转、审批辅助、内容生成流程等需要固定流程 模型决策的场景上手难度中等需要熟悉 Spring Boot 和基础的 Agent 概念这里需要先说清楚Spring AI Alibaba 的版本迭代比较快具体依赖坐标和版本号要以官方 Release 页面为准。下面的内容基于当前主流的 Spring Boot 3.x 和 Spring AI Alibaba 用法来写如果遇到 API 变化排查思路和概念是一样的。2. 适用场景与使用边界Graph Workflow 适合什么场景最典型的是“流程固定但流程中间的某些判断需要模型参与”的业务。例如客服工单处理先做意图识别再按不同意图走不同处理分支最后生成回复内容。内容审核流程先检查敏感词再调用模型判断语义风险最后按风险等级走不同出口。审批助手先做资料完整性检查再让模型摘要关键信息最后按规则决定是否进入人工审批。售后处理先判断问题类型再决定调工具查订单还是直接检索知识库回复。这类场景的共同特点是主干必须稳定分支需要智能。用 Workflow 做主干用 Agent 节点做局部决策正好是 Graph 的最优解。什么场景不适合完全开放式的自由聊天没有固定目标不需要流程约束直接用 ChatClient 更轻。需要长时间自主探索的复杂任务例如让 Agent 自己规划并执行几十个步骤Graph 的固定结构会限制自由度更适合用 SubAgent 或分层规划方案。对延迟极度敏感的场景每个节点跨一次模型调用链路越长延迟越高。使用边界也要明确。Graph 工作流可以调工具、调模型、处理业务数据但所有涉及用户隐私和版权素材的内容都必须先确认授权。模型输出不可直接作为最终结果发布建议在出口节点增加人工复核或规则校验。工具调用要加鉴权尤其是支付、订单、用户信息这类敏感操作不能让模型自主决定无限调用。3. 环境准备与前置条件开发 Spring AI Alibaba Graph 项目环境清单如下项目要求JDKJDK 17 或更高版本构建工具Maven 3.6框架Spring Boot 3.xIDEIDEA 或 VS Code 均可模型 API Key以 DashScope 为例需要先在阿里云百炼控制台申请网络能正常访问模型 API 服务即可不需要特殊网络环境先创建一个 Spring Boot 工程建议直接在 IDEA 里通过 Spring Initializr 创建Java 版本选 17。引入 Spring AI Alibaba 相关依赖。dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-starter/artifactId version版本号以官方 Release 为准/version /dependency dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-graph/artifactId version版本号以官方 Release 为准/version /dependency注意不同版本之间的 API 可能有差异如果编译报错先确认依赖版本和官方示例是否一致。配置文件 application.yml 示例spring: application: name: spring-ai-alibaba-graph-demo ai: dashscope: api-key: ${DASHSCOPE_API_KEY} chat: options: model: qwen-plus server: port: 8080这里把 API Key 放在环境变量里避免硬编码到代码仓库。如果不使用 DashScope而是接入其他兼容 OpenAI 协议的模型服务可以换成 Spring AI 对应的自定义配置同样以官方文档为准。本地开发机建议至少 8G 内存因为除了运行 Spring Boot 服务IDE 和后端服务会同时占用资源。磁盘空间不需要太大整个项目加依赖一般在几百 MB 到 1G 左右。4. 核心概念Graph、State、Node、EdgeSpring AI Alibaba Graph 的核心模型可以拆成四个概念State状态对象。Graph 执行过程中所有节点共享和传递的数据都放在 State 里。每个节点读取 State处理后再写回 State。Node节点。每个节点是一个执行单元可以是一段普通业务代码也可以是一个工具调用还可以是一个 LLM 调用节点。Edge边。连接两个节点的执行关系。Condition条件。条件边会根据当前 State 决定下一步走哪个节点。Graph 则是这些元素的容器。一张 Graph 从入口节点开始执行根据边和条件的约束逐节点推进直到到达结束节点。用一个例子理解用户输入 - 意图识别节点 - [需要工具] - 工具调用节点 - 回答生成节点 - 输出 \- [不需要工具] - 回答生成节点 - 输出这个例子中意图识别节点调用模型判断用户意图输出结果写入 State。接着走条件边判断 State 里的 needTool 字段。如果为 true先调工具获取信息再生成回答如果为 false直接生成回答。这就是“可控灵活”的关键主干流程是固定的但节点内部可以用 LLM 做决策条件边可以动态选择下一步所以业务变化时不需要重写整个流程只需要调整节点或边的配置。SubGraph 是进一步扩展的方式。当一个节点的逻辑过于复杂可以把它拆成一张子图子图内部有自己的节点和边对外只暴露入口和出口。这样大型 Agent 项目可以分层组织每张子图维护一个职责边界。5. 构建第一个 Graph Workflow5.1 先理解本质一个简版状态机在接入 Spring AI Alibaba Graph 之前先写一个不依赖任何框架的简版状态机理解 Graph 的本质。import java.util.HashMap; import java.util.Map; import java.util.function.Function; public class SimpleWorkflow { // State节点间传递的数据容器 static class State { public String userInput; public boolean needTool; public String toolResult; public String answer; public State(String userInput) { this.userInput userInput; } } static class Node { String name; FunctionState, State handler; Node(String name, FunctionState, State handler) { this.name name; this.handler handler; } } public static void main(String[] args) { // 创建三个节点 Node intentNode new Node(intent, state - { // 现实中这里会调用大模型 state.needTool state.userInput.contains(查订单); return state; }); Node toolNode new Node(tool, state - { // 现实中这里会调用订单接口 state.toolResult 订单状态已发货; return state; }); Node answerNode new Node(answer, state - { if (state.needTool) { state.answer 根据查询结果 state.toolResult; } else { state.answer 直接回答 state.userInput; } return state; }); // 维护节点表 MapString, Node nodeMap new HashMap(); nodeMap.put(intentNode.name, intentNode); nodeMap.put(toolNode.name, toolNode); nodeMap.put(answerNode.name, answerNode); // 执行流程 State state new State(帮我查一下订单); state nodeMap.get(intent).handler.apply(state); if (state.needTool) { state nodeMap.get(tool).handler.apply(state); } state nodeMap.get(answer).handler.apply(state); System.out.println(state.answer); } }这段代码把 Graph 的核心做了一次最小化还原State 传递数据Node 处理逻辑条件判断控制跳转。Spring AI Alibaba Graph 做的事情就是把这种模式工程化并提供对 LLM 节点、条件边、循环、SubGraph 的完整支持。先跑通这个简版状态机能帮你把 Graph 的直觉建立起来再去看官方 API 就不会觉得抽象。5.2 接入 Spring AI Alibaba Graph接入后的代码结构会和上面的简版状态机非常接近。下面给一个概念化的接入示例API 细节以官方当前版本为准// 概念示例具体类名和方法以官方文档为准 StateGraph.BuilderString, AgentState builder StateGraph.builder(); builder.addNode(intent, intentNode); builder.addNode(tool, toolNode); builder.addNode(answer, answerNode); // 固定边intent 走完通过条件边决定下一步 builder.addConditionalEdge(intent, state - state.needTool() ? tool : answer); // 固定边tool 执行完必须走到 answer builder.addEdge(tool, answer); // 终点必须是结束节点 builder.addEdge(answer, StateGraph.END); StateGraphString, AgentState graph builder.build(); AgentState output graph.invoke(new AgentState(帮我查一下订单)); System.out.println(output.getAnswer());在真实项目中intentNode 内部会调用 Spring AI 的 ChatClient 让模型做意图识别toolNode 会调用订单接口或检索服务answerNode 会再次调用模型生成最终回复。节点调用模型的方式类似这样Component public class IntentNode implements FunctionAgentState, AgentState { private final ChatClient chatClient; public IntentNode(ChatClient.Builder builder) { this.chatClient builder.build(); } Override public AgentState apply(AgentState state) { String prompt 判断用户意图只回答 needTool 或 noNeedTool。用户输入 state.getUserInput(); String result chatClient.call(prompt); state.setNeedTool(needTool.equals(result.trim())); return state; } }把模型判断封装在节点内部业务变更时只需要改节点实现不需要改图结构。这是 Graph 工作流项目里最推荐的写节点方式。5.3 加入工具调用节点工具节点是 Agent 项目里逃不开的环节。架构上建议把工具调用设计成独立节点而不是散落在多个节点里。例如售后 Agent意图识别节点判断用户是查订单、申请退款、还是咨询政策。工具节点根据意图调用订单查询接口、退款接口或知识库检索。回答生成节点把工具结果传给模型生成面向用户的最终回复。工具节点走什么接口、传什么参数都要在进入工具节点前从 State 里取参数而不是让工具节点自己解析用户原话。这样责任边界清晰测试也方便。6. 功能测试与效果验证6.1 测试用例设计Graph Workflow 的测试思路和普通接口测试不一样核心是验证两条链路链路是否走对、State 是否正确传递、模型输出是否符合预期。用例输入预期路径预期结果不需要工具你好你们有什么产品意图 - 回答返回正式回复不调用工具需要工具帮我查一下订单意图 - 工具 - 回答返回订单状态信息工具调用失败查一个不存在的订单意图 - 工具 - 回答返回兜底文案不报错测试时重点关注日志输出。在节点实现里加上日志Override public AgentState apply(AgentState state) { log.info(进入意图识别节点输入: {}, state.getUserInput()); // ... log.info(意图识别完成needTool: {}, state.isNeedTool()); return state; }通过日志能够看到完整的节点执行路径。如果发现某个用例没有走预期的分支优先检查条件边的判断逻辑和 State 字段是否写入正确。6.2 启动与本地验证Spring Boot 服务启动后直接写一个测试接口验证。RestController public class AgentController { private final GraphString, AgentState graph; public AgentController(GraphString, AgentState graph) { this.graph graph; } PostMapping(/api/agent/chat) public MapString, Object chat(RequestBody MapString, String request) { String input request.get(input); AgentState result graph.invoke(new AgentState(input)); return Map.of(answer, result.getAnswer()); } }启动服务mvn spring-boot:run用 curl 做一次调用测试curl -X POST http://localhost:8080/api/agent/chat \ -H Content-Type: application/json \ -d {input: 帮我查一下订单}判断成功的标准接口返回 200。回复内容包含模型生成的答案。日志里能看到完整的节点执行路径。工具节点被正确触发。如果日志里没有走工具节点但预期应该走检查条件边的判断条件和模型的意图识别结果。模型意图识别有概率出错必要时可以在意图节点里加规则兜底例如输入包含“订单”关键词时强制走工具路径。7. 接口 API 与批量任务7.1 同步接口上面的 Controller 示例已经演示了同步接口的写法。生产环境建议在 Graph 层做超时控制避免模型调用卡死导致接口挂起。try { AgentState result graph.invoke(new AgentState(input)); return Map.of(answer, result.getAnswer()); } catch (Exception e) { log.error(Agent 调用失败, e); return Map.of(answer, 服务暂时不可用请稍后重试); }7.2 SSE 流式输出Agent 项目里用户经常需要打字机效果。Spring AI 的 ChatClient 支持流式调用Graph 节点内部也可以把流式内容推出去。思路是在 State 里放一个 SseEmitter 或 FluxSink节点生成内容时实时推送。// 基础思路示例需要根据实际场景调整 GetMapping(value /api/agent/stream, produces MediaType.TEXT_EVENT_STREAM_VALUE) public SseEmitter stream(RequestParam String input) { SseEmitter emitter new SseEmitter(30000L); // 将 emitter 放入 State // 图中节点异步执行把结果推送出去 return emitter; }流式场景下要注意线程模型。Graph.invoke 默认是同步阻塞的流式输出建议把整个 Graph 执行放到异步线程池里避免阻塞 Web 容器线程。7.3 批量任务批量任务的实现思路有两种。第一种是同步批量用线程池并发调用 Graph适合单机跑一批测试数据。ExecutorService executor Executors.newFixedThreadPool(5); ListFutureAgentState futures inputs.stream() .map(input - executor.submit(() - graph.invoke(new AgentState(input)))) .toList();第二种是异步任务队列接收批量请求后立即返回任务 ID后台线程池处理处理状态写入数据库通过查询接口获取结果。批量任务需要特别注意点并发上限。模型 API 通常有 QPS 限制并发太高会被限流。幂等性。每个输入应该有一个唯一请求 ID重试时不会重复处理。失败重试。模型调用和工具调用都可能失败重试要有最大次数限制避免死循环。结果追踪。每个任务的状态记录下来方便排查问题。8. 资源占用与性能观察Graph Workflow 是 Java 服务端框架本身不消耗 GPU 显存本地资源占用主要体现在 JVM 内存和线程上。启动后可以通过 Spring Boot Actuator 观察服务状态。引入依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-actuator/artifactId /dependency访问/actuator/health查看健康状态访问/actuator/metrics/jvm.memory.used查看 JVM 内存使用。性能上重点观察三个指标单次请求耗时。Graph 链路里每多一个模型调用节点耗时增加一次模型响应时间。如果业务对延迟敏感建议把多个模型任务合并到单个节点内完成减少图跳数。State 传输大小。State 里不要塞大对象比如图片 Base64 字符串、大段文本全文。Graph 执行过程中 State 会在所有节点间传递数据越大GC 压力越高。线程池配置。同步调用 Graph 会占用 Web 容器线程并发量高时要评估线程池大小和业务容忍的最大等待时间。降低资源消耗的常规手段输出节点做缓存相同输入直接返回缓存结果。模型调用加合理超时避免请求堆积。State 只保留当前链路必要字段不把用户原始大文本一路带到最后。批量任务单独用队列执行不占用请求线程。9. 常见问题与排查方法问题现象可能原因排查方式解决方案依赖下载失败仓库地址或版本号不对检查 Maven 仓库配置和版本号使用官方文档指定的仓库和版本接口调用报模型错误API Key 未配置或额度不足检查配置项和控制台额度正确配置环境变量确认账户有调用权限条件边一直走固定分支State 字段没有正确写入查看节点日志检查节点内 State 赋值逻辑图执行出现死循环循环边缺少退出条件在循环路径加日志限制最大循环次数或在条件边增加兜底出口接口超时模型调用慢或链路过长查看调用链耗时增加超时时间或精简节点数量流式输出中文乱码Content-Type 或字符编码不对检查响应头统一使用 UTF-8SSE 响应设置正确 MIME并发调用时数据互相污染State 共享了静态变量或单例 Bean检查节点类和 State 类作用域每个请求独立创建 State节点内部不持有请求级数据编译报错找不到 Graph 类Graph 依赖未引入或版本不兼容检查依赖树确认 spring-ai-alibaba-graph 已引入且版本匹配这里重点说两个容易踩的坑。第一个是 State 污染。Graph 在并发场景下如果节点内部把请求数据放到了类成员变量里多个请求就会互相覆盖。解决办法是节点保持无状态所有业务数据都通过 State 线程隔离传递。第二个是条件边判断太依赖模型输出。模型不是 100% 稳定意图识别错一次整条链路就会走错。生产环境建议“规则优先 模型兜底”先看关键词和规则判断不了再交给模型。10. 最佳实践与使用建议第一次跑通先用最小 Graph。三个节点、一条固定边、一条条件边就够了不要一上来就做二十个节点的复杂图。先把链路跑通再逐步加节点。节点一定要有日志。Graph 的排查难度随着节点数量上升没有日志几乎没法定位问题。每个节点入口、出口、分支选择结果都要记录。State 设计要克制。只放当前链路需要的数据不放原始大对象不下塞数据库连接和 HttpClient 这类资源型对象。工具调用要设超时和重试。外部接口不可控不设超时的工具节点会把整条链路拖死。模型的最终输出要做校验。尤其是生成文案、回复客户、执行操作之前必须有格式校验和内容校验生产环境建议保留人工复核出口。涉及用户数据时要先做授权确认。Graph 会处理用户信息处理前要告知用户并取得授权工具调用不能越权读取数据。涉及人脸、声音、版权素材的 Agent 场景必须确认素材来源合法不能在未授权的情况下使用或生成相关内容。批量任务要单独设计任务表和重试机制不要直接 for 循环调用 Graph否则模型 API 限流一来就是一大片失败。11. 总结Spring AI Alibaba Graph 的价值不是把 Agent 做得更复杂而是给生产级 Agent 一个可约束的框架。你不需要放弃灵活性也不需要牺牲可控性只需要把业务流程拆成节点和边让模型在节点内部做决策让条件边在节点之间做路由。这篇文章最值得动手验证的部分是 5.1 的简版状态机和 5.2 的 Graph 接入。先跑通一条“意图识别 - 条件分支 - 工具调用 - 回答生成”的最小链路再逐步扩展子图和工具节点。最容易踩的坑是 State 设计不合理和条件边过度依赖模型输出这两点从一开始就要注意。后续扩展可以考虑 SubGraph 分层、多 Agent 协作中的主从模式、MCP 工具接入、以及把知识图谱引入工作流做更精确的上下文检索。把 Graph 的骨架搭对这些能力都能往同一个结构上叠加。
返回列表