资讯动态

Spring AI Alibaba Graph:从ReAct循环到图编排的Java Agent工程化实践

发布时间:2026/10/14 3:48:05 来源:尧图企业网站定制
这次我们来看一个 Java 后端与大模型结合的工程化方向在 Spring Boot 生态里用 Spring AI Alibaba 的 Graph 能力把一个传统 ReAct/Loop 的 AI Agent重构成显式、可编排、可观测的图结构工程。先直接说结论这个方向最值得关注的点不是“能不能调大模型”而是“Agent 的每一步怎么编排、怎么中断、怎么恢复、怎么观测”。如果把 ReAct 写成一次性 while 循环项目能跑但换一个场景就要重写。用 Graph Engineering 把节点、边、状态、条件分支拆开Agent 才能从 Demo 变成可以维护的工程系统。这也是标题里“工程化”三个字的含义不是把模型响应返回出去就结束而是把推理过程当作一条有起点、有终点、有分支的执行链路。本文会按工程化实操来展开。先梳理 ReAct 与 Graph 的关系再给出一个基于 Java Spring AI Alibaba 的最小可运行工程包含环境准备、启动方式、节点设计、接口调用、批量任务、性能观察和排查清单。适合正在用 Java 做 AI Agent、但对图编排还不够熟的读者。如果你团队里已经定了 Java 技术栈又想接大模型 Agent这篇可以直接收藏作为落地参考。1. 核心能力速览能力项说明技术定位Java 侧 AI Agent 编排将 ReAct 循环改造成显式图结构核心技能组合ReAct / Loop Tool Calling Graph Engineering Spring AI Alibaba运行环境JDK 17、Maven、Spring Boot 3.x、一个可访问的大模型服务模型接入阿里云百炼 DashScope 原生支持其他兼容 OpenAI 的模型服务也可配置主要功能多节点 Agent 编排、条件分支、工具调用、状态管理、接口暴露部署形态Spring Boot 应用支持 REST API、异步任务、批量任务是否需要 GPU不需要推理在云端或外部模型服务完成本地只做编排本地显存/内存不跑本地模型时无显存要求JVM 内存按常规 Spring Boot 分配启动方式命令行启动配置文件指定模型 Key本地模型端点也能接是否支持 API支持本身是 Spring Boot 服务可以暴露 /api/agent 等接口是否支持批量任务支持可基于消息队列或线程池做批量提交适合场景业务系统中需要可控、可审计、可重试的 AI Agent 服务这里需要解释清楚一件容易混淆的事这套 Java 工程本身是编排层不负责跑大模型。Agent 的算力消耗发生在 LLM 调用那一侧如果接云端模型本地不需要 GPU如果接本地部署的大模型显存压力在模型服务进程上不在 Spring Boot 进程上。所以文章后面不会再围绕显存展开重点会放在线程、内存、QPS 和调用延迟这些后端指标上。2. 为什么 Agent 要用 Graph而不是 while 循环2.1 ReAct 的本质ReAct 是 Reasoning Acting 的组合核心循环是“推理 → 行动 → 观察 → 再推理”。LLM 在每一轮里会决定调用某个工具、直接输出最终答案、或者要求补充信息。写代码时最容易出现的形态是 while 循环while (round maxRound) { String response chatClient.prompt().user(input).call().content(); if (containsToolCall(response)) { String result executeTool(response); input input result; round; } else { return response; } }这种写法不是不能用只是当你有多个工具、多个分支、需要人工确认、需要把过程记录下来做审计时循环体里的 if/else 会迅速膨胀。逻辑分散在局部变量里排查问题时只能靠日志和肉眼看代码。2.2 Graph 把控制流变成数据结构Graph Engineering 的思路是不要用代码写死流程而是把流程描述成“节点 边 状态”。节点负责具体动作比如调用 LLM、调用工具、格式化输出边负责决定下一步走去哪状态对象在节点之间传递上下文。维度普通 while 循环Graph 编排步骤个数写死在循环体内节点可独立增删分支条件if/else 堆在代码里条件边显式声明状态传递局部变量来回传统一 State 对象可观测性日志需要手动埋点节点前后可统一埋点复用性低换场景重写高节点可复用测试方式整体跑一遍才知道结果每个节点可单独测试Spring AI Alibaba 提供的 Graph 模块本质上就是把这类能力搬到 Java 生态里。你不需要再自己实现一套有向无环图框架直接用它的节点、边、状态模型来组织 Agent 即可。完整类名和 API 签名随版本迭代可能调整但核心范式是稳定的Node 做执行Edge 做路由State 做传递。3. 适用场景与使用边界3.1 适合什么业务图编排型 Agent 最适合的是“流程固定、分支多、需要审计”的业务比如企业客服助手接收用户问题判断是否需要查订单、查库存再结合结构化数据回答。数据查询 Agent把自然语言问题解析为 SQL 或 API 参数执行后返回结果。多工具协同工作流需要调用内部接口、搜索、计算器等多个工具。需要人工确认的审批类流程Agent 在关键节点停下来等用户确认后再继续。合规要求较高的系统每一步执行了什么工具、传了什么参数、模型返回了什么都能在状态对象里留痕。这些场景的共同点是任务不是一次模型调用能完成的而且中间存在明确的工具调用边界。Graph 能把边界拆出来每一段都可测试。3.2 不适合什么场景不需要把简单问题复杂化。一次问答、单轮摘要、普通文本分类这些场景直接调模型接口即可引入 Graph 反而增加维护成本。另外如果业务对延迟有硬性要求比如期望单次请求百毫秒内返回那么瓶颈在 LLM 推理本身不在编排层。图编排不能降低模型推理时间只能帮你把“调用模型”和“调用工具”的流程组织得更稳定。真正降低延迟需要靠模型选型、流式输出、缓存和并发控制。3.3 安全边界与合规提醒Agent 一旦带上工具调用能力就相当于开放了一个“AI 可以触发真实操作”的入口。第一个风险是越权调用必须有用户身份校验、工具权限校验和操作审计第二个风险是数据合规调用企业内部系统、读取个人信息之前要确认数据权限和隐私合规要求第三个风险是模型输出的可靠性无论模型表达得多肯定涉及支付、删除、修改等关键动作时必须有人工确认节点。如果你的 Agent 还会处理音视频、图像、人脸、声音等素材更要在数据采集前取得明确授权并且只在不扩散、不滥用的隔离环境中处理。这部分不是配置问题是上线前必须完成的评审项。4. 环境准备与前置条件4.1 开发环境清单项目要求备注JDKJDK 17推荐 JDK 21Spring Boot 3.x 对该版本支持较好构建工具Maven 3.6 或 Gradle 7文章示例使用 MavenSpring Boot3.2 及以上需要与 Spring AI 版本匹配模型服务任意兼容 Spring AI 的模型服务可以使用 DashScope也可以使用本地模型服务网络能访问模型服务地址本文示例以云端 API 为主Spring AI 的版本和 Spring AI Alibaba 的版本是独立发布的。写依赖时要注意版本号不是越高越好而是要匹配。建议先去 Maven 中央仓库或 Spring 官方文档确认当前稳定版本再写进 pom.xml。文章下面的依赖版本号只是结构示例实际部署以仓库最新稳定版为准。4.2 Maven 依赖parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.3.4/version relativePath/ /parent properties java.version17/java.version spring-ai-alibaba.version0.3.0/spring-ai-alibaba.version /properties dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-starter/artifactId version${spring-ai-alibaba.version}/version /dependency dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-graph/artifactId version${spring-ai-alibaba.version}/version /dependency /dependencies如果你的团队已经用过 Spring AI 的 OpenAI 兼容适配也可以保留 spring-ai-starter-model-compatible-openai让 Agent 服务同时支持多个模型来源。需要注意同时引入多个 starter 时Spring 的自动配置会生效其中一套最好在配置里显式指定 model 类型避免启动时出现多个 ChatModel Bean 冲突。4.3 模型服务配置以 DashScope 为例创建一个application.ymlspring: ai: dashscope: api-key: ${DASHSCOPE_API_KEY} base-url: https://dashscope.aliyuncs.com/api/v1 chat: options: model: qwen-plus server: port: 8080不推荐把 API Key 直接写在配置文件里。用环境变量DASHSCOPE_API_KEY注入能避免把密钥提交到 Git 仓库。启动前先确认模型服务地址可达如果之前没申请过 Key控制台会直接提示 401。5. Spring AI Alibaba Graph 工程化落地最小可运行 Agent5.1 设计一个最小流程先做一个小目标一个 Agent 能根据用户提问选择直接回答或调用天气查询工具。流程拆成四件事接收用户输入构造 Agent 状态。调用 LLM判断是否要查天气。如果要查天气执行工具并把结果放回状态。再次调用 LLM生成最终答案。5.2 定义状态对象状态对象是图里传递上下文的核心。把所有节点需要的数据都放进一个 AgentState不要用全局变量或散落的局部变量import java.util.ArrayList; import java.util.List; public class AgentState { private String userInput; private String lastReply; private String toolName; private String toolArguments; private String toolResult; private String finalAnswer; private int round 0; private ListString trace new ArrayList(); public boolean needTool() { return toolName ! null !toolName.isBlank(); } public void addTrace(String step) { trace.add([ System.currentTimeMillis() ] step); } public int getRound() { return round; } public void setRound(int round) { this.round round; } public String getUserInput() { return userInput; } public void setUserInput(String userInput) { this.userInput userInput; } public String getLastReply() { return lastReply; } public void setLastReply(String lastReply) { this.lastReply lastReply; } public String getToolName() { return toolName; } public void setToolName(String toolName) { this.toolName toolName; } public String getToolArguments() { return toolArguments; } public void setToolArguments(String toolArguments) { this.toolArguments toolArguments; } public String getToolResult() { return toolResult; } public void setToolResult(String toolResult) { this.toolResult toolResult; } public String getFinalAnswer() { return finalAnswer; } public void setFinalAnswer(String finalAnswer) { this.finalAnswer finalAnswer; } public ListString getTrace() { return trace; } }round 字段一定要加。即使 Graph 可以构造循环边也必须给 Agent 设置最大轮次防止模型调用工具后一直无法收敛白白消耗 Token 并拖死服务。5.3 编写 LLM 节点一个节点只负责一件事。LLM 节点只负责把当前状态转成提示词调用模型并把返回结果写回状态import org.springframework.ai.chat.client.ChatClient; public class LLMNode implements NodeAgentState { private final ChatClient chatClient; public LLMNode(ChatClient chatClient) { this.chatClient chatClient; } Override public AgentState execute(AgentState state) { String userText state.getUserInput(); String toolContext state.getToolResult() null ? : 工具返回结果 state.getToolResult(); String prompt 你是一个 Java 技术生态里的智能助手。 当用户的问题需要实时天气信息时必须返回工具调用指令 {tool:getWeather,args:{city:城市名}} 如果问题不需要工具直接返回自然语言答案。 目前系统上下文%s .formatted(toolContext); String response chatClient.prompt() .system(prompt) .user(userText) .call() .content(); state.setLastReply(response); state.addTrace(LLM 调用完成返回长度 response.length()); return state; } }在真实项目中LLM 返回内容可能需要解析成结构化工具调用。Spring AI 的 Tool Calling 支持直接声明工具方法框架会帮助把模型输出解析成参数。这里为了展示 Graph 控制流先采用字符串解析的模式逻辑直观不依赖太多框架魔法。5.4 编写工具节点工具节点负责解析 LLM 返回内容并执行真正的工具逻辑public class ToolsNode implements NodeAgentState { Override public AgentState execute(AgentState state) { String reply state.getLastReply(); // 简化解析从 JSON 中取 tool 与 args // 真实项目建议用 Jackson 解析 if (reply.contains(getWeather)) { state.setToolName(getWeather); // 真实场景需要从 args 中解析城市 state.setToolArguments(city: 杭州); state.setToolResult(queryWeather(杭州)); } else { state.setToolName(null); } state.setRound(state.getRound() 1); state.addTrace(工具节点执行完成round state.getRound()); return state; } private String queryWeather(String city) { // 替换为真实天气服务、企业内接口或数据库查询 return city 晴28 摄氏度体感温度 30; } }工具节点最容易犯的错误是把 LLM 返回解析和工具执行混在同一个方法里。建议拆成两个步骤解析失败时能单独定位。工具节点还应该对参数做强化校验因为模型可能产生幻觉参数不能直接拿参数去调用真实接口。5.5 建图并设置条件边图的核心是画清楚节点之间的路径。这里有三条规则入口是 llm 节点。llm 判断是否需要工具需要则走 tools不需要则走 finish。tools 执行完回到 llm继续下一轮推理。import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class AgentGraphConfig { Bean public AgentGraph agentGraph(ChatClient chatClient) { GraphAgentState graph new Graph(AgentState::new); graph.addNode(llm, new LLMNode(chatClient)); graph.addNode(tools, new ToolsNode()); graph.addNode(finish, new FinishNode()); graph.setEntryPoint(llm); graph.addEdge(llm, tools, state - state.getLastReply() ! null state.getLastReply().contains(getWeather)); graph.addEdge(llm, finish, state - !state.needTool()); graph.addEdge(tools, llm); return new AgentGraph(graph); } }代码里的NodeAgentState、GraphAgentState、AgentGraph是按模块通用模型写的模板实际包名和构造方式以 Spring AI Alibaba 当前版本为准。你不需要一字不差照搬关键是理解这条链路入口节点、条件边、回头边、结束节点。把这几样画清楚Agent 的执行路径就清晰了。5.6 结束节点结束节点负责把最终答案从状态对象里捞出来。它不调用模型也不执行工具只做收尾public class FinishNode implements NodeAgentState { Override public AgentState execute(AgentState state) { if (state.getFinalAnswer() null) { state.setFinalAnswer(state.getLastReply()); } state.addTrace(Agent 结束总轮次 state.getRound()); return state; } }这里有个细节最后一步不要把上一轮的历史对话拼进业务返回。很多 Agent 在结束节点才发现问题其实是因为前面几轮的历史消息混进了最终结果。结束节点里保留最小量的必要结果即可。5.7 启动服务启动方式和普通 Spring Boot 应用没有区别mvn spring-boot:run启动后观察日志。只要没有报 Bean 创建失败说明依赖和配置基本没问题。接下来就可以直接构造一个 AgentState调用图执行AgentState state new AgentState(); state.setUserInput(杭州现在多少度); state.setRound(0); AgentState result agentGraph.execute(state); System.out.println(result.getFinalAnswer()); System.out.println(result.getTrace());这段代码可以写在测试类里也可以写在 CommandLineRunner 里。第一次跑通 Graph 只需要几秒钟关键在于看清控制台里打印的 trace 顺序llm 节点先执行然后 tools再回到 llm最后 finish整个过程不超过两轮。6. 功能测试与效果验证6.1 测试一不需要工具的直接问答输入“介绍一下你自己”预期路径是 llm → finish。用最简单的问题先验证链路是通的。判断标准trace 里没有 tools 节点的执行记录。最终答案来自模型的一次直接返回。round 最终为 0 或 1。如果这一步失败优先检查 DashScope 的 api-key 和模型名称是否正确。常见的 401 或 404 错误都能在启动日志里直接看到。6.2 测试二需要工具调用的多轮流程输入“杭州现在多少度”预期路径是 llm → tools → llm → finish。判断标准trace 里出现 tools 节点执行记录。最终答案中包含“工具返回结果”里的天气信息。round 最终不超过 2。这一步能跑通说明条件边和回头边都工作正常。如果 tools 节点执行完没有回到 llm要检查graph.addEdge(tools, llm)是否配置正确。如果 return 后直接结束了检查 finish 节点的条件路径是否写错。6.3 测试三循环上限保护构造一个永远触发工具的输入比如连续提问“查询天气、继续查询、再查询”。在真实配置里Graph 要加一个最大轮次判断。当 round 超过 3 时强制走 finish 节点避免无限循环消耗 Token。graph.addEdge(llm, finish, state - state.getRound() 3);判断标准达到上限后 Agent 能正常返回而不是卡死。即使返回的答案质量可能一般服务也不应该崩溃。这一步验证的是系统的鲁棒性不是回答质量。6.4 测试四工具异常模拟修改 ToolsNode让 queryWeather 方法抛出一个异常。观察 Graph 执行是否会把异常打印出来是否影响下一个请求。判断标准当前请求返回失败响应但服务进程不退出。下一次请求能正常执行。如果使用的是事件循环或虚拟线程线程池不能被异常污染。工具调用是 Agent 中最容易出问题的环节。外部服务超时、参数格式不对、返回内容过长都可能触发异常。Graph 只能编排控制流不能替你做异常兜底这需要在节点实现里自己处理。7. 接口 API 与批量任务接入7.1 暴露 REST 接口工程化落地必须让 Agent 变成服务否则没法给前端、微信小程序或内部系统调用。写一个简单的 Controllerimport org.springframework.web.bind.annotation.*; RestController RequestMapping(/api/agent) public class AgentController { private final AgentGraph agentGraph; public AgentController(AgentGraph agentGraph) { this.agentGraph agentGraph; } PostMapping(/invoke) public AgentResponse invoke(RequestBody AgentRequest request) { AgentState state new AgentState(); state.setUserInput(request.query()); state.setRound(0); AgentState result agentGraph.execute(state); return new AgentResponse(result.getFinalAnswer(), result.getRound(), result.getTrace()); } }配合一个请求体和响应体public record AgentRequest(String query, String sessionId) { } public record AgentResponse(String answer, int round, java.util.ListString trace) { }调用示例curl -X POST http://127.0.0.1:8080/api/agent/invoke \ -H Content-Type: application/json \ -d {query:杭州现在多少度,sessionId:test-001}接口能跑通之后前端只需要关心这个 POST 接口。Agent 内部是走一条链还是两条链前端完全不感知。这也是把 Graph 封装成服务的价值内部复杂度不会泄漏到接口层。7.2 批量任务设计批量任务是 Agent 工程化的常见需求。直接把一批文本循环执行 Graph不一定可靠因为LLM 服务有 QPS 和 Token 并发限制。单个请求失败时没有重试机制。数据量大时线程池容易被打满。建议做法是用一个有界线程池配合 CompletableFuture 做异步批量提交import java.util.List; import java.util.concurrent.*; Service public class BatchAgentService { private final AgentGraph agentGraph; private final ExecutorService executor new ThreadPoolExecutor( 4, 8, 30, TimeUnit.SECONDS, new ArrayBlockingQueue(100), new ThreadPoolExecutor.CallerRunsPolicy() ); public BatchAgentService(AgentGraph agentGraph) { this.agentGraph agentGraph; } public ListCompletableFutureAgentState runBatch(ListString queries) { return queries.stream() .map(query - CompletableFuture.supplyAsync(() - { AgentState state new AgentState(); state.setUserInput(query); state.setRound(0); return agentGraph.execute(state); }, executor)) .toList(); } }ThreadPoolExecutor 的 CallerRunsPolicy 很关键。它意味着当队列满了新任务不会丢弃而是由提交线程自己执行。对批量任务来说宁可慢一点也不能丢请求。7.3 批量任务的失败重试建议即使有线程池和队列模型调用也可能因为限流、网络抖动失败。更稳妥的做法是给任务加状态字段PENDING、RUNNING、SUCCESS、FAILED。失败任务进入重试队列最多重试 3 次每次间隔按指数退避。这里给出一个简化的重试策略重试次数等待时间备注11 秒网络瞬时抖动25 秒模型服务限流恢复330 秒长时间超时或服务异常如果第 3 次仍然失败不要无限重试直接把任务标记为 FAILED 并写入日志。批量任务跑完后统计成功率和平均轮次这些数据会在后面性能观察里用到。8. 资源占用与性能观察8.1 观察哪些指标这套系统的资源占用要分两层看JVM 编排层CPU、内存、线程数、活跃连接数。模型调用层单次 LLM 调用延迟、Token 消耗、限流次数。如果模型跑在云端JVM 内存可能不是瓶颈。最值得关注的是线程池队列长度和模型接口的 P95 延迟。队列一旦堆满说明并发配置与模型 QPS 不匹配。8.2 如何观察Spring Boot 项目直接引入 Actuator 依赖后可以查看线程和指标management.endpoints.web.exposure.includehealth,metrics,threaddump management.metrics.enable.jvmtrue观察命令curl http://127.0.0.1:8080/actuator/health curl http://127.0.0.1:8080/actuator/metrics/jvm.memory.used curl http://127.0.0.1:8080/actuator/threaddump如果不想引入额外依赖也可以用 JDK 自带工具jps -l jstat -gc pid 1000 jstack pid dump.logjstack 可以看到线程是否卡在某个工具调用上。批量任务卡死的常见原因就是某个外部工具接口没有设置超时导致线程一直阻塞。8.3 如何降低 Token 消耗Graph 编排不会直接降低 Token 消耗但可以帮你减少无效轮次在 LLM 节点里写清楚“如果不确定是否要调用工具就直接回答”。在条件边里加最大轮次限制。在工具节点把返回结果裁剪到必要长度。对长文本做分段处理不要每次都把完整历史塞进去。真正消耗 Token 的地方是历史消息越长每次调用成本越高。Graph 虽然把上下文放进了 State但不等于要把所有历史都发给模型。可控的做法是每次只发送“系统提示词 当前输入 最近一轮工具结果”而不是整个 State。9. 常见问题与排查方法问题现象可能原因排查方式解决方案启动报 Bean 创建失败依赖版本与 Spring Boot 不匹配查看完整堆栈确认是哪几个 Bean 冲突调整 spring-ai-alibaba 版本或移除重复的 ChatModel 配置请求返回 401API Key 配置错误或没有权限检查环境变量 DASHSCOPE_API_KEY 是否注入重新配置 Key确认模型权限已开通Agent 一直循环不结束条件边判断错误needTool 一直返回 true打印 trace 中的 round 和 lastReply添加 maxRound 条件边超限强制 finish工具节点报参数解析失败模型返回的 JSON 格式与解析代码不匹配打印原始 lastReply用 Jackson 严格解析并加异常兜底批量任务线程被占满线程池太小或外部接口无超时jstack 查看线程卡点增大队列容量给外部调用加 socket 超时中文显示乱码控制台编码问题检查 JVM 默认 charset启动参数加 -Dfile.encodingUTF-8接口响应很慢单次 LLM 调用耗时长或触发了多次工具调用观察 trace 每轮耗时开启流式输出、缩短提示词、减少最大轮次结果质量不稳定提示词不稳定或模型温度设置过高对比不同输入下的输出固定 temperature使用更明确的 few-shot 示例排查顺序建议遵循先外后内先看模型服务通不通再看配置对不对最后看图编排逻辑。绝大多数第一次跑不通的问题集中在 API Key 和依赖版本这两类。10. 最佳实践与使用建议10.1 从小图开始不要一上来就画一个包含十几条边的复杂图。先把 LLM 和工具两个节点跑通再逐步增加条件分支、人工确认节点、异常节点。每加一条边都要单独测试一次。图结构虽然比循环清晰但复杂图同样有维护成本。10.2 保留最小可运行配置把 API Key、模型名、超时时间、最大轮次都抽到配置文件里不要硬编码在代码中。这样换一个环境测试时只需要修改配置不需要改代码。建议保留一个单独的 local 配置用来在本地环境快速验证图是通的。10.3 使用日志与追踪追踪 Agent 流程Graph 的 State 对象是非常好的日志载体。把每个节点的入参、出参、耗时、Token 用量写进一个 trace 列表方便后续排查和审计。特别要注意日志里不要输出完整的 API Key也不要输出用户敏感信息。涉及个人信息时只记录必要字段。10.4 权限与合规这是整个工程化过程中最容易被忽略的部分。一个带工具调用的 Agent等于一个自动化的业务执行器。任何外部输入都可能影响工具参数工具返回的数据也可能被模型错误引用。上生产前必须做到对每个工具调用做参数白名单校验。对用户身份做鉴权防止越权调用。涉及人脸、声音、个人信息、企业敏感数据时确认授权范围。模型输出在面向用户前做一轮过滤屏蔽不当内容和错误事实。10.5 接口访问范围控制Agent 服务一旦暴露出去就变成了内网或公网的一个新入口。建议把 Agent 接口放在网关后面限制来源 IP 和调用频率。批量任务的 API 要加鉴权防止被恶意刷量消耗模型费用。可以直接通过网关配置 RateLimit 策略也可以自己在服务里用 Redis 计数。11. 总结与下一步这个方向最值得尝试的点很简单用图的思想替换掉脑子里的 while 循环。ReAct 本身不复杂复杂的是后续的维护、观测和扩展。Graph Engineering 把 Agent 的每一步变成节点和边让整个执行过程从“读代码猜逻辑”变成“看状态看路径”。对于 Java 技术栈团队Spring AI Alibaba 的 Graph 模块提供了一个现成的落地方案不用自己造有向无环图框架。第一次接触的话先验证两个基础功能一个不带工具的直答流程一个带工具调用的两轮流程。跑通这两条链路再考虑批量任务、异步处理、人工确认和接口权限。最容易踩的坑有两个一个是依赖版本不匹配导致启动失败一个是 Agent 循环没有设置最大轮次。前者通过查看 Maven 依赖树解决后者在条件边里加一个 round 判断就能避免。后续扩展方向可以从三个角度考虑一是把 ToolsNode 扩展成一个工具注册中心让不同业务团队注册自己的工具二是接入消息队列让 Agent 处理耗时长、可异步的任务三是引入人工确认节点在关键操作前暂停流程。每一步都比继续维护 while 循环更有工程价值。如果这篇文章对你有用建议收藏备用下次要接 Java Agent 的时候直接照着这张图起项目。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑