ACP大模型应用开发之Memory短期缓冲、滚动压缩与向量召回

栈说明:示例运行在 AgentScope Javaio.agentscope:agentscope)上,模型为 阿里云通义 DashScope。短期记忆用 InMemoryMemory,长期记忆用 Mem0 扩展(Mem0LongTermMemory),上下文压缩可用内置 AutoContextMemory

本文代码:为可独立阅读的 Java 片段;落地单测可参考 module-ai/src/test/java/com/baoma/ai/debug/ 下既有 AgentScope 测试的写法(AgentScopeDashScopeModelsMsg.builder().textContent(...).block())。


前言

Agent 会做事了,但没有跨会话的记忆——关掉窗口、清空上下文就归零,积累的偏好和踩过的坑下次还要重新交代。这节课你将掌握 Agent 的记忆管理策略,从简单遗忘到主动记忆,让 Agent 越用越懂你。

本篇文章内容涉及

  • 建立短期记忆:对话上下文管理与 Token 限制应对
  • 三种记忆管理策略:上下文截断、滚动摘要、向量化召回
  • 从被动上下文到主动记忆管理:Agent 自主决定何时记、何时读
  • 构建短期与长期记忆的混合系统

在本节课程中,你将学习如何为 Agent 赋予记忆能力,解决大语言模型固有的「健忘」问题。你将从一个最朴素的方法开始,逐步发现其局限性,并最终掌握业界主流的短期和长期记忆构建策略。

首先,配置课程所需环境。Java 侧集中封装模型与默认 InMemoryMemory

package com.baoma.ai.debug.support;

import com.baoma.ai.debug.support.AgentScopeDashScopeModels;
import io.agentscope.core.ReActAgent;
import io.agentscope.core.memory.InMemoryMemory;
import io.agentscope.core.memory.Memory;
import io.agentscope.core.model.DashScopeChatModel;
import io.agentscope.core.model.Model;

/** 记忆课程:统一创建带短期记忆的 ReActAgent。 */
public final class MemoryAgentSupport {

    private MemoryAgentSupport() {
    }

    /**
     * 创建课程内容编写 Agent;调用方可覆盖 model / memory / longTermMemory 等。
     */
    public static ReActAgent createWriterAgent(
        String apiKey,
        String modelName,
        String sysPrompt,
        Memory memory) {

        Model model = AgentScopeDashScopeModels.buildDashScopeChatModel(apiKey, modelName);
        Memory mem = memory != null ? memory : new InMemoryMemory();

        return ReActAgent.builder()
            .name("Writer")
            .sysPrompt(sysPrompt)
            .model(model)
            .memory(mem)
            .maxIters(24)
            .build();
    }

    public static ReActAgent createWriterAgent(String apiKey, String modelName, String sysPrompt) {
        return createWriterAgent(apiKey, modelName, sysPrompt, null);
    }
}
// 单测入口示例:校验 API Key 后打印(勿在代码中硬编码 sk-...)
import org.junit.jupiter.api.Assumptions;
import com.baoma.ai.debug.support.AgentScopeDashScopeModels;

String apiKey = AgentScopeDashScopeModels.firstNonBlank(
    System.getenv("DASHSCOPE_API_KEY"),
    System.getenv("AGENTSCOPE_DEBUG_API_KEY")
);
Assumptions.assumeTrue(apiKey != null && !apiKey.isBlank(), "请配置 DASHSCOPE_API_KEY");
System.out.println("API Key 已加载:" + apiKey.substring(0, Math.min(5, apiKey.length())) + "*****");

1 建立短期记忆

在之前的课程中,你正在构建一个能帮你写作课程的 Agent 团队。内容编写 Agent 刚刚完成了一份出色的初稿。你很满意,并对它说:「很好,现在请根据我们上次讨论的教学风格,把第二部分写得更生动一些。」

然而,Agent 的回应却让你失望:「好的,请问我们上次讨论了什么样的教学风格?」——它忘记了过去的任务细节。这是因为你的 Agent 是无状态的。每次开启新的对话,它就会忘记过去对话的所有内容。

扩展阅读:大语言模型的核心特性——无状态 (Stateless)

你可以将大模型想象成一个记忆力只有几秒钟的专家。在每一次独立的 API 调用中,它能理解你给它的所有信息并给出精彩的回答。但一旦这次调用结束,它会彻底忘记一切。它不会记得你是谁,你们之前聊过什么,你的任何偏好和要求。Agent 的每一次 call 本质上都是一次独立的模型请求,因此它天然地继承了这种无状态性。

那我们该如何解决呢?一个最直接的想法,就是每次和它说话时,都把之前的聊天记录「复习」一遍。

在编程实现中,这意味着你需要维护对话历史列表,每次向 Agent 提问时都把完整历史一并格式化进 Prompt。AgentScope Java 中的 InMemoryMemory 就是这种朴素方案的实现:每次 agent.call(msg) 时,Formatter 会把 memory.getMessages() 中的历史与当前消息一起发给模型。

Java:验证短期记忆

import com.baoma.ai.debug.support.MemoryAgentSupport;
import io.agentscope.core.ReActAgent;
import io.agentscope.core.message.Msg;
import java.util.Objects;

String sysPrompt = "你是一个课程内容编写员。你的任务是编写一篇 Pandas 数据分析课程。";
ReActAgent writingAgent = MemoryAgentSupport.createWriterAgent(apiKey, modelName, sysPrompt);

// 第一次对话:设定教学风格
Msg msg1 = Msg.builder().textContent("我们的教学风格要严谨克制,请记住这一点。").build();
System.out.println("[user]: " + msg1.getTextContent());

Msg reply1 = Objects.requireNonNull(writingAgent.call(msg1).block(), "首轮回复为空");
System.out.println("[" + reply1.getName() + "]: " + reply1.getTextContent());

System.out.println("\n" + "=".repeat(20) + "\n");

// 第二次对话:基于之前的设定提出新要求
// writingAgent 会自动将 InMemoryMemory 中的历史与新消息一起发给模型
Msg msg2 = Msg.builder().textContent("很好,现在请把第二部分写得更专业一些。").build();
System.out.println("[user]: " + msg2.getTextContent());

Msg reply2 = Objects.requireNonNull(writingAgent.call(msg2).block(), "次轮回复为空");
System.out.println("[" + reply2.getName() + "]: " + reply2.getTextContent());

System.out.println("\n" + "=".repeat(20) + "\n");
System.out.println("Agent 的短期记忆内容:");
for (Msg m : writingAgent.getMemory().getMessages()) {
    System.out.printf("- [%s] %s: %s%n", m.getRole(), m.getName(), m.getTextContent());
}

这个方案立竿见影,Agent 立刻拥有了当前会话内的短期对话记忆。


2 信息精炼

但当你把这个 Agent 投入真实场景,连续使用十几轮、几十轮对话后,两个严重的问题会浮现出来:

问题 说明
上下文窗口限制 每个大模型都有最大上下文长度;历史像滚雪球一样变大,最终超出窗口,请求失败。
急剧上升的成本 API 按 Token 计费;多轮后每次都要重发全部历史,输入 Token 重复计费。
性能下降 注意力稀释:上下文越长,模型遗忘细节的概率越大。中间迷失:模型更易记住开头与结尾,忽略中间关键信息。

这种朴素的「记忆」方案,只是一种寅吃卯粮的短期策略。它很快就会导致程序异常或成本超支。

这引出了一个核心问题:如何在不牺牲关键信息的前提下,有效管理上下文的长度与成本?

这个问题的本质,是如何对信息进行高效的压缩和筛选。就像你在准备开卷考试时,不会把整本教科书都抄到小抄上,而是会提炼出最重要的公式、定义和关键论点。


3 记忆管理策略

让我们借鉴人类准备考试的思路,探索管理 Agent 记忆的策略。

3.1 策略一:简单「遗忘」—固定窗口截断 (Context Truncation)

最简单粗暴的方法,就是只记最近发生的事,这叫作固定窗口截断

image.png
维度 内容
思路 设定固定窗口:只保留最近 N 轮对话,或最近 N 条消息;超出时丢弃最老的记录。
相对优势 实现简单、开销小,上下文长度可控,避免报错与成本无限增长。
适用场景 信息价值随时间快速衰减:闲聊、简单客服。
边界条件 早期关键信息(如第一轮设定的核心目标)被截断后,Agent 再次「失忆」,对话逻辑断裂。
性能隐患 窗口长期接近上限时,模型仍带着接近极限的长上下文工作,注意力稀释依旧存在。

AgentScope Java 做法

package com.baoma.ai.debug;

import com.baoma.ai.debug.support.MemoryAgentScopeTestSupport;
import com.baoma.ai.debug.support.MemoryAgentSupport;
import com.baoma.ai.debug.support.WindowedInMemoryMemory;
import io.agentscope.core.ReActAgent;
import io.agentscope.core.message.Msg;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.Objects;

class AgentContextTruncationAgentScopeTest {

    private static final int WINDOW_MAX_MESSAGES = 4;

    @Test
    @DisplayName("AgentScope:窗口截断后难以复述最早规则")
    void contextTruncationForgetsEarliestRules() {
        String apiKey = MemoryAgentScopeTestSupport.requireDashScopeApiKey();
        String modelName = MemoryAgentScopeTestSupport.memoryModelName();
        MemoryAgentScopeTestSupport.printApiKeyLoaded(apiKey);

        String truncSysPrompt = """
            你是一个健忘的机器人,你只能记住最近发生的事情。
            用户会逐条给出规则 A/B/C/D;你只能根据当前对话记忆中仍存在的规则作答。
            若记忆中已无某条规则,请明确说「记忆中无该规则」,不要编造。
            """;
        WindowedInMemoryMemory windowed = new WindowedInMemoryMemory(WINDOW_MAX_MESSAGES);
        ReActAgent truncationAgent = MemoryAgentSupport.createWriterAgent(
            apiKey, modelName, truncSysPrompt, windowed);

        callUser(truncationAgent, "规则A:所有回答必须是陈述句。");
        callUser(truncationAgent, "规则B:不能使用「你」或「我」。");
        callUser(truncationAgent, "规则C:回答要尽量简短。");
        callUser(truncationAgent, "规则D:数字必须用大写汉字表示。");

        System.out.println("经过多轮对话后,Memory 中仍保留的消息(窗口上限 "
            + WINDOW_MAX_MESSAGES + " 条):");
        MemoryAgentScopeTestSupport.printMemoryDump(truncationAgent.getMemory().getMessages());

        Assertions.assertTrue(truncationAgent.getMemory().getMessages().size() <= WINDOW_MAX_MESSAGES);

        MemoryAgentScopeTestSupport.printSeparator();
        Msg summaryReply = Objects.requireNonNull(
            truncationAgent.call(Msg.builder().textContent("请总结一下所有规则。").build()).block(),
            "总结回复为空");
        MemoryAgentScopeTestSupport.printAgentMsg(summaryReply);

        boolean memoryMentionsRuleA = truncationAgent.getMemory().getMessages().stream()
            .map(Msg::getTextContent)
            .filter(Objects::nonNull)
            .anyMatch(t -> t.contains("规则A") || t.contains("陈述句"));
        System.out.println("\n[观测] Memory 中是否仍含「规则A」: " + memoryMentionsRuleA);
    }

    private static void callUser(ReActAgent agent, String text) {
        Msg user = Msg.builder().textContent(text).build();
        MemoryAgentScopeTestSupport.printUserMsg(user);
        Msg reply = Objects.requireNonNull(agent.call(user).block(), "Agent 返回为空");
        MemoryAgentScopeTestSupport.printAgentMsg(reply);
        System.out.println();
    }
}

方式 B:生产环境可结合 AutoContextMemory 按 Token 阈值自动压缩,而非单纯丢弃。

3.2 策略二:提炼重点——滚动摘要 (Rolling Summary)

简单截断会直接丢弃信息,显然不够理想。更聪明的做法是:在遗忘细节之前,先把重点提炼出来——这就是滚动摘要策略。

image.png
维度 内容
思路 历史快满时,用模型将最早一段对话压缩成摘要消息,用摘要替换冗长原文。
相对优势 压缩长度的同时保留核心信息,长期连贯性更好;去掉无关上下文可缓解注意力稀释。
适用场景 项目规划、长篇内容创作等需长期保持目标一致的任务。
边界条件 额外 API 调用成本;摘要质量直接影响后续对话。

AgentScope Java 中,同类能力已由扩展模块 AutoContextMemory 提供:按 maxTokentokenRatio 等配置在超限时调用模型做上下文压缩,并可 offload 大段工具输出。

package com.baoma.ai.debug;

import com.baoma.ai.debug.support.AgentScopeDashScopeModels;
import com.baoma.ai.debug.support.MemoryAgentScopeTestSupport;
import io.agentscope.core.ReActAgent;
import io.agentscope.core.memory.autocontext.AutoContextConfig;
import io.agentscope.core.memory.autocontext.AutoContextMemory;
import io.agentscope.core.message.Msg;
import io.agentscope.core.model.Model;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.Objects;

class AgentAutoContextMemoryAgentScopeTest {

    @Test
    @DisplayName("AgentScope:AutoContextMemory 多轮对话后可压缩历史")
    void rollingSummaryWithAutoContextMemory() {
        String apiKey = MemoryAgentScopeTestSupport.requireDashScopeApiKey();
        String modelName = MemoryAgentScopeTestSupport.memoryModelName();
        MemoryAgentScopeTestSupport.printApiKeyLoaded(apiKey);

        Model model = AgentScopeDashScopeModels.buildDashScopeChatModel(apiKey, modelName);

        AutoContextConfig ctxConfig = AutoContextConfig.builder()
            .maxToken(8_000)
            .tokenRatio(0.75)
            .lastKeep(6)
            .msgThreshold(8)
            .build();

        AutoContextMemory summaryMemory = new AutoContextMemory(ctxConfig, model);

        ReActAgent rollingAgent = ReActAgent.builder()
            .name("WriterWithSummary")
            .sysPrompt("你是课程内容编写员。用户会说明教学风格与章节要求;请简洁确认并记住要点。")
            .model(model)
            .memory(summaryMemory)
            .maxIters(24)
            .build();

        callUser(rollingAgent, "我们的教学风格要风趣幽默,请记住。");
        callUser(rollingAgent, "第二章需要增加一个关于成本的案例。");
        callUser(rollingAgent, "第三章要强调 Pandas 的 groupby 用法。");
        callUser(rollingAgent, "请用一句话复述我们约定的教学风格。");

        boolean compressed = summaryMemory.compressIfNeeded();
        System.out.println("compressIfNeeded() 是否触发压缩: " + compressed);
        System.out.println("压缩事件数: " + summaryMemory.getCompressionEvents().size());

        MemoryAgentScopeTestSupport.printSeparator();
        System.out.println("压缩后 Memory 中的消息:");
        MemoryAgentScopeTestSupport.printMemoryDump(summaryMemory.getMessages());

        Assertions.assertFalse(summaryMemory.getMessages().isEmpty());
    }

    private static void callUser(ReActAgent agent, String text) {
        Msg user = Msg.builder().textContent(text).build();
        MemoryAgentScopeTestSupport.printUserMsg(user);
        Msg reply = Objects.requireNonNull(agent.call(user).block(), "Agent 返回为空");
        MemoryAgentScopeTestSupport.printAgentMsg(reply);
        System.out.println();
    }
}

Java 侧由 AutoContextMemory 在压缩流程中写入结构化摘要/压缩事件,可通过 getCompressionEvents() 观测。


3.3 策略三:构建知识库——向量化召回 (Vector-based Retrieval)

前面的策略依然在用一种线性的、无差别的方式处理所有对话历史。但这并不符合人类的记忆模式——记忆更像相互关联的知识网络,而非按时间播放的磁带。

按需检索是构建高级记忆系统的核心:不再试图把所有历史都塞进上下文,而是将每轮对话变成可检索的「记忆碎片」,存入长期记忆库。

image.png

步骤 说明
存储 (Ingestion) 每轮对话结束后,你将对话内容转换成一个数学向量(Embedding)对话内容 Embedding 后连同原文写入向量库(或 Mem0 托管层)。
检索 (Retrieval) 用户提出新问题向量化,你先将这个问题也转换成向量,然后去数据库中进行相似度搜索,找出与当前问题最相关的几条历史对话记录。
组合 (Composition) 将检索到的记忆 + 最新问题组成精简上下文,再调用大模型。
维度 内容
相对优势 摆脱上下文长度硬上限;按当前意图精准「回忆」,可以极大的节约成本。
适用场景 个性化助手、企业知识库、智能学习伴侣等复杂场景。
边界条件 复杂度最高:Embedding、向量库/记忆服务、检索质量调优。

AgentScope Java:Mem0LongTermMemory

AgentScope Java 通过 Mem0LongTermMemoryio.agentscope.core.memory.mem0)集成 Mem0。Java 版通过 Mem0 APIMem0ApiType.PLATFORM 云服务,或 SELF_HOSTED 自建)访问记忆层,无需在单测里本地起 Qdrant。

支持两种工作模式:

Java 枚举 Python 字符串 行为
LongTermMemoryMode.STATIC_CONTROL static_control 每次回复前后自动保存/检索记忆
LongTermMemoryMode.AGENT_CONTROL agent_control Agent 获得 record_to_memory / retrieve_from_memory 工具,自主决定何时记、何时读

Java 单测:Mem0 长期记忆(STATIC_CONTROL + AGENT_CONTROL)

文件module-ai/src/test/java/com/baoma/ai/debug/AgentMem0LongTermMemoryAgentScopeTest.java

内含两个 @Testmem0StaticControlCrossSessionRecall(§3.3)、mem0AgentControlRecordAndRetrieve(§3.4)。

package com.baoma.ai.debug;

import com.baoma.ai.debug.support.AgentScopeDashScopeModels;
import com.baoma.ai.debug.support.MemoryAgentScopeTestSupport;
import io.agentscope.core.ReActAgent;
import io.agentscope.core.memory.InMemoryMemory;
import io.agentscope.core.memory.LongTermMemoryMode;
import io.agentscope.core.memory.mem0.Mem0ApiType;
import io.agentscope.core.memory.mem0.Mem0LongTermMemory;
import io.agentscope.core.message.Msg;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.time.Duration;
import java.util.Objects;

class AgentMem0LongTermMemoryAgentScopeTest {

  @Test
  @DisplayName("AgentScope:Mem0 STATIC_CONTROL 清空短期记忆后仍能回忆进度")
  void mem0StaticControlCrossSessionRecall() {
    String apiKey = MemoryAgentScopeTestSupport.requireDashScopeApiKey();
    MemoryAgentScopeTestSupport.assumeMem0ApiKeyPresent();
    String modelName = MemoryAgentScopeTestSupport.memoryModelName();
    MemoryAgentScopeTestSupport.printApiKeyLoaded(apiKey);

    Mem0LongTermMemory longTermMemory = buildMem0LongTermMemory("LTM_Writer_Static");

    ReActAgent ltmAgentStatic = ReActAgent.builder()
        .name("LTM_Writer_Static")
        .sysPrompt("你是一个拥有长期记忆的课程编写员。请根据已知记忆准确回答用户。")
        .model(AgentScopeDashScopeModels.buildDashScopeChatModel(apiKey, modelName))
        .memory(new InMemoryMemory())
        .longTermMemory(longTermMemory)
        .longTermMemoryMode(LongTermMemoryMode.STATIC_CONTROL)
        .maxIters(24)
        .build();

    Msg msg1 = Msg.builder()
        .textContent("记住,我们正在写一篇 Pandas 数据分析课程,目前已经写完初稿。")
        .build();
    MemoryAgentScopeTestSupport.printUserMsg(msg1);
    Msg reply1 = Objects.requireNonNull(ltmAgentStatic.call(msg1).block(), "首轮回复为空");
    MemoryAgentScopeTestSupport.printAgentMsg(reply1);

    System.out.println("\n" + "=".repeat(20) + " 模拟新的一次会话 " + "=".repeat(20) + "\n");
    ltmAgentStatic.getMemory().clear();
    System.out.println("Agent 的短期记忆已被清空。");

    Msg msg2 = Msg.builder().textContent("我们上次的工作进度到哪儿了?").build();
    MemoryAgentScopeTestSupport.printUserMsg(msg2);
    Msg reply2 = Objects.requireNonNull(ltmAgentStatic.call(msg2).block(), "次轮回复为空");
    MemoryAgentScopeTestSupport.printAgentMsg(reply2);
    Assertions.assertFalse(Objects.requireNonNullElse(reply2.getTextContent(), "").isBlank());
  }

  @Test
  @DisplayName("AgentScope:Mem0 AGENT_CONTROL 主动记录与检索写作风格")
  void mem0AgentControlRecordAndRetrieve() {
    String apiKey = MemoryAgentScopeTestSupport.requireDashScopeApiKey();
    MemoryAgentScopeTestSupport.assumeMem0ApiKeyPresent();
    String modelName = MemoryAgentScopeTestSupport.memoryModelName();
    MemoryAgentScopeTestSupport.printApiKeyLoaded(apiKey);

    Mem0LongTermMemory longTermMemory = buildMem0LongTermMemory("LTM_Writer_Active");

    ReActAgent ltmAgentActive = ReActAgent.builder()
        .name("LTM_Writer_Active")
        .sysPrompt("""
            你是一个拥有主动记忆管理能力的课程编写员。
            你可以使用以下工具来管理你的长期记忆:
            - record_to_memory:将一段重要的信息记录到长期记忆中。
            - retrieve_from_memory:根据查询从长期记忆中检索相关信息。
            在回答问题前,先思考是否需要检索记忆。在对话结束后,思考是否有关键信息需要记录。
            用户说明「核心要求」「请记住」类信息时,应调用 record_to_memory 落库。
            """)
        .model(AgentScopeDashScopeModels.buildDashScopeChatModel(apiKey, modelName))
        .memory(new InMemoryMemory())
        .longTermMemory(longTermMemory)
        .longTermMemoryMode(LongTermMemoryMode.AGENT_CONTROL)
        .maxIters(32)
        .build();

    Msg activeMsg1 = Msg.builder()
        .textContent("课程的写作风格必须非常严谨和学术化,这是一个核心要求。")
        .build();
    MemoryAgentScopeTestSupport.printUserMsg(activeMsg1);
    Msg activeReply1 = Objects.requireNonNull(ltmAgentActive.call(activeMsg1).block(), "首轮回复为空");
    MemoryAgentScopeTestSupport.printAgentMsg(activeReply1);

    System.out.println("\n" + "=".repeat(20) + " 模拟一次新的会话 " + "=".repeat(20) + "\n");
    ltmAgentActive.getMemory().clear();

    Msg activeMsg2 = Msg.builder()
        .textContent("我忘了,我们课程的写作风格是什么来着?")
        .build();
    MemoryAgentScopeTestSupport.printUserMsg(activeMsg2);
    Msg activeReply2 = Objects.requireNonNull(ltmAgentActive.call(activeMsg2).block(), "次轮回复为空");
    MemoryAgentScopeTestSupport.printAgentMsg(activeReply2);
    Assertions.assertFalse(Objects.requireNonNullElse(activeReply2.getTextContent(), "").isBlank());
  }

  private static Mem0LongTermMemory buildMem0LongTermMemory(String agentName) {
    String mem0Key = MemoryAgentScopeTestSupport.mem0ApiKeyOrNull();
    var builder = Mem0LongTermMemory.builder()
        .agentName(agentName)
        .userId("memory-demo-user")
        .apiKey(mem0Key)
        .timeout(Duration.ofSeconds(60));

    String baseUrl = AgentScopeDashScopeModels.firstNonBlank(System.getenv("MEM0_API_BASE_URL"));
    if (baseUrl != null) {
      builder.apiBaseUrl(baseUrl).apiType(Mem0ApiType.SELF_HOSTED);
    } else {
      builder.apiType(Mem0ApiType.PLATFORM);
    }
    return builder.build();
  }
}

3.4 进阶:从被动上下文到主动记忆管理

一个真正智能的 Agent,不应只是被动接收你处理好的上下文,它应该能主动地管理自己的记忆

longTermMemoryMode 设为 AGENT_CONTROL 时,ReActAgent 会暴露 record_to_memoryretrieve_from_memory 工具。实现见上一节单测中的 mem0AgentControlRecordAndRetrieve()

通过这种方式,记忆不再是你从外部「喂」给 Agent 的数据,而是它自己主动获取、存储和维护的内在知识。

扩展阅读:成本效益分析

向量化召回和主动记忆管理引入了 Embedding、向量检索以及额外的工具调用推理,表面上增加了单次调用的成本与时延。

但更公平的比较是:为获得一个「可用」的答案,两条路径的总成本是多少?

路径 描述
路径 A(无长期记忆) 一次调用得到错误/遗忘关键要求的答案 → 用户手动提醒 → 再次调用,总成本翻倍且体验差。
路径 B(有长期记忆) 一次调用(含检索)直接得到可用答案,问题解决。

为记忆系统增加的投入,是确保产出质量、避免重复无效尝试的必要投资


3.5 构建短期与长期记忆系统

通过上述策略的组合,你可以为 Agent 构建完整的记忆系统:

类型 实现要点 职责
短期记忆 InMemoryMemory + 窗口截断 / AutoContextMemory 维持当前会话连贯性,如「第二章要加一个案例」
长期记忆 Mem0LongTermMemory + STATIC_CONTROL / AGENT_CONTROL 跨会话持久化与检索,如「课程面向初学者、风格风趣幽默」

拥有记忆的 Agent,不再是一次性的问答机器;它能从经验中学习,记住偏好,理解长期语境,从「工具」向「伙伴」进化。


落地实践与使用建议

一、快速引入记忆能力

方案 说明
AgentScope Java InMemoryMemory 作基础短期记忆;AutoContextMemory 作上下文压缩;Mem0LongTermMemory 作长期记忆。
Mem0 专为 AI 应用设计的记忆层,封装向量化、冲突处理等;Java 通过 API 接入。
Spring AI ChatMemoryMessageWindowChatMemoryMessageChatMemoryAdvisor 等(见仓库 博客_Spring_AI_对话记忆_ChatMemory_MySQL与Advisor实践.md)。
阿里云百炼 可视化 Agent 流程中可配置长期记忆,适合快速验证。

二、记忆使用建议

  1. 有选择地记忆:低价值噪声会干扰检索;仅在用户显式「请记住…」或重要性高时写入;AGENT_CONTROL 便于让模型自行判断。
  2. 持续治理:定期清理过时条目、合并重复、校验事实;提供用户查看/修改/删除记忆的接口。
  3. 场景化应用:课程文档工作流可能不记录个性化偏好,但 API 参数、功能限制等产品事实值得记录并定期审查。

4 总结

让我们回顾一下你在本节学到的知识:

  • 问题的根源:无状态性 — 大模型每次调用独立;朴素传递完整历史会导致上下文超长与成本失控。
  • 短期记忆 vs 长期记忆 — 用「截断」与「摘要/压缩」管理短期;用「向量化召回 / Mem0」构建长期,实现跨会话存取。
  • 主动记忆管理AGENT_CONTROL 下 Agent 通过 record_to_memoryretrieve_from_memory 主动管理记忆,从被动上下文进化为可学习与成长的智能体。
  • 记忆的最佳实践 — 有选择地写入、持续清理与更新,并按业务场景决定记什么、不记什么。

Java 实现要点(便于对照代码)

能力 Java API
短期缓冲 InMemoryMemorygetMessages() / clear()
固定窗口截断 自定义 WindowedInMemoryMemory 或业务层 deleteMessage(0)
滚动摘要/压缩 AutoContextMemory + AutoContextConfig
长期记忆 Mem0LongTermMemory.builder() + LongTermMemoryMode
多轮调用 ReActAgent.call(Msg).block()(Project Reactor)
模型与 Key AgentScopeDashScopeModels.buildDashScopeChatModel,Key 仅环境变量
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容