1. 这个实验到底在折腾什么先把这个标题拆开看。上下文压缩指的是 AI 编码代理在长会话里因为上下文窗口塞满了不得不把历史对话做摘要、裁剪或者丢弃的过程。AI 编码代理就是那种能自己读代码、改文件、跑命令、看报错的工具比如 Codex 这类 CLI 形态的代理。long_mem和engram是两种记忆机制的代称前者偏向长期记忆存储后者偏向记忆痕迹的固化与召回。整个实验的核心问题就一句话当上下文被压缩之后代理还能不能接得上之前的工作。我之所以对这个题目感兴趣是因为我自己用 Codex 做日常开发已经有一段时间了。最开始觉得这东西真香一个任务丢过去它能自己翻文件、改代码、跑测试。但用久了就发现一个很尴尬的事会话一长它就开始失忆。前面刚说过的约束后面就忘了前面改过的文件后面又改回去了更离谱的是有时候它会把已经修好的 bug 又修一遍结果改坏了。这个实验用了 10 天时间积累了 430 条公开记录本质上就是在回答一个工程问题上下文压缩之后代理的连续性怎么保证。这不是学术问题这是每个把编码代理真正用在工作里的人都会撞上的墙。适合谁来读如果你只是偶尔让 AI 写个函数那无所谓但如果你想让代理跑一个跨小时、跨文件、跨多轮的任务那这篇文章里的东西你迟早要用到。我先把结论性的判断放前面上下文压缩本身不是问题问题是压缩之后没有一套可靠的接续机制。long_mem 和 engram 这两个词之所以被反复提到就是因为它们代表了两种不同的接续思路。下面我会把整个实验的逻辑、我自己的实操、踩过的坑一层层拆开讲。2. 上下文压缩为什么会把代理搞断片2.1 压缩的本质是信息有损很多人对上下文压缩有个误解以为它像 zip 一样解压之后还能还原。不是的。上下文压缩是有损的而且损失的是语义层面的细节。代理在长会话里上下文窗口就那么大塞满了之后必须做取舍。常见的做法有三种滑动窗口、摘要压缩、关键信息抽取。滑动窗口最简单就是把最早的消息丢掉。问题是编码任务里最早的消息往往包含最关键的约束比如这个项目用 pnpm 不用 npm、测试文件不要动、数据库迁移必须走 migration 目录。这些一旦被丢掉代理后面就会按自己的默认习惯来直接翻车。摘要压缩看起来聪明一点让模型把历史对话总结成一段话。但摘要本身也是一次模型调用它会丢细节、会引入偏差。我实测过一个 20 轮的调试会话摘要之后往往只剩下用户在调试一个登录问题这种废话具体的报错信息、试过的方案、排除掉的可能性全没了。关键信息抽取是最理想的但也是最难的因为你要判断什么信息关键。这个实验里 430 条记录很大一部分就是在记录哪些信息被压缩后导致代理接不上。2.2 断片的具体表现我把实验记录里代理接不上的表现归了几类这个分类对我自己排查问题特别有用断片类型具体表现根因约束遗忘用了错误的包管理器、改了不该改的文件早期约束被压缩掉状态错乱重复修复已解决的问题、回退已完成的改动任务进度状态丢失上下文漂移讨论的话题慢慢偏离原始目标摘要压缩引入偏差工具误用重复调用同一个失败的命令失败记录被压缩掉引用断裂提到刚才那个文件但不知道指哪个指代对象被压缩掉这张表是我自己整理的不是实验原文但逻辑和实验记录是一致的。你可以拿它当排查清单用。当你发现代理行为异常时先对照这张表基本能定位到是哪类信息丢了。2.3 为什么这个问题在编码场景特别严重普通聊天场景上下文丢了就丢了大不了重新说一遍。但编码场景不一样它有三个特点让压缩的代价被放大。第一编码任务的状态是累积的。你改了 A 文件B 文件的类型定义要跟着改C 文件的测试要跟着更新。这是一个链条任何一环的状态丢了后面全乱。第二编码任务的约束是隐性的。很多约束不在对话里明说而是藏在项目配置、代码风格、团队约定里。代理如果丢了这些隐性约束它不会报错它会默默地按错误的方式做。第三编码任务的验证成本高。聊天说错了你一眼能看出来。代码改错了可能要跑完测试、部署到环境、甚至上线之后才发现。所以压缩导致的断片在编码场景里的破坏力是最大的。3. long_mem 和 engram 两种接续思路的取舍3.1 long_mem把记忆外置long_mem 的核心思路是把记忆从上下文窗口里搬出来放到一个外部存储里。代理需要的时候主动去查。这就像你不再把所有资料都摊在桌面上而是放进文件柜需要哪份去拿哪份。这个思路的好处很明显上下文窗口的压力小了因为不用把所有历史都塞进去。而且外部存储可以做得很大理论上不受窗口限制。但坏处也很明显代理得知道什么时候去查、查什么。如果它不知道该查那外置的记忆等于不存在。我在实操里发现long_mem 要真正好用必须解决两个问题。一是索引问题外部记忆得能被快速检索到不能每次全量扫描。二是触发问题代理得在合适的时机主动去查而不是等你想起来提醒它。3.2 engram把记忆固化进痕迹engram 这个词借用了神经科学的说法指的是记忆在神经连接上留下的物理痕迹。放到 AI 代理里它的思路是把关键信息以某种形式固化下来让它不容易被压缩掉。具体做法有很多种。有的是把关键约束写成特殊标记让压缩算法优先保留有的是把重要状态写进一个代理每次都会读的文件里比如项目根目录下的一个约定文件还有的是把关键信息编码进系统提示里让它天然享有更高的保留优先级。engram 的好处是不需要代理主动去查信息就在那儿天然可见。但坏处是固化什么、怎么固化需要人来设计。固化得太多上下文又满了固化得太少关键信息还是丢。3.3 两种思路怎么选我的判断是两者不是二选一而是配合使用。engram 负责固化那些绝对不能丢的硬约束比如项目规范、关键路径、当前任务目标。long_mem 负责存储那些可能需要的软信息比如历史调试记录、试过的方案、参考文档。这个实验里 430 条记录我推测很大一部分就是在验证这个配合策略。哪些信息该固化哪些该外置固化的粒度多细外置的检索怎么触发这些都是要反复试的。提示不要一上来就追求完美的记忆系统。先用最简单的 engram 策略把项目规范和一个当前任务清单固化下来你会发现代理的稳定性立刻上一个台阶。4. 我自己的实操给 Codex 搭一套接续机制4.1 环境准备与基础配置先说环境。我用的是 Codex CLI装在 Windows 上通过 WSL 跑。安装过程网上教程很多我就不重复了。重点说几个和上下文接续相关的配置。第一个是会话持久化。Codex 默认的会话是临时的关掉就没了。但要做长任务你得让会话能续上。我的做法是把关键状态写进项目里的一个文件而不是依赖会话本身。这样即使会话断了新会话读一下文件就能接上。第二个是模型选择。热词里提到gpt-5.6-sol这个模型在 Codex 里不支持这个坑我踩过。选模型的时候要看清楚 Codex 支持哪些不要想当然。模型选错了代理的行为会变得很奇怪有时候不是接不上而是接错了。第三个是代理的权限边界。这个和上下文接续看似无关其实关系很大。如果代理权限太大它可能在你没注意的时候改了一堆文件这些改动如果没被记录进上下文后面就乱了。我的做法是限制代理的写权限关键目录只读改动必须经过我确认。4.2 固化关键约束的具体做法我在项目根目录放了一个AGENTS.md文件这个文件代理每次启动都会读。里面写什么我列一下我的模板# 项目约定 ## 包管理 - 使用 pnpm禁止使用 npm 或 yarn - 锁文件是 pnpm-lock.yaml不要动 ## 代码规范 - TypeScript strict 模式 - 组件用函数式不用 class - 测试文件放在 __tests__ 目录 ## 当前任务 - 目标修复登录接口的 token 刷新问题 - 状态已定位到 refreshToken 函数正在排查并发场景 - 已排除不是数据库连接问题不是前端传参问题 ## 禁止操作 - 不要修改 migration 目录 - 不要动 .env 文件 - 不要执行数据库重置命令这个文件就是我的 engram。它把最关键的约束和当前状态固化下来代理每次都能看到。实测下来光这一个文件就能把约束遗忘类的断片减少一大半。4.3 外置记忆的检索触发光有固化还不够因为有些信息不适合固化比如历史调试记录。这些我用 long_mem 的思路处理具体做法是维护一个debug-log.md记录每次调试的关键信息。但这里有个问题代理不会主动去读这个文件。所以我加了一个触发规则写进AGENTS.md里## 调试规则 - 遇到报错时先读 debug-log.md看是否遇到过类似问题 - 每次解决一个问题后把关键信息追加到 debug-log.md - 追加格式日期 | 问题描述 | 根因 | 解决方案这样代理就有了查记忆的习惯。实测下来这个规则能显著减少重复踩坑的情况。以前代理会反复试同一个失败的命令现在它会先查日志发现试过了就换思路。4.4 压缩后的接续验证做完上面这些还得验证代理是不是真的接上了。我的验证方法很简单在会话中途故意触发一次压缩然后看代理还能不能正确回答几个关键问题。我会问它三个问题当前任务目标是什么有哪些禁止操作上一个解决的问题是什么如果三个都能答对说明接续机制生效了。如果答错了就说明对应的信息没固化好或者没被检索到。这个验证方法我强烈建议你养成习惯。不要等代理改坏了代码才发现它断片了主动验证成本低得多。5. 430 条记录里反复出现的坑5.1 固化过度导致上下文又满了这是我最开始犯的错。既然固化有用那我就把所有东西都固化进去。结果AGENTS.md越写越长最后比上下文窗口还大代理读都读不完更别说理解了。教训是固化要克制只固化那些丢了会出大问题的信息。判断标准很简单问自己这条信息如果丢了代理会不会做出不可逆的错误操作会就固化不会就外置。5.2 外置记忆检索不到long_mem 的检索是个技术活。我一开始用简单的关键词匹配结果代理查token 刷新问题日志里写的是refreshToken 并发匹配不上等于没查。后来我改成让代理自己判断把日志的摘要放进上下文让它决定要不要读全文。这样灵活多了但也有代价就是每次都要多一次模型调用。权衡下来对于调试类信息这个代价是值得的。5.3 状态更新不及时这个坑很隐蔽。代理解决了一个问题但没有及时更新AGENTS.md里的任务状态。结果下一个会话读到的还是旧状态又开始重复排查。解决办法是把状态更新写进代理的工作流。我在AGENTS.md里明确规定每完成一个子任务必须更新当前任务状态。这样代理就有了更新状态的义务不会漏。5.4 多会话并发导致状态冲突如果你同时开多个会话跑不同的任务状态文件会冲突。我试过两个会话同时改AGENTS.md结果内容互相覆盖乱成一团。解决办法是一个项目同一时间只跑一个主会话。如果确实要并行就给每个会话分配独立的状态文件最后人工合并。这个成本有点高但比状态混乱强。5.5 常见问题速查表我把上面这些坑整理成一张表方便你排查现象可能原因排查方向代理忘记约束约束没固化或固化位置不对检查 AGENTS.md 是否包含该约束代理重复劳动历史记录没被检索检查 debug-log 触发规则代理状态错乱状态文件没及时更新检查任务状态更新流程代理行为漂移摘要压缩引入偏差减少摘要增加固化代理读不到记忆检索关键词不匹配改用摘要代理判断6. 这套机制还能怎么扩展6.1 从单项目到多项目我现在这套机制是单项目的。如果要在多个项目间复用可以把通用的约束抽出来做成一个全局的AGENTS.md项目级的约束再单独写。这样代理在不同项目间切换时通用规范不会丢。6.2 从手动固化到半自动目前固化还是手动的我写什么代理读什么。未来可以做成半自动的代理在运行过程中自己判断哪些信息值得固化然后提议写进AGENTS.md我确认后生效。这样既保留了人的控制权又减轻了手动维护的负担。6.3 记忆的版本管理状态文件改来改去有时候改错了想回退。我把AGENTS.md和debug-log.md都纳入了 git 管理每次改动都有记录。这样出问题了可以 diff可以回退比裸文件靠谱得多。6.4 和 Codex 生态的结合热词里提到 Codex 的各种安装、配置、接入问题说明用的人越来越多。我期待未来 Codex 能原生支持某种记忆机制不用我们自己搭。但在那之前上面这套土办法是能用的而且实测有效。我个人在实际操作中的体会是上下文压缩不是敌人遗忘才是。与其对抗压缩不如接受它然后设计一套让关键信息不被压缩掉的机制。engram 负责不让丢long_mem 负责丢了能找回来两者配合代理的连续性就能稳住。这套东西不复杂但需要你真正动手去搭、去试、去调。搭好之后你会发现编码代理从偶尔能用变成了真的能托付任务。