第 6 章:记忆、状态与上下文,不是一个东西
本章目标:把 Agent 系统里最容易混掉的三个概念拆开:记忆、状态、上下文。
本章对应总纲:docs/ebook-outline.md中“第 6 章正文写作提纲(2026-03-31 归档)”。
6.1 为什么很多 Agent 讨论一谈到“记忆”就开始变糊
一说到 Agent 的 memory,很多文章立刻就把一堆东西混成一团:
- 对话历史
- 长期记忆
- 用户偏好
- 任务进度
- 文件系统状态
- 检索结果
- 摘要压缩
最后什么都叫 memory。
这很糟。因为一旦概念不分,工程问题就没法诊断。
比如一个系统出问题,到底是:
- 忘了上一轮做过什么?
- 不知道当前任务进度?
- 丢了长期偏好?
- 还是上下文塞太多,已经读不动了?
这些根本不是一个问题。
所以这一章先做一件很朴素的事:
把记忆、状态、上下文拆开。
不拆开,后面所有“记忆设计”讨论都会飘。
6.2 先给三个词下最务实的定义
6.2.1 上下文(Context)
上下文是当前这一轮判断所能直接看到的信息集合。
它可能包括:
- 当前用户消息
- 最近几轮对话
- 刚刚的工具输出
- 当前读取到的文件片段
- 当前任务约束
上下文的特点是:
- 离当前决策最近
- 直接参与模型推理
- 容量有限
- 可能随轮次不断变化
6.2.2 状态(State)
状态是系统当前运行位置的结构化表示。
它关心的是:
- 任务进行到哪一步了
- 哪些动作已经做过
- 哪些结果已经确认
- 当前是否处于待确认、待重试、已完成等阶段
状态的重点不是“记住内容”,而是“标记系统所处位置”。
6.2.3 记忆(Memory)
记忆是跨轮次、跨阶段、甚至跨会话仍然值得保留的信息。
它可能包括:
- 用户长期偏好
- 项目背景事实
- 稳定工作规则
- 外部资源位置
- 已沉淀的经验性约束
记忆的重点不是当前局部判断,而是后续还值得复用。
6.3 为什么这三个概念不能混用
因为它们回答的是三种完全不同的问题:
| 概念 | 回答的问题 | 时间尺度 |
|---|---|---|
| 上下文 | 我这轮现在看到了什么? | 短 |
| 状态 | 我现在运行到哪里了? | 中 |
| 记忆 | 哪些信息以后还值得保留? | 长 |
这里还要再补一刀:
| 相关概念 | 它是什么 | 不是什么 |
|---|---|---|
| 外部环境状态 | 文件系统、仓库、接口返回、页面状态等真实世界情况 | 不是系统内部运行状态 |
也就是说:
- 内部状态 关心系统自己跑到哪一步
- 外部环境状态 关心外部世界现在是什么样
两者都会影响决策,但不是一回事。
如果把它们混在一起,系统很快会出现三类典型垃圾:
第一类:该短的不短
把一堆历史内容一直塞在当前上下文里,结果模型越来越迟钝。
第二类:该结构化的不结构化
本来应该用状态字段表示“当前已完成第 2 步”,结果却让模型从聊天记录里自己猜。
第三类:该持久的不持久
用户早就说明过偏好和项目规则,结果系统下一次又全忘了。
这些都不是“记忆能力不够强”,而是概念没分清。
6.4 上下文:它是当前推理的工作台,不是仓库
6.4.1 上下文的职责只有一个
上下文真正的职责很简单:
为当前这一轮判断提供足够且相关的信息。
注意关键词是“当前”“足够”“相关”。
它不是越多越好,更不是把能看到的东西全塞进去。
6.4.2 为什么上下文膨胀是 Agent 的常见病
只要任务稍微复杂一点,系统就会积累大量信息:
- 报错日志
- 搜索结果
- 文件内容
- 中间计划
- 多轮反馈
如果不做筛选和压缩,上下文很快就会膨胀到两个结果:
- 模型读不动重点
- 当前判断开始被噪音污染
所以好系统一定会主动处理上下文,而不是任由它无限累积。
6.4.3 上下文管理的核心不是“更多”,而是“更准”
很多人一提上下文,就只想到窗口长度。
这太表面了。真正关键的是:
- 当前信息是否相关
- 是否保留了关键约束
- 是否删掉了已经无用的细节
- 是否把过去的长内容压成了当前可用表示
上下文质量比上下文数量更重要。
6.5 状态:系统不靠回忆运行,而靠状态推进
6.5.1 为什么状态层本质上是运行位置标记
一个 Agent 如果要持续推进任务,就必须知道自己现在在哪。
这不是文学问题,是运行问题。
例如系统必须知道:
- 当前目标是否已建立
- 是否已经读过关键文件
- 当前修改是否已验证
- 是否正等待用户确认
- 是继续当前路径,还是已经进入回退分支
这些都更适合表示为状态,而不是让模型从整段历史对话里反向推理。
6.5.2 为什么“让模型自己记住”不是好设计
因为那会把本来明确的运行信息,变成模糊的自然语言猜测。
本来你可以直接记录:
- step = 2
- test_status = failed
- waiting_for_user = true
结果你却把这些信息埋进聊天记录里,期待模型每轮都重新理解一遍。
这不是灵活,这是偷懒。
6.5.3 状态设计得差,会出现什么问题
最典型的症状有:
- 重复执行已经做过的动作
- 忘记当前任务处于哪个阶段
- 对同一失败反复试错
- 明明在等用户确认,却继续自动往前跑
这些问题看起来像“智能不够”,其实经常只是状态管理烂。
6.6 记忆:不是为了显得聪明,而是为了减少重复成本
6.6.1 记忆真正该保存什么
记忆并不负责保存所有信息。它应该保留的是那些:
- 未来还会反复用到
- 当前代码和仓库状态里不容易直接推出来
- 对后续协作方式有稳定影响
比如:
- 用户偏好简洁回答
- 某项目当前的合规约束
- 某类问题要查哪个外部系统
- 某团队已有明确工作规则
6.6.2 什么不该进记忆
最容易犯的错,就是把一堆临时任务细节也塞进长期记忆。
例如:
- 这一轮刚跑过哪个命令
- 某个具体 bug 的临时定位过程
- 一次性的代码改法
- 当前会话里的短期上下文
这些东西通常应该留在状态、计划或当前上下文里,而不是污染长期记忆。
6.6.3 好记忆的标准
一个好记忆至少要满足三点:
- 对未来真的有用
- 能和当前任务区分开
- 会被验证和更新,而不是一直陈旧地躺着
记忆不是越多越聪明。烂记忆只会把后续判断越带越偏。
6.7 三者之间到底怎么配合
现在把三者放在一条任务链里看,就很清楚了。
当用户发来一个新任务时
- 当前消息进入上下文
- 系统建立初始状态
- 若有相关长期偏好或项目背景,则从记忆里取用
当系统执行了几轮动作之后
- 工具输出进入上下文
- 任务阶段变化写入状态
- 如果发现了值得长期保留的事实,才考虑进入记忆
当上下文过长时
- 旧内容被压缩
- 状态继续保留关键运行位置
- 记忆只保留真正长期有价值的内容
这就形成了一个很清楚的分工:
- 上下文负责当前看什么
- 状态负责当前走到哪
- 记忆负责以后还要记什么
6.8 为什么很多所谓“记忆系统”其实只是在做检索拼接
市场上很多产品喜欢说自己有 memory。
结果你一看,本质上只是:
- 从历史里检索几段文本
- 再拼回当前 prompt
这当然有用,但它并不自动等于一个成熟记忆系统。
因为真正的记忆系统还应该回答:
- 这些内容为什么值得长期保留?
- 它们什么时候该更新?
- 过期了怎么办?
- 和当前状态、当前上下文怎么分工?
如果这些问题不回答,那很多“记忆能力”其实只是检索增强,不是完整的记忆设计。
6.9 用 Claude Code 看一个现实里的分层样本
Claude Code 这类系统很适合拿来理解这种分层,因为它明显不是把所有东西都扔进一锅 prompt 里。
先看当前系统对“长期保留信息”是怎么设计的。会话里已经明确区分了 user、feedback、project、reference 四类 memory,而且要求:
- 先写到独立 memory 文件
- 再在
MEMORY.md里做索引 - 需要时先验证记忆是否仍然与当前代码或资源一致
这套规则本身就在说明:记忆不是聊天历史,也不是当前执行位置,而是跨会话仍值得保留、还能被校验的事实。
再看当前环境里的任务与计划机制。任务列表、in_progress / completed 状态、计划模式、当前步骤推进,这些显然更接近运行状态层,而不是长期记忆层。它们回答的是“现在跑到哪了”,不是“以后还值得记什么”。
至于上下文层,就更短平快了:当前用户消息、最近工具输出、刚读到的文件片段、这轮判断所需约束,都会直接进入当前推理工作台。它们最重要的特征不是长期价值,而是当前轮可见且当前轮相关。
如果再往源码样本上压一层,examples/settings/settings-strict.json:1 也在提醒你一个常被忽略的事实:系统运行边界本身也是上下文和状态管理的一部分。因为当前到底允许不允许 Bash、能不能访问 WebSearch / WebFetch,会直接改变这轮判断可选的动作空间。
所以从 Claude Code 这个样本里,至少能抽出几条非常硬的分层规则:
- 当前轮直接参与推理的信息,放上下文层
- 任务推进位置和阶段信号,放状态层
- 跨会话仍值得复用、且代码里不容易直接推出的事实,才放记忆层
- 外部世界本身的真实情况,要单独看作环境状态,别和内部运行状态混掉
- 所有长期信息都应该允许校验和更新,别把记忆当神谕
这个例子的价值,不只是印证概念区别,而是告诉你:现实里的 Agent 系统如果不把不同时间尺度、不同作用范围的信息拆开管理,后面一定会越来越乱。
6.10 本章小结
这一章最关键的事,是把三个经常被混用的词拆开。
你现在应该记住六件事:
- 上下文是当前推理的工作台,不是长期仓库。
- 状态是系统运行位置的表示,不该靠聊天记录反推。
- 记忆保存的是未来还值得复用的信息,而不是所有历史。
- 把三者混在一起,会直接造成上下文污染、状态混乱和长期记忆失真。
- 很多所谓 memory 系统,其实只是检索拼接,不等于完整记忆设计。
- 成熟 Agent 的关键,不是“记得更多”,而是“分层更清楚”。
下一章我们继续往下走,专门看上下文为什么会失控,以及一个 Agent 系统该怎样处理压缩、摘要、裁剪和信息保真这几个麻烦问题。