Status: Alpha。当前仍处于
0.x阶段,公开 API 与 SPI 已经划出边界,但仍在继续收敛。首次正式发布前,不提供旧 alpha 快照的兼容层、弃用桥接或 schema 兼容桥接;生产接入前请锁定精确版本并自行完成升级验证。
Publishing: 当前仓库尚未发布到任何 Maven 仓库,包括 Maven Central、GitHub Packages 或其他私有 Maven 仓库。现在请先在仓库根目录执行
./mvnw clean install,再从本地 Maven 缓存引用这些模块;仓库中的 Maven release profile 仅作为未来正式发布时的预留配置。
CharmFlow Agent Runtime 是一个嵌入 Spring Boot 应用的多步骤 Agent 执行框架。它把任务建模为显式的 step DAG,由本地 AgentEngine 驱动执行、恢复、查询、导出和观测,而不是把业务流程退化成单轮聊天。
TaskResult已切换到稳定读取面:finalResult、stepResults、businessArtifacts、systemArtifacts、exports。- 内置 Markdown / HTML / JSON / PDF exporter 默认不再把
systemArtifacts写进交付文件。 @AgentTask.resultType/resultProjector与execute(..., Class<T>)、getResult(..., Class<T>)组成真正可用的 typed final result。- 调度器既支持静态 fan-out / fan-in,也支持通过
@AgentFanOut/@AgentFanIn显式声明的单层运行时动态展开与汇聚。 - 控制面支持
pause、resume、cancel、任务列表分页、step run 分页。 - 事件体系支持 task / step 生命周期事件、监听器扩展、事件持久化。
- starter 提供基础 metrics、observation、Actuator endpoint 集成。
- JPA 存储使用 Flyway migration 管理 schema,不再依赖运行时 auto-DDL。
- 当前运行边界仍是单进程:结果、step run、artifact、event 可以持久化,但不保证进程重启后自动恢复在途异步任务或未完成的 pause / resume / cancel 控制流程。
- 仓库内包含 benchmark 资产、性能容量建议、API 稳定性边界和 semver / deprecation 说明。
- 开源版支持边界、安全基线、自定义存储 SPI 示例和依赖扫描流程均已单独留档,便于发布前审阅。
charmflow-agent-core注解、模型、执行引擎、artifact schema/codec、导出器、事件与核心 SPI;不再承载 Spring Boot 包扫描假设。charmflow-agent-spring-boot-starterSpring Boot 自动装配、@AgentTask类路径扫描、默认AgentEngine、事件发布器、metrics / observation / Actuator 接线。charmflow-agent-storage-memory默认内存存储实现,适合本地开发和测试。charmflow-agent-storage-jpaJPA 持久化实现,当前仓库内提供 H2 与 MySQL 的 Flyway migration,并通过JpaStorageDialectSPI 按数据库 vendor 选择脚本。模块本身不绑定具体 JDBC 驱动,数据库驱动与 Flyway 的数据库扩展由使用方主项目按需引入。charmflow-agent-benchmarks基于 JMH 的 benchmark 模块,用于比较顺序 baseline 与静态并行 DAG。
./mvnw clean install最小组合是 starter 加一个存储实现。
<dependency>
<groupId>com.charmflow.agent</groupId>
<artifactId>charmflow-agent-spring-boot-starter</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>com.charmflow.agent</groupId>
<artifactId>charmflow-agent-storage-memory</artifactId>
<version>0.1.0</version>
</dependency>如果需要持久化存储,改为:
<dependency>
<groupId>com.charmflow.agent</groupId>
<artifactId>charmflow-agent-storage-jpa</artifactId>
<version>0.1.0</version>
</dependency>如果你的业务应用使用 MySQL,还需要在业务应用里额外引入数据库驱动和 Flyway 的 MySQL 扩展:
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-mysql</artifactId>
<scope>runtime</scope>
</dependency>storage-jpa 的数据库接入边界:
- 内置仅提供
h2与mysql两个JpaStorageDialect。 - 方言解析顺序是:
agent.storage.jpa.dialect显式指定优先;否则根据spring.flyway.url/spring.datasource.url与驱动自动识别。 - 如果既没有命中内置或第三方方言,也没有显式配置
spring.flyway.locations,应用会在启动期直接失败,而不是默默加载错误脚本。 - 如果你要接 PostgreSQL、Oracle 等其他数据库,请在业务应用或独立扩展模块里同时提供 JDBC 驱动、对应 Flyway 数据库扩展,以及一个注册为 Spring Bean 的
JpaStorageDialect实现。
更完整说明见 docs/jpa-storage-dialect-and-driver-boundary.md。
import com.charmflow.agent.annotation.EnableAgentPlatform;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableAgentPlatform
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}agent:
enabled: true
storage:
type: IN_MEMORY # IN_MEMORY | JPA
export:
base-dir: ./agent-output选择 JPA 存储时,schema 由 Flyway migration 管理;默认示例使用 H2,切换到 MySQL 时需要额外引入数据库驱动和 Flyway MySQL 扩展(见上方依赖说明)。通常不需要手工设置 spring.jpa.database-platform,让 Hibernate 根据 JDBC 连接自动识别即可。
线程池、Actuator endpoint 和 exporter 的详细配置见 docs/execution-pool-configuration.md。
import com.charmflow.agent.annotation.AgentStep;
import com.charmflow.agent.annotation.AgentTask;
import com.charmflow.agent.model.ExportType;
@AgentTask(
code = "release-guide-task",
name = "Release Guide Task",
exportTypes = {ExportType.MARKDOWN},
inputType = ReleaseGuideInput.class,
resultType = ReleaseGuide.class,
resultProjector = ReleaseGuideProjector.class
)
public class ReleaseGuideTask {
@AgentStep(code = "prepare", executor = PrepareExecutor.class, outputType = PreparedBrief.class)
public void prepare() {
}
@AgentStep(code = "outline", dependsOn = {"prepare"}, executor = OutlineExecutor.class, outputType = OutlineSection.class)
public void outline() {
}
@AgentStep(code = "checklist", dependsOn = {"prepare"}, executor = ChecklistExecutor.class, outputType = ChecklistSection.class)
public void checklist() {
}
@AgentStep(code = "compose", dependsOn = {"outline", "checklist"}, executor = ComposeExecutor.class, outputType = String.class)
public void compose() {
}
}上面的任务图就是一个固定 fan-out / fan-in:
┌─── outline ───┐
prepare ──┤ ├── compose
└─── checklist ──┘
如果需要运行时动态展开,可以显式使用 @AgentFanOut / @AgentFanIn:
import com.charmflow.agent.annotation.AgentFanIn;
import com.charmflow.agent.annotation.AgentFanOut;
@AgentTask(code = "batch-release-task", name = "Batch Release Task", inputType = BatchReleaseInput.class)
public class BatchReleaseTask {
@AgentStep(code = "prepare", executor = PrepareBatchExecutor.class, outputType = java.util.List.class)
public void prepare() {
}
@AgentFanOut(
code = "write-item",
dependsOn = {"prepare"},
itemsFrom = "prepare",
itemType = ReleaseSectionBrief.class,
executor = WriteSectionExecutor.class,
outputType = ReleaseSection.class
)
public void writeItem() {
}
@AgentFanIn(
code = "compose",
dependsOn = {"write-item"},
gathers = "write-item",
executor = ComposeBatchExecutor.class,
outputType = String.class
)
public void compose() {
}
}import com.charmflow.agent.model.ExportType;
import com.charmflow.agent.model.PageRequest;
import com.charmflow.agent.model.TaskQuery;
import com.charmflow.agent.model.TaskResult;
import com.charmflow.agent.model.TaskSummary;
import com.charmflow.agent.spi.AgentEngine;
ReleaseGuide typed = agentEngine.execute("release-guide-task", input, ReleaseGuide.class);
TaskResult taskResult = agentEngine.execute("release-guide-task", input);
TaskResult sameTask = agentEngine.getResult(taskResult.taskId());
ReleaseGuide typedAgain = agentEngine.getResult(taskResult.taskId(), ReleaseGuide.class);
agentEngine.pause(taskResult.taskId());
agentEngine.resume(taskResult.taskId());
agentEngine.cancel(taskResult.taskId());
var tasks = agentEngine.listTasks(new TaskQuery(java.util.List.of(), java.util.List.of()), new PageRequest(0, 20));
TaskSummary first = tasks.items().isEmpty() ? null : tasks.items().get(0);
String markdownPath = agentEngine.export(taskResult.taskId(), ExportType.MARKDOWN);- 运行时支持静态 DAG,也支持显式
@AgentFanOut/@AgentFanIn的单层动态 fan-out / fan-in。 - 当前仍不支持多层嵌套动态 fan-out / fan-in,或运行时生成任意子图。
- step 间 typed 数据交换通过
StepExecutionResult+outputType+StepArtifacts完成,不再依赖裸Map<String, Object>总线。 - fan-in step 可通过
StepArtifacts.requireAll(stepCode, type)读取某个 fan-out 逻辑 step 的全部实例输出。 - fan-out 分支返回的
BUSINESSartifact 会自动保存为artifactKey:<stepInstanceId>,避免多个分支写同一个业务 key 时互相覆盖。 TaskResult是任务级稳定读取模型,typed final result 是它的上层投影能力。- 内置 exporter 默认不把
systemArtifacts当成稳定交付内容;如果需要内部运行面数据,应通过TaskResult程序化读取。 - 控制面状态来自结构化 task / step run 视图;动态 fan-out 时,
StepRunView会带stepInstanceId与fanOutIndex。 - 事件是第一叙事通道;trace artifact 只作为可选调试或导出材料。
- starter 通过 listener 方式接入 metrics / observation,不把观测逻辑硬编码进 engine。
- 更完整的当前 runtime 合同与已知限制见 docs/runtime-contract-and-known-limitations.md。
- 适合嵌入 Spring Boot 应用、单进程或受控实例内部运行的多步骤任务编排。
- 适合需要结构化 task / step 状态、事件、导出和本地
AgentEngine接入的场景。 - 当前不适合作为要求“进程重启自动恢复在途任务”或“多实例共享统一控制面状态”的平台型运行时。
更明确的开源版支持边界见 docs/open-source-support-boundary.md。
- examples/minimal-memory-demo 最小内存示例,演示 typed result、静态 fan-out / fan-in 和 Markdown 导出。
- examples/jpa-h2-demo
面向 H2 的 JPA 持久化示例,开箱即跑,演示 Flyway、失败后
retryStep(...)、typed result 和 JSON 导出。 - examples/jpa-mysql-demo 面向 MySQL 的 JPA 持久化示例,直接使用 MySQL 配置与运行时依赖,不再通过 profile 切换数据库。
- examples/dynamic-memory-demo
动态 fan-out / fan-in 示例,演示显式
@AgentFanOut/@AgentFanIn、typed result 和 Markdown 导出。
直接运行:
./mvnw clean install -DskipTests
./mvnw -f examples/minimal-memory-demo/pom.xml spring-boot:run
./mvnw -f examples/jpa-h2-demo/pom.xml spring-boot:run
CHARMFLOW_DB_URL='jdbc:mysql://localhost:3306/charmflow_agent?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC' \
CHARMFLOW_DB_USERNAME='root' \
CHARMFLOW_DB_PASSWORD='root' \
./mvnw -f examples/jpa-mysql-demo/pom.xml spring-boot:run
./mvnw -f examples/dynamic-memory-demo/pom.xml spring-boot:run./mvnw -q test./mvnw -pl charmflow-agent-benchmarks -am -DskipTests package./mvnw -B -Prelease -DskipTests -Dgpg.skip=true -Dcentral.skipPublishing=true verify./mvnw -B dependency-check:aggregate- 贡献指南(中文):CONTRIBUTING.md
- Contributing Guide (English): CONTRIBUTING.en.md
- 安全策略(中文):SECURITY.md
- Security Policy (English): SECURITY.en.md
- 行为准则(中文):CODE_OF_CONDUCT.md
- Code Of Conduct (English): CODE_OF_CONDUCT.en.md
- 中文入口:docs/README.md
- 英文 README:README.en.md
- 英文文档入口:docs/en/README.md
- Runtime 合同与限制:docs/runtime-contract-and-known-limitations.md
- API 稳定性边界:docs/api-stability-boundaries.md
- SemVer / deprecation policy:docs/semver-and-deprecation.md
- 开源版支持边界:docs/open-source-support-boundary.md
- 安全基线:docs/security-baseline.md
- 自定义存储 SPI 示例:docs/custom-storage-spi-minimal-example.md
- 依赖扫描流程与留档原则:docs/dependency-scan.md
- 性能与容量建议:docs/performance-and-capacity.md
- 执行线程池配置:docs/execution-pool-configuration.md