1. 上下文压缩这件事,为什么编码代理最容易翻车
先把场景摆出来。你让一个 AI 编码代理去改一个中型项目,它得先读文件、看依赖、翻历史提交、理解模块之间的调用关系。这些内容全塞进上下文窗口,很快就撑满了。撑满之后有两条路:要么截断,要么压缩。截断简单粗暴,直接丢掉最早的内容;压缩则聪明一点,把旧内容总结成一段更短的摘要,腾出空间给新内容。
问题就出在压缩这一步。普通的对话场景里,压缩丢点细节无所谓,反正用户下一句会补充。但编码代理不一样,它依赖的是精确的符号信息:函数名、变量名、文件路径、类型定义、导入关系。你把parseConfig压缩成"一个解析配置的函数",代理再想调用它的时候就抓瞎了。更麻烦的是,压缩往往是有损的、不可逆的,一旦关键约束被抹掉,代理后面生成的代码就会基于错误的假设往下走,越走越偏。
我见过太多这样的案例:代理前 20 轮表现完美,第 21 轮突然开始引用一个根本不存在的函数,或者把已经改过的接口又改回去。表面看是"模型变笨了",实际上是上下文压缩把它的记忆搞乱了。这个项目标题里提到的"10 天、430 条公开记录",本质上就是在系统性地观察这件事:压缩之后,代理到底还能不能接得上?
这里要先厘清一个概念。所谓"接得上",包含三层含义。第一层是事实接续:代理还记得之前做过什么、改过哪些文件。第二层是约束接续:代理还记得项目里的硬性规则,比如某个模块不能引入新依赖、某个接口签名不能变。第三层是意图接续:代理还记得用户最初的目标是什么,不会在中途跑偏。上下文压缩对这三层的破坏程度是不一样的,事实最容易丢,约束次之,意图相对顽强但也扛不住反复压缩。
关键词里出现的 long_mem 和 engram,其实指向的就是解决思路的两大流派。long_mem 走的是外部记忆库路线,把重要信息存到上下文之外,需要时再检索回来;engram 更偏向把记忆做成一种可寻址的结构,类似给代理装一个"记忆索引"。这两条路各有取舍,后面会展开讲。而 Codex 作为编码代理的代表性工具,它的上下文管理策略直接决定了实验的观察对象。
提示:判断一个编码代理是否"接得上",不要只看它单轮输出对不对,要看它在压缩发生后的第 3 到第 5 轮是否还能保持一致性。压缩的破坏往往是延迟显现的。
2. 430 条记录是怎么攒出来的:实验设计与观察维度
2.1 为什么是 10 天而不是 10 小时
10 天这个周期不是随便定的。编码代理的上下文问题有个特点:短会话里几乎看不出来。你跑一个 10 轮的小任务,上下文根本没到压缩阈值,一切正常。只有把任务拉长到几十轮、上百轮,压缩被触发多次之后,问题才会暴露。10 天的时间跨度,意味着实验覆盖了不同规模的任务、不同类型的压缩触发点,也覆盖了代理在多次压缩叠加后的表现。
430 条公开记录,平均下来每天 43 条。这个密度说明记录的不是"最终结果",而是过程性观察。每条记录大概包含:当前轮次、上下文占用比例、是否触发了压缩、压缩前后的关键信息对比、代理本轮输出的正确性判断。这种颗粒度的记录,才能支撑后面做归因分析。
2.2 观察维度不能只看"对错"
如果只用"这轮输出对不对"来打分,会漏掉大量信息。一个代理可能这轮输出是对的,但它依据的是已经被压缩扭曲的记忆,下一轮就会错。所以实验的观察维度至少要拆成四层:
| 观察维度 | 具体指标 | 为什么重要 |
|---|---|---|
| 事实一致性 | 引用的文件/函数是否真实存在 | 最容易被压缩破坏 |
| 约束遵守度 | 是否违反项目硬性规则 | 破坏后修复成本高 |
| 意图偏移度 | 是否偏离原始目标 | 反映长期记忆质量 |
| 恢复能力 | 被纠正后能否回到正轨 | 衡量代理的鲁棒性 |
这四个维度里,恢复能力是最容易被忽略但最有价值的。有些代理压缩后确实会犯错,但你一提醒它就能改回来;有些则一错到底,怎么纠正都没用。后者说明它的记忆结构已经被彻底打乱,不是"忘了",而是"记错了"。
2.3 记录方式决定了你能发现什么
430 条记录如果只是流水账,价值有限。真正有用的是结构化记录:每条记录都标注了压缩发生的位置、压缩策略、被压缩掉的内容类型。这样你才能回答"哪种内容被压缩后最容易导致代理翻车"这种问题。
我的经验是,被压缩内容按危险程度排序大概是:类型定义和接口签名 > 跨文件的调用关系 > 具体的业务规则 > 一般的实现细节。类型定义一旦丢失,代理就会凭空捏造字段;调用关系丢失,代理就会重复实现已有功能;业务规则丢失,代理就会写出"技术上正确但业务上错误"的代码。
3. long_mem 与 engram:两条记忆路线的真实取舍
3.1 long_mem 的本质是"外挂硬盘"
long_mem 的思路很直白:既然上下文窗口装不下,那就把记忆存到外面去。代理在运行过程中,把关键信息写进一个外部存储,需要的时候再查回来。这就像给电脑加了一块外挂硬盘,内存不够就往硬盘上放。
这条路线的优点是容量几乎无限,而且记忆可以跨会话持久化。今天没做完的任务,明天接着做,代理还能记得之前的进展。但缺点也很明显:检索质量决定一切。如果检索回来的内容不相关,或者漏掉了关键信息,代理照样翻车。而且检索本身要消耗时间和 token,频繁检索会拖慢整体速度。
实操中,long_mem 最容易踩的坑是"存了但没存对"。很多实现只存了结论,没存结论的上下文。比如存了"用户要求用 A 方案",但没存"为什么排除 B 方案"。等代理下次检索到这条记忆时,它可能会重新考虑 B 方案,因为它不知道 B 已经被否决过了。
3.2 engram 更像"记忆索引"
engram 这个词本身有"记忆痕迹"的意思,它的思路不是简单存储,而是建立一种可寻址的记忆结构。你可以理解为给每条记忆打上标签和关联,让代理能顺着线索找到相关内容。这比 long_mem 的"关键词检索"要精细,但也更复杂。
engram 的核心难点在于关联的建立和维护。一条记忆和哪些其他记忆相关?这个关系是静态的还是动态的?如果关联建错了,代理会顺着错误的线索越走越远。我实测下来,engram 在结构化程度高的项目里表现很好,因为模块之间的依赖关系本身就清晰;但在那种"祖传代码"式的项目里,关联关系一团乱麻,engram 反而容易帮倒忙。
3.3 两条路线不是二选一
实际项目里,long_mem 和 engram 往往是配合使用的。long_mem 负责"存得住",engram 负责"找得准"。先用 long_mem 把信息持久化,再用 engram 的结构去组织检索路径。这个组合的关键在于写入策略:什么信息值得存,什么信息存了反而添乱。
我的判断标准是:能被验证的信息才值得存。比如"文件 X 的第 42 行定义了函数 Y"这种可验证的事实,存了有用;而"用户可能想要 Z"这种推测,存了就是噪音。430 条记录里,相当一部分翻车案例都源于存了太多未经验证的推测。
4. Codex 类代理的上下文管理:从机制到实操
4.1 压缩触发点在哪里
Codex 这类编码代理,上下文管理通常有几个关键阈值。第一个是软阈值,达到这个比例时开始预警,可能会主动做一次轻量压缩。第二个是硬阈值,超过就必须压缩,否则新内容进不来。第三个是紧急阈值,这时候压缩会很激进,可能直接丢掉整段历史。
理解这三个阈值的区别很重要。软阈值下的压缩通常比较温和,只压缩最老的内容;紧急阈值下的压缩则可能把最近几轮也一起压了,导致代理"刚做的事就忘了"。430 条记录里,最严重的翻车基本都发生在紧急压缩之后。
4.2 压缩策略的选择逻辑
常见的压缩策略有三种:摘要式、抽取式、丢弃式。摘要式用模型把旧内容重写成短摘要;抽取式只保留关键句;丢弃式直接删。三者的信息损失程度依次递增,但计算成本依次递减。
| 策略 | 信息保留 | 计算成本 | 适用场景 |
|---|---|---|---|
| 摘要式 | 高 | 高 | 关键任务、约束多的项目 |
| 抽取式 | 中 | 中 | 一般开发任务 |
| 丢弃式 | 低 | 低 | 探索性、可重来的任务 |
选择策略时不能只看成本。一个约束密集的项目,用丢弃式压缩省下的那点算力,远不够弥补后面返工的代价。我的建议是:任务越接近生产环境,越要用保守的压缩策略。
4.3 让代理"接得上"的三个实操动作
第一个动作是显式锚点。在关键节点让代理主动记录一条锚点信息,比如"当前已完成 X,下一步要做 Y,约束是 Z"。这条锚点要写得足够具体,压缩时优先保留。这相当于给代理的记忆打了个桩。
第二个动作是压缩后自检。每次压缩发生后,让代理复述一遍当前的任务状态和关键约束。如果复述有偏差,立刻纠正。这个动作成本很低,但能拦住大量延迟性错误。
第三个动作是分段提交。不要等整个任务做完再验证,每完成一个可独立验证的小段就提交一次。这样即使后面压缩出了问题,前面的成果也是安全的,回滚成本低。
注意:压缩后自检这个动作,一定要在压缩发生的下一轮就做,不能拖。拖得越久,错误记忆被引用的次数越多,纠正成本越高。
5. 那些记录里反复出现的翻车模式
5.1 函数签名漂移
这是最高频的问题。代理在压缩前明明知道createUser(name, email, role)这个签名,压缩后变成了createUser(name, email),然后它就开始用两个参数去调用,编译直接报错。更隐蔽的是,它可能自己"补"了一个默认参数,代码能跑但行为错了。
根因在于签名这种信息高度依赖精确符号,摘要式压缩很容易把它模糊化。解决办法是在压缩策略里给函数签名、类型定义这类内容打上"不可压缩"标记,原样保留。
5.2 重复实现
代理压缩后忘了某个功能已经实现过,于是又写了一遍。这在大型项目里特别常见,因为功能分散在多个文件,压缩时很容易丢掉"这个功能在哪"的索引。结果就是代码库里出现两个功能重叠的函数,后面维护的人一脸懵。
这个问题的预防手段是维护一份功能清单,放在上下文里相对固定的位置,压缩时优先保留。清单不需要详细,只要记录"功能名 -> 所在文件"就够了。
5.3 约束遗忘导致的连锁错误
最典型的是"不要引入新依赖"这条约束被压缩掉。代理为了图方便,引入了一个新库,然后基于这个库写了一堆代码。等你发现的时候,要么接受新依赖,要么大改。这类错误的修复成本极高,因为它污染的不只是一处代码。
约束类信息应该单独管理,不参与常规压缩。可以把它放在系统提示的固定区域,或者用 long_mem 持久化,每次关键操作前检索一次。
5.4 意图漂移
代理做着做着,目标从"修复登录 bug"变成了"重构登录模块"。这不是它故意的,而是压缩过程中原始意图被稀释了。每压缩一次,意图就模糊一点,几轮下来就面目全非。
对抗意图漂移的办法是意图复述。每隔几轮,让代理用一句话复述当前目标,和最初的目标对比。一旦发现偏移,立刻拉回来。
6. 把实验结论落到日常开发里
6.1 任务拆分比压缩策略更重要
与其纠结怎么压缩,不如从源头减少压缩的需求。把大任务拆成小任务,每个小任务在上下文还没撑满时就完成并提交。这样压缩根本不会被触发,问题自然消失。430 条记录里,那些"接得上"表现好的案例,绝大多数都是任务拆分做得细的。
拆分的粒度怎么定?我的经验是:一个任务如果预计超过 30 轮对话,就该拆。30 轮是个经验值,具体还要看每轮的信息密度。信息密度高的任务,可能 15 轮就该拆。
6.2 给代理一份"项目宪法"
所谓项目宪法,就是一份简短但硬性的规则清单,放在上下文最稳定的位置。内容包括:技术栈约束、代码风格、禁止事项、关键接口签名。这份宪法不参与压缩,每次会话开始都重新注入。
宪法要短,最好控制在一屏以内。太长了反而会被压缩机制盯上。只放那些"违反了就会出大问题"的规则,一般的风格偏好可以不放。
6.3 建立压缩日志
每次压缩发生时,记录下压缩了什么、保留了什么。这份日志平时不看,但一旦代理出现诡异行为,它就是排查的第一手资料。你可以快速定位到"哦,原来是那次压缩把接口定义弄丢了"。
日志不用很复杂,一个简单的表格就够:时间、触发原因、压缩策略、丢失的关键信息、后续是否出问题。坚持记一段时间,你就能总结出自己项目里"最不能丢的信息类型"。
6.4 人工介入的时机
不要指望代理完全自主地处理压缩问题。有些节点必须人工介入:任务目标变更时、发现代理开始重复劳动时、连续两轮输出出现事实错误时。这些信号出现,说明记忆已经不可靠了,继续让它自主跑只会越跑越偏。
介入的方式不是直接改代码,而是重置记忆。把当前的真实状态、关键约束、下一步目标重新明确地告诉代理,相当于给它做一次记忆校准。这比在错误的记忆上修修补补有效得多。
7. 我在这 10 天里踩过的几个坑
第一个坑是过度信任摘要。一开始我觉得摘要式压缩很智能,就放任它压。结果发现摘要会把"这个函数返回 null 表示失败"这种关键语义压成"这个函数返回结果",语义完全变了。后来我给摘要加了约束:涉及返回值语义、异常行为、边界条件的内容,必须原样保留。
第二个坑是锚点写得太笼统。我一开始让代理记"正在处理用户模块",这种锚点等于没记。后来改成"正在给 UserService 的 updateProfile 方法加邮箱格式校验,约束是不能改方法签名",效果立竿见影。
第三个坑是忽略检索延迟。用 long_mem 的时候,我没考虑检索本身要花时间。高频检索把整体速度拖慢了一倍多。后来改成批量检索加缓存,才把速度拉回来。这个教训是:外部记忆不是免费的,检索成本要算进整体预算。
第四个坑是在错误的层级做压缩。我一开始按"轮次"压缩,把最早的几轮直接压掉。但最早的几轮往往包含任务定义和初始约束,压掉它们等于把地基抽了。后来改成按"信息类型"压缩,优先压掉过程性的调试信息,保留定义和约束,问题少了很多。
8. 关于长期记忆,一个还没解决的问题
long_mem 和 engram 能解决"存"和"找"的问题,但解决不了"更新"的问题。项目在演进,旧的记忆会过时。比如某个接口三个月前改了签名,但 long_mem 里还存着旧签名,代理检索到旧的就用错了。engram 的关联结构也一样,关联关系会随着代码重构而失效。
目前的处理办法是定期清理加版本标记。给每条记忆打上时间戳和版本号,检索时优先用最新的。但这只是缓解,不是根治。真正理想的状态是记忆能跟着代码自动更新,代码改了,相关记忆自动失效或刷新。这个方向目前还在探索,没有成熟的方案。
我在实操中的做法是:关键记忆手动维护,非关键记忆定期清理。关键的就是那些"错了会出大问题"的,比如接口签名、核心约束,这些手动更新,确保准确。非关键的比如调试过程、临时决策,定期清掉,避免积累噪音。这个策略不优雅,但管用。
回到标题里的那个问题:上下文压缩之后,AI 编码代理怎么接得上?我的答案是,靠的不是某一个神奇的技术,而是一整套记忆管理习惯。压缩策略要选对,锚点要打准,自检要及时,任务要拆细,人工介入要果断。这五件事做到位,代理在压缩后接不上的概率会大幅下降。430 条记录看下来,那些表现稳定的案例,没有一个是靠单一技巧撑住的,都是这套组合拳打得好。