Skip to content

Agent 记忆与状态

LLM 本身无状态:每轮对话它都是「第一次」遇见你。Agent 的智能上限,一半取决于把什么记住(写入),一半取决于用什么想起(检索)。Agent 架构通论 第四节给出了记忆的四层分类与上下文预算概览;本篇深挖工程落地:先判断需要哪级记忆,再按「写入 → 存储 → 检索 → 更新/过期」四环节设计系统,最后谈状态持久化、记忆安全与评测。

一、先判断:你的 Agent 需要哪级记忆

先纠正三个常见误解:

  • 上下文 ≠ 记忆:上下文只是每次请求时「载入的工作副本」;关掉就没了;
  • 会话历史 ≠ 长期记忆:它是原始素材,不是提炼后的知识;
  • 记忆不是缓存:缓存存「原样数据」,记忆存「可复用的提炼结果」。

按需求分级,先别一律上向量库:

级别典型场景需要什么复杂度
L0 无状态一次性问答/单任务工具什么都不用
L1 会话内多轮对话、单次任务的进度消息历史 + 状态结构
L2 跨会话记住用户偏好、常用设置、历史结论长期存储 + 检索
L3 跨任务积累团队规范、项目知识、技能沉淀长期存储 + 结构化 + 治理
  • 判断一句:用户/任务是否期待 Agent 记住上次的事?不确定时默认 L1,出现「用户反复纠正同样的事」再升 L2;
  • L2/L3 的收益衡量标准:记忆检索带来的成功率提升 vs 检索噪声/中毒带来的新失败,先加「记忆在什么场景该被用」的明确触发,不要全局注入历史(见第三节读取)。

二、记忆系统参考架构:四个环节

 事件流(对话/工具结果/用户反馈)
      │ ① 写入:提炼(总结/抽取事实/更新状态)——谁触发、提炼什么、校验可信度

 ② 存储:短期工作区(消息/状态) + 长期存储(结构化事实 + 非结构化文本/向量)


 ③ 检索:按需取回 → query 改写/重排 → 注入上下文(带来源与时间戳)


 ④ 更新与过期:冲突处理、用户纠正优先、TTL/合并/衰减 —— 记忆库不治理=垃圾场
  • 每环的取舍:
环节要点常见错误
① 写入提炼用专用 prompt;区分「事实 / 用户偏好 / 事件经过」;写入前校验来源可信度全量对话都写库,噪声爆炸
② 存储见下节选型;短期与长期分开存;敏感字段脱敏一个库里混所有
③ 检索按需注入 + 来源标注;查不到要能说「我不知道/我不记得」每轮把所有记忆塞上下文
④ 更新用户纠正 > 旧记忆;重复合并;过时衰减;定期治理旧记忆与新事实打架

三、工作记忆与状态管理(会话内)

  • 工作记忆 = 状态结构 + 上下文预算。把任务状态显式建模,而不是让它「漂在对话里」:
jsonc
// 显式状态结构(建议落盘而非只放上下文)
{
  "task_id": "t-123",
  "goal": "修复登录页在 iOS 上白屏的问题",
  "steps": ["复现", "定位", "修复", "验证"],
  "current_step": 2,
  "findings": ["白屏仅 iOS Safari,疑似 -webkit- 前缀缺失"],   // 关键结论
  "ruled_out": ["不是字体问题(桌面端正常)"],                     // 排除项,防重复探索
  "budget": { "steps_left": 8, "tokens_spent": 41230 }
}

「哪些该进状态」的判断:目标/进度/关键结论/排除项/预算——会被后续步骤用到、且窗口装不下的;

  • 上下文预算策略(方法详见 架构通论 第四节):截断、滚动摘要、结构化抽取、按需检索——组合使用,并给「哪些进窗口」定优先级:当前步骤相关 > 目标与关键结论 > 摘要历史 > 原始细节;
  • 压缩会丢事实,做「摘要一致性抽查」:定期抽样比对摘要与原文,丢了关键约束(如「禁止用 X 方案」)要能发现;
  • 状态持久化与恢复(生产必做):状态序列化到 DB/Redis/文件,带 task_id;
    • 恢复时机:进程重启、超时续跑、多实例切换、用户回来接着问;
    • 恢复后第一件事:把状态与当前上下文对齐(用户可能改了主意,先确认目标没变);
    • checkpoint 语义:关键里程碑(如验证通过)落一次盘,失败时可回退到最近 checkpoint 而不是从头跑。

四、长期记忆:存储什么、怎么存取

存储形态选型

形态代表适合不适合
键值/文档Redis / Mongo 类结构化偏好、简单 KV语义检索
向量库pgvector / Milvus 类非结构化文本按语义召回精确事实查询
知识图谱图数据库 / 三元组实体关系、推理可达快速起步、模糊需求
组合向量 + 元数据过滤生产大多数需要字段与向量一致治理
  • 起步建议:结构化事实用文档/键值 + 非结构化用向量,加统一的元数据(用户 id、来源、时间、类型);知识图谱等出现「需要多跳推理/去重关系」再引入;

写入:质量 > 数量

  • 触发时机:任务完成、里程碑、用户明确陈述偏好、用户纠正;不要在每轮对话末尾都写;
  • 提炼 prompt 的要点:只抽取可验证事实与明确偏好、过滤情绪化表达与临时想法、标注「置信度/来源/时间」;
  • 写入前校验可信度:来自网页/邮件检索的内容属于「外部事实」,要标来源与置信度;用户直接陈述 > 模型推断(宁可漏写不编造)。

读取:按需检索,不是全量灌入

  • 检索触发:什么时候需要记忆?目标相关、用户提到「上次/之前/我记得」、任务需要历史上下文——由分类器/规则判断,平时不查;
  • 检索 + 重排方法直接复用 RAG 的经验,区别:记忆检索要按用户/任务做范围过滤,且注入时标注时间与来源(「你上次(7-02)说过……」);
  • 「记得住但想不起」比「没有记忆」更糟:检索不到就诚实说不知道,别用旧的过期记忆糊弄;
  • 用户纠正优先:用户说「不是那样/改成 X」,必须先更新记忆再继续,且本次会话内立即生效。

更新与过期

  • 冲突处理:新旧事实矛盾时,以用户纠正与最近时间为准,并合并去重;
  • 过期策略:带 TTL 的事件型记忆自动衰减;长期偏好(如「我不用 PHP」)保留但要可被显式覆盖;
  • 定期治理:重复项合并、失效项归档、敏感数据复查(见第六节安全)。

五、现成方案与协议:少自建就少踩坑

  • MCP 的 memory 资源形态:把「记忆读写」做成一类标准工具/资源由协议承载(架构见 MCP),Agent 通过统一接口存取——工具层解耦、可替换;
  • 托管记忆库/服务(如 Mem0、Zep 一类):内部一般做「提取 → 存储 → 带时间与实体权重的检索」,价值是把第四节的写/查/更新做成产品级;
    • 适合:不想自己维护提炼与检索逻辑、跨会话记忆是核心卖点;
    • 注意:它们仍要你定义「哪些该记」,且数据出境与 PII 合规要先确认(见 AI 工程化);
    • 示例接口形态以各官方文档为准,本文不做具体版本断言。
  • 何时自建:数据留在内部网、记忆需求简单(几个字段 + 少量历史)、已有 DB——三张表(users / memory_items / events)往往比引一个服务更快。

六、记忆安全与评测

  • 记忆系统的三个评测面:
评测面怎么测
提取正确性人工标注「该记的」对照系统写的,算精确率/召回率
检索命中构造「依赖上次信息才能答」的任务集,测成功率
遗忘与更新测「改口后」是否按新事实回答;过期记忆是否不再被用
  • 记忆中毒是最隐蔽的攻击面(详见 Agent 安全与治理):网页/邮件里的恶意文本 → 被写入长期记忆 → 之后每轮都「记得」要按恶意指令行事——写入环节必须做来源可信度分级,不能把外部不可信内容无差别提炼成事实。

七、踩坑清单

  1. 没判断就上向量库:L0 的需求配 L3 的方案,检索噪声带来新失败;
  2. 把上下文当记忆:任务一长/一断,Agent 就从零开始;
  3. 状态不落盘:进程重启、超时续跑全部从头;
  4. 全量写库:每轮对话都提炼,库被噪声淹没,检索质量崩;
  5. 写入即编造:模型「推断」的偏好没标置信度,当事实存了;
  6. 读取全量灌:每轮把全部记忆塞上下文,又贵又互相打架;
  7. 检索范围不隔离:多用户/多任务共用一个记忆池,串记忆(A 的话 B 看到);
  8. 用户纠正被吞:旧记忆压过新指令,用户反复纠正同样的事;
  9. 无过期治理:几个月前的过期事实天天被检索出来当新鲜事;
  10. 敏感数据裸存:对话中的 PII/机密进记忆库不脱敏(见 AI 工程化 合规);
  11. 记忆中毒不设防:外部不可信内容直接写入长期记忆,回灌成持久后门(见 Agent 安全与治理)。

关联阅读:记忆四层分类与上下文预算概览见 Agent 架构通论 第四节;检索/重排/向量库方法直接复用于记忆检索,见 RAG 与 Agent;记忆读写做成标准工具的协议层见 MCP;记忆中毒与数据安全见 Agent 安全与治理;记忆存取涉及 PII 的合规要求见 AI 工程化

基于 VitePress 构建 · 内容以知识共享方式沉淀