资讯动态

AI编码代理的失忆症救星:一套上下文压缩免疫的外部记忆工作流

发布时间:2026/10/14 11:02:21 来源:尧图企业网站定制
我见过最抽象的一幕是AI编码代理在对话接近二十万token时系统弹出一条上下文压缩通知紧接着它就像被按了记忆清除键——忘了自己正在改哪个文件忘了我们两小时前定的架构方案甚至开始一本正经地复述十轮前已经被否决的旧想法。说这是“脑叶切除术”一点不夸张会话还活着但记忆被切掉了。而且这种“手术”在长任务里几乎必然发生只是早晚问题。为了治这个病我先后从两个完全不相干的地方偷师一个是Unix体系的init.d启动机制一个是电影《记忆碎片》里的外部记忆思路。最后给代理搭了一套简单的“记忆工作流”实测下来在上下文压缩发生之后代理能在一轮对话之内恢复状态继续干活。这篇文章就把这套东西的来历、结构、模板和踩坑记录完整拆开讲。1. 那场“脑叶切除术”AI在20万token边界的失忆实录1.1 上下文压缩到底在压缩什么先说清楚问题的根源。大多数AI编码代理的上下文窗口是128k到200k token。一旦对话累计超过这个配额系统不可能把新消息直接丢掉于是就会对已有历史下手。不同产品的压缩策略不太一样。有的把最早的一部分对话整体替换成一段AI生成的摘要有的直接以滑动窗口方式砍掉中间某段消息还有的会给每条旧消息设置一个“衰减系数”越老的对话权重越低模型越“看不太清”。不管哪种方式规律都一致最早进入上下文的那些基础约束被优先牺牲。最讽刺的是最先被压缩掉的往往就是最不能丢的东西——项目背景、用户偏好、架构选型理由、验收标准。这些信息通常是在对话前几千个token里反复确认过的结果压缩发生时一个不剩。1.2 失忆之后的典型症状被压缩后的代理并不会知道自己失忆了。它会表现得非常自信非常流畅只是逻辑接不上。我总结了三个最常见的症状。症状A是重复提问。“这个项目是做什么的”“这几份文件的定位分别是什么”——这些你在第一轮就回答过的问题它会像新同事入职一样重新问一遍。症状B是新旧方案冲突。压缩前你刚定下来用某一种设计模式重构模块C压缩后它基于残缺记忆提出了一套方向完全相反的改法而且从它的视角来看一切都很正常。症状C是进度回溯。明明已经把第三个模块改完了它恢复后问的第一句话是“第一个模块是不是还没处理完”。遇到这种场面最难受的不是要多花时间而是你根本不确定它下一步会不会又忘一次。只要任务够大、对话够长这个循环就无法避免。1.3 为什么常规的“把话说重一点”不解决根本问题一开始我尝试过在对话里反复强调关键约束让代理多“复习”几遍。但token是有限的每多强调一遍就多占一部分上下文空间反而让压缩来得更快。我也试过把任务拆成多次会话每次重新开一个对话但那种做法等于让代理每次从胎教开始学起上下文衔接全靠人工手动粘贴成本和错误率都上去了。这件事的本质是人脑里短期记忆和长期记忆分工的问题。人类睡一觉就会把不重要的对话沉淀掉但重要的事能靠海马体固化到长期记忆里。而AI编码代理没有这个机制它的一切“记忆”都活在上下文窗口这只“临时容器”里。容器一破一段都剩不下。所以问题变成了能不能给代理装一个外部装置让它不依赖上下文也能恢复状态2. init.d给我的第一课恢复应该是“可重入”的不是“重新培养”的2.1 init.d脚本为什么可以反复执行先讲一个我特别喜欢的系统设计细节Unix里的init.d脚本。你在Linux上跑过service即可无论某个服务当前是启动还是停止状态执行一遍start脚本结果总是服务正常运行。这种性质叫幂等或者叫“可重入”。实现这个效果靠的是脚本里隐藏的检查步骤脚本开头会先问“服务是否已经在跑进程文件是否存在配置文件是否已就位”如果已满足就直接跳过安装动作如果缺失才执行补齐动作。不管系统从哪种状态进来跑完一遍脚本一定会到达目标状态。这个哲学很有意思它不假设系统“记得”什么也不假设操作者“知道”刚才发生了什么。恢复的正确姿势不是从头推演而是把状态文件拉出来看一眼按约定顺序重放一遍。2.2 第一代方案我写过“记忆补丁”但用处不大受这个启发我最初给代理设计了所谓的“记忆补丁”——一段很长的提示词把项目背景、当前进度、下一步计划全部写进去每次压缩后粘贴给代理。它确实能让代理瞬间恢复但问题也明显补丁是静态的上一轮完成的新进度不会自动同步进去。每次做完一步我都得手工把补丁改一遍改漏一次恢复效果就大打折扣。而且“补丁”本质上仍然是在往上下文里塞信息。塞的越多越占token下一次压缩反而来得更快。这属于饮鸩止渴。2.3 第二次设计让代理每次进入会话时自己“重启”后来我把思路倒过来不再试图往上下文里塞历史而是给代理一个固定的“重启流程”。每次新会话或压缩发生之后代理不靠记忆回答“我们在做什么”而是主动执行一段恢复动作——读取状态文件重建项目认知确认任务清单然后才开始干活。这就像服务器一开机init.d自动把各个服务拉起来不需要操作员回忆上次关机前手工启动了什么。代理被压缩一次就相当于一次“重启”它要做的是执行同一套恢复协议而不是努力回忆已被删除的旧消息。这套协议因为每次都从同样的文件读取状态所以是幂等的。压缩后跑一遍恢复再压缩再跑一遍还是恢复。我开始觉得这个方向对了。3. 《记忆碎片》式外部记忆把关键信息从对话里“纹”到文件上3.1 电影里的做法不信任记忆信任笔记《记忆碎片》讲的是一个短期记忆严重受损的人靠什么来维持日常行动他没有随手记的好习惯而是强制自己把所有关键信息写在纸条上、照片背面甚至直接纹在身上。他有一条核心规则当我不信任自己的记忆时我只信任外部记录。这个设定几乎可以直接平移给AI编码代理。代理在每一轮对话里都是“清醒”的但它无法可靠地把第一轮埋下的约束带到第五百轮之后。既然不可靠就不要依赖它。我们的工作不是让代理“记住更多”而是让代理知道“该去哪看”。3.2 给AI代理建一个“外部海马体”外部记录最大的优势是稳定且可被重复读取。只要文件还在任何一次新会话都能通过读取它恢复认知。这比在对话里反复强调可靠得多。我设计了一套三层记忆结构用来划分哪些信息该放在哪里第一层是会话本身只承载当前一小段推理过程。它的一切内容都默认不可靠压缩后即消失。第二层是工作层也就是memory目录下的几个核心文件。这是代理日常恢复的主要依据要求每次会话必读、每步操作后必更。第三层是长效层包括git历史、代码注释、项目README。当代理需要更深入地理解项目全局时通过git log和git diff重建过去一段时间的变更脉络。关键的区别在于会话是暂时的memory/是工作的git历史是永久的。三层各有分工代理在恢复时按顺序取用不需要把所有东西都塞进上下文。3.3 “不要教AI记住什么要教它去哪里找”这个领悟对我是颠覆性的。以前我总想着把信息喂给代理希望它“知道得更多”。现在反过来——信息放在外部文件里代理只需要知道路径和读取顺序。这跟你自己工作是一样的你不会把项目所有细节都背在脑子里但你知道设计文档放在哪个共享目录代码规范写在哪个Wiki页面。需要的时候去查比硬记更可靠。AI代理也一样给它一套“去哪个文件查什么”的规则它就能在任何压缩后重新建立认知。我把这句话写进了项目的protocol文件开头“每次进入会话先执行恢复协议。如果你发现上下文里的信息与memory目录中的记录冲突一律以memory目录中的记录为准。”4. 从理念到文件一套让上下文压缩失效的记忆工作流4.1 目录结构长什么样理念落地之后我在项目根目录下建了一个memory文件夹结构很简单四个文件memory/ ├── current-task.md # 当前任务目标、范围、进度、下一步 ├── decisions.md # 决策日志做了什么选择为什么影响哪些文件 ├── file-map.md # 项目地图各文件的职责与相互依赖 └── protocol.md # 恢复协议代理每次会话必读的执行顺序不要小看这四个文件。它们体积都很小每个通常只有几KB但承载的“信息密度”远高于几十轮碎碎念的对话记录。压缩无论发生几次代理只要还能读文件就能快速回到正轨。4.2 三个核心文件的模板current-task.md是我最常更新的文件它的模板如下# 当前任务 ## 目标 一句话描述当前要完成的主任务。 ## 范围 - 涉及目录/文件src/xxx.py、tests/test_xxx.py - 暂时不碰xx模块、xx目录 ## 当前进度 - [x] 完成数据处理函数框架 - [ ] 接入新的API并处理错误边界 - [ ] 补测试用例 ## 上次可运行状态 - 分支feature/xxx - 验证命令python -m pytest ## 下一步 1. 实现错误重试逻辑 2. 运行测试并修复失败项 ## 风险与约定 - 不要在未经确认的情况下改变对外接口decisions.md记录的是“为什么”层面的信息## 2025-06-10 #17 - 决策改用异步SQLite驱动而非同步驱动 - 原因当前瓶颈集中在磁盘IO异步可让并发更高 - 影响db.py、service层的调用方式会变 - 替代方案保留同步驱动加线程池性能和可维护性平衡后选前者file-map.md则简单粗暴按文件路径列出职责和依赖关系代理读完它就能在几秒钟内重建项目版图。4.3 protocol.md代理的“开机自检流程”真正起最大作用的是protocol.md里那份“开机自检流程”。我把代理每次进入会话后的操作顺序明确写死# 会话恢复协议 进入会话后按以下顺序执行无需用户重复解释背景 1. git log --oneline -5 查看最近提交 2. 读取 memory/current-task.md 3. 读取 memory/decisions.md 中最近 3 条记录 4. 读取 memory/file-map.md 了解模块结构与依赖 5. 根据 current-task.md 中的“下一步”开始工作 每个子步骤完成后必须执行 1. 更新 memory/current-task.md 中的进度 2. 如果产生新决策追加一条到 memory/decisions.md 3. 若本阶段已完成运行测试并做一次 git commit第一到四步其实就是“重启流程”第五步才进入实际工作。代理不需要回忆任何历史只需要照做。4.4 可以直接抄的会话恢复提示词有了这套结构实际使用时我只需要在每次会话的第一条消息里发送一段固定提示词甚至不需要解释请先不要回答任何业务问题。执行以下操作 1. 读取 memory/protocol.md 2. 严格按协议中的顺序读取对应文件 3. 用不超过5句话总结你理解的当前任务状态与下一步计划 4. 等我确认后再开始本轮工作就这么简单。上下文压缩后只要我用这段提示词开启新会话它就能自己完成“重启”。把这套流程形象地说——代理对上下文压缩几乎免疫了因为它不再把记忆放在会丢失的地方。4.5 为什么这套结构不会被压缩摧毁这里有个很关键的点protocol.md、current-task.md这些文件本身不受上下文窗口影响。对话被压缩只影响代理“当前看到了什么”它仍然有读文件的能力。只要第一步让它“去读protocol.md”它就能自己找回整个项目的状态。所以免疫的本质不是让代理“记住”而是让代理“不依赖记忆”。这和人类在健忘的情况下使用笔记、日历、清单干活是一个道理——把认知负担转移给外部系统。5. 实测与踩坑被连续压缩三轮之后代理还能不能干活5.1 一轮对照实验是怎么设计的空谈理念没用我拿本地练手的一个数据清洗工具做了实测。任务目标是把这个工具从单一脚本改成模块化结构并把所有输入输出接口整理一遍。整个任务量足够大对话累计很快会超过窗口上限。第一轮测试不启用memory工作流让代理靠对话记忆继续。当上下文即将触顶时我手动触发了一次“模拟压缩”——就是清掉代理的对话历史只保留最后一条指令让它继续完成任务。第二轮测试启用完整的memory目录和恢复协议同样聊到接近触顶执行同样的模拟压缩然后再把恢复提示词发进去。5.2 结果对比有记忆系统和没有记忆系统的差距对比结果非常直观维度无记忆系统有记忆系统压缩后首次响应重新询问项目背景与目标直接输出当前进度总结任务方案一致性出现与之前相反的接口设计完全延续原有方案回到原进度的对话轮数约6到8轮1轮人工干预次数至少3次补充背景0次没有记忆系统的时候压缩后代理不仅不记得模块划分方案甚至主动建议把已经重构好的模块再拆一遍。我需要反复粘贴背景说明它才逐渐“想起”之前的设计——准确说是靠新上下文重建了认知。有记忆系统的时候压缩后第一轮就准确说出了当前改到哪个文件、卡在哪个测试、下一步优先级是什么。整个恢复过程不超过一分钟之后直接进入干活状态。5.3 我踩过的四个坑这套方案不是第一天就顺畅运行的。实际用了两三周踩过几个坑逐个记录一下。坑一是记忆文件本身变臃肿。一开始我把current-task.md当成通用笔记本什么都往里写两周后文件直奔两千行代理每次读一遍就要耗掉大量token恢复反而变慢。后来我把任务粒度调小每个任务建一个文件完成就归档current-task.md永远只保存当前这一轮的任务信息行数控制在150行内。坑二是代理只顾读文件不更新文件。我在prompt里写了“每步完成后更新状态”但代理有时会漏掉尤其在连续做多个小改动时。解决办法是把“更新current-task.md”写进协议里的强制步骤同时在每个子任务完成后让它执行一次git commit用git提交作为强制检查点——只要看到提交记录缺失就知道它漏了更新状态。坑三是记忆文件与代码现实脱节。有时候代理改完了代码但忘了同步更新current-task.md导致下一次恢复读到的是旧状态。我的处理规则是在protocol.md里写明如果memory文件与git历史冲突一律以git历史为准并要求代理把冲突点标注出来让我处理。这个仲裁规则很重要否则文件反而会变成误导源。坑四是多代理并行时互相覆盖。我试过开两个代理分别处理不同模块它们都会去更新同一个current-task.md结果就是后写覆盖先写。后来改成每个代理有独立的task文件公共的decisions.md只能追加不允许改写彻底避免互相踩踏。5.4 更轻量的入门变体直接用git当记忆系统如果你觉得建一整套memory目录工作量太大还有一个更轻量的起步方式把git本身当成记忆系统。做法是每次会话结束时强制提交一次压缩后让代理先看git log再执行git diff HEAD从最近的提交记录恢复上下文。这个变体需要的文件只有一个就是你项目里的.git目录——只要养成了“会话结束必提交”的习惯。实测下来它对中小型项目非常管用而且几乎零维护成本。我的完整memory工作流其实就是从这一招开始逐步叠加演化出来的。以我个人经验来说真正让这套方案成立的不是某一份文件格式多完美而是“每次会话从协议开始、每步操作落盘到文件、每个决策留痕到日志”这三个习惯。格式化模板反而没那么重要——你完全可以按自己项目的习惯改造。如果你也被20万token边界上的“脑叶切除术”坑过我建议先从最小方案开始一个current-task.md一段恢复提示词一次会话结束前的git提交。先跑两次确认能接受这个节奏再逐步加入decisions和file-map。这套东西初期投入很少但换来的回报是你和AI代理终于可以聊一个足够大的项目而不用时刻担心它中途“失忆”。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑