一篇面向 Agent 应用开发者的长文:从"为什么它记得上一句话"讲到 Checkpointer、Store、Backend、Memory RAG 与 Context Engineering。
很多人第一次做 Agent 时,会把 Memory 理解成一件很简单的事:把聊天记录存起来,下一轮再发给模型。
这个理解在三五轮闲聊里没有问题。但只要 Agent 开始做真正的工作------查资料、调用工具、修改文件、等待人工审批、拆分子任务、跨天继续执行------它立刻不够用了。
因为你会发现,所谓"记忆"实际上混着至少五种不同问题:
- 这次任务执行到哪一步了?
- 新的一次会话,为什么还应该知道用户偏好?
- Agent 写下的
notes.md到底在哪? - 几十次工具调用产生的海量内容,如何不把上下文撑爆?
- 什么东西值得长期保存;发生冲突又该如何更新?
LangGraph 与 Deep Agents 的价值,不是给"聊天记录"换一个新名字,而是把这些问题拆开,分别处理。理解这套拆分,是从"会调用模型"迈向"能设计 Agent Runtime"的关键一步。
一、先建立正确直觉:Memory 很大,Context 必须很小
先用一句话区分两个总被混淆的概念:
text
Memory = 系统保存了什么
Context = 这一次调用 LLM 时,真正给模型看了什么
一个 Agent 可以保存很多东西:上百条对话、数十个工具返回、研究报告、中间草稿、长期用户偏好、历史项目经验。
但一次模型调用不应该看到全部内容。它可能只需要看到:
text
System Prompt
+
当前任务与计划
+
最近几轮对话
+
与当前问题相关的一小段文件
+
少量已检索的长期记忆
这不是因为模型"看不下"。即使模型拥有很大的 Context Window,把所有材料一直塞进去仍会导致:
- token 成本持续上升;
- 推理延迟变高;
- 无关内容稀释注意力;
- 关键约束与最新决策被淹没;
- 工具原始输出不断堆积,最终难以控制和调试。
所以,一个成熟 Agent 追求的不是"所有东西永远在 prompt 中",而是:
让模型在当前这一步,只看到完成当前这一步真正需要的信息。
这是后面所有设计的共同目标。
二、Memory 不是一个组件,而是一种能力
假设你在和售后 Agent 对话:
text
用户:帮我查订单 123456。
Agent:订单已发货。
用户:那帮我退款。
最后一句没有重复订单号,但 Agent 应该知道"那"指的是 123456。我们可以把这称为记忆,但它至少分成两个时间尺度:
text
Agent Memory
│
┌───────────────┴────────────────┐
▼ ▼
Short-term Memory Long-term Memory
当前 thread 跨 thread
│ │
Graph State Persistent Store
│ │
Checkpointer namespace / key
短期记忆服务的问题是:
这次任务发生了什么?现在执行到哪里?
长期记忆服务的问题是:
未来再遇到这个用户、这个项目或同类任务,我应该记得什么?
从这个角度看,Memory 是能力概念;Checkpointer 和 Store 是实现不同记忆生命周期的基础设施。
三、Checkpointer:它记住的不是聊天记录,而是整个任务现场
1. Graph State 是什么
把一个 Agent 想成一个不断变更状态的工作流。它并不只有对话消息,还可能有订单号、当前意图、执行步骤、工具结果、待办事项和中断标记。
text
AgentState
├── messages
├── order_id
├── intent
├── current_step
├── tool_result
├── todos
└── interrupt / resume 信息
例如退款流程会演化成:
text
State 0: 用户刚进入
State 1: 已解析出 order_id = 123456
State 2: 已判断 intent = refund
State 3: 已查询订单,等待校验
State 4: 需要人工确认或继续执行
2. Checkpointer 做了什么
Checkpointer 是 Graph State 的持久化与恢复机制。工作流在重要节点后保存快照:
text
用户输入
↓
理解意图
↓ checkpoint 1
查询订单
↓ checkpoint 2
校验退款资格
↓ checkpoint 3
人工确认 / 后续执行
下次使用相同的 thread_id 进入时,运行时可以恢复先前的 State。于是,用户说"帮我退款"时,系统不只是拿到一条孤立的文本,而是重新获得"订单号是什么、上一步做了什么、工具返回了什么"的任务现场。
这也解释了 Checkpointer 的能力远不止"多轮聊天":
- 对话连续性;
- 失败重试;
- 人工审批后恢复;
- 长任务暂停与续跑;
- 状态追踪与调试;
- 在某些架构中回看或回放执行过程。
3. 为什么它是短期记忆
关键在于 thread_id。可以将它理解成一份任务或会话的身份:
text
thread-A → State A
thread-B → State B
同一个 thread 再次调用,恢复同一份 State;换一个 thread,则默认得到另一份独立 State。
因此,Checkpointer 的正确总结是:
它让 Agent 记住当前 thread 的完整执行状态,而不仅是消息历史。
它不是全局用户档案库,也不应该承担跨用户或跨会话的偏好记忆。
四、Store:让 Agent 跨会话记得"这个人是谁"
现在换一个场景:
text
Thread A:用户说"以后酒店尽量给我推荐五星级、无烟房,预算 1500 以内。"
一个月后,Thread B:用户说"帮我规划上海三日游。"
thread-A 的 State 不会自然变成 thread-B 的 State。可是如果这份偏好仍然成立,新的会话理应能使用它。
这就是 Store 的位置。
Store 可被理解成跨 thread 的长期 Key-Value / Document 存储:
text
namespace: (users, user_123, preferences)
key: hotel
value:
level: 5
non_smoking: true
budget: 1500
text
Thread A ──┐
Thread B ──┼──→ Store → user_123 preferences
Thread C ──┘
这里要建立一个极其有用的对比:
| 问题 | Checkpointer | Store |
|---|---|---|
| 主要用途 | 持久化 Graph State | 保存长期数据 |
| 作用域 | 当前 thread_id |
跨 thread |
| 核心索引 | thread 身份 | namespace / key / 元数据 |
| 典型内容 | 消息、步骤、工具结果、todo | 用户偏好、资料、历史经验、长期规则 |
| 断点恢复 | 是 | 不是主要职责 |
| 回答的问题 | "这次做到哪了?" | "以后应该记得什么?" |
一句好记的话:
Checkpoint 记住"这次做到哪了",Store 记住"这个人以前是什么样"。
当然,Store 和 Checkpointer 都是基础设施:Store 不只能存 Memory,Checkpointer 也不只为对话服务。但在 Agent Memory 的设计里,这样分工最清晰。
五、真正的生产边界:thread_id 不等于 user_id
一个演示系统中,可能让所有人都访问同一个 /memories/user.md,看起来很方便;生产系统中,这会变成严重的数据泄漏。
正确身份模型应当是:
text
Application
┌───────┴────────┐
▼ ▼
User Hans User Alice
│ │
┌─────┼─────┐ ┌───┴───┐
▼ ▼ ▼ ▼ ▼
T1 T2 T3 T4 T5
│ │ │ │ │
checkpoints checkpoints
│ │
▼ ▼
Hans long-term Store Alice long-term Store
thread_id 解决"这是哪一次会话/工作流";user_id 解决"这些数据属于谁"。再往上通常还有 tenant、organization、project 等维度。
因此,任何长期 Memory 的写入和检索都必须在数据模型与权限层面带上边界:
text
tenant → user → project → memory type → record
只在 prompt 里提醒"不要读错用户数据"不够。隔离必须落实在 namespace、查询过滤、授权、审计和存储策略里。
六、Deep Agents 做的事:把"文件"变成 Agent 的共同语言
LangGraph 给出 State、Checkpointer 和 Store 这些基础设施。Deep Agents 再往上走了一层:它让 Agent 用文件操作来处理工作记忆与长期记忆。
Agent 看见的是统一的文件工具:
text
read_file
write_file
edit_file
ls
glob
grep
但它并不需要知道文件实际放在内存、State、数据库,还是宿主机磁盘。
text
Deep Agent
/ \
Graph State Filesystem Tools
│ read / write / edit / search
▼ │
Checkpointer Backend Protocol
│
┌─────────────────────┼────────────────────┐
▼ ▼ ▼
StateBackend StoreBackend FilesystemBackend
这里存在两条独立但相关的线:
text
Graph State ──→ Checkpointer
文件操作 ──→ Backend
这也是最常见的误解来源:
StateBackend 不是 Checkpointer。
StateBackend 回答"虚拟文件放进哪里";Checkpointer 回答"整个 Graph State 怎么被保存和恢复"。如果 StateBackend 文件属于 Graph State,它可以随 checkpoint 被恢复,但这不代表两个组件是一回事。
七、四种 Backend:同一份"文件",四种完全不同的生命周期
1. StateBackend:当前 thread 的虚拟工作空间
当 Agent 写下:
text
/research.md
/todo.md
/draft.md
这些文件可以是当前 State 中的虚拟内容,并不意味着真的在 Mac 根目录写入一个文件。
text
Thread A
└── DeepAgentState
├── messages
├── todos
└── files
├── /research.md
└── /draft.md
这种 Backend 很适合当前任务的中间产物:分析笔记、计划、局部结果、临时草稿。它本质上是短期工作记忆的一部分。
2. StoreBackend:以文件形式呈现的长期记忆
如果 Agent 写:
text
/memories/preferences.md
/memories/profile.md
/memories/projects/rag.md
这些路径可以映射到 LangGraph Store。对模型而言是熟悉的文件;对系统而言是可跨 thread 持久化、按身份隔离的数据。
这里最容易被误解的一点是:路径名不是魔法。
/memories/之所以成为长期记忆空间,不是因为目录叫 memories,而是因为系统将这个路径路由到了持久化的StoreBackend。
3. FilesystemBackend:真实项目与真实文件
Coding Agent 常常需要读写真正的项目目录,例如:
text
/workspace/app/main.py
/workspace/tests/test_api.py
/workspace/README.md
这时使用的才是实际磁盘上的文件系统。它服务的是源码、文档和工作区资产,而非天然等同于长期用户记忆。
真实文件系统风险更高,必须做根目录约束、最小权限、审计和危险操作控制。
4. CompositeBackend:生产系统的路径路由器
现实中,一个 Agent 同时需要临时笔记、长期记忆和真实项目文件。因此需要把多个 Backend 组合起来:
text
CompositeBackend
│
┌───────────────────┼───────────────────┐
▼ ▼ ▼
/memories/* /workspace/* default
StoreBackend FilesystemBackend StateBackend
长期记忆 真实项目文件 临时工作区
它的职责不是"存储",而是根据路径选择正确的存储策略。路径前缀可以继续细分,让不同内容拥有不同隔离、生命周期、权限和成本策略。
把四种 Backend 放在一起看:
| Backend | 实际落点 | 最适合的数据 | 关键风险 |
|---|---|---|---|
| StateBackend | 当前 Agent State | 临时笔记、当前任务草稿 | 换 thread 后不可见;不应滥当长期库 |
| StoreBackend | 跨会话持久 Store | 偏好、项目摘要、长期规则 | 隔离、冲突、检索、过期治理 |
| FilesystemBackend | 真实工作区 | 代码、文档、构建产物 | 权限与破坏性操作 |
| CompositeBackend | 路由层 | 混合工作空间 | 路径策略配置错误 |
八、Middleware:能操作,不等于能看见
Deep Agents 中还有两个名字很像、职责却不同的概念。
FilesystemMiddleware:给 Agent 手和脚
它把读、写、编辑、列目录、搜索等文件能力暴露给 Agent。
text
Agent → FilesystemMiddleware → file tools → Backend
可以把它理解为:让 Agent 能操作 文件和记忆。
MemoryMiddleware:把少量重要记忆放进眼前
用户在新 thread 中问"我叫什么"。即使长期 Store 中有资料,模型也不会自动知道该读哪个文件。
有两条路:
- 让 Agent 按需调用文件工具,先检索/读取相关 Memory;
- 对很小、很重要的记忆,在启动时直接加载进 Context。
第二条的角色就是 MemoryMiddleware:
text
Persistent Memory Files → MemoryMiddleware → Model Context
它让模型 能看见 某些长期 Memory。比如小而稳定的用户档案、编码规范、长期 Agent 指令。
需要特别澄清:MemoryMiddleware 不是"自动把所有对话总结后写成长记忆"的魔法组件。它解决的是读取/注入,不替代记忆抽取、更新和冲突处理。
九、长期 Memory 不是一类东西:事实、经历和规则
"用户画像"只是长期记忆的一部分。一个更完整的划分是:
| 类型 | 它回答的问题 | 示例 |
|---|---|---|
| Semantic Memory | "我知道什么?" | 用户叫 Hans、默认用 Python、团队在用 Milvus |
| Episodic Memory | "以前发生过什么?" | 上次 RAG 项目选了什么方案、何时做过什么决策 |
| Procedural Memory | "以后应该怎样做?" | 先讲架构后写代码;代码必须有类型注解 |
text
Long-term Memory
├── Semantic:稳定事实与知识
├── Episodic:过去任务、事件、决策
└── Procedural:行为规范、工作流、可复用经验
这个分类很有价值,因为三类记忆的存储、更新与检索逻辑不同:
- 事实常适合结构化字段和明确覆盖规则;
- 事件保留时间、上下文和结果,常需要检索与摘要;
- 规则会直接影响 Agent 行为,更需要来源、权限和版本控制。
例如 AGENTS.md 一类文件特别适合承载 Procedural Memory。它很像可持续演化的 instruction:系统提示是开发者预置的,长期记忆则可以承载用户长期配置或 Agent 累积的工作准则。由于它会影响行为,不能把它当作普通日志随意追加。
十、真正难的不是"存进去",而是"什么值得记住"
假设用户说了四句话:
text
今天北京有点热。
我中午吃了面。
这个代码先别加缓存。
以后我的后端项目默认使用 Go。
如果 Agent 将它们全部写进长期 Memory,最终会发生三件坏事:
text
Memory Pollution --- 垃圾信息累积
Memory Conflict --- 相反信息并存
Context Explosion --- 读取时又塞满上下文
一个生产系统需要一条 Memory Governance 流水线:
text
Conversation / Tool Outcome
│
▼
Candidate Detection
"可能值得长期记吗?"
│
▼
Memory Extraction
"抽成什么结构?"
│
▼
Retrieve Existing Memory
│
▼
Policy + Conflict Check
│
┌──────┼────────┬─────────┐
▼ ▼ ▼ ▼
Ignore Add Update Ask/Review
1. 候选记忆的判断维度
至少要问五个问题:
| 维度 | 含义 |
|---|---|
| Stability | 它未来还成立吗,还是一次性任务信息? |
| Utility | 未来任务是否真的会受益? |
| Specificity | 信息是否明确、可用、可定位? |
| Confidence | 系统对该结论有多确定? |
| Sensitivity | 是否适合保存,需要同意、加密还是禁止? |
"今天想用 Java"可能是一次性任务要求;"以后后端项目默认用 Java"才更像长期偏好。
2. 抽取结果最好是结构化候选
不要直接把 LLM 输出 append 到一份巨大 Markdown。更稳妥的形态是候选对象:
text
type: preference
scope: user / backend projects
operation: update
key: default_language
value: Go
confidence: high
source: explicit user statement
这样系统才能进行规则判断、审计、冲突检测和精确更新。
3. 冲突不是异常,而是长期系统的常态
假设已有:
text
preferred_language = Python
用户后来明确说:
text
以后项目都改成 Go。
直接追加"用户喜欢 Go"会让两条相反的记忆同时存在。正确逻辑是:
text
New Memory
↓
Retrieve Existing Memory
↓
Compare scope / time / confidence / source
↓
ADD | UPDATE | IGNORE | ASK
典型规则包括:显式且较新的用户声明优先;项目局部偏好不要覆盖用户全局偏好;低置信度的高影响改动应询问用户;每个记忆应保留来源、时间、作用域、版本和审计轨迹。
这时你会发现,生产级 Memory 更接近一个"受治理的知识更新系统",而不是一个文本文件夹。
十一、Hot Path 还是 Background:什么时候写记忆
记忆写入有两种典型方式。
Hot Path:在对话主链路里立即写
text
User → Agent → 发现明确偏好 → 写 Store → 回复用户
优点是立即生效。用户刚说"以后代码都用类型注解",下一步生成的代码就可以马上遵守。
代价是更多模型调用、延迟和主链路复杂度。
Background:回答结束后异步治理
text
User → Agent → Answer
│
└→ 异步 Extraction / Dedup / Update → Store
优点是用户主链路更快,也便于批量去重、丰富冲突处理、人工审核和指标分析。代价是记忆不会立刻生效。
现实中通常采用混合策略:
- 用户明确表达、低风险、下一轮必需的规则走 Hot Path;
- 常规偏好归纳、事件摘要、经验提炼与清理走 Background。
更稳健的边界是:
Agent 可以提出 Memory Candidate;系统必须负责 Policy、隔离、审计和最终写入。
十二、Memory RAG:长期记忆多了以后,怎么读
每次启动都把所有长期记忆塞进 Context,最终会回到最初的问题:上下文爆炸。
因此,长期 Memory 通常分成三层:
text
Long-term Memory
├── Core Memory
│ 小、稳定、每次重要:profile / preferences / rules
├── Searchable Memory
│ 大、相关时才读:projects / episodes / experiences
└── Archive
原始历史、日志、旧资料:很少读取
Core Memory 可以在启动时经由 MemoryMiddleware 直接注入;Searchable Memory 要按需检索;Archive 是兜底证据和可追溯材料。
完整检索路径类似:
text
User Query + Current Task
↓
Metadata Filter
tenant / user / project / type
↓
Search
keyword / embedding / hybrid
↓
Rerank
↓
Top-K Relevant Memory
↓
Context Builder → LLM
这就是 Memory RAG。
它和知识库 RAG 技术上有很多共用点:索引、向量、元数据过滤、重排、Top-K。但两者回答的不是同一个问题:
| Knowledge RAG | Memory RAG | |
|---|---|---|
| 内容来源 | PDF、Wiki、公司文档、数据库 | 用户历史、任务结果、Agent 经验与偏好 |
| 主要问题 | "世界或组织知识是什么?" | "我和这个用户以前发生过什么?" |
| 主要风险 | 文档过期、检索不准 | 数据隔离、冲突、污染、过度个性化 |
所以即使基础检索组件相似,Memory RAG 更强调身份边界、时间、来源与更新语义。
十三、Context Engineering 的三把工具
长期记忆需要检索,短期工作同样需要控制上下文。Deep Agents 的关键思想是:不要让所有中间材料永远留在 messages 里。
text
Context Engineering
│
┌──────────────┼──────────────┐
▼ ▼ ▼
Summarization Filesystem SubAgent
Offloading Isolation
│ │ │
▼ ▼ ▼
压缩历史 移走大内容 隔离子任务
1. Summarization:压缩的是语义历史
对话跑得很久后,早期的讨论不能一直原样带着。Summary 可以把大量历史压缩为当前工作仍需要的决策与进度:
text
历史:需求讨论、工具调用、失败尝试、方案取舍......
↓
摘要:已完成 parser 与 chunking;选择 BGE-M3;当前在实现 retrieval
+
最近几轮消息
它比简单 Trim 更好:Trim 是直接删除,可能让模型忘掉关键约束;Summarization 是有损压缩,努力留下语义主线。
但"有损"二字很重要。订单精确金额、支付 ID、原始 JSON、可复现实验参数,不能只存摘要;这些要进入文件或结构化存储。
2. Filesystem Offloading:搬走,不是压缩
工具返回 50K token 的网页或数据时,把它直接作为消息持续放在 Context 里非常浪费。Offloading 的思路是:
text
Large Tool Result
↓
/tool_results/result_001.txt
↓
Context 里只保留路径与简短说明
↓
真正需要时再按 offset / limit 读取
这与 Summary 的本质不同:
| 机制 | 做了什么 | 原始信息是否保留 |
|---|---|---|
| Summarization | 压缩 | 可能丢失 |
| Offloading | 移出 Context | 保留,可按需读取 |
Filesystem 在这里不只是存储工具,而是 External Working Memory:LLM 不必一直背着所有材料,但仍能在需要时查回原文。
3. SubAgent Isolation:子 Agent 的深层价值是隔离
假设主 Agent 要研究中美自动驾驶差异,拆成中国市场、美国市场与监管比较三个子任务。每个子任务都可能有几十轮搜索、失败工具调用和长篇原始资料。
如果每个子 Agent 的完整过程都回灌主 Agent,主 Context 一样会爆炸。
text
Main Agent
│
┌──────────────────┼──────────────────┐
▼ ▼ ▼
SubAgent A SubAgent B SubAgent C
Context A Context B Context C
│ │ │
研究过程 研究过程 研究过程
└──── summary / artifact / result ───┘
│
Main Context
所以 SubAgent 不只是为了并行,更是 Context Boundary。主 Agent 只接收可决策的摘要、结构化结论或文件引用,避免被子任务的"过程噪声"污染。
十四、从"大窗口模型"到"受控工作集"
面对 Context 爆炸,一个直觉做法是换更大窗口模型。这只能推迟问题,不能解决问题。
只要 Agent 长时间运行,数据规模就可能超过任何固定窗口:更多搜索结果、更多用户历史、更多工具输出、更多子任务。成熟设计的目标是让外部信息可以持续积累,但每次模型调用的工作集始终有预算。
text
可积累的信息规模
Filesystem / Store / Archive
████████████████████████████████████
单次 LLM Context
██████ (始终受控)
因此生产系统应有显式的 Context Manager:
text
Conversation History ── summarize ─┐
Memory Retrieval ────── retrieve ──┼→ Context Builder → Token Budget → LLM
Workspace Files ─────── select/read ┘
一个概念性的预算可包括:系统规则、最近消息、任务状态、检索记忆、文件片段、工具摘要,以及为模型输出预留的 token。具体比例与模型、任务、工具形态有关,但"分区管理"比单纯累加消息重要得多。
十五、用操作系统类比把整套架构记牢
这个类比不完全等价,却非常好用:
| 操作系统 | Agent Runtime |
|---|---|
| CPU | LLM |
| RAM | Context Window |
| 进程状态 | Graph State |
| 进程快照 | Checkpoint |
| 磁盘/工作目录 | Filesystem / Backend |
| 数据库 | Store |
| 子进程 | SubAgent |
| Swap / 外置工作集 | Filesystem Offloading |
于是你可以这样理解:LLM 像 CPU,只应该处理当前工作集;Context 像 RAM,昂贵且有限;State 是当前进程现场;Checkpoint 负责恢复现场;Store 是需要长期保存的数据;Filesystem 是外部工作空间;SubAgent 是隔离执行边界。
这正是 Deep Agents 类设计要解决的问题:让 Agent 的"可处理信息量"不再等同于单次模型的 Context Window。
十六、一个完整的生产级心智模型
最后把所有组件放到同一张图里:
text
User / Tenant
│
▼
Agent Runtime
┌─────────────────┼─────────────────┐
▼ ▼ ▼
Graph Execution Context Manager Filesystem Tools
│ │ │
▼ ┌───────┼───────┐ ▼
Checkpointer │ │ │ CompositeBackend
│ History Memory Workspace │
▼ summarize retrieve select │
Thread State │ │
messages/todos/files ▼ ┌─────────┼─────────┐
Context Builder ▼ ▼ ▼
│ State Store FS
▼ Backend Backend Backend
LLM │
▼
Semantic / Episodic /
Procedural / Archive
Conversation / Task Outcome
│
▼
Candidate → Extract → Retrieve old → Policy / Conflict → Add / Update / Ignore
│
└────── Hot path 或 Background ──────┘
这张图中,每个组件各自回答一个问题:
| 组件 | 它负责回答的问题 |
|---|---|
| Checkpointer | Agent 执行到哪里了,怎样恢复? |
| StateBackend | 当前 thread 的工作文件放哪里? |
| StoreBackend | 跨 thread 的持久记忆如何读写? |
| FilesystemBackend | 怎样受控地操作真实项目文件? |
| CompositeBackend | 一条文件路径应该路由到哪个存储? |
| MemoryMiddleware | 哪些重要记忆应在推理时直接可见? |
| Memory Pipeline | 什么值得记,如何更新与解决冲突? |
| Memory RAG | 当前任务应该取回哪些长期记忆? |
| Context Manager | 单次 LLM 调用究竟看哪些内容? |
| Summarization / Offloading / SubAgent | 如何控制历史、材料与子任务的上下文规模? |
十七、面试时如何把它讲清楚
如果面试官问:"为什么要专门设计 Agent Memory?直接存聊天记录不行吗?"
可以这样回答:
聊天记录只覆盖了信息的一种形态。生产 Agent 需要同时处理 thread 内的任务状态恢复、跨 thread 的用户与项目记忆、工具与文件工作空间,以及单次调用的 Context Budget。LangGraph 中 Checkpointer 保存整个 Graph State,用于 thread-scoped 的短期工作记忆和可恢复执行;Store 保存跨 thread 的长期数据。Deep Agents 通过 filesystem 与 Backend 抽象,让 Agent 用统一文件操作访问 State、Store 或真实工作区,并用 MemoryMiddleware、检索和 Context Engineering 决定哪些信息真正进入模型上下文。真正难点还包括长期记忆的抽取、冲突、权限隔离、过期与检索治理。
如果追问"为什么不能只增加 Context Window",可以补一句:
大窗口不会改变长时运行 Agent 的数据持续增长这一事实。工程目标不是让模型永远背着所有历史,而是利用总结、外置文件、检索和子任务隔离,维持小而相关的工作集。
结语:Memory 的本质是"信息生命周期设计"
当你把 Agent Memory 理解为"聊天记录",系统只会不断积累文本;当你把它理解为信息生命周期设计,架构就会清晰得多:
- 当前任务现场进入 Graph State,并由 Checkpointer 保存;
- 跨会话的稳定价值进入 Store,并按身份隔离;
- Agent 用 Backend 抽象访问不同类型的工作空间;
- 重要小记忆可直接注入 Context,大记忆必须检索;
- 旧历史被总结,大材料被外置,子任务上下文被隔离;
- 长期记忆不是"多存",而是"有判断地写、可解释地更新、按需地读"。
最简洁的总结是:
用 Checkpointer 管当前 thread 的可恢复状态;用 Store 管跨 thread 的长期信息;用 Backend 统一文件读写;用 Memory Governance 决定什么值得记;用 Context Engineering 决定模型现在该看到什么。