Agent 记忆体系:短期、长期与工作记忆

做 AI 面试产品时最尴尬的场景:候选人在第 3 题提过"我有 K8s 集群运维经验",第 7 题追问时,面试官(Agent)忘了——上下文太长被截断,或者被新内容挤出。

Agent 的记忆不是"一个缓存",是三层体系:短期记忆(上下文窗口)、长期记忆(持久存储)、工作记忆(当前任务状态)。

一、三层记忆模型

记忆层 存什么 生命周期 实现
短期记忆 当前对话上下文 一次会话 LLM 上下文窗口
工作记忆 当前任务状态 一个任务 结构化状态(JSON)
长期记忆 用户画像、历史事实 永久 向量库 / 数据库

二、短期记忆:上下文窗口的管理

问题:上下文窗口有限(4k/32k/128k),对话越长越挤。

技术:上下文压缩

完 整 对 话 │ ├ ├ └ ( ─ ─ ─ 5 0 保 压 保 留 缩 留 轮 : : : ) 最 中 关 近 间 键 事 1 3 实 0 0 ( 抽 轮 轮 取 ( ( 结 原 摘 构 文 要 化 ) ) )
1
2
3
4
5
6
def compress_history(session):
    recent = session[-10:]                    # 原文保留
    middle = session[10:-10]
    summary = llm.summarize(middle)          # 摘要
    facts = extract_facts(session)           # 关键事实抽取
    return {"recent": recent, "summary": summary, "facts": facts}

关键事实抽取(面试场景):

1
2
3
4
{"facts": [
  {"type": "skill", "value": "K8s 集群运维", "round": 3},
  {"type": "experience", "value": "主导过 20+ 微服务迁移", "round": 5}
]}

追问时从 facts 里找,而不是翻完整历史——这就是"记得住前面说过什么"的实现。

三、工作记忆:任务状态的唯一事实源

工作记忆 = 当前任务的进行状态,必须结构化、可持久化:

1
2
3
4
5
6
7
8
9
{
  "session_id": "s-001",
  "current_step": "STEP3",
  "questions_asked": 3,
  "answers": [
    {"q": "Go GC 原理?", "a": "三色标记...", "score": null}
  ],
  "pending": "第 3 题未回答完"
}

为什么必须是结构化状态而不是自然语言:

  1. 可校验(current_step == expected_step)
  2. 可持久化(服务重启不丢)
  3. 可追踪(出问题能回放)
  4. 可并发(多实例共享状态)

关键:Agent 的每一轮动作前先读工作记忆,动作后更新——状态在系统里,不在模型的"记忆"里(这就是我在 Prompt 状态机里讲的原则)。

四、长期记忆:跨会话的积累

存什么

用 历 事 户 史 实 画 会 沉 像 话 淀 : : : 候 每 候 选 次 选 人 面 人 特 试 提 点 的 到 ( 完 过 沟 整 的 通 记 关 风 录 键 格 和 信 、 评 息 紧 估 张 程 度 、 技 术 强 项 )

怎么存

结 非 构 结 化 构 事 化 实 内 容 → → 数 据 向 库 量 ( 库 关 ( 系 语 表 义 ) 检 索 )

怎么用

新 对 会 话 话 中 开 : 始 需 时 要 : 时 加 检 载 索 用 ( 户 " 画 他 像 上 次 + 提 到 最 过 近 X 3 X 次 吗 会 " 话 ) 摘 要

长期记忆的价值:AI 面试官第二次面试同一个候选人时,记得上次的表现——这是"像个真人面试官"的关键。

五、记忆的一致性问题

问题 1:短期和长期不一致

会话中候选人说"我熟悉 Rust",会话结束时写入长期记忆——但中途 Agent 的回答可能已经用了旧画像。

解法:长期记忆只在会话结束(或关键节点)写入,会话中短期记忆为准。

问题 2:记忆污染

候选人的随口一提(“我了解一点 Rust”)被当成"精通 Rust"写进画像。

解法:写入长期记忆要过置信度门(确认/重复/关键上下文才写),别啥都存。

问题 3:隐私

长期记忆存了用户隐私,删除/导出要支持。

解法:记忆数据与用户账号绑定,提供查看/删除接口(合规必备)。

六、架构总览

┌ │ A │ └ ─ g ─ e 短 n 长 期 t 期 记 记 忆 ─ 忆 : ┼ : 上 ─ 向 下 量 文 工 库 窗 作 口 记 + ( 忆 压 : 数 缩 任 据 务 库 + 状 ( 态 画 事 ( 像 实 结 / 抽 构 历 取 化 史 ) / J 事 S 实 O , N 带 , 置 持 信 久 度 化 ) 到 R e d i s / D B )
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 每轮循环
def agent_loop(session, user_msg):
    # 1. 读工作记忆 → 当前状态
    state = load_state(session.id)
    # 2. 检索长期记忆 → 相关画像
    profile = memory.search_profile(session.user_id)
    # 3. 组装上下文(短期压缩 + 事实 + 状态 + 画像)
    ctx = build_context(session, state, profile)
    # 4. LLM 调用
    reply = llm.chat(ctx)
    # 5. 更新工作记忆
    save_state(session.id, update(state, reply))
    return reply

七、踩坑记录

  1. 压缩摘要失真:摘要丢细节(“用户问过 GC 但没深入”)→ 事实抽取用结构化,不依赖摘要
  2. 工作记忆和上下文不同步:状态说 STEP3,上下文显示 STEP2 → 每轮结束强制校验一致性
  3. 长期记忆写入过频:每轮都写画像 → 记忆被噪音污染 → 只写"高置信度事实"
  4. 记忆检索成本:每轮都查向量库 → 慢 → 画像缓存在工作记忆,变化才回写

总结

Agent 记忆的核心认知:

  1. 三层分工:短期管上下文、工作管任务状态、长期管跨会话积累
  2. 上下文压缩 + 事实抽取:让 Agent"记得住"前面的关键信息
  3. 状态放系统不放模型:工作记忆结构化,可校验可恢复
  4. 长期记忆要过置信度门:别让随口一提污染画像

Agent 没有记忆 = 每轮都是新同事。 有了三层记忆体系,它才像那个"了解你"的老熟人。