Skip to content

第 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 里。

先看当前系统对“长期保留信息”是怎么设计的。会话里已经明确区分了 userfeedbackprojectreference 四类 memory,而且要求:

  • 先写到独立 memory 文件
  • 再在 MEMORY.md 里做索引
  • 需要时先验证记忆是否仍然与当前代码或资源一致

这套规则本身就在说明:记忆不是聊天历史,也不是当前执行位置,而是跨会话仍值得保留、还能被校验的事实。

再看当前环境里的任务与计划机制。任务列表、in_progress / completed 状态、计划模式、当前步骤推进,这些显然更接近运行状态层,而不是长期记忆层。它们回答的是“现在跑到哪了”,不是“以后还值得记什么”。

至于上下文层,就更短平快了:当前用户消息、最近工具输出、刚读到的文件片段、这轮判断所需约束,都会直接进入当前推理工作台。它们最重要的特征不是长期价值,而是当前轮可见且当前轮相关

如果再往源码样本上压一层,examples/settings/settings-strict.json:1 也在提醒你一个常被忽略的事实:系统运行边界本身也是上下文和状态管理的一部分。因为当前到底允许不允许 Bash、能不能访问 WebSearch / WebFetch,会直接改变这轮判断可选的动作空间。

所以从 Claude Code 这个样本里,至少能抽出几条非常硬的分层规则:

  • 当前轮直接参与推理的信息,放上下文层
  • 任务推进位置和阶段信号,放状态层
  • 跨会话仍值得复用、且代码里不容易直接推出的事实,才放记忆层
  • 外部世界本身的真实情况,要单独看作环境状态,别和内部运行状态混掉
  • 所有长期信息都应该允许校验和更新,别把记忆当神谕

这个例子的价值,不只是印证概念区别,而是告诉你:现实里的 Agent 系统如果不把不同时间尺度、不同作用范围的信息拆开管理,后面一定会越来越乱。


6.10 本章小结

这一章最关键的事,是把三个经常被混用的词拆开。

你现在应该记住六件事:

  1. 上下文是当前推理的工作台,不是长期仓库。
  2. 状态是系统运行位置的表示,不该靠聊天记录反推。
  3. 记忆保存的是未来还值得复用的信息,而不是所有历史。
  4. 把三者混在一起,会直接造成上下文污染、状态混乱和长期记忆失真。
  5. 很多所谓 memory 系统,其实只是检索拼接,不等于完整记忆设计。
  6. 成熟 Agent 的关键,不是“记得更多”,而是“分层更清楚”。

下一章我们继续往下走,专门看上下文为什么会失控,以及一个 Agent 系统该怎样处理压缩、摘要、裁剪和信息保真这几个麻烦问题。