AgentFlow 入门与实战:Task-Based 并发、EWMA 动态调度与四道门禁的 Java 生产级编排
一、AgentFlow 是什么
1.1 一句话定义
AgentFlow 是一个用 Java 构建的、面向持久化异步 AI Agent 任务的 pub-sub 有向图编排框架,专为"永不终止的开放式工作流"设计,让多个独立 Agent 通过消息传递持续协作。
1.2 解决什么问题
传统 AI Agent 编排通常采用"请求-响应"的一次性模式------用户提问,Agent 处理,返回结果,结束。但现实中很多场景是持续运行、不断演进的:客服工单流转、监控告警处理、多阶段审批流水线。这些场景需要 Agent 长时间存活,持续接收和处理消息。
类比:AgentFlow 就像一条永不停歇的工厂流水线。 传统 Agent 是"接单-完工-关门"的作坊模式;AgentFlow 是"传送带不停运转、工位持续处理"的流水线模式。每个工位(Task)是一个独立线程,通过传送带(pub-sub 消息)传递工件(消息)。
1.3 核心设计哲学
AgentFlow 的核心设计选择是 Task-Based Concurrency ------每个操作封装为一个独立的 Task,运行在自己的 daemon 线程中,Task 之间通过发布-订阅模式通信,发布者不需要知道订阅者的存在。
注:
博客:
https://blog.csdn.net/badao_liumang_qizhi
二、核心架构
2.1 Task-Based Concurrency
java
public abstract class Task implements Runnable {
// 线程生命周期管理
public void start() { ... }
public void stop() { ... }
// 子类实现的抽象方法
protected abstract boolean shouldProcess();
protected abstract void process();
protected abstract long calculateSleepTime();
}
每个 Task 是一个自包含的工作单元,能够处理传入消息、调整自身处理频率、与其他 Task 通信、维护自己的状态。
2.2 Adaptive Timing(EWMA 动态调整)
AgentFlow 最具特色的设计是用指数加权移动平均(EWMA)算法动态调整每个 Task 的处理频率,而非固定轮询间隔。
java
public abstract class AdaptiveTimingTask extends Task {
double alpha = 0.1; // 学习率
double estimatedSleepTime = 100; // 初始休眠时间(ms)
@Override
protected long calculateSleepTime() {
if (lastWaitingTime() == 0) {
return (long) estimatedSleepTime;
}
estimatedSleepTime = alpha * lastWaitingTime()
+ (1 - alpha) * estimatedSleepTime;
return (long) estimatedSleepTime;
}
}
效果:繁忙的 Task 自动获得更短的休眠时间(更频繁运行),空闲的 Task 自动退避以节省资源。系统在响应性和效率之间自然平衡。
类比:EWMA 就像交通信号灯的自适应配时。 固定轮询是"不管车流量多少,绿灯都是 30 秒";EWMA 是"车多时绿灯延长,车少时绿灯缩短"------系统根据实际负载动态调整。
2.3 AdaptiveRelayTask:编排的核心组件
java
public class AdaptiveRelayTask<X, Y> extends AdaptiveTimingTask {
List<X> inbox = new ArrayList<>();
List<AdaptiveRelayTask<Y, ?>> relays = new ArrayList<>();
Function<X, Y> expression;
@Override
protected void process() {
for (X x : inbox) {
Y result = expression.apply(x);
for (AdaptiveRelayTask<Y, ?> relay : relays) {
relay.accept(result);
}
}
inbox.clear();
}
}
这个类提供了:泛型输入输出、函数式转换、消息队列管理、自动路由到下游 Task。
三、AgentFlow4J:Spring AI 之上的生产级治理层
cynthiasystems/AgentFlow 侧重于运行时架构 (pub-sub + EWMA),而 AgentFlow4J 则在其基础上增加了生产级治理能力------人机审批、检查点恢复、预算控制、工具策略。
3.1 两级 API
AgentFlow4J 暴露两层 API,按需要的控制粒度选择:
Level 1 --- Squad API(推荐大多数应用) :动态路由,最小化配置。CoordinatorAgent 将请求路由到一组 ExecutorAgent,你只需关注 Agent 本身,而非底层管道。
Level 2 --- Graph API(需要完全控制) :显式定义节点、边、条件边、循环。支持每个节点的重试策略、断路器、预算门禁、基于检查点的恢复。
java
AgentGraph graph = AgentGraph.builder()
.addNode("research", researcher)
.addNode("analyze", analyzer)
.addNode("write", writer)
.addEdge("research", "analyze")
.addEdge(Edge.conditional("analyze",
ctx -> ctx.get(CONFIDENCE).doubleValue() < 0.7,
"research")) // 循环回退
.addEdge("analyze", "write")
.errorPolicy(ErrorPolicy.RETRY_ONCE)
.build();
AgentResult result = graph.invoke(AgentContext.of("..."));
关键特性 :两级 API 可以组合------CoordinatorAgent 本身就是一个 Agent,可以作为节点放入 Graph 中。
3.2 治理模型:四道门禁
AgentFlow4J 的生产级治理围绕四道门禁展开:
| 门禁 | 作用 | 实现 |
|---|---|---|
| BudgetPolicy | 限制每次运行/每个节点/每次调用的花费 | 货币无关,成本可以是美元、Token 数或调用次数 |
| ToolPolicy | 阻止危险工具的执行 | 工具白名单/黑名单 |
| StatePolicy | 保护敏感状态字段 | 状态读写权限控制 |
| ApprovalGate | 在高风险操作前暂停,等待人工审批 | 基于检查点的暂停/恢复 |
Budget-aware Routing:AgentFlow4J v0.7.0 引入了预算感知路由------在预算充足时路由到高级 Agent,预算低于阈值时优雅降级到便宜的回退方案。
类比:四道门禁就像核电站的多层安全机制。 预算控制是"燃料限额",工具策略是"操作许可",状态保护是"辐射屏蔽",人工审批是"发射按钮的双人确认"。
3.3 持久化执行
AgentFlow4J 在每个节点后自动创建检查点。如果工作流中途崩溃,从最后一个成功的检查点恢复,而不是从头开始。
java
// 人机审批的暂停/恢复
ApprovalGate gate = ApprovalGate.builder()
.threshold(1000.0) // 金额超过 1000 时触发审批
.build();
// 暂停后通过 Slack/Webhook 通知人工
// 审批通过后从检查点恢复,不丢失已完成的工作
四、快速上手示例
4.1 Maven 依赖
xml
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependency>
<groupId>com.github.datallmhub.agentflow4j</groupId>
<artifactId>agentflow4j-starter</artifactId>
<version>v0.7.0</version>
</dependency>
<!-- Spring AI Provider --- 可替换为 OpenAI/Anthropic/Gemini/Ollama -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-mistral-ai</artifactId>
</dependency>
4.2 定义类型化状态
用 StateKey<T> 替代 Map<String, Object>,编译器可以捕获键不匹配的错误:
java
public final class ReviewKeys {
public static final StateKey<String> DOCUMENT =
StateKey.of("document", String.class);
public static final StateKey<String> DOC_TYPE =
StateKey.of("doc.type", String.class);
public static final StateKey<String> RISK_LEVEL =
StateKey.of("risk.level", String.class);
public static final StateKey<String> ISSUES =
StateKey.of("issues", String.class);
public static final StateKey<String> FINAL_REPORT =
StateKey.of("final.report", String.class);
}
4.3 编写三个 Agent
每个 Agent 是一个 Spring Bean,由 ExecutorAgent 支撑:
java
@Configuration
public class ReviewAgents {
@Bean
Agent classifier(ChatClient.Builder builder) {
return ExecutorAgent.builder()
.chatClient(builder.build())
.systemPrompt("""
你是一个法律文档分类器。阅读文档并返回 JSON:
"type": [CONTRACT, NDA, INVOICE, OTHER]
"risk": [LOW, MEDIUM, HIGH]
""")
.inputMapper(ctx -> ctx.get(ReviewKeys.DOCUMENT))
.outputMapper((ctx, result) -> ctx
.with(ReviewKeys.DOC_TYPE, extractField(result.text(), "type"))
.with(ReviewKeys.RISK_LEVEL, extractField(result.text(), "risk")))
.build();
}
@Bean
Agent analyst(ChatClient.Builder builder) {
return ExecutorAgent.builder()
.chatClient(builder.build())
.systemPrompt("你是法律分析师。提取最重要的三个条款并标记问题。")
.inputMapper(ctx -> ctx.get(ReviewKeys.DOCUMENT))
.outputMapper((ctx, result) -> ctx
.with(ReviewKeys.ISSUES, result.text()))
.build();
}
@Bean
Agent summariser(ChatClient.Builder builder) {
return ExecutorAgent.builder()
.chatClient(builder.build())
.systemPrompt("你是高级法律审核员。根据文档类型、风险等级和分析发现,生成一页审核报告。")
.inputMapper(ctx -> String.format(
"类型: %s\n风险: %s\n发现:\n%s",
ctx.get(ReviewKeys.DOC_TYPE),
ctx.get(ReviewKeys.RISK_LEVEL),
ctx.get(ReviewKeys.ISSUES)))
.outputMapper((ctx, result) -> ctx
.with(ReviewKeys.FINAL_REPORT, result.text()))
.build();
}
}
4.4 构建编排图
java
AgentGraph graph = AgentGraph.builder()
.addNode("classify", classifier)
.addNode("analyze", analyst)
.addNode("summarise", summariser)
.addEdge("classify", "analyze")
.addEdge("analyze", "summarise")
.build();
AgentResult result = graph.invoke(
AgentContext.of(Map.of(ReviewKeys.DOCUMENT, documentText)));
五、与其他框架的定位对比
| 维度 | AgentFlow (cynthiasystems) | AgentFlow4J | Spring AI Alibaba Graph |
|---|---|---|---|
| 核心定位 | 持久化异步 Agent 运行时 | Spring AI 治理层 | 企业级 Graph 编排 |
| 并发模型 | Task 线程 + EWMA 动态调整 | 基于 Spring AI | Flux 响应式 |
| 消息传递 | Pub-Sub 有向图 | AgentContext 类型化状态 | OverAllState |
| 治理能力 | 基础 | 四道门禁 + 检查点 | interruptBefore/After |
| 人机审批 | 无内置 | ApprovalGate | Graph Studio |
| 适用场景 | 长运行开放式工作流 | 生产级 Spring AI 应用 | 复杂 DAG 工作流 |
选型建议:
- 需要持续运行的开放工作流(监控、工单流转)→ cynthiasystems/AgentFlow
- 需要生产级治理(预算、审批、检查点)且使用 Spring AI → AgentFlow4J
- 需要复杂 DAG + 可视化编排 → Spring AI Alibaba Graph
六、总结
AgentFlow 的核心设计哲学是 "让 Agent 像流水线一样持续运转":
| 层面 | 核心技术 | 设计要点 |
|---|---|---|
| 并发模型 | Task-Based Concurrency | 每个 Task 独立线程 |
| 消息传递 | Pub-Sub 有向图 | 发布者不感知订阅者 |
| 动态调度 | EWMA 指数加权移动平均 | 繁忙 Task 获更多 CPU,空闲 Task 自动退避 |
| 类型安全 | StateKey | 编译器捕获键错误 |
| 治理 | 四道门禁 + 检查点 | 预算/工具/状态/审批 |
| 持久化 | 节点级检查点 | 崩溃后从断点恢复 |
参考资源: