文章目录
- [1. 概述](#1. 概述)
- [2. 成员变量(配置项)](#2. 成员变量(配置项))
-
- [2.1 SaverConfig](#2.1 SaverConfig)
- [2.2 Store](#2.2 Store)
- [2.3 ObservationRegistry](#2.3 ObservationRegistry)
- [2.4 GraphLifecycleListener](#2.4 GraphLifecycleListener)
- [2.5 recursionLimit](#2.5 recursionLimit)
- [2.6 releaseThread](#2.6 releaseThread)
- [2.7 interruptBeforeEdge](#2.7 interruptBeforeEdge)
- [2.8 interruptsBefore](#2.8 interruptsBefore)
- [2.9 interruptsAfter](#2.9 interruptsAfter)
- [3. Getter 方法](#3. Getter 方法)
- [4. Builder 构建器](#4. Builder 构建器)
- [5. ReactAgent 的编译配置](#5. ReactAgent 的编译配置)
1. 概述
CompileConfig 编译配置类,用于定义 StateGraph 编译时的核心配置与行为,包含检查点持久化、流程中断、生命周期监听、递归限制、线程管理、观测追踪等配置。
配置示例:
java
CompileConfig compileConfig = CompileConfig.builder()
// 1. 防死循环:最大循环50次
.recursionLimit(50)
// 2. 人工审核节点前中断
.interruptBefore("human_review")
// 3. LLM草稿生成后中断查看
.interruptAfter("draft_response")
// 4. 路由分支前可人工干预
.interruptBeforeEdge(true)
// 5. 挂起时释放线程
.releaseThread(true)
// 6. 内存检查点持久化
.saverConfig(SaverConfig.builder()
.register(MemorySaver.builder().build())
.build())
// 7. 生命周期日志监听
.withLifecycleListener(new GraphLifecycleListener() {
@Override
public void onNodeStart(String nodeId, OverAllState state) {
System.out.println("进入节点:" + nodeId);
}
})
.build();
StateGraph 只负责工作流的定义,需要编译为 CompiledGraph 才能运行,在编译方法中支持两种方式:
- 使用【默认配置】编译
- 使用【指定的配置】编译
源码如下:
java
public CompiledGraph compile(CompileConfig config) throws GraphStateException {
// 校验编译配置不能为空,为空则直接抛出空指针异常
Objects.requireNonNull(config, "config cannot be null");
// 执行【全局图结构校验】:校验所有节点、边、入口点的合法性
validateGraph();
// 基于当前状态图和编译配置,创建并返回最终的编译后图形
return new CompiledGraph(this, config);
}
/**
* 使用【默认配置】编译状态图(内置内存持久化策略)
* 默认配置会自动注册内存存储器,适用于无需持久化的临时/内存运行场景
* @return 编译完成的可执行图形实例
* @throws GraphStateException 图结构非法时抛出异常
*/
public CompiledGraph compile() throws GraphStateException {
// 构建内存持久化配置:注册 MemorySaver(内存存储,数据仅保存在运行内存中)
SaverConfig saverConfig = SaverConfig.builder()
.register(new MemorySaver())
.build();
// 构建默认编译配置(仅配置内存持久化),并调用带参编译方法完成编译
return compile(CompileConfig.builder().saverConfig(saverConfig).build());
}
2. 成员变量(配置项)
总览:
| 类 / 接口 / 属性 | 层级 | 核心作用 |
|---|---|---|
| GraphLifecycleListener | AI 图业务层 | 监听节点执行生命周期(业务事件) |
| SaverConfig | 状态配置层 | 管理检查点保存器(临时状态) |
| Store | 数据存储层 | 长期记忆持久化 |
| ObservationRegistry | 系统监控层 | 应用性能 / 链路监控(系统级) |
| recursionLimit | 流程控制层 | 限制工作流最大循环执行次数,防止节点死循环无限递归 |
| releaseThread | 线程调度层 | 控制图执行完成后是否释放/清理该执行线程的所有 checkpoint 资源 |
| interruptBeforeEdge | 流程控制层 | 节点执行完毕、路由分支前暂停工作流,支持人工干预路由走向 |
| interruptsBefore | 流程控制层 | 进入指定节点之前暂停工作流,等待人工输入 / 审批 |
| interruptsAfter | 流程控制层 | 指定节点执行完成后暂停工作流,支持人工确认节点输出 |
2.1 SaverConfig
配置状态检查点 存储器,支持内存/Redis/数据库持久化,实现断点续跑、历史回溯。
CompileConfig 中默认会使用内存检查点保存:
java
/**
* 检查点保存配置(默认使用内存保存器)
* 管理工作流状态的持久化、恢复、断点续跑
*/
private SaverConfig saverConfig = new SaverConfig().register(MemorySaver.builder().build());
SaverConfig 是一个检查点保存器配置管理类 ,核心作用是注册、管理多个 BaseCheckpointSaver 实例。
内部维护一个 BaseCheckpointSaver 的集合,统一管理保存器实例:
java
// 私有final列表:引用不可变,但列表内容可修改
private final List<BaseCheckpointSaver> savers = new ArrayList<>();
核心方法:
builder():创建建造者实例,是建造者模式的入口,支持链式调用创建对象。register():向集合中添加保存器get():单个获取方法,0个 → 返回null,1个 → 返回实例,≥2个 → 抛异常;getAll():全部获取方法,直接返回内部列表,存在封装性破坏风险。
代码案例:
java
// 方式1:使用默认内存存储(默认自带)
CompileConfig config1 = CompileConfig.builder()
.saverConfig(SaverConfig.builder()
.register(MemorySaver.builder().build())
.build())
.build();
// 方式2:替换为自定义 RedisSaver / MysqlSaver(分布式持久化)
// CompileConfig config2 = CompileConfig.builder()
// .saverConfig(SaverConfig.builder()
// .register(new RedisSaver(redisTemplate))
// .build())
// .build();
2.2 Store
配置全局长期记忆容器,跨会话、跨工作流共享记忆数据。
CompileConfig 支持配置长期记忆存储:
java
/**
* 长期记忆存储实例
* 用于工作流的持久化数据存储(如状态、历史记录)
*/
private Store store;
上面的 CheckpointSaver 存的是程序运行时的临时状态(用完可删),Store 存的是跨会话的长期数据(永久保存,比如用户配置、历史记忆)。
Store 是长期记忆存储标准接口,专注持久化、跨会话、结构化数据管理,可用实现类:

2.3 ObservationRegistry
配置接入 Micrometer + Sleuth/Prometheus,实现节点耗时、调用链路、指标监控。
CompileConfig 中默认是空实现:
java
private ObservationRegistry observationRegistry = ObservationRegistry.NOOP;
Micrometer 是 Spring Boot 默认集成的监控 / 追踪底层库,而 ObservationRegistry 是 Micrometer 中可观测性体系的核心接口,核心作用是统一管理应用的观测(Observation)生命周期、上下文和配置。
可用实现类:

2.4 GraphLifecycleListener
监听流程开始、节点进入、节点完成、流程结束、异常等全生命周期事件,用于日志、监控、埋点。可用于全流程日志打印、节点耗时统计、异常告警、流程审计。
CompileConfig 中支持配置多个监听器:
java
/**
* 图生命周期监听器队列
* 监听节点执行、流程开始/结束等事件,默认容量25
*/
private Deque<GraphLifecycleListener> lifecycleListeners = new LinkedBlockingDeque<>(25);
GraphLifecycleListener 是工作流的生命周期监听器接口,核心作用是监听图中节点的执行全过程,允许你在节点启动、执行前、执行后、成功完成、报错时插入自定义逻辑(日志、监控、告警、状态追踪等)。
可用实现类:

代码案例:
java
// 自定义生命周期监听器
GraphLifecycleListener listener = new GraphLifecycleListener() {
@Override
public void onNodeStart(String nodeId, OverAllState state) {
System.out.println("开始执行节点:" + nodeId);
}
@Override
public void onNodeEnd(String nodeId, OverAllState state) {
System.out.println("节点执行完成:" + nodeId);
}
@Override
public void onGraphComplete(OverAllState state) {
System.out.println("整个工作流执行结束");
}
};
// 注册到编译配置
CompileConfig compileConfig = CompileConfig.builder()
.withLifecycleListener(listener)
.build();
2.5 recursionLimit
限制工作流最大循环执行次数,防止节点死循环无限递归。
默认最大递归 100 次:
java
private int recursionLimit = 100;
代码案例:
java
// 限制最大循环 50 次,超过直接终止工作流
CompileConfig compileConfig = CompileConfig.builder()
.recursionLimit(50)
.build();
CompiledGraph compiledGraph = workflow.compile(compileConfig);
2.6 releaseThread
控制图执行完成后是否释放/清理该执行线程的所有 checkpoint 资源。
使用建议:
- 保持默认
false:需要Human-in-the-loop中断恢复、Time-travel回放历史状态 - 设置
true:一次性执行的短生命周期工作流,避免资源积累
默认配置为 false :
java
/**
* 线程释放标志
* 用于检查点保存时控制线程释放,避免阻塞
*/
private boolean releaseThread = false;
配置为 true 后,不同 Saver 的 release 实现:
| Saver | 释放方式 | 数据保留 | 并发机制 | 是否可恢复 |
|---|---|---|---|---|
| MemorySaver | 直接删除 Map 条目 | ❌ 完全删除 | ReentrantLock | ❌ 不可恢复 |
| PostgresSaver | UPDATE 设置 is_released = TRUE | ✅ 保留 checkpoint | DB 事务 | ❌ 标记后不可恢复 |
| RedisSaver | Meta 元数据设置 is_released = true | ✅ 保留 checkpoint | Redisson 分布式锁 | ❌ 标记后不可恢复 |
| MongoSaver | findOneAndUpdate 更新 is_released=true | ✅ 保留 checkpoint | MongoDB 事务 | ❌ 标记后不可恢复 |
持久化 Saver(Postgres/Redis/Mongo)选择标记释放而非物理删除的原因:
- 审计追溯 --- 保留执行历史,支持事后分析
- 防止误删 --- 释放是软删除,数据可手动恢复
- 分布式安全 --- 通过锁/事务/原子操作避免并发冲突
- 内存
Saver的差异 ---MemorySaver直接删除是因为数据本身就在内存中,释放后进程重启数据自然消失
代码案例:
java
CompileConfig compileConfig = CompileConfig.builder()
// 流程挂起时释放线程
.releaseThread(true)
.interruptBefore("human_review")
.build();
2.7 interruptBeforeEdge
配置节点执行完毕,还没进入条件分支路由前时是否暂停,可以人工干预路由走向。
默认配置为 false :
java
/**
* 条件边评估前中断标志
* true:节点执行完成后、条件路由前中断
* false:节点执行完成后直接路由
*/
private boolean interruptBeforeEdge = false;
代码案例:
java
// 节点执行完、条件分支跳转前中断
CompileConfig compileConfig = CompileConfig.builder()
.interruptBeforeEdge(true)
.build();
2.8 interruptsBefore
指定若干节点,进入节点之前立刻暂停工作流,等待人工输入/审批后再继续。
java
/**
* 节点执行前中断的节点ID集合
* 执行到指定节点前,自动暂停工作流
*/
private Set<String> interruptsBefore = Set.of();
代码案例:
java
// 在进入 human_review 节点**之前**中断
CompileConfig compileConfig = CompileConfig.builder()
.interruptBefore("human_review")
.build();
2.9 interruptsAfter
指定若干节点,节点执行完成之后立刻暂停,可查看节点输出再决定下一步。
java
/**
* 节点执行后中断的节点ID集合
* 执行完指定节点后,自动暂停工作流
*/
private Set<String> interruptsAfter = Set.of();
代码案例:
java
// draft_response 节点执行完后中断,人工确认草稿
CompileConfig compileConfig = CompileConfig.builder()
.interruptAfter("draft_response")
.build();
3. Getter 方法
各种配置项都提供了 Getter 方法:
java
/**
* 获取工作流递归限制次数
* @return 最大递归次数
*/
public int recursionLimit() {
return recursionLimit;
}
/**
* 获取线程释放标志状态
* @return true=释放线程,false=不释放
* @see BaseCheckpointSaver#release(RunnableConfig)
*/
public boolean releaseThread() {
return releaseThread;
}
/**
* 获取不可修改的生命周期监听器队列
* @return 生命周期监听器队列
*/
public Queue<GraphLifecycleListener> lifecycleListeners() {
return lifecycleListeners;
}
/**
* 获取观测注册表(用于监控、链路追踪)
* @return 观测注册表实例
*/
public ObservationRegistry observationRegistry() {
return observationRegistry;
}
/**
* 获取条件边评估前中断标志
* @return true=开启,false=关闭
*/
public boolean interruptBeforeEdge() {
return interruptBeforeEdge;
}
/**
* 获取【节点执行前】中断的节点ID集合(不可修改)
* @return 中断节点ID集合
*/
public Set<String> interruptsBefore() {
return interruptsBefore;
}
/**
* 获取【节点执行后】中断的节点ID集合(不可修改)
* @return 中断节点ID集合
*/
public Set<String> interruptsAfter() {
return interruptsAfter;
}
/**
* 获取默认的检查点保存器
* @return 检查点保存器(Optional包装)
*/
public Optional<BaseCheckpointSaver> checkpointSaver() {
return ofNullable(saverConfig.get());
}
/**
* 获取长期记忆存储实例
* @return Store实例,可为null
*/
public Store getStore() {
return store;
}
/**
* 设置长期记忆存储实例
* @param store 存储实例
*/
public void setStore(Store store) {
this.store = store;
}
4. Builder 构建器
提供了 Builder 构建编译配置类实例:
java
/**
* 创建默认配置的Builder实例
* @return Builder构造器
*/
public static Builder builder() {
return new Builder(new CompileConfig());
}
/**
* 基于现有配置创建Builder实例
* @param config 基础编译配置
* @return Builder构造器
*/
public static Builder builder(CompileConfig config) {
return new Builder(config);
}
/**
* CompileConfig 构造器Builder
* 支持链式调用,优雅配置所有工作流编译参数
*/
public static class Builder {
private final CompileConfig config;
/**
* 基于现有配置初始化Builder
* @param config 基础配置
*/
protected Builder(CompileConfig config) {
this.config = new CompileConfig(config);
}
/**
* 设置工作流递归限制次数
* @param recursionLimit 递归次数(必须>0)
* @return Builder实例
*/
public Builder recursionLimit(int recursionLimit) {
if( recursionLimit <= 0 ) {
throw new IllegalArgumentException("recursionLimit must be > 0!");
}
this.config.recursionLimit = recursionLimit;
return this;
}
/**
* 设置线程释放标志
* @param releaseThread true=释放线程
* @return Builder实例
* @see BaseCheckpointSaver#release(RunnableConfig)
*/
public Builder releaseThread(boolean releaseThread) {
this.config.releaseThread = releaseThread;
return this;
}
/**
* 设置观测注册表(监控/追踪)
* @param observationRegistry 观测注册表
* @return Builder实例
*/
public Builder observationRegistry(ObservationRegistry observationRegistry) {
this.config.observationRegistry = observationRegistry;
return this;
}
/**
* 设置检查点保存配置
* @param saverConfig 检查点配置
* @return Builder实例
*/
public Builder saverConfig(SaverConfig saverConfig) {
this.config.saverConfig = saverConfig;
return this;
}
/**
* 设置【节点执行前】中断的节点(可变参数)
* @param interruptBefore 节点ID数组
* @return Builder实例
*/
public Builder interruptBefore(String... interruptBefore) {
this.config.interruptsBefore = Set.of(interruptBefore);
return this;
}
/**
* 设置【节点执行后】中断的节点(可变参数)
* @param interruptAfter 节点ID数组
* @return Builder实例
*/
public Builder interruptAfter(String... interruptAfter) {
this.config.interruptsAfter = Set.of(interruptAfter);
return this;
}
/**
* 设置【节点执行前】中断的节点(集合参数)
* @param interruptsBefore 节点ID集合
* @return Builder实例
*/
public Builder interruptsBefore(Collection<String> interruptsBefore) {
this.config.interruptsBefore = interruptsBefore.stream().collect(Collectors.toUnmodifiableSet());
return this;
}
/**
* 设置【条件边评估前中断】开关
* 开启后:节点执行完成 → 中断 → 路由决策
* 关闭后:节点执行完成 → 直接路由决策
* @param interruptBeforeEdge true=开启
* @return Builder实例
*/
public Builder interruptBeforeEdge(boolean interruptBeforeEdge) {
this.config.interruptBeforeEdge = interruptBeforeEdge;
return this;
}
/**
* 设置【节点执行后】中断的节点(集合参数)
* @param interruptsAfter 节点ID集合
* @return Builder实例
*/
public Builder interruptsAfter(Collection<String> interruptsAfter) {
this.config.interruptsAfter = interruptsAfter.stream().collect(Collectors.toUnmodifiableSet());
return this;
}
/**
* 添加图生命周期监听器
* @param listener 监听器实例
* @return Builder实例
*/
public Builder withLifecycleListener(GraphLifecycleListener listener) {
this.config.lifecycleListeners.offer(listener);
return this;
}
/**
* 设置长期记忆存储实例
* @param store 存储实例
* @return Builder实例
*/
public Builder store(Store store) {
this.config.store = store;
return this;
}
/**
* 构建最终的CompileConfig配置实例
* @return 编译配置对象
*/
public CompileConfig build() {
return config;
}
}
/**
* 私有默认构造器
* 强制通过Builder模式创建实例,保证配置合法性
*/
private CompileConfig() {
}
/**
* 私有拷贝构造器
* 基于现有配置创建新实例,用于Builder模式
* @param config 待拷贝的配置
*/
private CompileConfig(CompileConfig config) {
this.saverConfig = config.saverConfig;
this.interruptsBefore = config.interruptsBefore;
this.interruptsAfter = config.interruptsAfter;
this.releaseThread = config.releaseThread;
this.lifecycleListeners = config.lifecycleListeners;
this.observationRegistry = config.observationRegistry;
this.interruptBeforeEdge = config.interruptBeforeEdge;
this.store = config.store;
}
}
5. ReactAgent 的编译配置
ReactAgent 构建时也是支持自定义编译配置的:

build() 最后调用 ReactAgent 构造函数时会构建编译配置:
java
public class DefaultBuilder extends Builder {
@Override
public ReactAgent build() {
// Validate name is not empty
if (!StringUtils.hasText(this.name)) {
throw new IllegalArgumentException("Agent name must not be empty");
}
// ......
return new ReactAgent(llmNode, toolNode, buildConfig(), this);
}
如果自定义了编译配置,则会直接返回使用自定义,否则会使用默认配置:
java
/**
* 构建编译配置对象(单例模式,仅构建一次)
* 该方法用于创建并返回编译核心所需的配置信息,包含持久化、递归限制、线程释放等核心配置
* @return 完整的编译配置实例 CompileConfig
*/
protected CompileConfig buildConfig() {
// 双重校验:如果编译配置已存在,直接返回,避免重复创建
if (compileConfig != null) {
return compileConfig;
}
// 构建持久化配置:注册指定的持久化处理器 saver
SaverConfig saverConfig = SaverConfig.builder()
.register(saver) // 注册持久化实现类
.build();
// 构建最终编译配置并返回
return CompileConfig.builder()
.saverConfig(saverConfig) // 设置持久化配置
.recursionLimit(Integer.MAX_VALUE) // 设置递归深度限制为最大值(无限制递归)
.releaseThread(releaseThread) // 设置线程释放策略
.build();
}