1. 前言

上一篇我们解析了 ReactAgent 的同步与流式执行方法,在所有执行方法(call/invoke/stream)中,都存在一个可选参数 RunnableConfig。作为 Spring AI AlibabaAgent 执行的核心配置类,RunnableConfig 负责管理线程、 checkpoint、元数据、上下文等关键执行参数,直接决定了 Agent 的运行行为,如状态持久化、流式模式、并行执行策略等。

2. RunnableConfig

RunnableConfig 是一个不可变 _final 类,用于表示运行任务的配置,封装了 Agent 运行任务的所有配置参数,并提供安全修改这些参数的方法,核心作用是为 Agent 执行提供统一的环境配置和状态管理,具体包括:

  • 线程与断点管理:通过 threadId 实现对话状态持久化,通过 checkPointId 实现断点续跑;
  • 流式模式控制:指定 Agent 流式执行的输出模式(StreamMode);
  • 元数据与上下文管理:区分不可变的 metadata(环境信息)和可变的 context(节点间通信信息);
  • 并行节点配置:为并行节点指定执行器(Executor)和聚合策略;
  • 中断节点管理:标记和管理执行过程中被中断的节点,支持恢复执行;
  • 扩展配置:支持人类反馈、推理内容合并、动态工具回调等高级功能。

注意事项:

  • 不可变性原则RunnableConfig 实例创建后不可修改,修改配置必须创建新实例,避免直接修改属性导致的线程安全问题;
  • metadata 与 context 区分:不要将临时执行信息(如工具调用结果)放入 metadata,避免不必要的持久化和内存占用;
  • threadId 作用:仅用于关联同一对话的上下文,无需每次执行都生成新的 threadId(否则无法保留多轮对话状态);
  • 并行节点配置:若未指定并行执行器,将使用默认执行器,高并发场景建议自定义执行器,控制线程数量;
  • 流式模式StreamMode 的取值需与 Agent 的流式执行方法匹配,避免配置与执行方式冲突。

2.1 核心常量

类中定义了多个常量,用于标记元数据(metadata)中的特定键,核心常量用途如下:

  • AGENT_MODEL_NAME/_AGENT_TOOL_:标记 Agent 使用的模型和工具,用于内部识别;
  • HUMAN_FEEDBACK_METADATA_KEY:标记是否需要人类反馈,用于断点续跑场景;
  • MERGE_REASONING_CONTENT_METADATA_KEY:控制流式执行时,是否合并多段推理内容的 metadata
  • DEFAULT_PARALLEL_EXECUTOR_KEY:并行节点的默认执行器键,用于全局并行配置。

源码如下:

 /**
     * 代理模型名称元数据键
     */
    public static final String AGENT_MODEL_NAME = "_AGENT_MODEL_";

    /**
     * 代理工具名称元数据键
     */
    public static final String AGENT_TOOL_NAME = "_AGENT_TOOL_";

    /**
     * 代理钩子名称前缀
     */
    public static final String AGENT_HOOK_NAME_PREFIX = "_AGENT_HOOK_";

    /**
     * 代理名称元数据键
     */
    public static final String AGENT_NAME_KEY = "_AGENT_";

    /**
     * 人工反馈元数据键
     */
    public static final String HUMAN_FEEDBACK_METADATA_KEY = "HUMAN_FEEDBACK";

    /**
     * 状态更新元数据键
     */
    public static final String STATE_UPDATE_METADATA_KEY = "STATE_UPDATE";

    /**
     * 默认并行执行器元数据键
     */
    public static final String DEFAULT_PARALLEL_EXECUTOR_KEY = "_DEFAULT_PARALLEL_EXECUTOR_";

    /**
     * 默认并行聚合策略元数据键
     */
    public static final String DEFAULT_PARALLEL_AGGREGATION_STRATEGY_KEY = "_DEFAULT_PARALLEL_AGGREGATION_STRATEGY_";

    /**
     * 动态工具回调元数据键(内部使用)
     * <p>
     * 存储工具回调列表,供 AgentLlmNode/AgentToolNode 内部推理使用,非公共API
     */
    public static final String DYNAMIC_TOOL_CALLBACKS_METADATA_KEY = "_DYNAMIC_TOOL_CALLBACKS_";

    /**
     * 流式消息推理内容合并开关元数据键
     * <p>
     * 为true时,合并流式消息的历史+当前元数据;为false时仅使用当前元数据
     */
    public static final String MERGE_REASONING_CONTENT_METADATA_KEY = "_MERGE_REASONING_CONTENT_";

/*
 * 版权所有 2024-2026 原作者或作者。
 *
 * 基于Apache许可证2.0版(以下简称"许可证")授权;
 * 除非遵守许可证的规定,否则您不得使用此文件。
 * 您可以在以下地址获取许可证副本:
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * 除非适用法律要求或书面同意,否则根据许可证分发的软件
 * 按"原样"分发,不附带任何明示或暗示的保证或条件。
 * 请查看许可证以了解管理权限和限制的具体条款。
 */
package com.alibaba.cloud.ai.graph;

import com.alibaba.cloud.ai.graph.action.InterruptionMetadata;
import com.alibaba.cloud.ai.graph.internal.node.ParallelNode;
import com.alibaba.cloud.ai.graph.store.Store;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executor;

import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import static java.util.Optional.ofNullable;

/**
 * 一个最终类,用于表示可运行任务的配置。此类包含多种参数,
 * 如线程ID、检查点ID、下一个节点和流式模式,并提供安全修改这些参数的方法,
 * 不会永久改变原始配置。
 */
public final class RunnableConfig implements HasMetadata<RunnableConfig.Builder> {









    /**
     * 通过在元数据中设置节点值为false,标记节点为未中断状态。
     * @param nodeId 要标记为未中断的节点ID
     */
    // 恢复被中断的节点(标记为未中断)
    public void withNodeResumed(String nodeId) {
        String formattedNodeId = HasMetadata.formatNodeId(nodeId);
        interruptedNodes.put(formattedNodeId, false);
    }





    /**
     * 创建一个与当前配置属性相同,但流式模式不同的新RunnableConfig。
     * @return 具有更新后流式模式的新RunnableConfig
     */
    // 修改流式模式:返回新实例(原实例不变,保证不可变性)
    public RunnableConfig withStreamMode(CompiledGraph.StreamMode streamMode) {
        if (this.streamMode == streamMode) {
            return this;
        }
        return RunnableConfig.builder(this).streamMode(streamMode).build();
    }

    /**
     * 更新配置的检查点ID。
     * @return 具有更新后检查点ID的新RunnableConfig实例
     */
    // 修改检查点ID:返回新实例
    public RunnableConfig withCheckPointId(String checkPointId) {
        if (Objects.equals(this.checkPointId, checkPointId)) {
            return this;
        }
        return RunnableConfig.builder(this).checkPointId(checkPointId).build();
    }

    /**
     * 返回一个新的RunnableConfig,复制当前配置并向元数据中添加
     * {@link #HUMAN_FEEDBACK_METADATA_KEY},值为{@code "placeholder"}。
     * 用于构建恢复运行的配置(例如,收集人类反馈后继续执行图)。
     */
    // 添加人类反馈占位符:用于断点续跑场景
    public RunnableConfig withResume() {
        return RunnableConfig.builder(this)
                .addMetadata(HUMAN_FEEDBACK_METADATA_KEY, "placeholder")
                .build();
    }

    /**
     * 返回是否应跨片段合并流式助手消息元数据中的推理内容。
     */
    // 检查是否合并流式推理内容(用于流式执行时,合并多段推理 metadata)
    public boolean mergeReasoningContent() {
        return metadata(MERGE_REASONING_CONTENT_METADATA_KEY).map(v -> Boolean.TRUE.equals(v)).orElse(false);
    }

    /**
     * 返回一个新的RunnableConfig,复制当前配置并设置合并推理内容的标志。
     */
    // 设置是否合并流式推理内容:返回新实例
    public RunnableConfig withMergeReasoningContent(boolean merge) {
        return RunnableConfig.builder(this).mergeReasoningContent(merge).build();
    }



    // 重写toString:便于日志打印和调试
    @Override
    public String toString() {
        return format("RunnableConfig{ threadId=%s, checkPointId=%s, nextNode=%s, streamMode=%s }", threadId,
                checkPointId, nextNode, streamMode);
    }




}

2.2 配置项

属性名 类型 是否可变 核心用途
threadId String 不可变 对话线程ID,用于关联同一对话的所有执行请求,实现状态持久化(如多轮对话上下文保留)
checkPointId String 不可变 断点ID,标记 Agent 执行中断的位置,用于断点续跑(如人类反馈后恢复执行)
nextNode String 不可变 指定 Agent 执行的下一个节点,用于自定义执行流程(默认按 graph 定义的节点顺序执行)
streamMode CompiledGraph.StreamMode 不可变 流式执行模式,控制流式输出的内容(如仅输出结果、输出中间过程等)
metadata Map<String, Object> 不可变 执行环境信息(如用户ID、请求ID、工具回调),仅用于传递信息,不参与执行状态变更
context ConcurrentMap<String, Object> 可变 节点间通信的临时信息(如工具调用结果、中间推理结论),仅当前执行有效,不持久化
store Store 不可变 状态存储组件,用于持久化 threadId、checkPointId 等信息,支持断点续跑
interruptedNodes ConcurrentMap<String, Object> 可变 标记被中断的节点,key为格式化后的节点ID,value为中断状态(true/false)

2.2.1 threadId

对话线程 ID ,用于关联同一对话的所有执行请求,实现状态持久化(如多轮对话上下文保留)。

    // 核心属性:线程ID(用于状态持久化,关联同一对话上下文)
    private final String threadId;

获取线程 ID 方法(Optional 包装,避免空指针):

    /**
     * 以{@link Optional}形式返回线程ID。
     * @return 包装线程ID的{@code Optional},如果未设置线程ID则返回空的{@code Optional}。
     */
    // 获取线程ID(Optional包装,避免空指针)
    public Optional<String> threadId() {
        return ofNullable(threadId);
    }

2.2.2 checkPointId

断点 ID,标记 Agent 执行中断的位置,用于断点续跑(如人类反馈后恢复执行)。

    // 核心属性:检查点ID(用于断点续跑,标记执行中断位置)
    private final String checkPointId;

获取检查点 ID 方法:

    /**
     * 以{@link Optional}形式返回当前的{@code checkPointId}。
     * @return 包含{@code checkPointId}的{@link Optional},如果为null则返回{@link Optional#empty()}。
     */
    // 获取检查点ID(Optional包装)
    public Optional<String> checkPointId() {
        return ofNullable(checkPointId);
    }

创建新配置,修改检查点 ID

    /**
     * 创建新配置:修改检查点ID(原配置不变)
     * @param checkPointId 新的检查点ID
     * @return 新的RunnableConfig实例
     */
    public RunnableConfig withCheckPointId(String checkPointId) {
        if (Objects.equals(this.checkPointId, checkPointId)) {
            return this;
        }
        return RunnableConfig.builder(this).checkPointId(checkPointId).build();
    }

2.2.3 nextNode

默认情况下,执行流程按 Graph 定义的节点顺序执行,可以通过 nextNode 指定 Agent 执行的下一个节点,用于自定义执行流程。

    // 核心属性:下一个节点ID(用于指定执行的下一个节点,支持自定义执行流程)
    private final String nextNode;

获取下一个节点方法:

    /**
     * 返回描述序列中下一个节点的{@code Optional},如果没有此类节点则返回空的{@code Optional}。
     */
    // 获取下一个节点ID(Optional包装)
    public Optional<String> nextNode() {
        return ofNullable(nextNode);
    }

2.2.4 streamMode

流式执行模式,用于控制流式执行的输出行为。

    // 核心属性:流式模式(控制流式执行的输出方式,来自CompiledGraph)
    private final CompiledGraph.StreamMode streamMode;

其枚举类型 StreamMode 具体定义如下:

/**
 * 流式模式枚举,用于控制Agent流式执行的输出方式
 */
public enum StreamMode {

    /**
     * 结果值模式:仅输出最终执行结果,不输出中间过程(如节点执行日志、推理过程)
     */
    VALUES,
    /**
     * 快照模式:输出执行过程中的所有快照信息,包括中间节点执行结果、推理过程等
     */
    SNAPSHOTS

}

获取流式模式方法:

    /**
     * 返回编译图的流式模式。
     * @return 表示当前流式模式的{@code StreamMode}。
     */
    // 获取流式模式(用于控制流式执行输出)
    public CompiledGraph.StreamMode streamMode() {
        return streamMode;
    }

修改流模式,返回新配置实例:

    /**
     * 创建新配置:修改流模式(原配置不变)
     * @param streamMode 新的流模式
     * @return 新的RunnableConfig实例
     */
    public RunnableConfig withStreamMode(CompiledGraph.StreamMode streamMode) {
        if (this.streamMode == streamMode) {
            return this;
        }
        return RunnableConfig.builder(this).streamMode(streamMode).build();
    }

提示:所有修改配置的方法,均不会修改原实例,而是返回一个新的 RunnableConfig 实例,避免多线程环境下的配置冲突。

2.2.5 metadata

执行环境信息(如用户ID、请求ID、工具回调),仅用于传递信息,不参与执行状态变更。

    // 核心属性:元数据(不可变,用于传递执行环境信息,如用户ID、请求ID)
    private final Map<String, Object> metadata;

获取元数据方法:

    // 获取元数据(Optional包装,不可修改)
    @Override
    public Optional<Map<String, Object>> metadata() {
        return Optional.of(metadata);
    }

根据 key 获取元数据值方法:

    /**
     * 返回指定键的元数据值
     */
    // 根据key获取元数据值(Optional包装)
    @Override
    public Optional<Object> metadata(String key) {
        if (key == null) {
            return Optional.empty();
        }
        return ofNullable(metadata).map(m -> m.get(key));
    }

创建新配置,添加人工反馈元数据(用于恢复执行):

    /**
     * 创建新配置:添加人工反馈元数据(用于恢复执行)
     * @return 新的RunnableConfig实例
     */
    public RunnableConfig withResume() {
        return RunnableConfig.builder(this)
                .addMetadata(HUMAN_FEEDBACK_METADATA_KEY, "placeholder")
                .build();
    }

判断是否开启流式消息推理内容合并:

    /**
     * 判断是否开启流式消息推理内容合并
     * @return true=开启合并,false=关闭
     */
    public boolean mergeReasoningContent() {
        return metadata(MERGE_REASONING_CONTENT_METADATA_KEY)
                .map(v -> Boolean.TRUE.equals(v))
                .orElse(false);
    }

创建新配置,设置推理内容合并开关:

    /**
     * 创建新配置:设置推理内容合并开关
     * @param merge 合并开关
     * @return 新的RunnableConfig实例
     */
    public RunnableConfig withMergeReasoningContent(boolean merge) {
        return RunnableConfig.builder(this).mergeReasoningContent(merge).build();
    }

2.2.6 context

节点间通信的临时信息(如工具调用结果、中间推理结论),仅当前执行有效,不持久化。

    /**
     * 与元数据相比,上下文在执行过程中是可变的。它用于在节点之间传递信息。
     * 与全局状态(OverAllState)不同,上下文特定于一次运行,不会被持久化。
     */
    // 核心属性:上下文(可变,用于节点间传递临时信息,不持久化)
    private final ConcurrentMap<String, Object> context;

获取上下文方法:

    // 获取上下文(可变,用于节点间通信)
    public Map<String, Object> context() {
        return context;
    }

清空上下文方法:

    // 清空上下文(清除节点间传递的临时信息)
    public void clearContext() {
        this.context.clear();
    }

metadatacontext 的关键区别:

对比维度 metadata context
设计特性(不变性) 不可变:实例创建后核心参数无法修改,需通过 Builder 模式生成新实例 可变:支持动态增删、修改、清空,适配执行过程中临时数据的流转需求
核心用途 传递执行环境信息(如用户ID、请求ID、模型/工具配置、人类反馈标记) 传递节点间临时执行数据(如工具调用结果、中间推理结论、并行节点聚合状态)
持久化特性 可通过 Store 组件持久化,关联 threadId 实现多轮对话上下文留存 仅当前执行周期有效,执行结束后自动清空,不参与持久化
线程安全实现 通常为普通 HashMap(不可变场景下无需特殊安全机制,读写无并发冲突) 采用 ConcurrentHashMap(线程安全,适配 Agent 多节点并行执行的并发修改场景)

2.2.7 store

状态存储组件,用于持久化 threadIdcheckPointId 等信息,支持断点续跑。

    // 核心属性:存储组件(用于持久化执行状态,支持断点续跑)
    private final Store store;

获取存储组件方法:

    // 获取存储组件(用于状态持久化)
    public Store store() {
        return this.store;
    }

2.2.8 interruptedNodes

存储标记被中断的节点,key 为格式化后的节点 IDvalue 为中断状态(true/false)。

    // 核心属性:中断节点映射(标记被中断的节点,key为格式化后的节点ID,value为中断状态)
    private final ConcurrentMap<String, Object> interruptedNodes;

标记节点为中断状态:

    /**
     * 通过将节点添加到带有格式化键的元数据中,标记节点为中断状态。
     * @param nodeId 要标记为中断的节点ID;不能为null
     * @throws NullPointerException 如果nodeId为null
     */
    // 标记节点为中断状态
    public void markNodeAsInterrupted(String nodeId) {
        interruptedNodes.put(HasMetadata.formatNodeId(nodeId), true);
    }

获取中断节点的相关数据:

    /**
     * 检索与指定键关联的中断数据。
     */
    // 获取中断节点的相关数据
    public Optional<Object> interruptData(String key) {
        if (key == null) {
            return Optional.empty();
        }
        return ofNullable(interruptedNodes).map(m -> m.get(key));
    }

检查某个节点是否标记为中断状态:

    /**
     * 检查元数据中是否标记某个节点为中断状态。
     * @param nodeId 要检查中断状态的节点ID
     * @return 如果节点被标记为中断则返回true,否则返回false
     */
    // 检查节点是否被中断
    public boolean isInterrupted(String nodeId) {
        return interruptData(HasMetadata.formatNodeId(nodeId)).map(value -> Boolean.TRUE.equals(value)).orElse(false);
    }

移除节点的中断标记:

    /**
     * 移除节点的中断标记
     * @param nodeId 节点ID
     */
    public void removeInterrupted(String nodeId) {
        String formattedNodeId = HasMetadata.formatNodeId(nodeId);
        if (interruptedNodes == null || !interruptedNodes.containsKey(formattedNodeId)) {
            return;
        }
        interruptedNodes.remove(formattedNodeId);
    }

标记节点为【已恢复】状态:

    /**
     * 标记节点为【已恢复】状态
     * @param nodeId 节点ID
     */
    public void withNodeResumed(String nodeId) {
        String formattedNodeId = HasMetadata.formatNodeId(nodeId);
        interruptedNodes.put(formattedNodeId, false);
    }

2.3 Builder 构建

2.3.1 构建方式

RunnableConfig 采用 Builder 模式构建,支持链式调用,核心构建方式有两种:

  • 构建新配置RunnableConfig.builder(),从无到有构建配置
  • 修改已有配置RunnableConfig.builder(existingConfig),基于已有配置修改,返回新实例。

构建方式支持源码如下:

    /**
     * 创建一个RunnableConfig的新实例,作为提供的{@code config}的副本。
     * @param builder 配置构建器。
     */
    // 私有构造方法:仅通过Builder创建实例,保证不可变性
    private RunnableConfig(Builder builder) {
        this.threadId = builder.threadId;
        this.checkPointId = builder.checkPointId;
        this.nextNode = builder.nextNode;
        this.streamMode = builder.streamMode;
        this.metadata = ofNullable(builder.metadata()).map(HashMap::new).orElse(null);
        this.interruptedNodes = new ConcurrentHashMap<>();
        this.store = builder.store;
        this.context = builder.context;
    }

    /**
     * 创建{@link Builder}类的新实例。
     */
    // 创建空Builder(用于构建新配置)
    public static Builder builder() {
        return new Builder();
    }

    /**
     * 创建一个带有指定{@link RunnableConfig}的新{@code Builder}实例。
     */
    // 基于已有配置创建Builder(用于修改配置,返回新实例)
    public static Builder builder(RunnableConfig config) {
        return new Builder(config);
    }

2.3.2 build()

提供了 Builder 内部类用于构建 RunnableConfig 实例,最终通过 build() 方法生成:

  /**
     * 用于构建{@link RunnableConfig}对象的构建器模式类。
     * 此类提供流畅的接口来设置{@link RunnableConfig}对象的各种属性,然后构建最终配置。
     */
    // Builder内部类:用于构建RunnableConfig实例( fluent接口,支持链式调用)
    public static class Builder extends HasMetadata.Builder<Builder> {

        private String threadId;
        private String checkPointId;
        private String nextNode;
        private Store store;
        private ConcurrentMap<String, Object> context;
        private CompiledGraph.StreamMode streamMode = CompiledGraph.StreamMode.VALUES;

        /**
         * 构建一个带有默认配置设置的{@link Builder}新实例。
         * 初始化一个新的{@link RunnableConfig}对象用于配置。
         */
        // 空构造:初始化上下文为ConcurrentHashMap(线程安全)
        Builder() {
            this.context = new ConcurrentHashMap<>();
        }

        /**
         * 使用指定的{@link RunnableConfig}初始化{@code Builder}类的新实例。
         */
        // 基于已有配置的构造:复制已有配置的参数,便于修改
        Builder(RunnableConfig config) {
            super(requireNonNull(config, "配置不能为null!").metadata);
            this.threadId = config.threadId;
            this.checkPointId = config.checkPointId;
            this.nextNode = config.nextNode;
            this.streamMode = config.streamMode;
            this.store = config.store;
            this.context = new ConcurrentHashMap<>(config.context);
        }

        // 设置线程ID
        public Builder threadId(String threadId) {
            this.threadId = threadId;
            return this;
        }

        // 设置检查点ID
        public Builder checkPointId(String checkPointId) {
            this.checkPointId = checkPointId;
            return this;
        }

        // 设置下一个节点ID
        public Builder nextNode(String nextNode) {
            this.nextNode = nextNode;
            return this;
        }

        // 设置流式模式
        public Builder streamMode(CompiledGraph.StreamMode streamMode) {
            this.streamMode = streamMode;
            return this;
        }

        // 添加人类反馈元数据
        public Builder addHumanFeedback(InterruptionMetadata humanFeedback) {
            return addMetadata(HUMAN_FEEDBACK_METADATA_KEY, humanFeedback);
        }

        /**
         * 添加恢复元数据({@link #HUMAN_FEEDBACK_METADATA_KEY},值为{@code "placeholder"}),
         * 使构建的配置适合恢复运行。
         */
        // 添加断点续跑占位符(链式调用便捷方法)
        public Builder resume() {
            return addMetadata(HUMAN_FEEDBACK_METADATA_KEY, "placeholder");
        }

        /**
         * 启用或禁用跨片段合并流式助手消息元数据中的推理内容。
         */
        // 设置是否合并流式推理内容
        public Builder mergeReasoningContent(boolean merge) {
            return addMetadata(MERGE_REASONING_CONTENT_METADATA_KEY, merge);
        }

        // 添加状态更新元数据
        public Builder addStateUpdate(Map<String, Object> stateUpdate) {
            return addMetadata(STATE_UPDATE_METADATA_KEY, stateUpdate);
        }

        /**
         * 为指定的并行节点添加自定义{@link Executor}。
         * 为指定并行节点添加自定义执行器
         */
        public Builder addParallelNodeExecutor(String nodeId, Executor executor) {
            return addMetadata(ParallelNode.formatNodeId(nodeId), requireNonNull(executor, "执行器不能为null!"));
        }

        /**
         * 为所有并行节点设置默认{@link Executor}。
         * 为所有并行节点设置默认执行器
         */
        public Builder defaultParallelExecutor(Executor executor) {
            return addMetadata(DEFAULT_PARALLEL_EXECUTOR_KEY, requireNonNull(executor, "执行器不能为null!"));
        }

        /**
         * 为指定并行节点的目标节点添加聚合策略。
         * 为指定并行节点的目标节点添加聚合策略
         */
        public Builder addParallelNodeAggregationStrategy(String targetNodeId, NodeAggregationStrategy strategy) {
            return addMetadata(ParallelNode.formatTargetNodeId(targetNodeId),
                    requireNonNull(strategy, "策略不能为null!"));
        }

        /**
         * 为所有并行节点设置默认聚合策略。
         * 为所有并行节点设置默认聚合策略
         */
        public Builder defaultParallelAggregationStrategy(NodeAggregationStrategy strategy) {
            return addMetadata(DEFAULT_PARALLEL_AGGREGATION_STRATEGY_KEY,
                    requireNonNull(strategy, "策略不能为null!"));
        }

        // 设置存储组件
        public Builder store(Store store) {
            this.store = store;
            return this;
        }

        // 清空上下文
        public Builder clearContext() {
            this.context.clear();
            return this;
        }

        /**
         * 构建并返回配置好的{@code RunnableConfig}对象。
         */
        // 构建RunnableConfig实例(私有构造,保证不可变性)
        public RunnableConfig build() {
            return new RunnableConfig(this);
        }

    }

3. 演示案例

3.1 短期记忆(会话级持久化)

Spring AI Alibaba 中,要向 Agent 添加短期记忆(会话级持久化),你需要在创建 Agent 时配置 BaseCheckpointSaver 外,还需要使用 thread_id 维护对话上下文。

示例:

        // 使用 thread_id 维护对话上下文
        RunnableConfig config = RunnableConfig.builder()
                .threadId("user-123456") // 线程ID,关联同一用户的多轮对话
                .build();

        // 配置内存存储
        MemorySaver memorySaver = new MemorySaver();

        ReactAgent agent = ReactAgent.builder()
                .name("chat_agent")
                .model(zhiPuAiChatModel)
                .saver(memorySaver)
                .build();

        agent.call("我叫张三", config);
        agent.call("我叫什么名字?", config); // 输出: "你叫张三"

运行后,可以看到内存中使用 thread_id 存储了多条历史对话信息:

在这里插入图片描述

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐