跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaAIjava

Spring AI Alibaba 短期记忆与长期记忆实现原理

综述由AI生成Spring AI Alibaba 框架通过 MemorySaver 和 MemoryStore 组件分别实现短期记忆与长期记忆。短期记忆基于内存存储会话状态,支持线程隔离;长期记忆支持结构化数据存储及跨会话共享。文章结合源码解析了检查点保存恢复机制及命名空间管理方式,并提供了 Agent 调用示例。

JavaCoder发布于 2026/3/27更新于 2026/5/2828 浏览

记忆系统概述

在 AI Agent 应用中,记忆系统是维持对话连贯性和个性化体验的核心能力:

  • 短期记忆(Short-term Memory):保存当前会话的对话历史,类似人类的'工作记忆'
  • 长期记忆(Long-term Memory):持久化存储关键信息,类似人类的'长时记忆'

Spring AI Alibaba 通过 MemorySaver 和 MemoryStore 两个组件实现了这两种记忆机制。

短期记忆实现原理

核心组件:MemorySaver

MemorySaver 是短期记忆的实现类,负责保存和恢复会话状态(Checkpoint)。其核心特点:

  • 存储结构:ConcurrentHashMap<String, Map<String, Checkpoint>>
  • 隔离维度:通过 threadId 隔离不同会话
  • 生命周期:应用重启后数据丢失(内存存储)
实现机制
保存检查点

当 Agent 执行完一轮对话后,会调用 MemorySaver.save() 保存状态:

// MemorySaver.java
public class MemorySaver implements CheckpointSaver {
    private final ConcurrentHashMap<String, Map<String, Checkpoint>> storage = new ConcurrentHashMap<>();

    @Override
    public void save(Checkpoint checkpoint, RunnableConfig config) {
        String threadId = config.threadId().orElseThrow();
        String checkpointId = checkpoint.getId();
        // 按 threadId 分组存储
        storage.computeIfAbsent(threadId, k -> new ConcurrentHashMap<>()).put(checkpointId, checkpoint);
    }
}

关键要点:

  • 每个 threadId 对应一个独立的 Map
  • Checkpoint 包含完整的对话历史(messages)和状态(state)
  • 恢复检查点

    当用户继续对话时,Agent 会加载上一次的 Checkpoint:

    @Override
    public Optional<Checkpoint> load(RunnableConfig config) {
        String threadId = config.threadId().orElseThrow();
        Map<String, Checkpoint> threadCheckpoints = storage.get(threadId);
        if (threadCheckpoints == null || threadCheckpoints.isEmpty()) {
            return Optional.empty();
        }
        // 返回最新的 checkpoint
        return threadCheckpoints.values().stream().max(Comparator.comparing(Checkpoint::getCreatedAt));
    }
    
    使用示例

    来自测试文件 ShortTermMemoryTest.java:82-116:

    @Test
    void testBasicShortTermMemory() throws Exception {
        // 1. 创建带 MemorySaver 的 Agent
        ReactAgent agent = ReactAgent.builder()
                .name("memory_agent")
                .model(chatModel)
                .saver(new MemorySaver()) // ← 启用短期记忆
                .build();
        // 2. 创建带 threadId 的配置
        RunnableConfig config = RunnableConfig.builder()
                .threadId("conversation_1") // ← 会话隔离标识
                .build();
        // 3. 第一轮对话:告诉名字
        agent.invoke("你好!我叫张三。", config);
        // 4. 第二轮对话:询问名字(依赖短期记忆)
        Optional<OverAllState> result = agent.invoke("我叫什么名字?", config);
        AssistantMessage response = extractLastMessage(result);
        // Agent 能记住之前的对话
        assertTrue(response.getText().contains("张三"));
    }
    

    执行流程:

    1. 第一轮对话后,MemorySaver 保存 Checkpoint(包含用户消息 + 回复)
    2. 第二轮对话时,Agent 加载 Checkpoint 恢复对话历史
    3. 将新消息追加到历史中,发送给 LLM
    4. LLM 基于完整历史回答问题

    长期记忆实现原理

    核心组件:MemoryStore

    MemoryStore 用于存储结构化的长期信息,支持命名空间(namespace)组织数据:

    • 存储结构:namespace + key + value(类似 K-V 数据库)
    • 持久化:支持扩展到 Redis/MongoDB(当前版本为内存实现)
    • 跨会话:不依赖 threadId,可在不同会话间共享
    数据模型
    // StoreItem.java
    public class StoreItem {
        private List<String> namespace; // 命名空间:如 ["user_profiles"]
        private String key;             // 键:如 "user_001"
        private Map<String, Object> value; // 值:如 {"name": "张三", "age": 28}
    
        public static StoreItem of(List<String> namespace, String key, Map<String, Object> value) {
            return new StoreItem(namespace, key, value);
        }
    }
    
    实现机制
    存储数据
    // MemoryStore.java
    public class MemoryStore implements Store {
        private final Map<String, Map<String, StoreItem>> storage = new ConcurrentHashMap<>();
    
        @Override
        public void putItem(StoreItem item) {
            String namespaceKey = String.join("/", item.getNamespace());
            storage.computeIfAbsent(namespaceKey, k -> new ConcurrentHashMap<>()).put(item.getKey(), item);
        }
    }
    
    检索数据
    @Override
    public Optional<StoreItem> getItem(List<String> namespace, String key) {
        String namespaceKey = String.join("/", namespace);
        Map<String, StoreItem> namespaceMap = storage.get(namespaceKey);
        if (namespaceMap == null) {
            return Optional.empty();
        }
        return Optional.ofNullable(namespaceMap.get(key));
    }
    
    使用示例

    来自测试文件 LongTermMemoryTest.java:88-188:

    @Test
    void testLongTermMemoryWithInterceptor() throws Exception {
        // 1. 创建记忆拦截器
        ModelHook memoryInterceptor = new ModelHook() {
            @Override
            public CompletableFuture<Map<String, Object>> beforeModel(OverAllState state, RunnableConfig config) {
                // 从配置获取用户 ID
                String userId = (String) config.metadata("user_id").get();
                // 从长期记忆加载用户资料
                Optional<StoreItem> profile = memoryStore.getItem(List.of("user_profiles"), userId);
                if (profile.isPresent()) {
                    Map<String, Object> data = profile.get().getValue();
                    // 注入到系统消息
                    String context = String.format("用户信息:姓名=%s, 年龄=%s, 邮箱=%s",
                            data.get("name"), data.get("age"), data.get("email"));
                    // ... 后续逻辑
                }
                return CompletableFuture.completedFuture(state);
            }
        };
    }
    

    目录

    1. 记忆系统概述
    2. 短期记忆实现原理
    3. 核心组件:MemorySaver
    4. 实现机制
    5. 保存检查点
    6. 恢复检查点
    7. 使用示例
    8. 长期记忆实现原理
    9. 核心组件:MemoryStore
    10. 数据模型
    11. 实现机制
    12. 存储数据
    13. 检索数据
    14. 使用示例
    • 💰 8折买阿里云服务器限时8折了解详情
    • Magick API 一键接入全球大模型注册送1000万token查看
    • 🤖 一键搭建Deepseek满血版了解详情
    • 一键打造专属AI 智能体了解详情
    极客日志微信公众号二维码

    微信扫一扫,关注极客日志

    微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

    更多推荐文章

    查看全部
    • LangChain4j Java AI 开发:快速入门与 Hello World
    • AIGC 结合 Photoshop 实现 Spine 2D 骨骼动画拆件工作流
    • 低空无人机车辆目标跟踪技术研究
    • Ant 构建报错“非法字符:\65279”的解决方案
    • Linux 命令行进度条实现原理解析
    • JDK 21 安装与环境配置实战指南
    • FPGA 部署 YOLOv5 算法的一般流程
    • VS Code 前端开发高效插件推荐与配置实战
    • Claude Code 替代方案:OpenCode 搭配 GitHub Copilot
    • GESP C++ 一级考试全流程及编程题核心模板
    • Flutter 底部导航与顶部选项卡实战:状态保持与鸿蒙适配
    • TSDK 淘宝开放平台及登录爬虫 SDK
    • 智能小车快速循迹串级 PID 算法实现
    • Mac mini M4 部署 OpenClaw + Ollama 本地大模型接入飞书机器人
    • Stable Diffusion v1.5 图片生成:主图/Banner/邮件头图
    • Web 自动化测试实战:常用函数全解析与场景化应用指南
    • 双指针算法原理与经典题目解析
    • OpenClaw 101:从零部署与实战指南
    • PostgreSQL 动态分区裁剪技术:查询性能优化解析
    • 世界模型发展脉络整理:理解世界还是预测未来?

    相关免费在线工具

    • Keycode 信息

      查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

    • Escape 与 Native 编解码

      JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

    • JavaScript / HTML 格式化

      使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

    • JavaScript 压缩与混淆

      Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

    • RSA密钥对生成器

      生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

    • Mermaid 预览与可视化编辑

      基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online