Skip to content
Zegging's Tech Blog
Go back

Agent Memory 到底在解决什么问题?

和 Agent 相关的知识传递,一直是一个问题。

模型作为 Agent 的核心引擎,在预训练和后训练结束之后,它自身掌握的知识也就被固化在了模型权重中。所谓固化,是指仅凭已经确定的模型权重,它不可能知道未来全新出现的新概念、新单词、新故事或者新事件。

但大语言模型的应用场景非常多样,它们遇到的问题也往往非常细分。在一家电商企业的某个落地场景中,可能存在 A、B、C、D 这样一套专有概念;在艺术创作和文本工作中,可能存在 E、F、G 这样的另一套概念;回到 Coding 领域,又会有属于某个项目、团队或者开发环境的知识。这些细分知识往往没有在互联网上公开流传。相关语料掌握在企业或者个人手中,模型在预训练和后训练阶段没有办法接触到它们。模型虽然具有很强的泛化能力,但这种泛化不能让它凭空、准确地理解某个企业、项目或者用户特有的知识。

那么,模型应该怎样获取训练结束以后才产生,或者训练期间根本无法接触到的知识?

从 Prompt Engineering 到 Agentic Retrieval

这件事可以从 Prompt Engineering 的阶段讲起,最早的一类解决方案是 Retrieval:从数据库、向量存储或者其他数据源中召回与当前问题相关的知识,再把这些内容预先填充到与模型对话的 Prompt 中。我们预先判断模型在回答某个问题时需要哪些信息,然后主动检索并注入这些信息。从使用者的视角来看,模型就像突然获得了原本并不知道的知识,从而能够完成作答。在客服系统中,我们可以向模型提供操作手册、订单信息和客户信息,让它回答业务问题、指导用户操作,或者处理某个具体订单。这是一种由应用主动注入知识的方式:我们判断模型需要什么,提前把相关信息放进 Prompt,再通过这些信息改善整个工作流或者产品的表现。这也是 Prompt Engineering 阶段非常典型的一类工作。

到了 Agent 模式,知识获取的方式又发生了变化。后训练增强了模型调用工具的能力,推理阶段的受约束输出和结构化输出又进一步提高了工具调用的可靠性。模型因此可以主动探索外部知识,而不再只能被动接受应用预先放进 Prompt 的内容。这种模式可以称为 Agentic Retrieval。

以前,是应用提前完成检索,把召回的数据直接写进 Prompt;现在,我们可以向模型提供一个 Retrieval Tool,由模型自己判断什么时候需要调用、应该搜索什么,以及如何根据搜索结果继续行动。模型可以向工具输入自然语言或者关键词,也可以通过标签、元数据和其他过滤条件缩小范围。底层既可以使用全文检索,也可以使用向量数据库。关键的变化在于:检索不再完全由预先编排好的工作流决定,而是成为了 Agent 推理和行动过程的一部分。

Skill 是另一种知识组织和分发方式

但很多知识并不只是一段能够被单独召回的文本。它们可能是系统化、结构化、上下文完整,并且具有逻辑链条的领域知识。对于这类知识,出现了 Skill 这样的组织方式。一个 Skill 本质上是一个文件夹。里面既可以包含 Skill 本身的说明,也可以包含相关脚本、参考文档和其他资源。对模型来说,它的核心仍然是一个能够被发现并按需加载的知识单元:Agent 发现这个 Skill,主动读取其中的内容,获得完成当前任务需要的信息和操作方法。

这在企业和细分领域的落地场景中很有用。企业可以把自己的领域概念、工作流程和操作细节制作成 Skill。即使模型在训练阶段从未接触过这些知识,它也可以依靠自身的泛化能力,在读取 Skill 以后理解相关概念,并按照其中描述的方法继续完成任务。这些知识也需要被组织和分发。企业可能需要集中管理自己的 Skills;Agent 在部署或者运行时获取最新版本,再根据其中的知识处理问题。GitHub 上也已经存在很多 Skill 仓库,用户可以通过工具安装或者更新其中的 Skills。

回头来看,从 Prompt Engineering 阶段的上下文注入,到 Agentic Retrieval,再到 Skill,我们一直在解决同一个问题:

模型如何获取自身权重之外的信息,并把这些信息用于当前任务?

flowchart TB
    accTitle: 权重之外的知识如何进入 Agent
    accDescr: 模型训练结束后,外部知识可以由应用注入 Prompt,也可以由 Agent 主动检索、按需加载 Skill,或者从持续更新的 Memory 中读取。

    weights["模型训练完成<br/>通用知识固化在权重中"]
    outside["训练后出现、训练时不可见的知识<br/>企业概念 · 项目事实 · 用户环境 · 任务经验"]

    subgraph paths["权重之外的四条知识路径"]
        prompt["Prompt Engineering<br/>应用预先判断并注入"]
        retrieval["Agentic Retrieval<br/>Agent 决定何时检索、检索什么"]
        skill["Skill<br/>领域知识、流程、脚本与资料"]
        memory["Memory<br/>偏好、环境与任务经验"]
    end

    agent(["当前任务中的 Agent"])

    weights -->|"已有能力"| agent
    outside --> prompt
    outside --> retrieval
    outside --> skill
    outside --> memory
    prompt -->|"被动接收"| agent
    retrieval -->|"主动探索"| agent
    skill -->|"按需加载"| agent
    memory <-->|"读取与更新"| agent

这几种机制并不是简单的替代关系。变化主要发生在两个维度:一是由谁决定需要什么信息,控制权逐渐从应用预编排转向 Agent 自主判断;二是信息以什么粒度被组织,从一次检索返回的片段,扩展到结构化的知识包和使用过程中持续积累的经验。

从 Skill 到用户自己的 Memory

随着 Agent 继续演化,我们又会遇到另一类信息。它们不能准确地称为 Skill,却与 Skill 面临相似的组织和传递问题。例如用户自己的偏好、操作习惯和本地设备信息。仍然以软件工程为例,有些用户在 Windows 上开发,有些使用 macOS,还有一些使用 Linux。不同用户的本地环境也可能完全不同:有人使用 VPN,有人使用特殊的 Linux 发行版;有人依赖某个特定版本的软件;有人使用 NVIDIA GPU,另一些人使用 AMD GPU。这些信息与项目本身没有直接关系,也不是项目成员共同拥有的知识。它们只与某个用户有关,却会直接影响 Agent 如何完成任务,因此同样非常重要。而且,这些信息通常不是预先整理好的。它们是在用户持续使用 Agent、与 Agent 沟通并共同完成任务的过程中逐渐被发现的,也需要随着用户和环境的变化不断更新。

于是出现了 MEMORY.md 这样的组织形式。它本质上仍然只是一个文本文件。不同之处在于,Agent 的运行规则会明确告诉它这个文件的存在,并要求它在合适的时候主动读取和更新其中的信息。这样,用户偏好、本地环境和过去任务中发现的细节,就能够跨越不同 Session 被后续的 Agent 再次获取。

多 Agent 协作中的经验孤岛

当多个 Agent 开始协作时,这个问题会变得更加明显。我使用 Raft 组织过一个多 Agent 团队。在同一个团队中,不同 Agent 扮演不同角色。它们部署在不同机器上,有各自的 workspace、文件、Memory 和工具,甚至各自掌握的 Skills 也完全不同。它们的一种协作方式是:Agent A 处理某个任务并获得了一条经验。后来 Agent B 在同一个公共频道中遇到了相似的问题,如果 B 主动提出问题,A 可能会把自己的经验告诉它;或者 A 看到 B 接手了相关任务,主动提醒 B 注意这个问题。

这种协作可以生效,但它依赖一次偶然发生的交流。如果 Agent A 没有看到那个任务,Agent B 没有在公共频道中提问,或者它们根本不在同一个 Channel,A 在过去任务中获得的经验就会被困在自己的 Session 里。除非有人明确要求 A 把经验整理成 Skill,提交到 Skill 仓库,再要求其他 Agent 安装或者更新这个 Skill,否则其他 Agent 完全无法获得这条信息。

这里隐含着一个非常重要的问题:有些信息的发现和总结是有成本的。

它可能消耗时间和 Token,可能需要准备特殊环境、运行实验,也可能让整个协作流程停顿。Agent A 已经为获得一条信息支付了这些成本,但这条信息没有被良好地分发下去。未来的 Agent 仍然需要再次支付同样的成本。比如,一个实验需要运行三十分钟以后才能暴露问题。Agent A 在执行任务时已经运行过这个实验,发现了问题并找到了解法。Agent B 后来执行相似任务时,如果不知道这段经历,就仍然要再等三十分钟,才能发现并解决同一个问题。

Agent B 需要这条信息,却无法以足够低的成本获得它。

flowchart TB
    accTitle: 多 Agent 协作中的经验孤岛
    accDescr: 没有共享机制时,Agent A 付出成本得到的经验无法到达 Agent B 和 C,它们会重复探索;共享 Memory 让其他 Agent 可以检索、验证和复用经验。

    subgraph isolated["经验没有被分发"]
        direction LR
        a1["Agent A<br/>实验 30 分钟"] -->|"首次支付成本"| finding["问题与解法<br/>只留在 A 的 Session"]
        finding -. "经验不可达" .-> b1["Agent B<br/>重新实验 30 分钟"]
        b1 --> c1["Agent C<br/>再次重新探索"]
    end

    subgraph connected["经验可以被发现"]
        direction LR
        a2["Agent A<br/>完成实验"] -->|"保存经验"| shared[("共享 Memory<br/>证据 · 适用范围 · 更新时间")]
        shared -->|"检索、验证、复用"| b2["Agent B"]
        shared -->|"检索、验证、复用"| c2["Agent C"]
    end

    finding -. "建立共享与检索机制" .-> a2

真正缺失的并不只是一块共享存储,而是一条从“经验产生”到“未来 Agent 能够发现、理解并验证”的完整路径。只把所有内容集中保存起来,并不会自动消除孤岛;如果检索成本太高、适用范围不清楚,或者无法确认信息是否仍然有效,未来的 Agent 仍然可能选择重新探索。

真正的问题是经验和信息的孤岛

这和人类社会中的知识传播很相似。一个人可能拥有一段记忆、一个观点、一种解法,或者对某个问题的独特认识。但只要他没有把它写下来、发表出来或者告诉别人,世界上的其他人就不知道这条信息存在。更麻烦的是,因为其他人根本不知道某个地方已经存在一种解法,他们甚至不会主动去问。所以问题不只是信息有没有被保存,而是分散在不同 Agent、Session、设备和 workspace 中的经验形成了孤岛。它们没有被串联起来,也就无法进入未来 Agent 的决策过程。

我认为,这才是根本的问题:

是否存在大量昂贵、重复,并且原本可以通过过去的信息或者证据避免的探索?

如果存在,那么一段过去经验的价值至少需要满足几个条件:

  1. 未来仍然会遇到相似的决策;
  2. 相关信息不能从代码、文档、环境或者普通搜索中低成本获取;
  3. 未来的 Agent 能够发现这条信息,而不需要预先知道谁拥有它;
  4. 这条信息能够在当前环境中被理解和验证;
  5. 使用它所节省的成本,高于保存、分发、检索和验证它的成本。

Memory 的价值不是保存了多少内容,而是它究竟避免了多少原本会再次发生的探索。

flowchart TD
    accTitle: 一条经验是否值得进入 Memory
    accDescr: 依次判断未来是否会有相似决策、信息能否低成本重新获得、是否可以验证,以及节省的重复探索成本是否高于保存和使用成本。

    start(["得到一条任务经验或证据"]) --> recurring{"未来还会遇到<br/>相似决策吗?"}
    recurring -->|"否"| noLong(["不进入长期 Memory"])
    recurring -->|"是"| cheap{"能从代码、文档、环境或普通搜索中<br/>低成本重新获得吗?"}
    cheap -->|"是"| source(["留在原始信息源<br/>需要时直接检索"])
    cheap -->|"否"| verifiable{"能说明适用范围、证据和更新时间,<br/>并允许未来 Agent 验证吗?"}
    verifiable -->|"否"| qualify(["先补充证据或限定条件"])
    verifiable -->|"是"| saving["估算节省的<br/>重复探索成本"]
    saving --> upkeep["估算保存 + 分发 + 检索 + 验证成本"]
    upkeep --> positive{"节省的成本更高吗?"}
    positive -->|"是"| remember(["保存为可发现、可验证的 Memory"])
    positive -->|"否"| trace(["不保存,或只保留原始 Trace"])

因此,并不是每一条任务记录都值得被提升为 Memory。能够从代码和文档中便宜地重新获取的信息,应该继续留在它原本的事实来源中;只有那些会重复影响决策、重新发现代价较高,并且可以被限定和验证的信息,才更可能产生正收益。

从这个角度看,Memory、Skill 甚至模型训练,背后都有某种相似的东西:它们都在尝试把过去获得的信息压缩、组织起来,再让未来的执行者能够使用。模型权重是对训练数据的压缩,Skill 是对领域知识和操作流程的组织,Memory 则试图保存 Agent 在运行过程中获得的信息。

本地的 MEMORY.md 可能已经完全够用

虽然问题确实存在,但它并不天然需要一个复杂的 Memory System。

如果一个 Agent 长期在同一个 workspace 中工作,它的经验也主要只对这个 workspace 有效;信息规模不大,不需要复杂的权限控制;System Prompt 又明确要求 Agent 在任务开始或者遇到阻塞时搜索 MEMORY.md,那么一个本地文本文件可能已经完全够用。这些信息都在同一台机器、同一个 workspace 中,因此可以被快速搜索、验证和修改。软件迭代几轮以后,如果以前的某条 Memory 已经不再适用,Agent 也可以直接更新或者删除它。这里不涉及跨设备分发,不涉及其他 Agent 的协作,也没有复杂的权限和治理问题。但到了真实的企业环境中,情况会变得复杂。

有些问题看起来很小,却会在每次任务中重复发生。比如,本地机器上的 Java 是直接安装的,某台开发环境中的 Java 却由 mise 管理。Agent 在寻找 Java 环境时可能会先失败,再通过一些特殊操作定位到它。Agent 通常可以自己解决这个小问题。如果我们只关心最终的大任务是否完成,就很容易忽略这段过程。但实际上,每次执行大任务以前,Agent 可能都要先重新解决一遍这个小问题。如果没有良好的 Agent Observability 和 Trace,我们甚至不会发现这类重复成本的存在。还有一些信息更加抽象。它们可能是一个组织对某类问题的认识、多个 Repo 之间的协作方式,或者团队正在从一种设计模式转向另一种设计模式。这些知识很难简单地归入项目文档、用户偏好或者某个固定 Skill,却仍然会影响 Agent 的判断和行动。

不同范围、不同生命周期、不同抽象程度的信息混在一起,使得 Memory 的真实需求很难被清楚描述。

为什么 Agent Memory 还没有收敛

现在并不存在一个在真实工作中被普遍证明足够好用的 Agent Memory 产品。各种系统采用了完全不同的形式:本地 Markdown、向量数据库、对话历史检索、自动摘要、经验反思、中心化共享池、每个 Agent 的私有 Memory,以及各种组合。之所以没有收敛,可能并不是大家还没有找到正确的数据库或者检索算法,而是 Memory 所对应的需求本身就没有完全收敛。

项目知识、用户偏好、设备环境、任务经历、失败教训、团队共识和领域判断,虽然都可以被叫作 Memory,但它们并不是同一种信息。它们的产生方式、适用范围、更新频率、验证方法和分发边界都不同。需求不清晰,解决方案自然也不会清晰。大家现在看到的各种探索,可能只是从不同场景出发,分别解决了其中的一部分问题。它们未必最终需要收敛成一个统一的 Memory System,更重要的是,Memory 只是解决这个问题的候选方式之一,甚至未必是未来最好的方式。

我们之所以习惯用 Memory 来描述和设计它,很大程度上是因为人类依靠记忆积累经验,于是自然地把这个机制类比到了 Agent 身上。但未来更好的答案可能是搜索、自动化、训练、Skill、可观察性、组织协议,或者一种现在还没有出现的机制。所以,当我们讨论一个 Agent Memory System 时,最先需要回答的并不是它应该使用什么存储、如何检索、怎样更新,而是两个更加基础的问题:

它到底要避免哪一种重复探索?

避免这些探索,究竟能够带来多少价值?

我认为,这个问题的定义和价值是清晰的:过去工作产生了一些有价值的信息,未来的执行者仍然需要它,却无法以低于重新探索的成本发现并利用它。至于最后是不是应该用一个叫作 Memory 的系统来解决,则仍然是一个开放问题。


Share this post on:

Previous Post
Codex 的浏览器调试报错 ERR_BLOCKED_BY_CLIENT 的真正原因
Next Post
特修斯之船:DeepSeek Harness 与模型的协同进化