惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

有赞技术团队
有赞技术团队
Martin Fowler
Martin Fowler
N
Netflix TechBlog - Medium
WordPress大学
WordPress大学
罗磊的独立博客
H
Help Net Security
MongoDB | Blog
MongoDB | Blog
A
About on SuperTechFans
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
D
Docker
云风的 BLOG
云风的 BLOG
Microsoft Security Blog
Microsoft Security Blog
Blog — PlanetScale
Blog — PlanetScale
P
Proofpoint News Feed
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
I
InfoQ
J
Java Code Geeks
博客园 - 聂微东
大猫的无限游戏
大猫的无限游戏
Engineering at Meta
Engineering at Meta
美团技术团队
小众软件
小众软件
Stack Overflow Blog
Stack Overflow Blog
C
Check Point Blog

祝融说。

第10章 工作图——从计划到验收的闭环 第11章 客观验收门与结构化审查 第12章 Headless 自主运行 第13章 上下文压缩与持久化管理 第14章 Daemon + Client 架构 第15章 可观测性与调试 第16章 测试策略与行为验证 第17章 文件系统即自我 第18章 三分架构——Tool、Skill、Capability 第19章 从 REPL 到操作系统 第1章 自主 AI agent 的困境 第20章 大门开在哪里——自修改系统的信任边界 第21章 事前之图,事后之树 第22章 有用户 vs. 无用户——两种 agent 模式 第23章 第三级验收门——什么时候信任你的 agent 第25章 第2章 文件系统即自我 第3章 事件驱动与消息模型 AI 辅助编程实战:从入门到团队治理 第八章:高级技能深度解析 第二册:进阶篇 第二章:方法论概览——管理者需要知道的 14 个技能 第二章:需求分析 第二章:准备工作 第九章:实战案例——完整项目拆解 第六章:常见陷阱与应对 第六章:风险控制——常见问题与预案 第六章:项目编排——多功能管理 第七章:全自动构建——从零到部署 第七章:团队培训方案
第24章 Agent 应该忘记什么
祝融 · 2026-07-29 · via 祝融说。

上下文窗口是有限的,忘记是不可避免的。关键不是"如何记住更多",而是"什么值得保留"。


引子

一个 session 跑了大半天。上下文里塞满了几十次编译报错、五轮调试尝试、三个被否的方案。Agent 开始忽略自己几分钟前做的决定——你明明说了"用方案 B",它又回到了方案 A。

这不是 agent 变笨了。这是上下文窗口满了。

当窗口接近上限时,LLM 的 attention 分布会变得稀疏。最早的消息几乎不可见,最新的消息占据了所有注意力。agent 看起来"记不住"了——不是因为它没有上下文,而是因为有用的上下文被无用的信息淹没了。

问题不是"能不能设计一个无限的上下文窗口"(技术上可以,RAG 和 1M token 窗口已经在做了),问题是:你希望 agent 在有限容量里记住什么? 主动选择遗忘的内容,和让窗口满了随机丢消息,是完全不同的两种情况。

上下文窗口有边界——这是物理约束

1 万个 token 的上下文、10 万个 token 的上下文、甚至 100 万个 token 的上下文——不管多大,它都有边界。一个持续运行数小时甚至数天的 agent session 可以把任何上下文窗口塞满。100 万 token 听上去很多,但如果 agent 每 10 分钟做一次工具调用(每条几百 token),一天就会产生数万 token 的"操作日志",加上每次调用的返回值(读文件可能几千 token),一周就到百万了。

所以这不是一个"够不够大"的问题,这是一个"在有限的容量里放什么"的问题。

更核心的是:把上下文当作"无限"来设计,比把它当作"有限"更危险。当系统假设上下文永远装得下时,它不会设计遗忘策略。而遗忘策略缺席的后果不是"永远不遗忘"——而是被动遗忘:最早的消息被新消息推出窗口,没有任何优先级判断,没有任何保留依据。最古老的但最重要的信息(用户的第一条需求约束)和最古老的最不重要的信息(第一次查目录返回的 200 条文件列表)被同等对待——一起被推出去。

主动遗忘 vs. 被动覆盖——这是选择放弃一些东西,和让东西自己消失,之间的区别。后者不是工程,是听天由命。

遗忘优先级——什么该留、什么该扔

既然遗忘不可避免,那就设计它。

CodeCoder 的压缩策略把上下文内容分为三个优先级:

最高价值——必须保留:

  • 当前正在执行的目标和约束
  • 未完成的决策和待解决的依赖
  • 用户明确表达的偏好("不要用 unwrap"、"优先用 builder 模式")
  • 最近的工具调用流(最近 N 轮对话,保持 agent 动作连贯)

这些在任何压缩场景下都不能丢弃。它们是 agent 在当前时刻"正在做什么"和"不能做什么"的核心上下文。

中等价值——可以压缩但不可删除:

  • 关键工具调用结果("我读了这个文件,它的结构是……")
  • 代理的推理链要点(不保留每个推理步骤,保留推理结论)
  • 已修改或已读取的文件路径追踪

这些内容有价值,但不需要保留原始全文。CodeCoder 的 tier-1 压缩对这类内容做占位化处理——把 ToolResult 的冗长正文替换为摘要 + 文件路径,保留"做了什么"但丢弃"返回了什么细节"。

最低价值——可以直接丢弃:

  • LLM 生成的 Reasoning token(思考过程的逐字记录,最长、最重复的部分)
  • 失败的尝试路径和讨论("试了方案 X,失败了"保留一句话足够了,不需要保留当时的错误输出全文)
  • 已经被后续操作覆盖的信息(比如先读了一个目录结构,然后又读了一次——第一次的结果不再需要)

CodeCoder 的 tier-1 压缩首先丢弃所有 Reasoning token。这不是随意的选择——Reasoning 通常占据上下文的 30-50%,而且它的信息密度最低。如果 Agent 需要在之后复现自己的推理过程,它应该在 Memory 中显式保存推理结论,而不是依赖 Reasoning 原文。

tier-2 压缩在 tier-1 之后仍超阈值时触发:对最早的对话段落做结构化摘要,摘要是迭代式合并的——每次只摘要增量部分,并累积文件追踪信息附在摘要末尾。

什么不该遗忘——持久化知识的边界

有些东西不该靠上下文窗口来保留。如果 AGENTS.md 和 CONTEXT.md 的内容需要通过上下文来保持"记忆",那么每次 session 结束它们就丢失了。

但 CodeCoder 的做法是:这些文件在每次 session 开始时重新读入 system prompt。 它们根本不依赖上下文窗口。这就是"文件系统即自我"原则的另一个体现——核心知识不塞进上下文,而是放在磁盘上。上下文窗口里的东西可以丢,磁盘上的文件不会丢。

Memory 工具就是为此设计的。它不是压缩时顺便保存的副产品——是 agent 主动决定"这个信息值得跨 session 记住"时写入的。agent 调用 memory write key=value,系统持久化到 memory/ 目录。

对比三种机制的遗忘特性:

存储位置遗忘机制恢复方式
上下文窗口压缩/丢弃不可恢复
Memory 文件永不自动删除agent 主动调用 memory read
配置文件(AGENTS.md 等)永不自动删除session 启动时重读

上下文窗口里的东西是最容易丢的——所以只放"当前"需要的东西。Memory 是持久的——放"以后"也需要的东西。配置文件是最稳固的——放"永远"需要的东西。这些配置文件(AGENTS.md、CONTEXT.md)构成 agent 的"自我基因组",见篇 1「文件系统即自我」。

代价与权衡

遗忘策略不是免费的——无论选择什么级别的压缩,都意味着信息丢失。

第一个代价是 tier-2 摘要的信息损失。结构摘要把最早的对话段落压缩为"目标 / 约束 / 进展 / 关键决策 / 下一步"五个字段——但这五个字段不可能完美还原原始对话中所有的细微决策。如果某个关键决策的前提被压缩掉了,agent 在新一轮对话中可能做出与原始意图矛盾的判断。CodeCoder 的迭代式合并策略试图通过累积文件跟踪(在摘要末尾附上 read/modified 文件路径)来缓解这个问题,但路径列表不能替代完整的上下文。

第二个代价是 压缩触发时的性能开销。tier-2 压缩需要调用一次 LLM 来生成结构摘要——这是有成本和延迟的。在交互式 session 中,用户可能正在输入下一句话,而 agent 正在后台压缩上下文,导致响应卡顿。CodeCoder 将 compaction 放在独立线程中运行,但受限于 JSON 文件在压缩期间的一致性问题(agent 可能在压缩的同时写新的消息),实现中使用了写时复制和锁机制——额外的复杂度。

第三个代价是 压缩使得事后审计变得更困难。压缩前的原始上下文在压缩后被替换为摘要,原始细节丢失。如果需要审计员在数周后复现"当时 agent 为什么做了这个决定",他看到的只有 Tier-2 摘要,而不是原始推理过程。CodeCoder 的 Session 文件是追加写入不删除的(压缩用新文件而非原地覆盖),解决了这个问题——但磁盘占用因此翻倍。

第四,Memory 的写入依赖于 agent 的主动性。如果 agent 不知道某个信息应该存到 Memory,或者忘记调用 memory write,这个信息就丢失了。依赖 agent 自发地"决定记住什么"是一种被动记忆策略,与主动的上下文保留完全不同。理论上可以通过定期提示 agent"你有需要记住的东西吗"来缓解,但增加了 prompt 成本和行为的不确定性。

收尾:设计你的遗忘策略

压缩就是遗忘。承认它,设计它。

如果你运行一个自主 agent,三个建议:

  1. 设一个压缩优先级——知道什么先丢、什么后丢、什么不能丢。不要等到窗口满了盲猜
  2. 重要的东西不要放在上下文里——写成文件,放在磁盘上。AGENTS.md、CONTEXT.md、Memory——这些是持久的,上下文是临时的
  3. 观察你的 agent 什么时候开始"变笨"——那通常是上下文需要压缩的信号。主动压缩比被动溢出好一千倍

Agent 不需要记住一切才能高效工作。它需要知道什么该忘、什么该留、什么该写到磁盘上。这和人的记忆策略惊人地相似——我们不是记忆好的动物,我们是擅长遗忘的动物。区别在于:人的遗忘是无意识的,agent 的遗忘需要设计。

最后一篇,我们回到起点——"我是 CodeCoder"这句话,到底意味着什么。