Agent Memory:为什么有记忆的 Agent 仍然会忘事?

举报
yd_225949750 发表于 2026/11/05 10:46:21 2026/11/05
【摘要】 从短期上下文到长期记忆,深入理解 AI Agent 的记忆架构、Memory Consolidation 与遗忘机制一、一个奇怪的现象:Agent 明明有记忆,为什么还会反复犯错?假设我们开发了一个 AI 编程 Agent。第一天,用户告诉它:“这个项目统一使用 PostgreSQL,不允许引入 MongoDB。”Agent 理解了要求,顺利完成任务。第二天,用户让它设计一个新的日志分析模块...

从短期上下文到长期记忆,深入理解 AI Agent 的记忆架构、Memory Consolidation 与遗忘机制


一、一个奇怪的现象:Agent 明明有记忆,为什么还会反复犯错?

假设我们开发了一个 AI 编程 Agent。

第一天,用户告诉它:

“这个项目统一使用 PostgreSQL,不允许引入 MongoDB。”

Agent 理解了要求,顺利完成任务。

第二天,用户让它设计一个新的日志分析模块。

Agent 却给出了一套基于 MongoDB 的技术方案。

用户提醒:

“我昨天已经说过,这个项目不能使用 MongoDB。”

Agent 回答:

“抱歉,我忘记了。”

我们可能会觉得,这只是因为模型没有长期记忆。

于是给 Agent 增加一个 Memory 模块,把用户的要求保存到向量数据库。

问题似乎解决了。

但过了一段时间,新的问题出现了。

用户已经决定将项目从 PostgreSQL 迁移到 MySQL,Agent 却仍然反复推荐 PostgreSQL。

这次它并没有忘记,而是记住了错误的旧信息。

于是我们发现:

Agent 的问题不只是不会记忆,还包括不知道什么值得记、什么时候应该更新,以及什么时候必须忘记。

这正是 Agent Memory Engineering 要解决的核心问题。

上一篇文章讨论了 Context Engineering:如何让模型在当前推理中获得正确的信息。

今天我们进一步讨论:

当任务跨越多个会话、多个小时甚至多个星期时,Agent 怎样持续积累有用的信息,同时避免记忆污染?


二、什么是 Agent Memory?

很多开发者会把 Memory 理解为:

“把历史聊天记录存到数据库里,下次再查出来。”

这种方案确实能提供基本的历史检索能力,但距离完整的 Agent Memory 还很远。

我们可以把 Agent Memory 定义为:

Agent Memory 是一套对历史信息进行提取、组织、持久化、检索、更新和遗忘的机制,让 Agent 能够跨越当前上下文窗口,持续利用过去的知识与经验。

注意,这个定义包含六个动作:

  1. Extract:从交互和执行结果中提取值得保存的信息。

  2. Organize:对记忆进行分类和结构化。

  3. Store:将记忆持久化保存。

  4. Retrieve:根据当前任务检索相关记忆。

  5. Update:当信息变化时修正已有记忆。

  6. Forget:删除过期、错误或不再需要的记忆。

如果只实现 Store 和 Retrieve,得到的通常只是一个历史信息检索系统。

要真正提高 Agent 的长期可靠性,必须管理记忆的完整生命周期。

Agent Memory 的基本架构

                用户与环境
                    │
                    ▼
               Agent Runtime
                    │
          ┌─────────┴─────────┐
          │                   │
          ▼                   ▼
    当前上下文             Memory Manager
          │                   │
          │          ┌────────┴─────────┐
          │          │                  │
          │          ▼                  ▼
          │     Memory Writer      Memory Retriever
          │          │                  │
          │          ▼                  │
          │    Validation Layer         │
          │          │                  │
          │          ▼                  │
          │     Memory Store ───────────┘
          │                   │
          ◄───────────────────┘
          │
          ▼
         LLM
          │
          ▼
      Tools / Actions

这里有一个很重要的设计原则:

Memory Store 不应该直接等于模型的全部历史上下文。

记忆需要根据当前任务动态检索、筛选,再进入 Context。

Memory 决定保存什么,Context Engineering 决定当前使用什么,Harness 决定如何执行。


三、Agent 到底需要哪些记忆?

在现代 Agent 架构中,一个很有用的分类来自认知科学。

LangGraph 的官方文档借鉴了人类记忆的分类方式,将长期记忆划分为:

  • Semantic Memory:语义记忆。

  • Episodic Memory:情景记忆。

  • Procedural Memory:程序性记忆。

此外,工程上还需要区分短期记忆与长期记忆的作用范围。

1. Short-term Memory:短期记忆

短期记忆主要保存当前会话和任务执行状态。

例如:

用户正在让 Agent 修复一个 Bug。

Agent 需要记住:

  • 当前任务是什么。

  • 已经检查了哪些文件。

  • 修改过哪些代码。

  • 上一次测试为什么失败。

  • 下一步计划做什么。

这些信息对于当前任务非常重要,但不一定适合永久保存。

LangGraph 把这类记忆与 Thread State 联系起来,通过 Checkpointer 保存执行状态,让任务能够在同一个线程中恢复。

这里需要区分:

保存当前执行状态,不等于建立了长期知识记忆。

Checkpoint 更侧重恢复当前任务;长期记忆则侧重让未来任务利用过去的信息。

2. Semantic Memory:语义记忆

语义记忆保存相对稳定的事实、知识和偏好。

例如:

{
  "type": "semantic",
  "scope": "project:order-service",
  "key": "primary_database",
  "value": "PostgreSQL",
  "source": "architecture_decision",
  "status": "active"
}

它可以帮助 Agent 在未来设计系统时遵守已有架构约束。

但要注意,语义记忆并不意味着永远正确。

项目架构、用户偏好、组织结构和业务规则都可能改变。

因此,语义记忆应该支持来源追踪、版本管理和更新。

3. Episodic Memory:情景记忆

情景记忆保存的是过去发生过的事情。

例如:

“上次执行数据库迁移时,由于未处理空值字段,导致迁移脚本失败。”

这条记忆的价值不在于描述当前系统状态,而在于帮助 Agent 避免重复失败。

一个完整的情景记忆通常包含:

任务:执行数据库迁移

尝试:
直接修改字段约束

结果:
迁移失败

原因:
历史数据存在空值

有效解决方案:
先清理历史数据,再执行约束迁移

验证结果:
迁移测试通过

这类记忆对 Coding Agent、自动化运维 Agent 和长期研究 Agent 非常有价值。

但是,过去一次成功并不意味着方法可以无条件迁移到所有任务。

情景记忆应该附带适用条件。

4. Procedural Memory:程序性记忆

程序性记忆保存的是如何执行任务的知识。

例如:

“在这个项目中,修改API之前必须更新Schema,完成后执行集成测试。”

它更像执行规范、操作流程或技能。

在 Coding Agent 中,这类知识可能体现在:

  • AGENTS.md

  • CLAUDE.md

  • 项目 Skills

  • 团队开发规范

  • 测试与部署流程

需要特别注意:程序性记忆并不应该允许 Agent 随意修改系统最高优先级的安全规则。

用户偏好可以更新,项目工作流程可以根据权限修改,但系统安全边界必须独立控制。

四类记忆的对比

记忆类型 保存什么 生命周期 典型用途
短期记忆 当前对话和任务状态 会话或任务级 任务恢复
语义记忆 事实、偏好、约束 跨会话 个性化与知识复用
情景记忆 历史行动与结果 跨任务 从过去成功和失败中学习
程序性记忆 工作方法与规则 长期、可版本化 执行规范与技能复用

一个成熟的 Agent 通常不是选择其中一种,而是根据任务组合使用。


四、Memory、RAG 和 Context Compaction 到底有什么区别?

这是 Agent 开发中非常容易混淆的三个概念。

RAG:从外部获取知识

例如:

用户问:“公司的最新报销政策是什么?”

Agent 从知识库中检索官方制度。

这里主要解决的是外部知识获取问题。

Memory:保存过去的经验和事实

例如:

用户之前已经告诉 Agent:

“我所在部门使用研发中心的差旅审批流程。”

下次处理相关任务时,Agent 可以取回这条偏好或业务上下文。

Context Compaction:压缩当前执行历史

例如:

Agent 已经执行了100轮工具调用,上下文接近窗口上限。

它可以将冗余的日志和历史消息压缩为一份结构化任务摘要,然后继续执行。

三者之间存在重要区别。

技术 核心问题 主要数据来源 是否天然跨会话
RAG 当前缺少什么知识? 外部文档与知识库 不一定
Memory 过去有哪些信息值得复用? 历史交互与执行经验 是其主要目标
Compaction 当前上下文太长怎么办? 当前任务上下文 否,除非另行持久化
Tool-result Clearing 哪些旧工具输出不必继续占用窗口? 可重新读取的工具结果 否

Anthropic 在2026年3月发表的工程实践中,专门比较了 Memory、Compaction 和 Tool-result Clearing。

其核心结论是:这三种技术解决的不是同一个问题,需要根据上下文膨胀、长期任务和跨会话记忆的实际需求组合使用。

OpenAI 的《Building Reliable Agents with Memory and Compaction》也通过合规证据分析 Agent 展示了一个类似思路:

Compaction 负责当前运行的延续,Memory 让后续运行复用过去的工作经验,而最终产出的、经过人工审查的文档仍是事实依据。

这说明一个重要问题:

Memory 不应该取代原始事实来源。

Agent 可以记住之前的分析结论,但当涉及金融数据、法律条文、软件版本或最新政策时,仍然应当重新核实权威来源。


五、记忆系统真正困难的地方:不是存储,而是写入

假设一个 Agent 每天和用户交互100次。

它应该保存多少条记忆?

如果把所有对话都存下来,数据会越来越多。

但大量信息可能只有一次性价值。

例如:

“今天下午帮我检查一个文件。”

这个任务可能不需要形成长期记忆。

而下面的信息可能很重要:

“以后这个项目的所有API都要使用OpenAPI规范。”

问题来了:

Agent 如何判断一条信息是否值得保存?

我建议采用 Memory Write Policy。

一个简单的记忆写入判断模型

每条候选记忆都从以下维度评估:

持久性: 这条信息未来还会有效吗?

复用价值: 未来任务是否可能需要它?

可信程度: 信息来自用户明确声明、已验证数据,还是模型自己的猜测?

敏感程度: 是否涉及个人隐私或金融、健康等敏感数据?

变化频率: 这条信息是否可能很快失效?

例如:

信息 是否建议长期保存 原因
项目使用PostgreSQL 建议 长期架构约束
用户喜欢简洁的技术报告 视授权和使用需要 可复用偏好
今天北京下雨 通常不建议 时效性短
上次部署失败原因 建议保留结构化经验 可避免重复错误
用户的一次性验证码 禁止保存 高敏感、无长期价值
模型推测的用户身份 不应作为事实保存 缺少可靠依据

最重要的是:

不是所有用户说过的话,都应该变成永久记忆。

长期记忆的写入应该受到隐私策略、数据最小化原则和用户控制机制约束。


六、Memory Consolidation:为什么 Agent 需要整理记忆?

如果只是不断追加记忆,系统迟早会出现三个问题。

第一,重复记忆。

例如:

用户偏好Python
用户习惯使用Python
用户喜欢用Python开发后端

这三条信息可能表达相近的含义。

第二,冲突记忆。

2025年:项目使用PostgreSQL
2026年:项目已经迁移到MySQL

第三,过期记忆。

当前项目版本为1.2

一年之后,项目可能已经升级到3.0。

这就需要 Memory Consolidation,即记忆巩固和整理。

它主要完成:

  • 合并重复信息。

  • 从多次事件中提取稳定模式。

  • 发现互相冲突的记忆。

  • 更新已经失效的事实。

  • 将重要经验转化为可复用的知识。

  • 降低长期记忆检索的噪声。

可以把这一过程理解为:

        历史对话与任务执行
                 │
                 ▼
           候选记忆提取
                 │
                 ▼
             可信度校验
                 │
                 ▼
         重复与冲突检测
                 │
        ┌────────┼────────┐
        ▼        ▼        ▼
       新增      合并      替换
        │        │        │
        └────────┼────────┘
                 ▼
             Memory Store
                 │
                 ▼
         周期性复核与清理

Letta 的实践值得关注

Letta 延续了 MemGPT 对分层记忆的研究方向,让 Agent 能够管理可持久化的记忆内容。

其当前文档还介绍了基于记忆文件系统的管理方式,以及 Dreaming:通过后台任务分析已有对话,整理长期有价值的知识。

这里的 Dreaming 并不意味着模型真的像人类一样做梦。

它本质上是一种异步记忆维护流程。

不过,自动整理记忆存在一个风险:

如果 Agent 把错误推断反复写入并强化,记忆可能越来越自洽,却越来越偏离事实。

因此,Memory Consolidation 需要来源追踪和冲突处理,不能仅靠语言模型给自己生成总结。


七、Agent 应该如何遗忘?

这一节可能比“如何记忆”更重要。

传统数据库系统通常追求持久保存。

但 Agent Memory 不应该默认永久保留所有信息。

原因有三个。

1. 事实会过期

例如:

“公司现在使用 Kubernetes 1.30。”

几年之后,这条记忆可能不再准确。

2. 用户偏好会改变

例如:

用户以前喜欢详细回答,现在更喜欢精简结论。

Agent 不应该因为旧记忆而忽视新的明确要求。

3. 不必要的记忆会增加风险

个人信息、任务临时数据和敏感业务资料,保存得越久,潜在的隐私和安全成本越高。

因此,建议设计明确的 Memory Lifecycle。

Created
   │
   ▼
Active
   │
   ├────► Updated
   │
   ├────► Superseded
   │
   ├────► Expired
   │
   └────► Deleted

其中 Superseded 表示已被新事实取代。

Expired 表示超出有效期,需要重新验证。

Deleted 表示依据用户请求、保留策略或其他合法要求删除。

对于个人敏感信息,除了从当前数据库删除,还需要考虑索引、缓存、备份和日志中的副本。

“模型不再检索这条记忆”和“数据已经被彻底删除”不是同一件事。

给 Memory 增加时间维度

记忆不应该只有 Value。

建议至少保存:

{
  "id": "project-db-001",
  "scope": "project:order-service",
  "type": "semantic",
  "key": "primary_database",
  "value": "MySQL",
  "source": "architecture-decision-2026",
  "observed_at": "2026-10-20T10:00:00Z",
  "valid_until": null,
  "status": "active",
  "supersedes": "project-db-000"
}

这样,当 Agent 检索数据库技术栈时,就可以优先读取当前有效版本,而不是随机召回一条旧信息。


八、如何设计一个生产级 Memory Architecture?

我建议采用分层结构,而不是一开始就依赖向量数据库存储所有内容。

第一层:Session State

保存当前对话、工具执行和任务状态。

适合使用 LangGraph Checkpointer 或关系数据库实现。

第二层:Structured Memory

保存明确的用户偏好、项目约束、业务事实和任务经验。

建议使用 PostgreSQL 等关系数据库。

第三层:Semantic Retrieval

当记忆数量较多时,再引入向量检索。

例如 pgvector、Qdrant 或其他向量数据库。

向量检索适合语义相近内容的召回,但不能直接解决版本冲突、权限控制和事实有效性问题。

第四层:Memory Manager

负责:

  • 记忆提取。

  • 来源验证。

  • 去重与冲突检测。

  • 生命周期管理。

  • 记忆检索与排序。

  • 用户授权和删除。

推荐架构

                  User
                   │
                   ▼
             Agent Harness
                   │
         ┌─────────┴─────────┐
         ▼                   ▼
    Context Manager      Memory Manager
         │                   │
         │           ┌───────┼────────┐
         │           ▼       ▼        ▼
         │         Write   Retrieve  Consolidate
         │           │       │        │
         │           └───────┼────────┘
         │                   │
         │           ┌───────┴────────┐
         │           ▼                ▼
         │       PostgreSQL       Vector Index
         │           │                │
         │           └───────┬────────┘
         │                   │
         ◄───────────────────┘
         │
         ▼
        LLM
         │
         ▼
    Tools / Actions

这里我特别建议增加 Namespace,也就是记忆作用域。

例如:

user:123
project:order-service
team:backend
agent:coding-assistant

不同用户和项目的记忆不能混用。

即使向量检索结果高度相关,也必须先执行租户和权限过滤。

相关性不能取代授权。


九、动手实现:一个支持更新和过期的最小 Memory Store

下面我们不依赖复杂Agent框架,仅使用Python标准库中的SQLite,构建一个最小的结构化记忆系统。

它支持:

  • 保存记忆。

  • 按作用域隔离。

  • 更新旧记忆。

  • 设定有效期。

  • 查询当前有效信息。

这段代码可以直接运行。

import sqlite3
import time
from datetime import datetime, timezone

class MemoryStore:
    def __init__(self, db_path="memory.db"):
        self.db = sqlite3.connect(db_path)
        self.db.execute("""
            CREATE TABLE IF NOT EXISTS memories (
                scope TEXT NOT NULL,
                key TEXT NOT NULL,
                value TEXT NOT NULL,
                source TEXT NOT NULL,
                updated_at REAL NOT NULL,
                expires_at REAL,
                PRIMARY KEY (scope, key)
            )
        """)
        self.db.commit()

    def remember(
        self, scope, key, value,
        source="user", ttl_seconds=None
    ):
        now = time.time()
        expires_at = (
            now + ttl_seconds
            if ttl_seconds is not None
            else None
        )

        self.db.execute("""
            INSERT INTO memories
            (scope, key, value, source,
             updated_at, expires_at)
            VALUES (?, ?, ?, ?, ?, ?)
            ON CONFLICT(scope, key)
            DO UPDATE SET
                value=excluded.value,
                source=excluded.source,
                updated_at=excluded.updated_at,
                expires_at=excluded.expires_at
        """, (
            scope, key, value, source,
            now, expires_at
        ))
        self.db.commit()

    def recall(self, scope):
        now = time.time()

        cursor = self.db.execute("""
            SELECT key, value, source
            FROM memories
            WHERE scope=?
              AND (
                  expires_at IS NULL
                  OR expires_at > ?
              )
            ORDER BY updated_at DESC
        """, (scope, now))

        return [
            {
                "key": row[0],
                "value": row[1],
                "source": row[2]
            }
            for row in cursor.fetchall()
        ]

    def forget(self, scope, key):
        self.db.execute("""
            DELETE FROM memories
            WHERE scope=? AND key=?
        """, (scope, key))
        self.db.commit()

    def close(self):
        self.db.close()


if __name__ == "__main__":
    store = MemoryStore(":memory:")

    store.remember(
        scope="project:order-service",
        key="primary_database",
        value="PostgreSQL",
        source="architecture-doc-v1"
    )

    # 项目发生架构迁移
    store.remember(
        scope="project:order-service",
        key="primary_database",
        value="MySQL",
        source="architecture-doc-v2"
    )

    print(store.recall("project:order-service"))

    store.close()

预期输出:

[
    {
        "key": "primary_database",
        "value": "MySQL",
        "source": "architecture-doc-v2"
    }
]

虽然代码不复杂,但已经体现了一个非常关键的思想:

长期记忆应该可以被更新,而不是无限追加。

不过,这只是一个教学示例。

它采用 Key-Value 结构,直接覆盖旧版本,因此不保留完整历史。

实际项目还需要:

  • 版本表与审计日志。

  • 来源真实性验证。

  • 写入权限与用户授权。

  • 冲突审批机制。

  • 敏感信息加密。

  • 租户隔离。

  • 备份数据保留策略。

  • 并发更新控制。

  • 语义检索。

  • 记忆质量评测。

另外,生产系统不能仅根据更新时间就自动认为一条新信息更可信。

例如,来自不可信网页的新信息,不能直接覆盖经过人工确认的项目架构规范。


十、什么时候应该让 Agent 自动写入记忆?

Memory Write 有两种典型方式。

Hot Path:在任务执行过程中写入

Agent 在当前任务中发现重要信息,立即更新记忆。

优点是信息可以马上被后续步骤利用。

缺点是可能增加延迟,也可能把尚未验证的中间推断写入长期存储。

例如:

Agent 调查服务故障,初步怀疑数据库连接池。

如果它立即把“数据库连接池有问题”写成长期事实,后续即使发现根因是网络故障,也可能留下错误记忆。

Background Consolidation:任务完成后整理

另一种方式是在任务结束后,根据已经验证的结果提取记忆。

例如:

任务执行
   ↓
测试验证
   ↓
生成任务总结
   ↓
筛选可复用经验
   ↓
校验来源
   ↓
写入长期记忆

这种方式可以降低把中间假设保存为事实的风险。

对于个人助手,可以根据用户授权在交互后整理偏好和长期计划。

对于 Coding Agent,则可以在测试通过、代码合并或任务验收后提取工程经验。

我更推荐:

任务中的临时发现保存在 Task State;经过验证、确实具有长期价值的信息,再进入 Long-term Memory。

对于高风险领域,关键记忆更新应该增加人工确认。


十一、如何证明 Memory 真的提高了 Agent 能力?

给 Agent 添加一个向量数据库,并不意味着 Agent 一定变得更好。

Memory 可能提高成功率,也可能引入错误和延迟。

因此,需要专门设计 Memory Evals。

我建议重点评测六个指标。

指标 关注的问题
Memory Recall 该记住的信息是否能找到?
Memory Precision 找到的信息是否真正相关?
Staleness Rate 使用了多少过期记忆?
Conflict Resolution 新旧事实冲突时是否正确处理?
Task Success Rate 记忆是否真正改善任务完成率?
Privacy Compliance 是否错误保存或泄露敏感信息?

例如,可以设计一组连续任务。

任务一: 用户指定项目采用PostgreSQL。

任务二: 在新会话中设计数据库模块。

任务三: 用户明确变更为MySQL。

任务四: 再次设计数据库模块。

任务五: 要求 Agent 删除这一项目记忆。

系统应该能够:

  1. 正确保存初始约束。

  2. 在第二次任务中使用正确的约束。

  3. 在约束改变后更新记忆。

  4. 不继续使用已经失效的信息。

  5. 在删除后停止检索该信息,并按数据保留策略处理存储副本。

还应该设置对照组:

A:没有长期记忆的Agent。

B:直接检索完整历史对话的Agent。

C:使用结构化记忆、来源验证和生命周期管理的Agent。

在相同模型、相同任务与工具配置下比较最终任务结果。

这比仅仅观察“Agent能

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。