【AgentScope Java新手村系列】(5)记忆与会话管理

简介: 记忆与会话管理 — AgentState 管理上下文窗口,AgentStateStore 持久化,RuntimeContext.sessionId 隔离多用户会话。

第五章 记忆与会话管理:用 AgentStateStore 替换 Memory,实现多轮对话持久化

"早上问了 weather_agent 杭州天气,半小时后追问'那上海呢?'——它竟然记得前文。这是 2.0 用 AgentStateStore 持久化 + RuntimeContext.sessionId 的作用,对老版本 Memory 接口的彻底替代。"

本章你将学到:.stateStore() + RuntimeContext.sessionId() 双钥匙机制、四种 Store 后端的选型与配置、以及生产环境下的多用户隔离。

5.1 为什么把 Memory 改成 AgentState + AgentStateStore?

1.x 的 Memory / InMemoryMemory / LongTermMemory 接口在 2.0.0-RC2 中被标为 @Deprecated(forRemoval = true),原因有三:

  1. 职责单一Memory 既是"当前对话上下文"又是"长期知识库",两件事放在一个抽象里很难扩展。
  2. 持久化无关 — 1.x 时代需要自己把 Memory 序列化进 Redis/MySQL;2.0 把这件事下沉到 AgentStateStore 后端里,业务代码与持久化彻底解耦。
  3. 与 harness 解耦HarnessAgent 鼓励把状态放在 workspace 目录、subagent 文件、skill 仓库中,这些内容天然不适合塞进一个 Java 对象。

新模型:

概念 2.0 替代 说明
Memory(当前对话窗口) AgentState (框架内部对象,用户不直接操作) + AgentStateStore Agent 自动读写,你只需配 Store
LongTermMemory workspace 下的 MEMORY.md + memory/YYYY-MM-DD.md + CompactionMiddleware / MemoryFlushMiddleware 跨会话的稳定知识
自定义持久化 AgentStateStore 后端(InMemoryAgentStateStore / JsonFileAgentStateStore / RedisAgentStateStore / MysqlAgentStateStore 跨进程、跨重启保留状态

核心认知:你只需要配好 Store + 传好 sessionId,其余全交给 HarnessAgentAgentState 是框架内部对象,日常开发不需要碰它。

⚠️ 2.0 重大变更

旧代码里 agent.getMemory().add(...)LongTermMemory.retrieve(...)InMemoryMemory 子类等 API 全部走 @Deprecated 通道,2.0 之后会被删除。本章末尾给出一份最小迁移清单

5.2 第一个例子:双钥匙缺一不可

要实现跨调用的记忆,需要两样东西:

钥匙 作用 在哪配
AgentStateStore 决定状态存哪里(内存 / 文件 / Redis / MySQL) HarnessAgent.builder().stateStore(...)
RuntimeContext.sessionId 决定「这是哪场会话」——Store 查询的主键 每次 agent.call(msg, rt) 时传入

少任何一样,就没有记忆。 不配 Store 无法持久化;不传 sessionId 每次都是新会话。

import io.agentscope.core.RuntimeContext;
import io.agentscope.core.state.JsonFileAgentStateStore;
import io.agentscope.core.message.UserMessage;
import io.agentscope.core.model.DashScopeChatModel;
import io.agentscope.harness.HarnessAgent;

import java.nio.file.Path;
import java.util.List;

public class Chapter05_Basic {
    public static void main(String[] args) {
        // (1)配 Store ———— 钥匙一:决定状态存哪
        JsonFileAgentStateStore store = new JsonFileAgentStateStore(
                Path.of("./workspace", "state"));

        HarnessAgent agent = HarnessAgent.builder()
                .name("weather_bot")
                .sysPrompt("你是一个中文天气助手,每次回答不超过 50 字。")
                .model(DashScopeChatModel.builder()
                        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                        .modelName("qwen-plus")
                        .build())
                .workspace(Path.of("./workspace"))
                .stateStore(store)          // ← 钥匙一
                .build();

        // (2)传 sessionId ———— 钥匙二:决定是哪场会话
        RuntimeContext rt = RuntimeContext.builder()
                .sessionId("user-9527-2026-06-07")
                .userId("9527")
                .build();

        // 第一轮
        agent.call(
                List.of(new UserMessage("user", "今天杭州天气怎么样?")), rt).block();

        // 第二轮 ———— 同一个 sessionId,上下文自动恢复
        System.out.println(agent.call(
                List.of(new UserMessage("user", "那上海呢?")), rt).block().getTextContent());
    }
}

内部流程(框架自动完成,你不用管):

agent.call(msg, rt)
  |
  +-- 根据 rt.sessionId 去 store 查有无旧状态
  |     |-- 有 --> 反序列化成 AgentState(内部对象)--> 恢复上下文
  |     \-- 无 --> 新建空的 AgentState
  |
  +-- 把 msg + agent 的回复追加进 AgentState
  |
  \-- 完成后把 AgentState 写回 store

你只做了两件事.stateStore(store) + sessionId,剩下全自动。AgentState 是框架内部对象,日常开发不需要直接操作它。

5.3 AgentState 的三个核心方法

AgentStateio.agentscope.core.state)对外只暴露三件事:

方法 用途
List<Msg> getContext() 只读视图,拿到当前上下文里所有消息
void addMessage(Msg msg) 往上下文里追加一条消息(业务方主动注入时用)
int size() 当前上下文的消息条数

Msg 在 2.0 依旧是不可变对象,任何想修改消息的尝试都需要新建一条。所以“清空上下文”也不是 state.clear(),而是用新的 Session 实例,或在 Session 之上自己开一个新的 sessionId

5.4 RuntimeContext —— 给单次调用贴上标签

RuntimeContext 解决的是“同一份 agent 跑多个用户 / 多场对话”这件事。把它作为 call() 的第二个参数传入:

import io.agentscope.core.RuntimeContext;

agent.call(
        List.of(new UserMessage("user", "晚上想喝粥")),
        RuntimeContext.builder()
                .sessionId("user-9527-2026-06-07")
                .userId("9527")
                .build());

字段说明:

  • sessionId — 把这一通对话归到某个会话桶。配合 AgentStateStore 后端时,这是主键
  • userId — 多租户场景下区分用户,方便 RedisAgentStateStore 命名空间隔离。
  • 其他traceId / metadata 用于在事件流里打点,配合 streamEvents() 做日志关联。

5.5 AgentStateStore —— 把状态搬到磁盘 / Redis / MySQL

5.5.1 不传 AgentStateStore:默认 InMemoryAgentStateStore

HarnessAgent.builder() 不显式 .stateStore(...) 时,框架默认安装一个 InMemoryAgentStateStore(每个 HarnessAgent 进程内独立)。但即便有默认 Store,不传 sessionId 也不会有跨调用记忆——Store 按 sessionId 做主键索引,空 key 每次覆盖。
重启进程、部署多实例时数据会丢。

5.5.2 单机文件版:JsonFileAgentStateStore

开发环境推荐用 JsonFileAgentStateStore,状态会落到 workspace/state/session-<id>.json,重启服务能恢复:

import io.agentscope.core.state.JsonFileAgentStateStore;
import io.agentscope.harness.HarnessAgent;

HarnessAgent agent = HarnessAgent.builder()
        .name("weather_bot")
        .sysPrompt("...")
        .model(model)
        .workspace(Path.of("./workspace"))
        .stateStore(new JsonFileAgentStateStore(Path.of("./workspace/state")))
        .build();

workspace/state/ 目录里会看到这样的文件:

workspace/
└── state/
    ├── session-user-9527-2026-06-07.json
    └── session-user-9528-2026-06-07.json

5.5.3 生产环境:RedisAgentStateStore

生产环境必须把状态放 Redis。AgentScope 提供现成的 RedisAgentStateStore(在 agentscope-extensions-redis 模块里):

<dependency>
    <groupId>io.agentscope</groupId>
    <artifactId>agentscope-extensions-redis</artifactId>
    <version>2.0.0-RC2</version>
</dependency>

import io.agentscope.extensions.redis.state.RedisAgentStateStore;
import io.agentscope.harness.HarnessAgent;
import redis.clients.jedis.UnifiedJedis;

UnifiedJedis client = new UnifiedJedis("redis://127.0.0.1:6379");

HarnessAgent agent = HarnessAgent.builder()
        .name("weather_bot")
        .sysPrompt("...")
        .model(model)
        .workspace(Path.of("./workspace"))
        .stateStore(RedisAgentStateStore.builder()
                .jedisClient(client)
                .build())
        .build();

RedisAgentStateStore 使用 Builder 模式配置:

  1. jedisClient — 由你控制连接配置(单机、哨兵、集群均可通过 UnifiedJedis 实现)。
  2. 也支持 LettuceRedisson 客户端适配,通过对应的 LettuceClientAdapter / RedissonClientAdapter

5.5.4 重型企业级:MysqlAgentStateStore

需要事务、强一致、审计时,用 MysqlAgentStateStore(在 agentscope-extensions-mysql 模块里):

import io.agentscope.extensions.mysql.state.MysqlAgentStateStore;
import javax.sql.DataSource;

HarnessAgent agent = HarnessAgent.builder()
        .stateStore(new MysqlAgentStateStore(dataSource, true))
        .build();

迁移到 MySQL 时记得在首次启动前执行模块自带的 schema.sql,会创建 agent_state 表。

5.6 完整可运行示例

import io.agentscope.core.RuntimeContext;
import io.agentscope.core.message.UserMessage;
import io.agentscope.core.model.DashScopeChatModel;
import io.agentscope.extensions.redis.state.RedisAgentStateStore;
import io.agentscope.harness.HarnessAgent;
import redis.clients.jedis.UnifiedJedis;

import java.nio.file.Path;
import java.util.List;

public class Chapter05_Redis {
    public static void main(String[] args) {
        UnifiedJedis client = new UnifiedJedis("redis://127.0.0.1:6379");

        HarnessAgent agent = HarnessAgent.builder()
                .name("weather_bot")
                .sysPrompt("你是一个中文天气助手,每次回答不超过 50 字。")
                .model(DashScopeChatModel.builder()
                        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                        .modelName("qwen-plus")
                        .build())
                .workspace(Path.of("./workspace"))
                .stateStore(RedisAgentStateStore.builder()
                        .jedisClient(client)
                        .build())
                .build();

        // user-9527 的第一通对话
        agent.call(
                List.of(new UserMessage("user", "今天杭州天气怎么样?")),
                RuntimeContext.builder()
                        .sessionId("user-9527-2026-06-07")
                        .userId("9527")
                        .build())
                .block();

        // user-9528 的第一通对话 —— 同一份 agent 进程,state 完全隔离
        agent.call(
                List.of(new UserMessage("user", "上海今天冷不冷?")),
                RuntimeContext.builder()
                        .sessionId("user-9528-2026-06-07")
                        .userId("9528")
                        .build())
                .block();

        // user-9527 半小时后再问 —— 上下文从 Redis 恢复
        agent.call(
                List.of(new UserMessage("user", "那上海呢?")),
                RuntimeContext.builder()
                        .sessionId("user-9527-2026-06-07")
                        .userId("9527")
                        .build())
                .block();

        client.close();
    }
}

这段代码里两个用户共享同一个 HarnessAgent 实例——RuntimeContext.sessionId() 是把状态映射到不同桶的钥匙,2.0 的这种设计可以让你在生产里只起 1 个 agent 进程服务所有用户。

5.7 与长期记忆(MEMORY.md)的协作

AgentStateStore 只负责“当前会话上下文”;想跨会话记忆用户的偏好 / 习惯,得借助 workspace 下的两套文件:

  • MEMORY.md — 一份长期稳定的“事实笔记”(用户昵称、过敏原、长期目标)。

  • memory/YYYY-MM-DD.md — 按天追加的“事件笔记”(昨天吃了什么、今天计划做什么)。

    2.0 提供了两个 Middleware 让这件事全自动:

  • CompactionMiddleware — 当上下文超过 token 阈值时,把旧消息压缩成摘要写进 MEMORY.md

  • MemoryFlushMiddleware — 每轮对话结束后把需要长期保留的内容刷到当日 memory/<date>.md

详细配置见第 18 章 Skill & 长期记忆。

5.8 最小迁移清单(1.x → 2.0)

AgentState 是框架内部对象。迁移表中的 agent.state() 指 RC1 旧 API,RC2 中为 agent.getAgentState()。这些接口仅在 Middleware 等编程场景使用,日常对话不需要。

1.x 用法 2.0 等价
agent.getMemory() 读上下文 agent.getAgentState().getContext()(内部 API)
agent.getMemory().add(Msg) agent.getAgentState().addMessage(Msg)(内部 API)
agent.getMemory().size() agent.getAgentState().size()(内部 API)
new InMemoryMemory() 默认行为,无需配置
LongTermMemory.retrieve(...) workspace 下 MEMORY.md + SkillRepository
LongTermMemory.record(...) MemoryFlushMiddleware
自定义 Memory 子类持久化 AgentStateStore 后端
agent.call(messages) agent.call(messages, RuntimeContext.empty())
agent.stream(messages) agent.streamEvents(messages, ctx)
Msg.builder().role(USER)... new UserMessage("name", "text")

5.9 本章小结

  • 2.0 的记忆 = .stateStore(store) + RuntimeContext.sessionId——两样缺一就没有记忆。
  • 同一个 HarnessAgent 实例可以服务多个用户 / 多场会话,靠 RuntimeContext.sessionId() 区分。
  • 开发期用 JsonFileAgentStateStore、生产用 RedisAgentStateStore / MysqlAgentStateStore,按需切换。
  • Agent 在 RC2 中完全无状态化——同一实例可安全并发服务多 (userId, sessionId) 组合。
  • 跨会话的稳定知识靠 workspace 下的 MEMORY.md + memory/*.md + CompactionMiddleware / MemoryFlushMiddleware,见第 18 章。

下一章我们会在此基础上接入 Hook/Middleware 系统,演示怎么在每一轮里插桩做日志/计费/审计。

目录
相关文章
|
2天前
|
人工智能 自然语言处理 文字识别
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
Qwen3.7-Max是阿里云百炼面向智能体时代推出的新一代旗舰模型,对标GPT-5.5、Claude Opus 4.7等闭源旗舰。该模型支持百万级token上下文窗口,具备顶级推理能力、多模态搜索与视觉理解增强、流式输出低延迟响应等核心优势,覆盖编程、办公、长周期自主执行等复杂场景。同时支持OpenAI接口兼容,便于系统快速迁移。用户可通过Token Plan团队或节省计划等订阅方式灵活调用,适合企业级高要求场景使用。
7899 34
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
|
2天前
|
数据采集 人工智能 前端开发
让 Coding Agent 从黑盒到透明:阿里云 Agent 观测审计数据采集实践
AI Agent 规模化落地带来执行黑盒、行为难追溯、成本难度量三大难题。阿里云基于 OTel 标准,面向 Coding Agent、个人通用助理和框架型 Agent,推出 LoongSuite Pilot、插件及探针等无侵入采集方案,让 Agent 实现可看见、可分析、可审计、可治理。
679 145
|
2天前
|
人工智能 缓存 自然语言处理
阿里Qwen3.7-Max评测:Agent能力显著提升,耗时与调用成本大幅下降
阿里云百炼推出面向智能体的旗舰大模型Qwen3.7-Max,具备长周期自主执行能力,显著提升编程、办公自动化等复杂任务处理水平;支持MCP集成与多框架兼容,并以限时5折+100万Tokens免费试用大幅降低使用门槛,助力企业高效落地AI应用。在阿里云百炼平台快速体验:https://t.aliyun.com/U/fPVHqY
1898 10
|
2天前
|
人工智能 运维 JavaScript
阿里云Qoder CN(原通义灵码)全解析 产品形态、版本划分与技术适配说明
在AI辅助开发与智能办公工具持续普及的当下,阿里云旗下原通义灵码正式更名为Qoder CN,同时延伸出QoderWork CN、Qoder CN CLI、Qoder CN Mobile等多款配套产品,形成覆盖代码开发、日常办公、终端交互、移动端使用的完整工具矩阵。Qoder CN核心定位为AI智能编码助手,深度适配主流代码编辑器、集成开发环境以及终端场景;QoderWork CN则偏向桌面端综合办公辅助,二者面向不同使用场景,划分了多个版本档位,搭配差异化资源配额、功能权限与计费规则,同时兼容多款主流大模型。
475 4
|
2天前
|
人工智能 安全 定位技术
CodeGraph深度解析 让Claude Code工具调用直降七成的核心原理与实操教程
如今以Claude Code为代表的AI编程智能体已经成为开发者日常编码、项目重构、漏洞修复的必备工具。但在长期使用过程中,几乎所有开发者都会遇到同一个明显痛点:AI虽然具备强大的代码生成与分析能力,却常常陷入盲目探索的循环中。
1293 2
|
2天前
|
JavaScript 定位技术 API
CodeGraph 爆火:编程 Agent 需要的不是更多上下文,而是一张提前画好的代码地图
CodeGraph 是一款爆火的本地代码智能工具,通过 tree-sitter 解析 AST 构建结构化知识图谱(存于 SQLite),为编程 Agent 提前生成“代码地图”。它显著降低 Agent 在中大型项目中的探索成本——实测工具调用减少71%、Token 降57%、速度提升46%,支持19+语言及主流框架路由识别,完全离线、无需 API Key。
423 1
CodeGraph 爆火:编程 Agent 需要的不是更多上下文,而是一张提前画好的代码地图
|
2天前
|
人工智能 弹性计算 运维
阿里云发布堡垒机智能运维Agent,运维交互进入自然语言新时代
支持自然语言运维,提升效率与安全双保障。
1178 1
|
2天前
|
存储 安全 Java
AgentScope Java 2.0:打造分布式、企业级智能体底座
AgentScope 2.0 面向分布式部署、稳定运行、权限安全等企业级需求全面升级,打造支持多租户隔离与长期稳定运行的企业级智能体底座。
|
2天前
|
存储 定位技术 数据库
CodeGraph 如何让 Claude Code减少 7 成工具调用?
CodeGraph 为 Coding Agent 提供本地代码知识图谱,把函数、类、调用链和框架路由提前整理成“项目地图”,减少盲目搜索和文件读取。它不是新 Agent,而是上下文基础设施,让 Agent 更快找到正确代码路径,平均减少 7 成工具调用。
1335 4
|
2天前
|
人工智能 运维 API
2026年阿里云百炼通义千问Qwen3.7-plus深度介绍 功能特性、使用优势及618大促订阅方案指南
大模型技术的普及,让AI能力逐步融入个人办公、内容创作、代码编写、企业运营、教育培训等各类场景。不同定位的模型对应不同使用需求,旗舰级模型性能强劲但使用成本偏高,轻量化模型价格低廉却难以胜任复杂任务,而介于两者之间的中端主力模型,凭借均衡的能力、亲民的定价、广泛的场景适配性,成为绝大多数个人用户、小型团队、中小企业的首选。
579 1

热门文章

最新文章