Spring AI Alibaba 1.x 系列【48】状态图编译配置类:CompileConfig 源码解析

文章目录

  • [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 个 → 返回null1 个 → 返回实例,≥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;

MicrometerSpring Boot 默认集成的监控 / 追踪底层库,而 ObservationRegistryMicrometer 中可观测性体系的核心接口,核心作用是统一管理应用的观测(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 后,不同 Saverrelease 实现:

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 事务 ❌ 标记后不可恢复

持久化 SaverPostgres/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();
    }
相关推荐
知行产研1 小时前
300台验证+原生定义!雷沃×易控智驾,重新定义矿山无人运输新标准。
人工智能·自动驾驶
zhangfeng11332 小时前
SothisAI 是曙光给超算/智算中心用的「AI 任务管理+算力调度平台
人工智能
金融Tech趋势派2 小时前
2026企业微信AI服务商实测:微盛·企微管家领跑私域客户运营赛道
大数据·人工智能·企业微信
武汉知识图谱科技2 小时前
从材料到实物:神经符号AI如何重构轨道车辆吸能结构仿真流程
人工智能·知识图谱
贫民窟的勇敢爷们2 小时前
Java 与 Python 如何选型与融合
java·开发语言·python
青岛前景互联信息技术有限公司2 小时前
又到一年开学季,大学校园安全管理中的突出问题分析
大数据·人工智能·物联网
折哥的程序人生 · 物流技术专研2 小时前
从“卡死”到“跑通”:WMS机器学习全流程实战排坑记
数据库·人工智能·机器学习
AC赳赳老秦2 小时前
可视化方案提效:用 OpenClaw 对接 XMind/ProcessOn,自动生成流程图、架构图、工作脑图
人工智能·深度学习·caffe·xmind·processon·deepseek·openclaw
coderyi2 小时前
理解AI Code Agent
人工智能·agent