LangGraph 是 Python 生态广为人知的 Agent 状态图编排框架,凭借循环分支、检查点持久化、人在回路等能力被广泛使用。但对于 Java Spring 技术栈开发者,直接使用 LangGraph 会带来跨语言的运维与集成成本。Spring AI Alibaba WorkFlow 在设计理念上对标 LangGraph,提供图、节点、条件分支、检查点持久化、任务中断恢复一整套编排能力,让开发者可以在 Java/Spring 体系内实现复杂 AI Agent。本文结合工程样例讲解这套组件落地生产 AI Agent 的实践要点。
⚠️版本说明:Spring‑AI‑Alibaba 0.3.x+ 正式提供 WorkFlow 能力。0.3.x 系列属于早期版本,部分 API 存在变动可能性,升级版本时需要查阅官方迁移文档做好兼容性适配;Spring AI Alibaba WorkFlow 在设计理念对齐 LangGraph,但 API 是 Java 面向对象风格,并非直接移植 LangGraph。
一、概念对照:LangGraph - Spring AI Alibaba WorkFlow
表格
| LangGraph(Python) | Spring AI Alibaba WorkFlow(Java) | 说明 |
|---|---|---|
| StateGraph | WorkFlowGraph | 定义整个图,节点、边、条件分支 |
| State | WorkFlowState | 全局状态,存储 Agent 全部上下文、子任务、中间结果 |
| Node | WorkFlowNode | 业务节点(推理、工具调用、结果解析) |
| Edge | WorkFlowEdge | 普通流转边,A 节点执行完流转到 B |
| Conditional Edge | ConditionalWorkFlowEdge | 条件分支,根据状态选择下一个节点,实现 ReAct 循环 |
| Checkpoint | WorkFlowCheckpoint | 检查点 / 持久化,断点续跑、Worker 崩溃恢复 |
| Human‑in‑the‑Loop interrupt | WorkFlowInterrupt | 任务中断,人工介入之后恢复执行(人在回路) |
| MemorySaver / RedisSaver | CheckpointRepository | 状态持久化仓库:内存、Redis、数据库 |
核心思想对齐:
- 所有信息收敛到 State:不要把任务状态塞到大模型对话历史,全部放到
WorkFlowState,对应前文生产原则:禁止完全依赖 LLM 上下文保存任务状态,外置状态机存储。 - 支持循环:ReAct"思考‑行动‑观察" 循环,依靠条件分支实现。
- 支持中断恢复:高风险操作触发 interrupt,人工审批完成,从 Checkpoint 继续执行。
- 可持久化:任务崩溃、服务重启,可以从最近 Checkpoint 恢复,不会重复调用工具、重复请求大模型。
二、架构视角:WorkFlow 对应 Agent 八大模块
WorkFlowGraph 本身是流程编排运行时底座,不是完整 Agent。
- WorkFlowGraph + WorkFlowState = 规划模块 + 有限状态机 FSM
- 各个 Node 内部实现:感知、大模型推理、工具调用、执行反馈逻辑
- CheckpointRepository = 任务状态持久化
- WorkFlowInterrupt = 人在回路
- 记忆模块(向量库记忆、短期会话记忆)、管控安全、复盘评估属于外部组件,在 Node 内部调用。
重要:WorkFlow 只管流转与状态;记忆、安全校验、工具权限校验依然需要自己实现,框架不会自动处理业务安全。
三、Spring AI Alibaba WorkFlow 快速入门:实现 ReAct Agent(Java 完整示例)
3.1 Maven 依赖xml
<dependencies>
<!-- Spring AI Alibaba WorkFlow核心 -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring‑ai‑alibaba‑workflow</artifactId>
<version>0.3.2.0</version>
</dependency>
<!-- Spring AI 大模型核心,通义千问 -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring‑ai‑alibaba‑dashscope‑spring‑boot‑starter</artifactId>
</dependency>
<!-- Redis Checkpoint持久化,生产必须;Demo可以用内存存储 -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring‑ai‑alibaba‑workflow‑redis</artifactId>
</dependency>
</dependencies>
3.2 自定义 Agent 状态 WorkFlowState
对应 LangGraph State,存放全部任务信息,不要依赖 ChatMemory 承载任务进度。
import com.alibaba.cloud.ai.workflow.WorkFlowState;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class AgentState implements WorkFlowState {
/** 唯一任务ID,对应TraceId */
private String traceId;
/** 用户原始query(感知模块输出) */
private String userQuery;
/** 大模型推理输出 */
private String llmThought;
/** 需要调用的工具名称 */
private String toolName;
/** 工具调用参数JSON */
private String toolArguments;
/** 工具返回观测结果(observation) */
private String toolObservation;
/** 最终回答,任务完成输出 */
private String finalAnswer;
/** 记录迭代轮次,防死循环,对应最大迭代轮次限制 */
private int iteration = 0;
/** 子任务列表,规划模块产出 */
private List<String> subTasks = new ArrayList<>();
/** 是否任务完成标记 */
private boolean isFinished = false;
/** 是否触发人工中断(人在回路标记) */
private boolean needHumanInterrupt = false;
@Override
public String getWorkflowInstanceId() {
// workflow实例唯一ID,checkpoint以此为key
return traceId;
}
}
3.3 定义数据传输实体 ReActOutput
用于接收并解析大模型 ReAct 格式输出。java
import lombok.Data;
@Data
public class ReActOutput {
/** 思考过程 */
private String thought;
/** 工具名称 */
private String toolName;
/** 工具入参 */
private String args;
/** 最终回答 */
private String finalAnswer;
/** 是否结束任务 */
private boolean finish;
}
3.4 定义工具抽象接口 ToolProvider
统一工具调用抽象,便于实现工具白名单、参数校验逻辑。
java
public interface ToolProvider {
/** 判断工具是否在白名单 */
boolean isAllowTool(String toolName);
/** 执行工具调用 */
String callTool(String toolName, String toolArguments);
}
3.5 定义各个 Node 节点(对应 Agent 业务逻辑)
ReAct 循环链路:用户输入解析节点 → LLM推理思考节点 →【条件判断】 - 如果需要调用工具:进入工具调用节点 → 返回推理节点(循环) - 如果任务完成:进入输出结果节点结束 - 如果迭代超限 / 需要人工审批:触发 interrupt 人工中断
Node1:输入解析节点
import com.alibaba.cloud.ai.workflow.WorkFlowNode;
import com.alibaba.cloud.ai.workflow.context.WorkFlowContext;
public class InputParseNode implements WorkFlowNode<AgentState> {
@Override
public AgentState execute(WorkFlowContext<AgentState> context) {
AgentState state = context.getState();
// 上层传入用户query;生产这里做输入清洗、脱敏、Prompt注入检测
String rawInput = context.getVariable("rawUserInput");
state.setUserQuery(rawInput);
state.setIteration(0);
state.setFinished(false);
return state;
}
}
Node2:LLM 推理思考节点
import com.alibaba.cloud.ai.workflow.WorkFlowNode;
import com.alibaba.cloud.ai.workflow.context.WorkFlowContext;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.response.ChatResponse;
public class LLMReasonNode implements WorkFlowNode<AgentState> {
private final ChatModel chatModel;
public LLMReasonNode(ChatModel chatModel) {
this.chatModel = chatModel;
}
@Override
public AgentState execute(WorkFlowContext<AgentState> context) {
AgentState state = context.getState();
// 迭代计数,防止死循环,生产最大迭代轮次配置,例如10轮
state.setIteration(state.getIteration() + 1);
if(state.getIteration() > 10){
state.setNeedHumanInterrupt(true);
return state;
}
// 组装prompt:带入历史工具观测结果,实现ReAct思考
Prompt prompt = buildReActPrompt(state);
ChatResponse resp = chatModel.call(prompt);
String content = resp.getResult().getOutput().getText();
// 生产这里做JSON Schema解析容错,区分故障类型
ReActOutput parseResult = parseReActOutput(content);
state.setLlmThought(parseResult.getThought());
state.setToolName(parseResult.getToolName());
state.setToolArguments(parseResult.getArgs());
state.setFinalAnswer(parseResult.getFinalAnswer());
// 如果返回最终答案标记任务结束
if(parseResult.isFinish()){
state.setFinished(true);
}
return state;
}
private Prompt buildReActPrompt(AgentState state){
// 业务自行实现:构造ReAct Prompt,带入userQuery、toolObservation
return new Prompt("");
}
private ReActOutput parseReActOutput(String llmOutput){
// 业务自行实现JSON解析、清洗容错逻辑,处理截断、多余文本等异常
return new ReActOutput();
}
}
Node3:工具调用节点(工具调用 + 执行反馈模块)
import com.alibaba.cloud.ai.workflow.WorkFlowNode;
import com.alibaba.cloud.ai.workflow.context.WorkFlowContext;
public class ToolInvokeNode implements WorkFlowNode<AgentState> {
private final ToolProvider toolProvider;
public ToolInvokeNode(ToolProvider toolProvider) {
this.toolProvider = toolProvider;
}
@Override
public AgentState execute(WorkFlowContext<AgentState> context) {
AgentState state = context.getState();
// 生产安全校验
// 1、工具白名单校验;2、参数前置校验;3、高危操作检测,高危设置needHumanInterrupt=true
if(!toolProvider.isAllowTool(state.getToolName())){
state.setToolObservation("error:工具不在白名单,禁止调用");
return state;
}
// 执行工具
String observation = toolProvider.callTool(state.getToolName(), state.getToolArguments());
state.setToolObservation(observation);
return state;
}
}
Node4:输出完成节点
import com.alibaba.cloud.ai.workflow.WorkFlowNode;
import com.alibaba.cloud.ai.workflow.context.WorkFlowContext;
public class OutputFinishNode implements WorkFlowNode<AgentState> {
@Override
public AgentState execute(WorkFlowContext<AgentState> context) {
AgentState state = context.getState();
System.out.println("Agent最终输出:" + state.getFinalAnswer());
return state;
}
}
3.6 构建 WorkFlowGraph,配置条件分支
重点:条件边 ConditionalWorkFlowEdge 实现 ReAct 循环;检测人工中断触发 Interrupt。
import com.alibaba.cloud.ai.workflow.WorkFlowGraph;
import com.alibaba.cloud.ai.workflow.edge.ConditionalWorkFlowEdge;
import com.alibaba.cloud.ai.workflow.repository.CheckpointRepository;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AgentWorkFlowConfig {
@Bean
public WorkFlowGraph<AgentState> agentWorkFlowGraph(ChatModel chatModel,
CheckpointRepository checkpointRepository,
ToolProvider toolProvider){
// 注册全部节点
WorkFlowGraph<AgentState> graph = WorkFlowGraph.builder(AgentState.class)
.addNode("inputParse", new InputParseNode())
.addNode("llmReason", new LLMReasonNode(chatModel))
.addNode("toolInvoke", new ToolInvokeNode(toolProvider))
.addNode("outputFinish", new OutputFinishNode())
// 设置checkpoint持久化仓库:Redis生产;Memory仅Demo
.checkpointRepository(checkpointRepository)
// 设置入口节点
.entryPoint("inputParse")
.build();
// 普通边:输入解析完成,流转到推理节点
graph.addEdge("inputParse", "llmReason");
// 条件分支:ReAct核心循环逻辑
graph.addConditionalEdge("llmReason", ConditionalWorkFlowEdge.<AgentState>builder()
.condition(context -> {
AgentState state = context.getState();
// 优先级1:触发人工中断
if(state.isNeedHumanInterrupt()){
return "humanInterrupt";
}
// 优先级2:任务完成,输出结束
if(state.isFinished()){
return "finish";
}
// 优先级3:需要调用工具
if(state.getToolName() != null){
return "callTool";
}
// 默认回到推理,继续思考
return "reasonAgain";
})
.putTarget("humanInterrupt", graph.interrupt())
.putTarget("finish", "outputFinish")
.putTarget("callTool", "toolInvoke")
.putTarget("reasonAgain", "llmReason")
.build());
// 工具调用结束,回到推理节点,继续ReAct循环
graph.addEdge("toolInvoke", "llmReason");
// 设置终止节点
graph.setEndNode("outputFinish");
return graph;
}
}
3.7 运行 Workflow、中断恢复(人在回路示例)
import com.alibaba.cloud.ai.workflow.WorkFlowExecuteResult;
import com.alibaba.cloud.ai.workflow.WorkFlowGraph;
import com.alibaba.cloud.ai.workflow.context.WorkFlowContext;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AgentController {
private final WorkFlowGraph<AgentState> agentWorkFlowGraph;
public AgentController(WorkFlowGraph<AgentState> agentWorkFlowGraph) {
this.agentWorkFlowGraph = agentWorkFlowGraph;
}
/** 启动Agent任务 */
@PostMapping("/agent/start")
public String startAgent(@RequestParam String traceId,
@RequestParam String userInput){
// 初始化上下文,传入外部变量
WorkFlowContext<AgentState> context = agentWorkFlowGraph.createContext(traceId);
context.setVariable("rawUserInput", userInput);
// 执行,遇到interrupt会挂起,不会阻塞
WorkFlowExecuteResult result = agentWorkFlowGraph.execute(context);
if(result.isInterrupt()){
return "任务挂起等待人工审批,traceId:" + traceId;
}
return context.getState().getFinalAnswer();
}
/** 人工审批完成,恢复被中断的任务,从Checkpoint断点继续执行 */
@PostMapping("/agent/resume")
public String resumeAgent(@RequestParam String traceId,
@RequestParam boolean humanApprove){
WorkFlowContext<AgentState> resumeCtx = agentWorkFlowGraph.loadContext(traceId);
AgentState state = resumeCtx.getState();
state.setNeedHumanInterrupt(false);
// 可将人工审批结果写入state供后续逻辑使用
// state.setHumanApprove(humanApprove);
WorkFlowExecuteResult result = agentWorkFlowGraph.resume(resumeCtx);
return resumeCtx.getState().getFinalAnswer();
}
}
关键特性说明:
- 如果使用 RedisCheckpointRepository,服务重启之后,调用
loadContext(traceId)依然可以恢复任务,不会从头跑。 graph.interrupt()不会阻塞线程,长任务适合异步,不要用同步 HTTP 接口跑大循环 Agent。
四、WorkFlow 工程落地要点
4.1 状态设计避坑
- 不要把任务业务状态放在 ChatMemory 聊天记录,全部放入
WorkFlowState;聊天历史只做 LLM 输入素材。 - State 中必须带上
iteration迭代计数器,防止 ReAct 死循环;配置最大迭代上限。 - TraceId 作为 workflowInstanceId,打通全链路 Trace,用于日志、告警、故障排查。
4.2 Checkpoint 持久化(对应 Durable Execution)
Demo 环境可使用 InMemoryCheckpointRepository;该实现数据驻内存,服务重启数据全部丢失,严禁上生产。生产环境推荐 RedisCheckpointRepository,也可以自定义实现数据库存储。
注意:Checkpoint 保存的是 Workflow 流转状态,不等于 Agent 长期记忆。向量形式的业务记忆仍然需要单独接入 Milvus 等向量数据库。
4.3 人在回路 Human‑in‑the‑Loop
- interrupt 只用于不可逆高危操作,不要滥用,避免审批疲劳。
- 中断后,人工修改的业务数据写入
AgentState,再 resume 恢复执行。 - 业务上增加超时机制:中断超过指定时长自动终止任务。
4.4 安全防护实现
编排框架本身不提供安全能力,相关逻辑需要在 Node 业务代码显式实现。
- 输入侧:输入清洗、脱敏,检测 Prompt 注入风险,隔离用户输入与系统 Prompt,禁止原始用户输入直接拼接系统指令。
- 工具侧:工具白名单、参数前置校验、高危操作识别,高危动作触发人工中断。
- 输出侧:大模型返回内容做合规校验,过滤违规输出,对关键业务输出做事实校验与证据溯源绑定。
4.5 记忆模块怎么和 WorkFlow 结合
WorkFlowGraph 没有内置记忆能力,需要在 Node 内部主动调用记忆组件:
- 推理节点执行前:在
LLMReasonNode读取瞬时 / 短期 / 长期记忆,把召回的记忆内容送入 Prompt。 - 任务完成之后:在
outputFinishNode,执行记忆写入逻辑,同时做记忆写入校验,防止记忆污染、记忆投毒。
4.6 成本与防死循环
- State 维护
iteration迭代计数,条件分支直接拦截超限,强制 interrupt 或终止; - 在 Node 中统计 token 消耗,state 记录 token 使用量,到达预算上限直接终止任务。
五、Java Agent 方案横向对比
表格
| 方案 | 特点 | 适用场景 |
|---|---|---|
| Spring AI Alibaba WorkFlow | 基于 Spring 生态,状态图编排,支持 Checkpoint、中断恢复;上层 Agent 能力需要自行封装 | Spring Boot 业务系统,需要 Java 原生编排,需要断点续跑、人在回路 |
| LangChain4j | Java 生态 Agent 工具库,提供工具调用、记忆抽象;缺少原生状态图与持久化中断能力 | 简单 Agent、单轮 / 少轮任务,不需要复杂循环与断点续跑 |
| 自研状态机 | 完全自主可控,可深度定制;开发成本高,需要自行实现循环、检查点、中断等底层能力 | 高度定制、强监管业务,团队有充足研发人力 |
补充:Python 生态 LangGraph 可以通过 HTTP 接口供 Java 系统调用,适合团队混合技术栈,需要承担跨语言部署运维成本。
六、生产环境 Agent 测试策略
Agent 系统输出存在概率性、非确定性特征,传统单元测试不足以保障质量,需要分层测试体系。
-
确定性组件单元测试针对工具函数、参数解析器、状态流转逻辑、安全校验组件编写单元测试,保证基础模块行为稳定。
-
Prompt 单元测试针对核心 Prompt 模板编写测试用例,覆盖正常场景、边界场景、Prompt 注入对抗用例,防止 Prompt 迭代后发生行为漂移。
-
WorkFlow 集成测试编写集成测试,完整运行 Workflow 实例,校验状态流转、分支跳转、检查点持久化、中断恢复逻辑是否符合预期,不依赖大模型真实返回,可对 ChatModel 做 Mock。
-
端到端场景测试构建业务端到端测试集,包含普通业务用例、边界用例、对抗用例,运行完整 Agent 链路,评估任务完成率、工具调用准确率。
-
混沌测试主动注入故障,模拟工具调用超时、模型返回异常、记忆检索错误等场景,验证 Agent 的容错、重试、降级、终止逻辑。
-
CI/CD 门禁将自动化测试纳入 CI 流水线,代码变更、Prompt 迭代自动执行测试套件,核心指标不达标阻止版本合入,防止能力退化。
七、生产环境落地架构建议
HTTP 接口 → 异步任务队列(Spring Async/RocketMQ)↓WorkFlowGraph(Spring AI Alibaba WorkFlow)├─ 各个 Node 节点│ ├─感知输入清洗、注入检测│ ├─记忆服务(瞬时 / 短期 / 向量长期记忆)│ ├─LLM 推理 + JSON 解析容错│ ├─工具服务(白名单、参数校验、沙箱)│ └─人在回路 Interrupt 中断├─Checkpoint Redis 持久化└─全链路 Trace 日志、指标监控、告警↓任务完成 → 复盘评估服务(高阶可选)
重要提醒:WorkFlow 解决的是任务流转、状态持久、循环分支、断点续跑;不等于开箱即用完整 Agent。管控安全、评估、测试、成本管控都需要业务侧自行实现。
八、生产环境常见风险点
- 不要直接使用 InMemoryCheckpointRepository 上生产,服务重启任务全部丢失。
- 业务状态全部存放在 ChatMemory,WorkFlowState 只保存少量字段,会引发任务漂移。
- ReAct 循环没有迭代计数器,大模型陷入死循环,持续消耗 Token 资源。
- 大量普通只读操作也使用 interrupt 中断,造成审批疲劳,降低人工审核有效性。
- 在同步 HTTP 接口执行长 Workflow,HTTP 超时断开,任务状态发生混乱。
- 将 Workflow Checkpoint 快照和向量长期记忆混淆,Checkpoint 只保存流程运行时状态。
- 忽略大模型输出解析容错,遇到模型输出格式异常直接引发流程崩溃。
- 缺少 Prompt 注入、输出合规校验,带来业务安全风险。
- 忽略 0.3.x 版本 API 迭代风险,升级版本没有查阅官方迁移文档。
九、总结
- Python 生态流行 LangGraph 做 Agent 状态编排,Java Spring 技术栈可选用 Spring AI Alibaba WorkFlow 实现理念相近的 Agent 图编排能力,支持循环、条件分支、Checkpoint 持久化、Interrupt 人在回路、断点续跑。
- WorkFlowGraph 只是编排运行底座,Agent 各类业务能力需要在 Node 中调用外部业务组件实现。
- 生产落地关键要点:外置状态 WorkFlowState、Redis 持久化 Checkpoint、迭代轮次防死循环、异步执行长任务、仅高危操作触发人工 Interrupt、完整输入输出安全校验、建立分层 Agent 测试体系。
- Java 技术栈存在多种 Agent 实现路线,需要结合业务场景、团队技术栈做选型权衡。