正文:
上一期我们讲了 Skill Agent 小知识 | Skill 的设计与生命周期:从工具接口到能力模块。一套做事方法被封装以后,Agent 可以在需要时发现、加载,再把它用于新的任务。但一次任务留下的,不只有一套方法。它还可能包括发生的故障、仓库配置、用户偏好,以及尚未验证成熟的经验。这些内容不一定适合写进 Skill,也不会因为在上一轮对话里出现过,就自动来到下一次会话。
假设一个开发者 Agent 正在维护 payment-service。在会话 A 里,回调接口的集成测试一直超时。Agent 查看终端报错、Makefile 和 compose.yaml,发现测试依赖没有通过当时的 test profile 启动。修复配置,重新运行测试,问题解决。
一周后,会话 B 又遇到了相似的超时。Agent 能不能找到上次的排障经历?即使找到了,它又该取回完整聊天,还是只取回其中几条结论?再过一段时间,会话 C 打开仓库,发现项目已经取消旧的 test profile,测试入口也发生了变化。旧记忆和当前代码给出不同答案时,系统应该怎样处理?
跨会话记忆要解决的,就是这三个问题:会话结束后该记什么,新会话开始时怎样取回,以及旧记忆怎样面对新事实。
懒人图解版

图 1. 跨会话记忆的三个核心环节:会话 A 结束后,系统筛选值得长期保留的信息并附上必要元数据;会话 B 根据当前用户、项目和任务取回少量相关记忆,放入当前上下文;会话 C 发现事实变化后,让旧记忆与新证据对账,保留真实历史并更新当前事实。
这张图展示的是一条常见的工程链路,不是所有 Agent 系统统一采用的固定接口。不同系统可以选择不同的存储、索引和触发方式,但都绕不开三个动作:写入、取回和更新。
跨会话的缺口
在会话 A 里,Agent 手上有很多正在变化的信息:当前目标、刚读到的文件、终端报错、待验证的假设、已经执行的命令,以及接下来的计划。这些信息共同支撑它完成眼前的任务,也会占用模型此刻的上下文。
会话结束以后,情况就变了。新的会话会重新构建当前上下文。上次出现过的日志、结论和文件片段,如果没有被外部系统筛选、保存并重新取回,模型通常无法继续使用。这里的问题不是机器学习中常说的「灾难性遗忘」,而是过去的信息已经不在模型当前能够看到的范围内。
那把完整聊天记录保存下来行不行?它当然可以留下原始材料,却没有直接得到可用的记忆。聊天和执行日志往往很长,里面混着失败尝试、临时假设、重复内容和敏感信息。下一次任务如果把全部历史重新塞进上下文,不但成本更高,还可能让已经过期的判断压过眼前的新证据。
所以,存得下和想得起并不是一回事。跨会话记忆关心的也不是怎样恢复一项尚未完成的任务。任务状态和 Checkpoint 主要回答「任务已经进行到哪里,怎样从中断处继续」;跨会话记忆关心的是「一项任务已经结束,其中哪些信息仍值得在未来任务中再次使用」。一个偏向续跑,一个偏向复用。
真正的链路,要从会话 A 结束时的写入判断开始。
会话 A:任务结束后,哪些内容值得保存
会话 A 完成排障以后,系统手上有一大堆材料:最初的超时报错、几次失败尝试、当时查看过的配置、真正的故障原因、最终修改,以及回归测试结果。如果什么都不记,Agent 无法在未来复用这次经历。但如果什么都记,记忆库很快就会出现重复、过期和噪声,敏感信息的范围也会越来越难控制。
所以写入的第一步不是保存,而是筛选。候选信息可以来自用户明确提供的事实、当前仓库和文档、工具执行结果、任务产物,以及已经验证的结论。系统需要继续判断:这条内容对未来任务是否重要,是否足够稳定,属于哪个用户和项目,来源是否可靠,有没有经过验证,是否包含敏感信息,以及系统里是否已经存在重复或冲突条目。
记忆系统经常借用工作记忆、情景记忆、语义记忆和程序性记忆这几种分类,帮助判断不同内容应该怎样保存和使用。对本期来说,不需要把它们展开成四套完整体系。回到会话 A,看它们可能留下什么就够了。
| 信息类型 | 会话 A 中的例子 | 在跨会话链路中的作用 |
| 工作记忆 | 当前报错、正在查看的文件、待验证假设 | 服务眼前任务,任务结束后通常不会整体保留 |
| 情景记忆 | 这次故障的症状、根因、动作和结果 | 保留一次可追溯的历史经历 |
| 语义记忆 | 当时版本下的测试入口和配置关系 | 保存相对稳定的项目事实,但需要时间和适用范围 |
| 程序性记忆 | 排查测试超时的一组步骤或顺序 | 作为方法候选,经过验证后再复用 |
这是一种便于设计读写规则的工程抽象,不代表系统必须部署四套数据库。同一次经历也可以产生不同用途的条目:完整修复过程可以成为情景记忆,从中确认的项目配置可以成为语义记忆,反复验证有效的排查步骤则可能成为程序性记忆。
分类只是第一层。要让一条记忆在未来能够被正确取回和更新,还需要为它留下判断依据。会话 A 结束时,一条情景记忆可能写成这样:
type: episodic
scope: project/payment-service
content: 回调集成测试因测试依赖未启动而超时,修复后回归通过
source: session-A/test-run-42
observed_at: 2026-08-18T10:30:00+08:00
verification_status: passed
confidence: high
sensitivity: internal
retention: project_policy
这里的字段只是示意,不是行业统一的记忆结构。真正重要的是,内容之外还保留了作用域、来源、时间、验证状态和保留策略。
scope 说明它适用于哪个项目或仓库,source 说明结论从哪里来,observed_at 记录它在什么时候被观察到,verification_status 区分已经验证的事实和尚待确认的推断,retention 则约束它应该保留多久。
这些元数据看起来比正文更像工程细节,却直接决定了未来能不能对账。只有一句「测试应该这样启动」,系统既不知道它属于哪个项目,也不知道它在什么版本下成立,更不知道它来自实际执行结果,还是来自模型的一次总结。
用户明确说过的话、系统根据行为做出的推断、外部文档里的信息,也需要分开标记。一次临时选择不能直接升级成永久偏好,一次模型总结也不能自动获得和仓库文件相同的可信度。
到这里,系统只是把值得保留的内容写到了会话之外。它能不能在未来发挥作用,还要看下一次任务能否在正确的时机,把正确的条目找回来。
会话 B:新会话如何找到相关历史
一周后,会话 B 再次出现了相似的回调超时。Agent 此刻能够看到的是新的任务描述、当前仓库和刚产生的错误,而不是会话 A 的全部过程。系统需要从这些当前信号出发,判断是否检索历史记忆。用户、组织、项目、仓库、任务目标、错误信息和当前任务阶段,都可以成为检索线索。但在查找「内容是否相似」之前,系统应该先回答另一个问题:这条记忆是否允许被当前身份和当前项目读取?
身份和权限过滤应该先于内容召回。否则,一条文字上高度相似、实际却属于另一个用户或另一个项目的记录,就可能被带进当前任务。对生产系统来说,这不只是相关性错误,还可能构成越权访问。
确定可访问范围以后,系统再召回候选条目。关键词、语义相似度、结构化字段和时间范围都可以参与检索;排序时还要考虑来源、验证状态、版本和适用范围。
向量相似度可以帮助找到「说法不一样但含义接近」的内容,却不适合独自决定结果。两条文字很像的记录,可能对应不同版本;一条稍旧但经过实际测试验证的记录,也可能比刚刚生成、尚未验证的推断更可靠。
检索还要服从上下文预算。会话 B 不需要重新加载会话 A 的全部聊天,只需要取回与当前故障直接相关的经历、项目事实和排查方法,并保留必要的来源信息。

图 2. 跨会话记忆的写入与取回
到了这一步,记忆与当前上下文的关系就很清楚了。本文讨论的跨会话记忆保存在模型之外,当前上下文则是模型这一轮能够看到的信息。外部记忆只有经过检索、筛选并加入当前上下文,才会成为当前任务可以使用的内容,并影响这一轮推理。
Agent 并不是凭空「想起」了会话 A,而是外部系统在会话 B 中重新提供了过去的信息。如果系统没有找到足够可靠的结果,就应该明确返回空结果,让 Agent 根据当前仓库重新调查。没有记忆不可怕,把猜测伪装成记忆才危险。
取回让过去重新可见,但过去曾经正确,不等于现在仍然正确。当仓库和运行结果给出新证据,系统还需要处理旧记忆与当前事实之间的冲突。
会话 C:旧记忆如何面对新事实
到了会话 C,项目已经取消旧的 test profile,集成测试迁移到了新的任务入口。旧语义记忆仍然记录着过去的启动方式,而当前 README、任务配置和实际命令结果给出了新的答案。
这时不能盲信记忆,也不适合把旧记录一键覆盖。系统需要先判断冲突双方是否描述同一个用户、项目和事实对象,再比较来源、时间、验证状态与适用范围。处理结果可能是并存、合并、版本化、继续验证、请求用户确认,或者删除错误和敏感条目。具体采用哪一种,要看信息类型和风险。
发现冲突
→ 核对用户、项目和事实对象
→ 比较来源、时间、验证状态与适用范围
→ 选择并存、合并、版本化、继续验证、用户确认或删除
→ 更新当前有效版本,并保留必要的变更历史
这是一组工程判断点,不是所有记忆系统必须照搬的固定算法。
在 payment-service 的案例里,当前仓库文件和实际执行结果通常比旧会话总结更接近当前状态,但来源优先级不能写死。仓库文档可能没有同步,单次命令结果也可能受到环境影响。证据不足时,系统可以暂时保留多个候选,并继续验证。
这里有一个很关键的区分:历史事件本身仍然成立,但从历史事件中抽出的「当前事实」可能已经过期。「会话 A 曾经因为测试依赖没有启动而超时」是一条情景记忆。那次故障确实发生过,不会因为项目后来迁移就变成假的。
「payment-service 当前必须通过旧 test profile 启动测试」则是一条面向当前状态的语义记忆。项目迁移以后,它就需要结束有效期,并由新版本接替。
变化的是项目现在怎样运行,不是过去是否发生过那次故障。证据足够时,系统可以关闭旧语义条目的有效期,再写入新版本,同时保留来源和变更历史。这样,会话 A 的排障经历仍然可以用于复盘,但下一次任务不会继续把旧入口当成当前答案。

图 3. 旧记忆与新事实的对账:系统根据来源、时间、验证状态和适用范围进行判断,再选择版本化、并存、继续验证或人工确认,而不是让新内容无条件覆盖旧内容。
这也解释了为什么会话 A 写入时必须保存时间和来源。没有这些元数据,系统很难区分过期事实、真实历史和错误结论,只能在两段互相冲突的文本之间猜测。
写入、取回和更新,到这里构成了跨会话记忆的完整主链路。
跨会话记忆与上下文、任务状态、RAG 的边界
把这条链路走完,再看几个容易混淆的概念,边界会清楚很多。
| 概念 | 主要回答 | 与跨会话记忆的关系 |
| 当前上下文 | 模型这一轮能够看到什么 | 外部记忆只有被取回并加入当前上下文,才能参与当前推理 |
| 任务状态 | 同一项任务进行到哪里、怎样从中断处继续 | 状态更偏向任务续跑,记忆更偏向在未来任务中复用过去的信息 |
| RAG | 怎样检索并提供外部信息 | RAG 可以为记忆读取提供检索能力,但不覆盖写入、更新、失效和删除 |
记忆和 RAG 最容易被放在一起讨论,因为记忆读取确实可以使用向量检索、关键词检索或结构化查询。但一套完整的记忆系统还要决定写什么、怎样隔离身份和项目、什么时候更新、何时删除,以及用户能否查看和纠正。检索只是其中一段链路。
跨会话记忆也天然涉及隐私、安全和用户控制。系统在写入时应尽量少存,读取时先检查用户、组织、项目、权限和租户边界。用户明确提供的事实、系统推断和外部资料需要保留不同的来源标签,不能默认把一次隐式行为固化为长期偏好。
用户还应该能够查看、修正和删除自己的记忆。不同内容可以按照业务风险设置保留期,但系统不应默认永久保存所有历史。一个只会不断收集、却无法纠错和删除的存储层,容量可能越来越大,可信度反而越来越低。
结语
回到开头的三个会话:
会话 A 结束后,系统没有照单全收,而是筛选值得留下的经历、事实和方法候选,并为它们保存作用域、来源、时间和验证状态。
会话 B 开始后,系统根据当前身份、项目和任务找到相关条目,只把少量可靠内容放回当前上下文。
会话 C 面对新的仓库证据,不是盲信过去,也不是一键抹掉过去,而是保留真实发生过的历史,同时更新已经变化的当前事实。
这才是跨会话记忆真正要完成的事。
随着经历不断积累,系统还可能从多次任务中提炼出更稳定的事实或方法。但反思得到的结论仍然需要来源、验证、反例和适用范围,不能因为听起来合理,就自动升级为长期规则或 Skill。从情景记忆走向语义记忆、程序性记忆,再走向 Skill,是另一条值得单独展开的链路。
Agent 的记忆能力,不取决于保存了多少历史,而取决于能否选择性写入、按任务取回,并在事实变化后及时对账。存得下,只说明过去还在;能在需要时找回来,并在事实变化后及时修正,才算真正记住。
当单个 Agent 需要处理的任务和上下文继续膨胀,仅靠记忆仍然不够。下一期,我们将讨论为什么要给 Agent 开子 Agent,以及「隔离优于压缩,主 Agent 只拿结论不拿过程」背后的设计思路。
参考资料
Haggai Roitman, The Hitchhiker's Guide to Agentic AI: From Foundations to Systems。
李博杰,《深入理解 AI Agent:设计原理与工程实践》。
《Agent 小知识|长任务不重来:Agent 状态保存的工程设计》。
《Agent 小知识|Skill 的设计与生命周期:从工具接口到能力模块》。
标签:#Agent小知识 #Agent记忆 #Agent #Memory #上下文管理