Spring AI Alibaba 1.x 系列【12】RunnableConfig :Agent 运行的配置参数
文章目录
1. 前言
上一篇我们解析了 ReactAgent 的同步与流式执行方法,在所有执行方法(call/invoke/stream)中,都存在一个可选参数 RunnableConfig。作为 Spring AI Alibaba 中 Agent 执行的核心配置类,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();
}
metadata 和 context 的关键区别:
| 对比维度 | metadata | context |
|---|---|---|
| 设计特性(不变性) | 不可变:实例创建后核心参数无法修改,需通过 Builder 模式生成新实例 | 可变:支持动态增删、修改、清空,适配执行过程中临时数据的流转需求 |
| 核心用途 | 传递执行环境信息(如用户ID、请求ID、模型/工具配置、人类反馈标记) | 传递节点间临时执行数据(如工具调用结果、中间推理结论、并行节点聚合状态) |
| 持久化特性 | 可通过 Store 组件持久化,关联 threadId 实现多轮对话上下文留存 |
仅当前执行周期有效,执行结束后自动清空,不参与持久化 |
| 线程安全实现 | 通常为普通 HashMap(不可变场景下无需特殊安全机制,读写无并发冲突) |
采用 ConcurrentHashMap(线程安全,适配 Agent 多节点并行执行的并发修改场景) |
2.2.7 store
状态存储组件,用于持久化 threadId、checkPointId 等信息,支持断点续跑。
// 核心属性:存储组件(用于持久化执行状态,支持断点续跑)
private final Store store;
获取存储组件方法:
// 获取存储组件(用于状态持久化)
public Store store() {
return this.store;
}
2.2.8 interruptedNodes
存储标记被中断的节点,key 为格式化后的节点 ID,value 为中断状态(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 存储了多条历史对话信息:

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