一、Graph Workflow 是什么?
1.1 核心概念
Graph Workflow(图工作流) 是一种基于有向图(DAG)的流程编排机制。


1.2 Graph vs 可视化拖拽平台
说到工作流,很多人第一反应会是:都叫'图'了,那不就是可视化拖拽拼装吗?这里先明确一点:Spring AI Alibaba 的 Graph Workflow 并不是可视化拖拽平台。它和 n8n、Zapier、飞书多维表格自动化这类低代码工具,定位完全不同。
| 特性 | 可视化拖拽平台 | Spring AI Graph Workflow |
|---|
| 定义方式 | 🖱️ UI 拖拽 | 💻 Java 代码 |
| 适用人群 | 业务人员、零代码用户 | 开发者 |
| 灵活性 | 受平台能力限制 | 完全可编程,自由度拉满 |
| 调试 | 平台日志查看 | 代码级调试 |
| 版本控制 | 平台内管理 | Git 友好 |
| 可视化 | ✅ 原生支持 | ✅ 可导出 Mermaid/PlantUML 图 |
二者在底层逻辑上其实是相通的,本质都是有向图(DAG),都由节点(Node)和边(Edge)构成,支持条件分支、循环逻辑,也都会管理任务的状态流转。
但它们的设计思路截然不同:Spring AI Graph 没有提供拖拽式 UI,也不主打零代码,而是以代码为核心,更适合复杂 AI 应用的工程化落地。同时它又保留了可视化能力,能通过代码直接生成流程图,在可编程性与可读性之间做到了很好的平衡。
二、Graph Workflow 三大核心组件

2.1 State(状态)
State 是什么?
- 在整个 Graph 执行过程中流转的数据
- 本质是
Map<String, Object>
- 每个节点都可以读取和修改 State
Map<String, Object> state = Map.of(
"user_query", "北京今天天气怎么样?",
"intent", "weather_query",
"result", "北京今天晴,15°C",
"messages", List.of("msg1", "msg2")
);
2.2 Node(节点)
Node 是什么?
- 执行具体业务逻辑的单元
- 接收 State,处理后返回新的 State
- 可以是同步或异步
public class WeatherNode implements NodeAction {
@Override
public Map<String, Object> apply(OverAllState state) throws Exception {
String city = (String) state.value("city").orElse("北京");
String weather = getWeather(city);
return Map.of("weather", weather);
}
}
2.3 Edge(边)
Edge 是什么?
workflow.addEdge("nodeA", "nodeB");
workflow.addConditionalEdges("classifier", edge_async(state -> {
String intent = (String) state.value("intent").orElse("default");
return intent;
}), Map.of(
"weather", "weather_node",
"news", "news_node",
"default", "default_node"
));
三、构建你的第一个 Graph Workflow
3.1 完整流程
KeyStrategyFactory keyStrategyFactory = () -> {
Map<String, KeyStrategy> strategies = new HashMap<>();
strategies.put("messages", new AppendStrategy());
strategies.put("result", new ReplaceStrategy());
return strategies;
};
StateGraph workflow = new StateGraph(keyStrategyFactory);
workflow.addNode("nodeA", node_async(new NodeA()));
workflow.addNode("nodeB", node_async(new NodeB()));
workflow.addEdge(START, "nodeA");
workflow.addEdge("nodeA", "nodeB");
workflow.addEdge("nodeB", END);
CompiledGraph compiled = workflow.compile();
Map<String, Object> initialState = Map.of("input", "Hello");
OverAllState result = compiled.invoke(initialState, config).orElseThrow();
3.2 小 Demo 案例:智能客服路由
public class CustomerServiceGraph {
public static class ClassifyNode implements NodeAction {
private final ChatClient chatClient;
@Override
public Map<String, Object> apply(OverAllState state) {
String query = (String) state.value("user_query").orElse("");
String prompt = String.format("""
分类用户意图(只返回类别):
- technical: 技术问题
- billing: 账单问题
- general: 一般咨询
用户问题:%s
""", query);
String intent = chatClient.prompt()
.user(prompt)
.call()
.content()
.trim()
.toLowerCase();
return Map.of("intent", intent);
}
}
public static class TechnicalSupportNode implements NodeAction {
@Override
public Map<String, Object> apply(OverAllState state) {
String query = (String) state.value("user_query").orElse();
searchTechDocs(query);
Map.of(, answer);
}
}
{
Map<String, Object> {
(String) state.value().orElse();
queryBillingSystem(query);
Map.of(, answer);
}
}
CompiledGraph {
ChatClient. ChatClient.builder(chatModel);
() -> {
Map<String, KeyStrategy> strategies = <>();
strategies.put(, ());
strategies.put(, ());
strategies.put(, ());
strategies;
};
(factory)
.addNode(, node_async( (builder.build())))
.addNode(, node_async( ()))
.addNode(, node_async( ()))
.addNode(, node_async( ()));
workflow.addEdge(START, );
workflow.addConditionalEdges(, edge_async(state -> (String) state.value().orElse()), Map.of(
, ,
, ,
,
));
workflow.addEdge(, END);
workflow.addEdge(, END);
workflow.addEdge(, END);
workflow.compile();
}
{
createGraph(chatModel);
Map<String, Object> initialState = Map.of(
,
);
RunnableConfig.builder()
.threadId()
.build();
graph.stream(initialState, config)
.doOnNext(output -> {
System.out.println( + output.node());
System.out.println( + output.state().data());
})
.blockLast();
}
}
四、状态管理:KeyStrategy
4.1 什么是 KeyStrategy?
KeyStrategy(键策略) 是 Graph Workflow 中用于控制状态更新行为的核心机制。
public interface KeyStrategy {
Object apply(Object oldValue, Object newValue);
}
作用:当节点返回新的状态数据时,KeyStrategy 决定如何将新值与旧值合并。
4.2 什么是 KeyStrategyFactory?
KeyStrategyFactory 是一个工厂接口,用于为 State 中的每个键指定更新策略。
public interface KeyStrategyFactory {
Map<String, KeyStrategy> getStrategies();
}
KeyStrategyFactory factory = () -> {
Map<String, KeyStrategy> strategies = new HashMap<>();
strategies.put("messages", new AppendStrategy());
strategies.put("result", new ReplaceStrategy());
strategies.put("counter", new CustomStrategy());
return strategies;
};
4.3 为什么需要 KeyStrategy?
问题场景:当多个节点修改同一个 State 键时,如何合并?

KeyStrategy 就是用来解决这个问题的!
4.4 工作原理

4.5 内置策略详解
1️⃣ ReplaceStrategy(替换策略)
用途:直接用新值替换旧值(最常用)
strategies.put("result", new ReplaceStrategy());

2️⃣ AppendStrategy(追加策略)
用途:将新值追加到列表中
strategies.put("messages", new AppendStrategy());

3️⃣ 自定义策略
用途:实现自己的合并逻辑
strategies.put("counter", (oldValue, newValue) -> {
int old = oldValue != null ? (int) oldValue : 0;
int add = (int) newValue;
return old + add;
});
strategies.put("metadata", (oldValue, newValue) -> {
Map<String, Object> old = (Map<String, Object>) oldValue;
Map<String, Object> newMap = (Map<String, Object>) newValue;
Map<String, Object> merged = new HashMap<>(old);
merged.putAll(newMap);
return merged;
});
strategies.put("tags", (oldValue, newValue) -> {
Set<String> tags = new HashSet<>((List<String>) oldValue);
tags.add((String) newValue);
return new ArrayList<>(tags);
});

4.6 完整的实现 KeyStrategyFactory 示例
public class MyKeyStrategyFactory implements KeyStrategyFactory {
@Override
public Map<String, KeyStrategy> getStrategies() {
Map<String, KeyStrategy> strategies = new HashMap<>();
strategies.put("user_query", new ReplaceStrategy());
strategies.put("intent", new ReplaceStrategy());
strategies.put("result", new ReplaceStrategy());
strategies.put("status", new ReplaceStrategy());
strategies.put("messages", new AppendStrategy());
strategies.put("history", new AppendStrategy());
strategies.put("logs", new AppendStrategy());
strategies.put("token_count", (oldValue, newValue) -> {
int old = oldValue != null ? (int) oldValue : 0;
return old + (int) newValue;
});
strategies.put("metadata", (oldValue, newValue) -> {
if (oldValue == ) newValue;
Map<String, Object> merged = <>((Map) oldValue);
merged.putAll((Map) newValue);
merged;
});
strategies;
}
}
( ());
4.7 KeyStrategy 最佳实践
✅ 好的实践
KeyStrategyFactory factory = () -> {
Map<String, KeyStrategy> strategies = new HashMap<>();
strategies.put("user_input", new ReplaceStrategy());
strategies.put("conversation", new AppendStrategy());
strategies.put("final_answer", new ReplaceStrategy());
strategies.put("error", new ReplaceStrategy());
strategies.put("metadata", new ReplaceStrategy());
return strategies;
};
❌ 不好的实践
KeyStrategyFactory factory = () -> {
Map<String, KeyStrategy> strategies = new HashMap<>();
strategies.put("messages", new AppendStrategy());
strategies.put("result", new AppendStrategy());
return strategies;
};
4.8 默认行为
如果某个键没有定义 KeyStrategy,会怎样?
建议:为所有可能出现的键都显式定义策略,避免依赖默认行为。
五、边的类型详解
5.1 普通边(固定路由)

workflow.addEdge("nodeA", "nodeB");
workflow.addEdge(START, "nodeA");
workflow.addEdge("nodeZ", END);
5.2 条件边(相当于动态路由)

workflow.addConditionalEdges(
"classifier",
edge_async(state -> {
String type = (String) state.value("type").orElse("default");
if ("urgent".equals(type)) {
return "urgent_handler";
} else if ("normal".equals(type)) {
return "normal_handler";
} else {
return "default_handler";
}
}),
Map.of(
"urgent_handler", "urgent_handler",
"normal_handler", "normal_handler",
"default_handler", "default_handler"
)
);
5.3 并行边

workflow.addEdge("A", List.of("B1", "B2", "B3"));
workflow.addEdge(List.of("B1", "B2", "B3"), "C");
六、可视化导出
虽然 Graph Workflow 是代码定义的,但可以导出为可视化图表!
GraphRepresentation mermaid = workflow.getGraph(
GraphRepresentation.Type.MERMAID,
"Customer Service Workflow"
);
System.out.println(mermaid.getContent());
将输出的 Mermaid 代码粘贴到支持 Mermaid 的平台(如 GitHub、Notion),即可看到可视化图表!
七、Graph vs ReactAgent
7.1 ReactAgent 的本质
ReactAgent 本质上就是一个预定义的 StateGraph!
StateGraph reactGraph = new StateGraph()
.addNode("llm_node", llmNode)
.addNode("tool_node", toolNode)
.addEdge(START, "llm_node")
.addConditionalEdges("llm_node", edge_async(state -> {
return needsTools(state) ? "tool_node" : END;
}), Map.of("tool_node", "tool_node", END, END))
.addEdge("tool_node", "llm_node");
7.2 何时使用 Graph?何时使用 ReactAgent?
| 场景 | 使用 | 原因 |
|---|
| 标准的 ReAct 循环 | ReactAgent | 开箱即用 |
| 自定义复杂流程 | StateGraph | 完全控制 |
| 多个 Agent 协作 | StateGraph | 灵活编排 |
| 需要人工介入 | StateGraph | 支持中断点 |
| 并行执行任务 | StateGraph | 支持并行边 |
八、总结
8.1 核心要点回顾
- Graph Workflow 是底层机制
- ReactAgent 基于 Graph 实现
- 提供完全的控制能力
- 三大核心组件
- State:数据流转
- Node:业务逻辑
- Edge:执行顺序
- 与可视化平台的对比
- 本质相同(都是 DAG)
- 形式不同(代码 vs UI)
- 各有优势
- 灵活的编排能力
8.2 Graph Workflow vs ReactAgent
| 特性 | Graph Workflow | ReactAgent |
|---|
| 核心能力 | 自定义流程编排 | 标准 ReAct 循环 |
| 适用场景 | 复杂流程、多 Agent 协作 | 标准工具调用 |
| 可组合性 | ✅ ReactAgent 基于它实现 | ✅ 可以作为 Graph 的节点 |
参考资源