记忆不是保存过去,而是决定:哪些过去、以什么可信度、在什么范围内,可以影响下一次行动。
过去一年,Agent 记忆逐渐变成一个热门话题。有人把它理解为更长的上下文,有人把聊天记录切块后存进向量库,也有人用时序图谱记录实体关系,或者让 Agent 自己管理常驻上下文。Mem0、Letta、Zep/Graphiti 等产品又进一步放大了这种差异。
这些方案都在解决真实问题,但如果一开始就问“应该用哪个记忆框架”,往往会跳过更重要的问题:系统究竟希望过去的什么信息,在未来产生什么行为变化?
对普通对话 Agent,这可能是用户偏好和跨会话连续性;对 Coding Agent,可能是项目规范、构建命令和反复踩过的坑;而对 SRE Agent,记忆面对的是一个更苛刻的世界:系统状态持续变化,错误经验可能放大确认偏误,历史结论必须被当前遥测重新验证,跨租户泄漏还可能直接成为安全事故。
因此,我越来越倾向于把 Agent 记忆理解为一套受治理的状态演化与经验复用系统,而不是某一种数据库或检索算法。
一、先拆开四个经常被混用的概念
上下文不等于记忆
上下文是模型当前能够看到的信息载体,可能包含系统提示、对话、工具结果、文件、规则、检索内容和任务状态。Working Memory 则是其中围绕当前任务被选择、组织和持续更新的短期状态,例如当前目标、计划、证据与未决假设。因此,上下文可以承载 Working Memory,但上下文本身不会自动成为记忆;上下文窗口再长,也没有回答哪些信息值得保留、旧事实何时失效、不同用户的数据如何隔离。
历史记录不等于可用记忆
聊天、观察和工具轨迹是原始事件历史。Session Memory 是从这些历史中选择、压缩并结构化出的可恢复状态,例如阶段摘要、已完成步骤、未决问题、关键证据引用和 checkpoint。保存全部历史得到的是日志;能够支持任务续跑,并接受更新和遗忘的历史投影,才构成工程意义上的会话记忆。
上下文和历史是记忆的载体或原材料;选择、组织、作用域、生命周期和使用策略,才让它们成为工程意义上的记忆。
RAG 不是记忆
RAG 解决的是从外部语料中取回相关内容。记忆则多了一条写入与演化链路:系统需要判断是否值得记住、属于谁、现在是否仍然有效、是否与旧记录冲突,以及被召回后能否影响行动。
向量索引也不是记忆
Embedding 可以寻找语义近邻,却不天然表达权限、实体身份、事实版本、有效时间和证据强度。向量适合做候选召回信号,但不应该成为规范真源。
CoALA 从认知架构角度把语言 Agent 描述为模块化记忆、结构化动作空间与决策过程的组合。这给我的最大启发不是照搬人类记忆名词,而是:记忆只有和行动、状态变化以及外部环境连接起来,才对 Agent 有意义。
二、讨论记忆时需要两条坐标轴
很多争论把“记忆保存了什么”和“用什么技术实现”混在一起。更清晰的方式是同时使用两条轴。
第一条轴:记忆的语义类型
| 类型 | 解决的问题 | 典型内容 | 主要风险 |
|---|---|---|---|
| Working Memory | 当前任务如何连续推理 | 当前目标、计划、工具结果、未决假设 | 上下文膨胀、压缩丢失 |
| Session Memory | 跨上下文窗口保持本次任务连续 | 阶段摘要、检查点、引用 ID、待办项 | 摘要把推断写成事实 |
| Semantic Memory | 保存相对稳定的事实 | 用户偏好、项目属性、实体事实 | 过期、冲突、作用域串线 |
| Episodic Memory | 从过去经历中复用经验 | 一次任务轨迹、事故、成功与失败案例 | 把历史结论当成当前真相 |
| Procedural Memory | 复用做事方法 | Runbook、Skill、工作流、操作约束 | 版本漂移、越权执行 |
这五类记忆的失忆边界不同。Working Memory 可以随运行结束而消失;Session Memory 要支持恢复;Semantic Memory 需要事实更新;Episodic Memory 需要保留来源和结果;Procedural Memory 则更像受版本控制的可执行知识。
第二条轴:记忆的实现范式
| 范式 | 长处 | 局限 | 更适合什么 |
|---|---|---|---|
| 常驻上下文 | 简单、确定、无需检索 | 占用 Token,规模很小 | 核心身份、少量关键规则 |
| 文件优先 | 可读、可审计、适合 Git 和 Agent 工具 | 并发和复杂查询较弱 | Coding Agent、规则、经验笔记 |
| 结构化数据库 | 适合权限、状态、时间、冲突和审计 | 需要先设计数据模型 | 用户事实、任务状态、领域记忆 |
| 全文/关键词检索 | 精确、便宜、容易解释和降级 | 同义改写与跨语言召回较弱 | 错误码、服务名、领域术语 |
| 向量检索 | 擅长语义改写和模糊回忆 | 不懂权限、时效和业务关系 | 作为混合召回的一条支路 |
| 时序图谱 | 擅长关系演化、多跳和时间点查询 | 抽取、运维与纠错成本较高 | 关系本身就是核心产品能力 |
| Agent 自主管理 | 能动态维护常驻块和归档内容 | 行为状态空间和评测难度增加 | 长程、强状态化的个人 Agent |
这里最重要的结论是:语义类型和实现范式不是一一对应。 Episodic Memory 可以存在文件、关系表或图里;Semantic Memory 可以由结构化字段加全文索引实现;图和向量是表示与检索手段,不是新的记忆语义。
Letta 的 context hierarchy 就体现了这种分层:少量高价值信息放在常驻 memory blocks,更大的内容进入文件、archival memory 或外部数据库。Graphiti 则选择用可增量更新的 temporal knowledge graph 表达关系演化,并结合语义、关键词和图检索。它们不是谁替代谁,而是在不同问题上押注不同的复杂度。
三、真正困难的不是“能不能搜到”,而是记忆生命周期
一个最小可用的长期记忆系统至少要回答七个问题:
- 记什么: 哪些信息会在下一次改变行为,哪些只是当前噪声?
- 替谁记: 属于用户、Agent、组织、项目,还是某一次运行?
- 为什么可信: 来自用户明确声明、可信工具结果,还是模型推断?
- 何时有效: 事实从什么时候成立,何时失效?
- 如何更新: 新内容是确认、补充、纠正、替代还是撤回?
- 何时召回: 当前任务真的需要它,还是只在文字上相似?
- 如何使用: 它是背景、线索、建议,还是有权驱动动作的规则?
因此,记忆主链路不应该是“对话 → Embedding → Top-K”,而应该是:
观察
→ 生成记忆候选
→ 校验来源、权限和复用价值
→ 结构化、去重与冲突判断
→ 持久化规范记录
→ 建立可重建索引
→ 有作用域的候选召回
→ 排序并注入少量上下文
→ 用当前证据验证
→ 确认、替代、撤回或遗忘
LongMemEval 把长期记忆能力拆成信息抽取、跨会话推理、时间推理、知识更新和拒答。这个划分比单一 Recall@K 更接近真实系统,因为“召回了旧地址”与“知道旧地址已经失效”是两种完全不同的能力。
Mem0 的核心价值也不只是提供向量检索,而是把显著事实抽取、合并和取回做成完整链路;它的论文报告了相对完整上下文方案的延迟和 Token 优势。但厂商 benchmark 只能说明一种实现可能有效,不能代替自己的写入精度、冲突处理和任务效果评测。
四、“不用向量库”到底意味着什么
“不用向量库”至少有三种不同含义:
- 不用独立向量数据库。 规范事实存在 PostgreSQL,向量只是同库扩展或外部可重建索引。这通常是合理的起点。
- 第一版不用 Embedding。 先用结构化字段、全文检索和领域规则,指标不足再增加语义召回。对强领域系统也很合理。
- 永远拒绝语义检索。 这通常没有必要,会主动放弃同义改写、中文表达差异和跨语言召回能力。
对 Coding Agent,文件优先经常足够有效。Claude Code 的官方记忆机制就是一个很好的工程案例:项目规则放在 CLAUDE.md,自动学习以简洁的 MEMORY.md 作为索引,详细主题文件按需读取。它并不要求先建向量数据库,而是利用文件系统、作用域和渐进加载控制上下文。
对有明确实体和字段的领域 Agent,也可以先建立这样的召回链路:
权限、租户、项目、状态、有效期硬过滤
→ service / signal / error code / entity 精确匹配
→ PostgreSQL FTS 或 BM25 候选召回
→ 领域关系、时间、证据和置信度重排
→ 只注入少量高价值记录
PostgreSQL 已经提供 tsvector、tsquery 和排序函数。对于规模尚未证明需要 ANN 的系统,它足以承担第一版文本召回。真正需要向量的信号,不是“大家都在用”,而是离线数据反复证明 lexical-only 漏掉了有业务价值的语义改写,并且这些漏召回会影响最终任务质量。
五、SRE Agent 的记忆为什么不同
SRE Agent 的目标不是让对话显得更连贯,而是在不断变化的生产环境里形成可靠判断。这决定了它的记忆必须遵守几条更严格的原则。
1. 实时状态不能被长期记忆替代
“checkout-api 当前有 12 个 Pod”“昨天部署了 v2.7.1”“CI 已恢复”都属于易变事实。它们应该从 Kubernetes、Prometheus、日志、Trace、CMDB 或 CI 系统重新查询,而不是被长期记住后继续复述。
长期记忆更适合保存:
- 哪类证据组合曾经支持某个根因;
- 哪些信号看起来相关但后来被证明具有误导性;
- 哪种调查顺序减少了无效工具调用;
- 哪条 Runbook 在什么环境和版本范围内有效;
- 哪些环境陷阱值得下一次优先检查。
2. 历史记忆是线索,不是当前证据
如果上一次 5xx 来自数据库连接池耗尽,这一次相似告警仍可能由证书过期、下游超时或错误发布导致。历史事故可以提高假设生成效率,却不能直接成为新的 Root Cause。
因此,SRE Agent 最重要的记忆原则是:
历史记忆只能形成假设;当前证据才有资格形成结论。
3. 原始证据、事故 Episode 和可复用知识必须分层
- Evidence Ledger: 工具在某次调查中实际观察到了什么,追加写、不可静默修改。
- Incident Episode: 对一次已完成调查的有界结构化摘要,包括告警、实体、验证证据、根因、动作、误导信号和结果。
- Memory Candidate: 从 Episode 中提取出的可复用经验候选,尚不能自动进入后续调查。
- Active MemoryRecord: 通过证据、作用域和必要审批后激活的长期知识。
这样做看似比“总结后直接写向量库”复杂,却把事实、解释和经验分开了。事实可以保持不可变,经验允许被纠正,检索索引则可以随时重建。
4. 写入风险通常大于召回风险
错误召回可能影响一次回答,错误写入却会跨会话持续污染系统。NeurIPS 2025 的 MINJA 表明,攻击者甚至不需要直接修改记忆库,也可能仅通过与 Agent 交互把恶意记录写入长期记忆。
因此,来自网页、日志、工单和用户输入的文本都应视为不可信数据。模型只能提出候选,不能仅凭一段自然语言把内容升级为可驱动生产动作的程序性记忆。
六、一套适合 SRE Agent 的记忆架构
综合前面的边界,一套通用的 SRE Agent 记忆架构可以采用“结构化事实与全文检索为主、领域关系重排、向量可插拔”的路线。下面给出的不是某个具体系统的实现,而是一组可以按业务约束裁剪的设计原则。
实时调查(Prometheus / Logs / Trace / Kubernetes)
→ Evidence Ledger(不可变观察)
→ Incident Episode(一次调查的结构化摘要)
→ Memory Candidate(可复用经验候选)
→ 审批 / 规则门禁
→ Active MemoryRecord(规范真源)
├─ FTS / Metadata / Topology(可重建索引)
└─ Optional Embedding(语义召回支路)
→ Historical Briefing(少量历史线索)
→ 当前证据验证
→ 采纳 / 反驳 / 忽略
写入:先沉降事实,再提炼经验
调查收敛后,系统先保存 Episode,而不是直接保存一句“根因总结”。只有满足复用价值、来源可追踪、根因有已验证证据、作用域明确等条件,才生成 Memory Candidate。共享知识或高风险程序性知识需要人工审批。
一条规范记录至少应表达:
identity: id / tenant / project / owner / memoryType
content: summary / canonicalContent / services / signals / entities
provenance: source / evidenceRefs / writer / contentHash
time: observedAt / validFrom / validUntil / lastVerifiedAt
quality: confidence / reviewState / authorityLevel
lifecycle: active / superseded / deleted / supersedes
applicability: environment / cluster / version / topologyFingerprint
读取:安全过滤先于相关性排序
读取顺序应该是:
- 从认证上下文推导 tenant、project 和 user,模型无权自行指定可见范围;
- 排除 pending、rejected、expired、superseded、deleted 和环境不兼容记录;
- 使用服务、信号、实体、全文检索产生候选;
- 结合根因、证据形态、拓扑关系、置信度和时间衰减重排;
- 只向 Planner 注入少量带来源和警告的历史 briefing;
- Planner 必须用本次遥测支持或反驳记忆,再决定是否采用。
中文召回是容易被忽略的工程边界
如果词法召回主要使用面向英文的切词规则,或者数据库只采用简单分词配置,它可能很擅长匹配服务名、错误码和英文 label,却会漏掉中文自然语言中的同义表达,例如:
- “连接池耗尽”与“数据库连接全部被占满”;
- “下游依赖变慢”与“调用链尾延迟升高”;
- “发布后内存持续增长”与“新版本疑似存在泄漏”。
所以“不上向量库”是合理选择,但不能把它误解为“不解决语义召回”。更稳妥的顺序是:先加强结构化实体、领域别名和中文词法处理;再用真实事故查询集比较 lexical-only 与 hybrid;只有 Embedding 明显提高最终 RCA 或处置质量时才启用。
七、如何证明记忆真的有用
Agent 记忆不能只看“搜到了多少”。一个召回率很高的系统,可能因为注入了更多过期经验而让最终判断更差。
| 阶段 | 关键指标 | 要回答的问题 |
|---|---|---|
| 写入 | Write Precision、误写率、重复率 | 保存的是值得长期复用的内容吗? |
| 更新 | 冲突处理正确率、Supersede 正确率 | 新事实能替代旧事实且保留历史吗? |
| 候选召回 | Recall/Hit@K、MRR | 正确记忆进入候选池了吗? |
| 最终注入 | Precision/NDCG@K、Stale Injection Rate | 上下文里是不是少量高价值线索? |
| 任务效果 | Memory-on Δ、RCA 正确率、工具调用数、调查耗时 | 记忆真正改善了任务吗? |
| 安全治理 | 跨租户泄漏率、投毒写入率、未授权动作率 | 记忆是否扩大了持久攻击面? |
LongMemEval-V2 进一步把 Agent 经验拆成静态状态、动态状态、工作流知识、环境陷阱和前提意识。对 SRE Agent,这比“能否回答用户历史问题”更贴近真实目标:一个有经验的同事不只记得答案,还知道环境如何变化、哪些流程有效、哪里容易踩坑,以及什么时候问题的前提本身就是错的。
建议建立固定的 memory-on / memory-off 回放集,并至少包含:
- 同一告警名、不同根因,防止历史 RCA 造成确认偏误;
- 同一根因、不同中文表述,检查语义漏召回;
- 服务拓扑变化后,旧 Episode 只能部分复用;
- 旧记忆被 supersede 或 delete 后,任何索引都不能继续返回;
- Embedding 服务不可用时,调查能够降级到 lexical 和结构化路径;
- 恶意日志或网页内容不能形成可执行的长期规则;
- memory-on 召回更多但 RCA 质量下降时,发布门禁必须失败。
八、一条更务实的演进路径
Phase 0:先写 Memory Contract
定义记忆类型、作用域、来源等级、有效时间、更新动作、删除语义和可驱动的权限。没有这份契约,任何记忆框架都只会更快地积累混乱。
Phase 1:结构化存储与可解释召回
使用 PostgreSQL 保存规范记录;用 metadata、FTS、领域实体和拓扑做召回;建立 Candidate 审批、supersede、soft delete、审计与 memory trace。
Phase 2:用评测决定是否增加 Embedding
收集真实查询和相关 Episode,比较 lexical-only 与 hybrid 的 Candidate Recall、最终 NDCG、RCA 正确率、延迟和成本。Embedding 只是增强链路,失败时可以安全降级。
Phase 3:关系演化成为刚需时再考虑时序图
只有当系统频繁需要回答“某依赖在什么时间有效”“某次事故发生时拓扑是什么”“跨多条关系如何找到共同故障域”时,时序图的复杂度才可能值得。图数据库不应该因为架构图好看而引入。
Phase 4:从存储经验走向治理经验
随着数据积累,系统需要识别 stale、duplicate、low-confidence 和 never-hit 记忆,合并重复 Episode,提炼稳定 Runbook,同时保留来源链、反例和回滚能力。真正成熟的记忆系统一定包含遗忘和纠错,而不仅是持续写入。
结语
Agent 没有必要像人一样记住一切。它需要的是一种工程化能力:在有限上下文中,从受治理的历史里取出少量真正相关的信息,并清楚知道这些信息来自哪里、是否仍然有效、能否影响当前行动。
对于 SRE Agent,这个边界尤其重要。生产系统不会因为 Agent “以前见过类似事故”就停止变化,历史经验也不会因为被向量检索命中就自动成为证据。
我最终形成的判断是:
- 记忆首先是生命周期与治理问题,其次才是检索问题。
- 记忆类型与存储技术必须分开讨论。
- 结构化事实、全文检索和领域关系应当先于专用向量库。
- 向量适合扩大候选覆盖,不适合承担真相、权限和时间。
- SRE 记忆只能提供历史线索,最终结论必须回到当前证据。
- 是否引入更复杂的记忆范式,应该由 memory-on 的任务净收益决定。
如果把整篇文章压缩成一句话,那就是:
好的 Agent 记忆,不是让系统更执着于过去,而是让它更有能力在当前证据面前正确地使用、修正或放下过去。
参考资料
- Cognitive Architectures for Language Agents (CoALA)
- LongMemEval: Benchmarking Chat Assistants on Long-Term Interactive Memory
- LongMemEval-V2: Evaluating Long-Term Agent Memory Toward Experienced Colleagues
- Mem0: Building Production-Ready AI Agents with Scalable Long-Term Memory
- Letta: Context hierarchy
- Graphiti: Temporal context graphs
- Claude Code: How Claude remembers your project
- Memory Injection Attacks on LLM Agents via Query-Only Interaction
- PostgreSQL Full Text Search