Agent 记忆(Memory):短期 / 长期 与”七个追问”

1. 定义

Agent 记忆 = 让无状态的 LLM 在多轮、多会话之间保留信息的能力。默认情况下每次调用模型都是”失忆”的——上下文窗口一满、会话一关,之前说的就都没了。记忆就是把该留的存下来、该取的取回来。

一句话:记忆解决”模型天生健忘”的问题——把跨会话有用的信息从易失的上下文,搬进可持久化的外部存储(文件 / 数据库 / 向量库)。

类比:短期记忆像你当下的工作台(手边摊着的资料、正在想的事),长期记忆像档案柜(归档的偏好、过往决策、踩过的坑),要用时再抽出来摊回桌面。

2. 基础知识点(别漏的这些)

  • 为什么需要记忆:LLM 每次推理只看上下文窗口;窗口有限且会话结束即清空,连续性必须靠外部持久化。
  • 两条路径
    • 写入路径:对话 → 抽取记忆点 → 判断值不值得存 → 冲突检测 → 落库(带元数据)
    • 读取路径:新对话 → 检索相关记忆 → 去重/调和 → 注入上下文
  • 长期记忆常以 RAG 方式存读:事实存进向量库/DB,用时按相关性检索再注入(见 embedding_model.mdrag_optimization.md)。
  • 记忆是上下文的一个来源:它和检索、历史、压缩共同构成 Context Engineering 的”喂什么”(见 context_engineering.md)。
  • Agent 循环里的记忆:每轮循环的状态/草稿(scratchpad)是工作记忆的一部分(见 loop_engineering.mdagent_harness.md)。
  • 用户主权:用户应能查看、更正、删除自己的记忆——“忘记我说的话”就是删除指令。

3. 核心二分:短期 vs 长期

维度短期记忆(工作记忆)长期记忆
存哪上下文窗口 / 当前会话状态外部存储(文件/DB/向量库)
生命周期本轮或近期对话,易失跨会话持久
内容最近对话、当前任务中间结果、计划草稿用户画像、偏好、约束、决策、反馈、过往坑
超限处理裁剪 / 摘要(lost in the middle)检索式读取,不全会进窗口
典型实现对话历史数组、滚动缓冲、scratchpad带元数据的记忆条目 + 检索

记忆类型关系图(简略)

                上下文窗口 Context Window(易失、有限)
                        │
            ┌───────────┴────────────┐
            │   短期 / 工作记忆        │  ← 活在窗口内,随会话/窗口失效
            │   (Short-term /         │     (工作记忆=短期里被"正在用"的部分)
            │    Working Memory)      │
            │   最近对话 + scratchpad  │
            └───────────┬────────────┘
                        │ 读取时检索注入
                        │
       写入时抽取落库    │
   ┌────────────────────▼─────────────────────┐
   │            长期记忆 Long-term(外部存储)    │  ← 跨会话持久
   │  ┌────────────┐  ┌────────────┐ ┌────────┐│
   │  │ 语义记忆    │  │ 情景记忆    │ │程序记忆││
   │  │ Semantic   │  │ Episodic   │ │Proc.   ││
   │  │ 用户画像/  │  │ 过往会话/  │ │ →Skills││
   │  │ 偏好/事实  │  │ 决策/反馈  │ │(技能)  ││
   │  └────────────┘  └────────────┘ └────────┘│
   └────────────────────────────────────────────┘

   循环:长期 ──检索──▶ 注入窗口 ──▶ 成为短期/工作记忆的一部分
         短期里"值得的" ──抽取──▶ 落库 ──▶ 回到长期(带时间戳/来源)

说明:短期记忆与工作记忆在 Agent 语境常作同一桶——工作记忆是短期里”正在被推理使用”的那部分。长期记忆可再分:语义(稳定知识:画像/偏好/事实)、情景(具体经历:过往会话/决策/反馈/踩坑)、程序(怎么做某事 → 对应本仓库的 skills.md)。

4. 七个追问(给 Agent 加了记忆,用户常反手就问)

当你给 Agent 接上记忆,用户大概率会追问下面七个问题。逐一答清楚,记忆设计才站得住。

4.1 短期记忆主要用来存什么?

  • 最近若干轮对话(上下文窗口内的原文或摘要)
  • 当前任务的工作状态:未完成步骤、工具返回的中间结果、Agent 的计划/草稿(scratchpad)
  • 本轮临时变量:比如”本次要查的表名""刚才用户改的需求”
  • 不持久:短期记忆默认随会话/窗口失效,不适合存”以后还有用”的东西。

4.2 怎么判断要落库为长期?/ 一条信息值不值得记长期?

合并看,落库判据 = 稳定 × 跨会话有用 × 关于用户/世界而非一次性任务细节

  • ✅ 存:用户身份/角色、稳定偏好(“输出中文”)、硬约束(“别用某框架”)、用户给的反馈与纠正、已做的决策、反复踩的坑。
  • ❌ 不存:本次任务的中间产出、可从代码/文件推导的东西、纯临时状态。
  • 经验法则:这条信息下次对话还能帮上忙吗?它短期内会变吗? 两个都”是/否”偏向存。

4.3 记忆每轮都要写吗?

不要。 每轮写会引入噪声、成本与冲突漂移。

  • 选择性写:只在出现”记忆点”时写(一个偏好、一次纠正、一条稳定事实)。
  • 批量/总结写:会话末或达阈值时,抽取本会话值得长期留的内容再落库。
  • 权衡:太频繁 → 噪音/冲突/贵;太稀疏 → 漏掉重要信息。多数系统用”会话末抽取 + 显式信号触发”。

4.4 记忆冲突了怎么办?

新信息可能和旧记忆打架。处理策略:

  • 就近优先:新的一般更准确,但用户可能回退,不全信。
  • 来源加权:用户显式陈述 > 模型推断;高置信度覆盖低置信度。
  • 保留溯源:每条带 created_at / source / confidence;读到冲突时由 Agent 现场调和,而非默默覆盖。
  • 高风险才问:涉及关键事实冲突时反问用户——“你之前说 X,现在说 Y,以哪个为准?”
  • 版本化:旧条标记 superseded,不物理删,留审计。

4.5 记忆有没有过期的逻辑?

有,且重要。 世界会变,盲信旧记忆会出错。

  • TTL(存活时间):给记忆设过期时间,到期转”待核验”。
  • 时间戳 + 最后核验:读取时检查 updated_at,久未确认的事实标 stale。
  • 衰减/遗忘:长期不用的低重要记忆降级,减少噪音。
  • 再校验:关于快速变化事实(API、价格、政策)的记忆,用时重新核实,不盲目采信。
  • 用户可显式更新/删除

4.6 用户输入”忘记我说的话”怎么处理?

这是遗忘指令,先判范围再动手:

  • 仅本次会话:清空/截断本轮工作记忆即可(注意别打断进行中的任务)。
  • 某条具体长期记忆:按内容匹配定位那条,只删它,其余保留。
  • 全部长期记忆:高风险、不可逆——先确认再清空该用户的长库。
  • 实现上记忆条目建议带 scope 字段(session / task / user),删除时按 scope 精准命中,避免误删系统或其它用户数据。
  • 边界:“忘掉这次对话”≠“删我全部档案”,务必区分会话重置与长期档案清除。

4.7 (补)记忆条目长什么样?

{
  "id": "mem_001",
  "content": "用户是产品经理,偏好中文输出",
  "type": "user_profile",          // user_profile / preference / feedback / fact
  "scope": "user",                 // session / task / user
  "source": "explicit_user_statement", // 显式 > 推断
  "confidence": 0.9,
  "created_at": "2026-07-19",
  "updated_at": "2026-07-19",
  "ttl": null                      // 或 "30d"
}

5. 典型工作流

写入: 对话 ──▶ 抽取记忆点 ──▶ 稳定?跨会话有用? ──▶ 冲突检测(新 vs 旧)
                                                     │
                                            ├─ 无冲突 ─▶ 落库(带 meta)
                                            └─ 有冲突 ─▶ 就近/来源加权 + 标记旧条 superseded

读取: 新对话 ──▶ 检索相关记忆 ──▶ 去重/调和冲突 ──▶ 注入上下文(短期)

遗忘: 用户"忘记X" ──▶ 定位 scope ──▶ (批量? 先确认) ──▶ 删除对应条目

6. 常见误区

“有记忆 = 每轮都写” → 每轮写带来噪音与冲突;应选择性/会话末抽取(见 4.3)。

“记忆越久越准” → 世界在变,旧事实会过期;需 TTL / 再校验逻辑(见 4.5)。

“新记忆直接覆盖旧的” → 静默覆盖丢溯源;应保留时间戳/来源,冲突时调和或询问(见 4.4)。

“短期记忆和长期记忆是一回事” → 短期在窗口、易失、装任务状态;长期在外部、跨会话、装用户知识(见第 3 节)。

“‘忘记我说的话’就是清空一切” → 要先分清会话级还是档案级,精准删,别误伤(见 4.6)。

“记忆越多越好” → 无关记忆会稀释注意力、增加成本;重质不重量,靠检索按需取(呼应 Context Engineering)。

7. 延伸阅读 / 关联概念