惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Latest
Security Latest
Recorded Future
Recorded Future
人人都是产品经理
人人都是产品经理
S
SegmentFault 最新的问题
Hacker News - Newest:
Hacker News - Newest: "LLM"
C
CXSECURITY Database RSS Feed - CXSecurity.com
博客园 - 三生石上(FineUI控件)
博客园 - 聂微东
P
Privacy & Cybersecurity Law Blog
WordPress大学
WordPress大学
Know Your Adversary
Know Your Adversary
Spread Privacy
Spread Privacy
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
量子位
L
LINUX DO - 热门话题
L
Lohrmann on Cybersecurity
博客园 - Franky
酷 壳 – CoolShell
酷 壳 – CoolShell
T
Tor Project blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
雷峰网
雷峰网
阮一峰的网络日志
阮一峰的网络日志
V
Visual Studio Blog
T
Threatpost
T
Tenable Blog
有赞技术团队
有赞技术团队
大猫的无限游戏
大猫的无限游戏
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI
C
Cisco Blogs
H
Heimdal Security Blog
Attack and Defense Labs
Attack and Defense Labs
A
About on SuperTechFans
Last Week in AI
Last Week in AI
N
News and Events Feed by Topic
T
Threat Research - Cisco Blogs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
I
Intezer
V
V2EX
Cyberwarzone
Cyberwarzone
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
B
Blog RSS Feed
V
Vulnerabilities – Threatpost
N
Netflix TechBlog - Medium
T
The Blog of Author Tim Ferriss
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
U
Unit 42
PCI Perspectives
PCI Perspectives
P
Privacy International News Feed
D
Docker

博客园_首页

Plist 二进制格式 Milvus 和 PGVector,哪个更好? OpenClaw 已过时?在 VS Code 中运行 Hermes Agent! 第30篇文章:一个大三计科生的自白 Manim如何在数学公式中完美显示中文? Docker 部署 RocketMQ 5 并发编程核心概念辨析 C#事务处理最佳实践:别再让“主表存了、明细丢了”的破事发生 CLI 是什么?为什么大厂突然集体卷命令行? 【从0到1构建一个ClaudeAgent】协作-自主Agent UIImageView 设置图片不生效的原因排查 最小二乘问题详解20:无先验约束下的增量式SFM自由网平差 痞子衡嵌入式:大话双核i.MXRT1180之XIP应用里借助MU实现可靠Flash IAP的方法 AI Chat 封装, SemanticKerne.AiProvider.Unified 已发布 Windows下右键编辑js文件无法打开记事本——在注册表中使用环境变量 在后台服务中使用 Scoped 服务,为什么总是报错? H200 安装驱动并使用sglang启动模型 wireshark 抓包Trap上报告警内容 我用 AI 辅助开发了一系列小工具(2):图片压缩工具 [A Primer On MC and CC] 2.1 Memory Consistency 1 - 指令重排序和 SC 模型 Oracle数据库SCN推进技术详解与实践指南 玩转控件:封装个带图片的Label控件 Claude Code 4.7 真正该升级的不是模型,而是你的工作流 前端小白一句话,AI 帮我做了个颜值拉满的桌面媒体播放器。当代码不再是门槛,一句话编程就是现实。 5. WorkBuddy: 小龙虾的灵魂三件套,让你的小龙虾不只是工具 SQLite 分片方案实战:三种分片策略的深度对比 告别简陋 UI!一款基于 Fluent Design 和基于 WinUI 的开源免费、现代化的 Avalonia UI 控件库 关于二进制排列组合枚举的总结 AI开发-python-LangGraph框架(3-27-LangGraph从零实现大模型智能决策工作流) ElasticSearch主分片和副本分片概念详解 【002】HTTPS 粗解:证书、TLS 握手与对后端配置的影响 Hermes Agent 一周暴涨五万 Star,但我劝你别急着追 明明连接的是Redis的DB0,为什么能查到DB3的数据? 【从0到1构建一个ClaudeAgent】协作-Agent团队 熟悉电子元器件之后,电子小白下一步该怎么走? MAF快速入门(23)通过C#类定义Skills .NET 高级开发 | 手写一个对象映射框架 FastAPI数据库ORM怎么选?我肝了三个Demo后,终于不再纠结了 mysqldump 参数拾遗:在遗忘与铭记之间 C# .NET 周刊|2026年3月5期 Claude code入门 - 陈彦斌 一文学习入门 ThingsBoard 开源物联网平台 GitHub 热门项目 | 2026年04月16日 如何为GIT设置全局勾子,为每次提交追加信息 Number.isFinite和isFinite与isNaN()和Number.isNaN的区别 PortSwigger SQL注入LAB2 推荐一个测试人必备的Skills,从功能到性能全搞定(附详细实操和安装下载方式) 筑基期:掌握Odoo基础核心知识点02(Odoo XML 开发方式详解) GLM模型这么火,咱们用vllm也咧一个呗! 深入理解 AbortController:从底层原理到跨语言设计哲学 字符串学习笔记 多租户系统框架的基础模块设计和分析设计 Apache SeaTunnel Zeta 为什么能做到“又快又稳”? AI开发-python-LangGraph框架(3-26-LangGraph基本概念及第一个简单样例) Vue 3 组件通信,别只会用 Props 和 Emits 了,这几个狠活儿你得看看 ElasticSearch7.X版本配置密码 用Manim实现动态交点计算--从一个动点问题说起 团结引擎+Addressable+Instant Game打包抖音小游戏 function call 实战:让 LLM 自动判断 pod 异常、调用日志工具并完成故障分析 bubseek —— 让 Agent 的足迹,变成团队的洞察 通过 C# 读取并导出 PDF 书签 如何用 GitHub Actions 实现 Steam 自动化发布 【从0到1构建一个ClaudeAgent】并发-后台任务 .NET 高级开发 | 定制 ASP.NET Core 框架 电子小白:什么是运算放大器(运放) zero2Agent:面向大厂面试的 Agent 工程教程,从概念到生产的完整学习路线 堆上的ORW HC32F460 USB CDC通信异常:非对齐访问异常排查 20260413-Hyperbridge 攻击事件:发生在默克尔山上的验证绕过 那些喊着AI 要淘汰你的人,正在靠你的焦虑赚大钱! 深度学习进阶(八)Swin Transformer 最小二乘问题详解19:带先验约束的增量式SFM优化与实现 SnapTranslate 3.0 正式发布:全局划词翻译 + 完整英语学习闭环,一站式搞定查词、记词、复习 工作的意义、工作的困难认知再思考 .NET + AI 进阶实战:基于类的技能开发 - 打造可治理的 Agent 能力模块 【从0到1构建一个ClaudeAgent】规划与协调-技能 上周热点回顾(4.6-4.12) 电子小白的工具三件套:面包板、杜邦线、万能板 单表五亿数据的查询优化 | Mysql、StarRocks 2. WorkBuddy:从“我是谁”到“帮我干活” C# 如何减少代码运行时间:7 个实战技巧 基于HelixToolkit.SharpDX 渲染3D模型 - 笺上知微 从零开始的双臂具身VLA起源及现阶段发展综述 - SkyXZ 记对 xonsh shell 的使用, 脚本编写, 迁移及调优 - pluvium27 受够了Vibe Coding的失控?换个起点,让AI事半功倍 从开始配置漏洞环境到漏洞复现流程 - 難しい 关于10年工作经验的程序员对OpenClaw的实战经验分享以及看法 - 虚无境 Any metadata 的内存布局 C# .NET 周刊|2026年3月2期 - InCerry 我帮你测过了,测试圈排名第二的 Skill 依然很牛逼 Skill Discovery | 无监督技能发现的经典工作总结 - MoonOut 上下文工程是什么?过时了么?一文讲明白! - 一枫说码 开了 TUN 模式还是直连?90% 的人都踩过这个坑 AScript扩展多种脚本语言 - rockey627 AI 学习笔记:Agent 的记忆机制 你能被装进一个文件里吗?——7 万人把同事"蒸馏"成了 AI - 我没有三颗心脏 Claude Code 通关手册(七):给 AI 装上技能包——Skills 完全指南 - 暮色之狐 在浏览器中快速编辑代码:VSCode Web 集成实践 - Newbe36524 蒸馏自己 skill?基于 Deepseek 的蒸馏器,丐版蒸馏方式,简单便捷 - To_Carpe_Diem Spring AI Aliababa和AgentScope,哪个更好? - 苏三说技术
Java 流程编排新范式 Solon Flow:一个引擎,七种节点,覆盖规则/任务/工作流/AI 编排全场景
带刺的坐椅 · 2026-05-17 · via 博客园_首页

当业务复杂度爆炸,你的代码还能撑多久?

做过复杂业务的 Java 开发者,大概都经历过这样的噩梦:一个订单处理方法,从最初的 50 行,经过三轮需求迭代,膨胀到 500 行。里面嵌套着六层 if-else,夹杂着硬编码的分支逻辑,改一处怕崩一片。新人来了看不懂,老人走了不敢改。更糟糕的是,产品经理隔三差五就跑过来说:"这个审批流程要加一个总监审批环节"、"满减规则从三档改成五档"、"大客户走特殊通道"……每一次变更都是一次代码外科手术。

流程编排就是为解决这个问题而生的。把散落在代码各处的业务逻辑,抽象为一个个独立的"节点",然后用声明式的方式定义它们的执行顺序和分支条件。这样既解耦了代码,又让业务规则一目了然,更重要的是——规则的变更不再需要修改 Java 代码、走完整的发版流程。

今天要介绍的是——Solon Flow。它不仅覆盖了 “规则编排” 和 “任务流水线”,还原生支持 “AI Agent 编排”,而且不绑定任何特定框架,Spring Boot 项目一样能用。

一、Solon Flow 是什么?

Solon Flow 是基于 Solon 框架 构建的通用流程编排引擎,采用"偏平式编排"设计,所有节点平铺在同一个层级,通过 link(连接线)描述节点之间的流转关系。它不依赖树形嵌套、不依赖 EL 表达式,而是用最直觉的图结构来表达业务流程。

设计理念

1. 偏平式编排

Solon Flow 把所有节点平铺,用 link 的 when 条件控制流向。这种风格更接近流程图的直觉表达,也更容易被非开发角色理解。

# 偏平式编排:节点平铺,link 描述连接关系
id: order_flow
layout:
  - id: start
    type: start
    link: check_order
  - id: check_order
    type: activity
    task: @checkOrderTask
    link:
      - nextId: vip_route
        when: "amount >= 1000"
      - nextId: normal_route
  - id: ...

2. 元数据无限扩展

每个节点都可以附加任意 meta 属性。这意味着你可以在不修改引擎代码的前提下,为节点注入角色信息、表单定义、超时策略、重试次数等业务元数据,实现高度的定制化。比如审批流中,你可以在 meta 里定义每个审批节点对应的角色(role: tl)和表单(form: approval_form),运行时由驱动器读取并执行对应的权限检查。这种设计让 YAML 文件不仅是执行编排的定义,同时也是一份业务级的"配置文档"。

3. 驱动可定制

Solon Flow 引入了类似 JDBC 驱动的机制——引擎本身只定义执行骨架,具体的任务调度、条件评估等行为通过 driver(驱动器)接口注入。这意味着同一套编排定义,换一个驱动器就能变成不同的执行范式。默认驱动器使用 Solon 的 IoC 容器来解析 TaskComponent,但你完全可以提供一个纯 Spring 驱动器,让它通过 Spring 的 ApplicationContext 来获取 Bean。这种可插拔的驱动设计,是 Solon Flow 实现"框架无关"的关键技术基础。

4. 可中断可恢复

这是 Solon Flow 最独特的能力之一。通过 context.stop() 中断流程,用 context.toJson() 将执行快照序列化持久化,之后通过 FlowContext.fromJson() 恢复上下文,引擎会自动从中断节点继续执行。注意——不是从起点重新执行,而是精确地从上次中断的节点继续。这个能力对审批流、长流程、AI Agent 的持久化至关重要。你可以把快照存到数据库、Redis、甚至消息队列中,根据业务需要灵活选择持久化策略。

二、七种节点类型全解析

Solon Flow 定义了 7 种节点类型,覆盖了流程编排中最常见的执行模式。

节点类型 标识 说明 典型场景
开始节点 start 图的唯一入口,无任务执行 流程起点
活动节点 activity 执行具体业务逻辑的默认节点 计算任务、服务调用
包容网关 inclusive 多选分支,满足条件的都执行,汇聚时等待所有已激活分支 多条件触发
排它网关 exclusive 单选分支,按优先级选择唯一一条路径 条件路由
并行网关 parallel 全选分支,所有连接都执行,汇聚时等待全部完成 并行计算
循环网关 loop 遍历集合(或区间),每个元素执行一次子流程 批量处理
结束节点 end 图的终点 流程结束

下面逐个看 YAML 配置示例。

start — 开始节点

- id: s1
  type: start
  title: 流程开始
  link: n1

start 节点是图的唯一入口,不执行任务,只负责触发后续节点。每个图有且只有一个 start 节点。从 v3.8.4 开始,start 节点支持自由流出连接(与 activity 类似),可以连接多个下游节点。

activity — 活动节点(默认)

- id: n1
  type: activity
  title: 数据校验
  task: @validateTask
  meta:
    role: admin
  link: n2

activity 是最常用的节点类型,执行具体的业务逻辑(通过 task 绑定 TaskComponent),还可以通过 meta 携带任意扩展数据。

exclusive — 排它网关(单选)

- id: g1
  type: exclusive
  title: 金额分级
  link:
    - nextId: n2
      title: "3天以下"
    - nextId: n3
      title: "3天以上"
      when: "day >= 3"

排它网关按连接声明的优先级依次评估 when 条件,选择第一个满足条件的路径执行。没有 when 条件的连接视为默认路由(兜底)。

inclusive — 包容网关(多选)

- id: g1
  type: inclusive
  title: 权益发放
  link:
    - nextId: coupon_task
      when: "orderAmount >= 100"
    - nextId: point_task
      when: "orderAmount >= 50"
    - nextId: gift_task
      when: "orderAmount >= 500"

包容网关会评估所有流出连接的条件,所有满足条件的分支都会执行,汇聚时等待所有已激活的分支完成。类似于"多选多"。

parallel — 并行网关(全选)

- id: p1
  type: parallel #流出
  title: 并行查询
  link:
    - nextId: query_user
    - nextId: query_order
    - nextId: query_inventory

# ... 三个任务各自完成后汇聚到 p2
- id: p2
  type: parallel #流入,网关汇聚
  title: 汇聚结果
  link: merge_result

并行网关的流出连接全部执行(多线程并行,或单线程执行),汇聚端等待所有流入连接到齐后才继续。适合同时调用多个独立服务的场景。

loop — 循环网关(遍历)

- id: loop1
  type: loop #流出
  title: 遍历订单项
  meta:
    $for: "order"  # 指定要遍历接收变量名
    $in: "orderList"  # 指定要遍历的集合变量名
  link: process_item

- id: process_item
  type: activity
  task: @processItemTask
  
- type: loop  #流入,网关汇聚

循环网关会对集合中的每个元素执行一次子流程,通过 $for$in 元数据指定遍历的集合变量名。

end — 结束节点

- id: e1
  type: end
  title: 流程结束

end 节点标记流程的终点。一个图可以有多个 end 节点(对应不同的结束路径),但每个 end 节点不能有流出连接。流程执行到 end 节点时,引擎会记录完成状态,context.lastRecord().isEnd() 返回 true

三、五大实战场景

掌握了七种节点类型后,我们来看五个典型的实战场景,从简单到复杂逐步深入。

场景 A:业务规则引擎 — 订单金额分级积分计算

先看一个经典的需求:根据订单金额计算积分,规则经常变化,不想每次改代码重新发版。

传统 if-else 写法:

public int calculatePoints(Order order) {
    if (order.getAmount() >= 10000) {
        return (int)(order.getAmount() * 0.15);
    } else if (order.getAmount() >= 5000) {
        return (int)(order.getAmount() * 0.10);
    } else if (order.getAmount() >= 1000) {
        return (int)(order.getAmount() * 0.05);
    } else {
        return (int)(order.getAmount() * 0.01);
    }
}

每次规则变化都要改代码、测试、发版。现在用 Solon Flow 改造。

YAML 编排定义:

id: points_calc
nodes:
  - id: start
    type: start
    link: g1

  - id: g1
    type: exclusive
    title: 积分分级
    link:
      - nextId: diamond
        when: "amount >= 10000"
      - nextId: gold
        when: "amount >= 5000"
      - nextId: silver
        when: "amount >= 1000"
      - nextId: normal

  - id: diamond
    type: activity
    title: 钻石级积分
    meta:
      rate: "0.15"
    task: @ratePointsTask
    link: end

  - id: gold
    type: activity
    title: 黄金级积分
    meta:
      rate: "0.10"
    task: @ratePointsTask
    link: end

  - id: silver
    type: activity
    title: 白银级积分
    meta:
      rate: "0.05"
    task: @ratePointsTask
    link: end

  - id: normal
    type: activity
    title: 普通积分
    meta:
      rate: "0.01"
    task: @ratePointsTask
    link: end

  - id: end
    type: end

Java 调用代码:

// 引擎初始化(一行代码搞定)
FlowEngine engine = FlowEngine.newInstance();
Graph graph = Graph.fromUri("points_calc.yml");

// 执行
FlowContext context = FlowContext.of();
context.put("amount", 6800);
engine.eval(graph, context);

int points = context.getAs("points");

核心 API 就三个:FlowEngine.newInstance() 创建引擎、Graph.fromUri() 加载编排定义、engine.eval() 执行。学习成本极低,五分钟上手。

TaskComponent 实现(所有分级共用一个):

@Component("ratePointsTask")
public class RatePointsTask implements TaskComponent {
    @Override
    public void run(FlowContext ctx, Node node) throws Throwable {
        double amount = ctx.getAs("amount");
        double rate = Double.parseDouble(node.getMeta("rate"));
        ctx.put("points", (int)(amount * rate));
    }
}

注意看:四个分级节点共享同一个 ratePointsTask,通过 node.getMeta("rate") 读取 YAML 中定义的 rate 元数据。这意味着新增一个分级只需要在 YAML 中加一个节点和对应的 rate 值,Java 代码完全不用动

优势对比: 传统 if-else 方式,新增分级要改 Java 代码、走测试流程、发版上线;Solon Flow 方式只需修改 YAML 文件中的阈值和费率,运维同学甚至可以在线上直接修改配置。当规则从四档变成六档、十档时,收益会更加明显。

场景 B:任务编排 — 数据抓取流水线

一个典型的 ETL 场景:抓取数据 → 清洗 → 存储 → 通知。每个环节都是独立的组件,用 activity 节点串联。

YAML 定义:

id: etl_pipeline
nodes:
  - id: start
    type: start
    link:  fetch

  - id: fetch
    type: activity
    title: "数据抓取"
    task: @fetchDataTask
    link: clean

  - id: clean
    type: activity
    title: "数据清洗"
    task: @cleanDataTask
    link: store

  - id: store
    type: activity
    title: "数据存储"
    task: @storeDataTask
    link: notify

  - id: notify
    type: activity
    title: "完成通知"
    task: @notifyTask
    link: end

  - id: end
    type: end

TaskComponent 实现:

@Component("fetchDataTask")
public class FetchDataTask implements TaskComponent {
    @Override
    public void run(FlowContext ctx, Node node) throws Throwable {
        // 调用外部 API 抓取数据
        List<RawData> data = apiClient.fetch(ctx.getAs("source"));
        ctx.put("rawData", data);
    }
}

@Component("cleanDataTask")
public class CleanDataTask implements TaskComponent {
    @Override
    public void run(FlowContext ctx, Node node) throws Throwable {
        List<RawData> raw = ctx.getAs("rawData");
        List<CleanData> cleaned = raw.stream()
            .filter(d -> d.isValid())
            .map(this::transform)
            .collect(Collectors.toList());
        ctx.put("cleanData", cleaned);
    }
}

流水线的每一步都是一个独立的 TaskComponent,通过 FlowContext 传递数据。这种设计带来了几个好处:

  1. 每个 TaskComponent 可以独立测试——不依赖 FlowEngine,直接构造 FlowContext 传入即可单元测试
  2. 组件复用——同一个 TaskComponent 可以在不同的图中被引用
  3. 插入/删除步骤零侵入——如果需要在"清洗"和"存储"之间插入一个"去重"步骤,只需要在 YAML 里加一个节点和一条 link,Java 代码完全不需要改动
  4. 执行顺序可视化——YAML 文件本身就是一份可读的流程文档,产品经理和测试同学都能看懂

场景 C:并行计算 — 多任务并行执行

当流水线中存在多个互不依赖的任务时,可以用 parallel 网关让它们并行执行,显著缩短总耗时。

YAML 定义:

id: parallel_query
nodes:
  - id: start
    type: start
    link: fork

  - id: fork
    type: parallel
    title: "并行查询"
    link:
      - nextId: query_user
      - nextId: query_order
      - nextId: query_risk

  - id: query_user
    type: activity
    title: "查询用户信息"
    task: @queryUserTask
    link: join

  - id: query_order
    type: activity
    title: "查询订单信息"
    task: @queryOrderTask
    link: join

  - id: query_risk
    type: activity
    title: "风控评估"
    task: @queryRiskTask
    link: join

  - id: join
    type: parallel
    title: "汇聚结果"
    link: aggregate

  - id: aggregate
    type: activity
    title: "汇总决策"
    task: @aggregateTask
    link: end

  - id: end
    type: end

三个查询任务并行执行,join 节点(parallel 类型)会等待三个分支全部完成后,再流转到 aggregate 节点进行汇总。原来串行 3 秒的任务(1s + 0.8s + 1.2s),并行后总耗时取决于最慢的那个分支,可能只需 1.2 秒。

使用 parallel 网关需要注意几个要点:

  • parallel 网关必须成对使用——一个 fork(分叉)、一个 join(汇聚)
  • join 端会等待所有流入连接到齐,任何一个分支异常都会导致汇聚失败
  • 并行执行的线程策略由 driver 决定,默认使用线程池并行执行
  • 各分支之间通过各自的 FlowContext 隔离,互不干扰

场景 D:可中断与恢复的审批流

审批流是流程编排的经典场景。一个订单需要经过主管和总监两级审批,但审批人不是实时在线的,流程需要在中途"暂停",等审批完成后再"继续"。

YAML 定义:

id: order_approval
nodes:
  - id: start
    type: start
    link: submit

  - id: submit
    type: activity
    title: 提交订单
    task: @submitTask
    link: tl_review

  - id: tl_review
    type: activity
    title: 主管审批
    task: @tlReviewTask
    link: vp_review

  - id: vp_review
    type: activity
    title: 总监审批
    task: @vpReviewTask
    link: end

  - id: end
    type: end

审批 Task 的中断逻辑:

@Component("tlReviewTask")
public class TlReviewTask implements TaskComponent {
    @Override
    public void run(FlowContext ctx, Node node) throws Throwable {
        ApprovalState state = ctx.getAs("approvalState");

        if (!state.isTlApproved()) {
            // 主管尚未审批,中断流程
            System.out.println("等待主管审批...");
            ctx.stop();  // 关键:停止执行
        } else {
            System.out.println("主管已通过,流转到总监审批。");
        }
    }
}

中断后的持久化与恢复:

FlowEngine engine = FlowEngine.newInstance();
Graph graph = Graph.fromUri("order_approval.yml");
FlowContext context = FlowContext.of("order-001");

// 第一次执行:提交后主管审批环节被中断
context.put("approvalState", new ApprovalState());
engine.eval(graph, context);

// context.isStopped() == true,流程被暂停了
System.out.println("当前停在节点: " + context.lastNodeId()); // 输出: tl_review

// 持久化到数据库
String snapshot = context.toJson();
approvalRepository.saveSnapshot("order-001", snapshot);

// ---- 几天后,主管完成了审批 ----

// 从数据库恢复
String json = approvalRepository.getSnapshot("order-001");
FlowContext restored = FlowContext.fromJson(json);
restored.put("approvalState", new ApprovalState(true, false)); // 主管已批

// 引擎自动从 tl_review 节点继续执行
engine.eval(graph, restored);

这就是 Solon Flow 的"中断-恢复"机制:stop()toJson() 持久化 → fromJson() 恢复 → eval() 继续。整个过程中,业务数据的完整性由快照保证,引擎自动定位到中断节点。

场景 E:AI 智能体编排

这是 Solon Flow 最差异化的能力,也是其他编排框架几乎没有覆盖的领域。

Solon 的 AI 生态构建在 Flow 之上,提供了三个层次的智能体能力:

插件 智能体模式 说明
solon-ai-flow AiFlow 工作流模式 偏软编排,用 YAML 编排 AI 工作流
solon-ai-agent ReActAgent 自我反省模式 单兵作战,思考+行动循环
solon-ai-agent TeamAgent 团队协作模式 多智能体系统,分工协作

ReActAgent:思考-行动-观察的闭环

ReActAgent 的核心是"思考(Thought)→ 行动(Action)→ 观察(Observation)"的推理循环。它底层就是一个由 Solon Flow 构建的计算图:

Start → [Plan(可选)] → [Reason(决策)] ↔ [Action(执行工具)] → End
// 构建一个技术支持专家
ReActAgent techAgent = ReActAgent.of(chatModel)
    .name("tech_support")
    .role("技术支持专家")
    .instruction("负责处理客户技术问题,可查询数据库和排查日志")
    .defaultToolAdd(dbQueryTool)    // 注入数据库查询工具
    .defaultToolAdd(logSearchTool)  // 注入日志搜索工具
    .maxSteps(12)                   // 最多推理 12 步
    .build();

// 执行任务
AssistantMessage result = techAgent
    .prompt("查询最近1小时订单号为 ORD-20260517-001 的错误日志")
    .call();

TeamAgent:多智能体团队协作

当任务需要多个不同角色的专家协作时,TeamAgent 登场。它本身不执行任务,而是作为"总指挥",通过 TeamProtocol(协作协议)将多个 Agent 编织成协同作战单元。

TeamAgent tripAgent = TeamAgent.of(chatModel)
    .name("trip_manager")
    .role("旅行规划团队")
    .agentAdd(ReActAgent.of(chatModel)
        .name("searcher")
        .role("天气搜索员")
        .instruction("负责提供实时气候数据")
        .defaultToolAdd(weatherTool)
        .build())
    .agentAdd(ReActAgent.of(chatModel)
        .name("planner")
        .role("行程规划师")
        .instruction("根据天气数据规划行程")
        .build())
    .protocol(TeamProtocols.SEQUENTIAL)  // 顺序协作协议
    .build();

// 执行团队任务
AssistantMessage result = tripAgent
    .prompt("帮我规划上海周末行程")
    .call();

AiFlow:工作流智能体(YAML 编排 AI)

如果你更喜欢声明式地编排 AI 工作流,solon-ai-flow 提供了类似 Dify 的工作流模式,但它是纯开发框架而非低代码平台:

<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-ai-flow</artifactId>
</dependency>

AiFlow 内置了多种预置组件:输入组件(接收用户消息)、模型组件(调用 LLM)、RAG 组件(检索增强生成)、输出组件(返回结果)。你可以用 YAML 定义这些组件之间的流转关系,像搭积木一样拼装出复杂的 AI 工作流。而且由于底层就是 Solon Flow,你可以随时用自定义的 TaskComponent 替换或扩展任何预置组件——这是它区别于 Dify 等封闭式低代码平台的核心优势。

关键洞察: Solon Flow 不是为了 AI 而生,但它的图驱动执行模型天然适合 AI Agent 的编排需求。ReActAgent 的推理循环(Reason ↔ Action)、TeamAgent 的多角色协作(路由决策 + 专家分发),底层都是 Solon Flow 的 Graph 在驱动。这意味着——你在 Flow 上积累的编排经验、调试手段和可视化工具,可以无缝复用到 AI 场景。当你的业务系统未来需要引入 AI 能力时,不需要再学习一套全新的编排框架。

另一个值得注意的点:TeamAgent 支持持久化与恢复。你可以将多智能体协作的中间状态序列化为 JSON 快照存入数据库,系统重启后从中断点继续执行。这对于耗时较长的 AI 任务(如多轮分析、大规模报告生成)非常关键。

四、框架无关:六种框架都能用

一个常见的疑虑:"Solon Flow 是不是必须用 Solon 框架?"

答案是不需要。

Solon Flow 可以作为纯 JAR 包引入,不需要 Solon 容器。官方提供了完整的嵌入式示例,覆盖主流 Java 框架:

嵌入框架 示例模块
Spring Boot 2 solon-flow-in-springboot2
Spring Boot 3 solon-flow-in-springboot3
Spring Boot 4 solon-flow-in-springboot4
Spring MVC solon-flow-in-springmvc
jFinal solon-flow-in-jfinal
Vert.X solon-flow-in-vertx
Quarkus solon-flow-in-quarkus
Micronaut solon-flow-in-micronaut

示例仓库地址:

Maven 依赖(就一个 JAR):

<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-flow</artifactId>
    <version>3.10.7</version>
</dependency>

在 Spring Boot 项目中,只需要引入这个依赖,然后通过 Java API 方式使用 FlowEngine,不需要任何 Solon 相关的配置。核心 API 非常简洁:

// 1. 创建引擎
FlowEngine engine = FlowEngine.newInstance();

// 2. 从 classpath 加载 YAML
Graph graph = Graph.fromUri("my_flow.yml");

// 3. 构建上下文并执行
FlowContext context = FlowContext.of();
context.put("key", "value");
engine.eval(graph, context);

// 4. 读取结果
Object result = context.getAs("result");

这就是全部的 API 了。没有 XML 配置,没有 Spring Boot Starter 要引入,没有自动装配要理解。FlowEngine 是无状态的,线程安全,可以全局复用一个实例。Graph 加载后也是不可变的,可以缓存。只有 FlowContext 是每次执行需要新建的。