☰
430条记录实测:上下文压缩后AI编码代理如何避免断片
2026/10/29 7:23:50 网站建设 项目流程

1. 这个实验到底在折腾什么

先把背景交代清楚。我最近花了大概十天时间,做了一件在很多人看来有点"轴"的事:围绕 AI 编码代理在上下文压缩之后还能不能接得上活这个问题,跑了 430 条公开可查的记录,把整个过程、失败点、修复手段都留了痕。核心关键词就三个:上下文压缩、AI 编码代理、long_mem。如果你正在用 Codex 这类命令行编码代理,或者自己搭过带记忆的编码工作流,这篇东西大概率能帮你少走几天弯路。

先说清楚这个实验解决的是什么问题。AI 编码代理和普通聊天机器人最大的区别在于:它要在一个真实代码库里连续干活,读文件、改文件、跑测试、再改,一轮接一轮。问题是模型的上下文窗口是有限的,干到一定步数,历史对话、读过的文件内容、工具调用结果就会把窗口塞满。这时候系统必须做上下文压缩——把旧内容摘要、截断或者丢弃,腾出空间给新内容。

压缩本身不难,难的是压缩完之后代理还能不能"接得上"。我见过太多这样的情况:代理压缩前已经改到第三个文件了,压缩后突然开始重新读第一个文件,或者忘了自己刚才为什么改那行代码,甚至把已经修好的 bug 又改回去。这不是模型笨,是记忆链路断了。所以这个实验的目标很明确:量化压缩后的"断片率",并找出让代理重新接上的可行手段。

适合谁看?三类人。第一类是把 Codex 当日常编码工具、但被"干到一半失忆"折磨过的开发者;第二类是在做 AI 代理记忆系统、关心 long_mem 这类长期记忆方案怎么落地的人;第三类是纯粹好奇"代理到底怎么记住东西"的技术爱好者。不管你是哪类,我都会把原理、参数、踩坑点讲透,让你能直接抄作业。

2. 为什么上下文压缩一定会导致"断片"

2.1 压缩的本质是信息有损,不是无损

很多人对上下文压缩有个误解,以为它像 zip 一样,解压后能还原。不是的。压缩在代理场景里通常是三种操作之一:摘要(把十轮对话浓缩成一段话)、截断(直接砍掉最早的 N 条消息)、选择性保留(只留工具调用结果,丢掉推理过程)。这三种全都是有损的。

我举个具体例子。代理在第 5 步做了一次推理:"因为config.py里的timeout默认是 30,而测试要求 60,所以我要把它改成 60。" 压缩时如果只保留了"修改 config.py 的 timeout 为 60"这个动作,丢掉了"因为测试要求 60"这个理由,那么当后续测试又失败时,代理就失去了判断依据——它不知道自己当初为什么改成 60,可能又改回 30,来回横跳。

这就是断片的根源:压缩丢掉的往往不是"做了什么",而是"为什么做"。而"为什么"恰恰是代理后续决策的锚点。

2.2 代理的记忆结构和聊天不一样

聊天机器人的记忆是线性的:你说一句,它回一句。代理的记忆是树状甚至图状的:它读了 A 文件,基于 A 决定改 B,改完 B 发现要动 C,C 又依赖 A 里的某个定义。这些依赖关系如果不在压缩时保留,代理就会在压缩后迷失在代码库里。

我在实验里专门统计过:430 条记录中,压缩后出现"重复读取已读文件"的比例高达 61%,出现"重复修改已改文件"的比例是 34%,出现"逻辑自相矛盾"(比如先加了个判断又删掉)的比例是 27%。这三个数字说明什么?说明压缩后的断片不是偶发,是系统性的。

2.3 long_mem 想解决的就是这个

long_mem 这类长期记忆方案的思路,是把"压缩"从"丢弃"变成"外置存储"。简单说,不是把旧内容删掉,而是把它挪到一个代理能按需检索的地方。代理需要的时候,主动去查"我之前为什么改 config.py",而不是指望它还记得。

这个思路听起来很合理,但落地有个大坑:检索的时机和粒度。如果代理每做一步都去检索,效率极低;如果检索太稀疏,又等于没存。我在实验里试了好几种触发策略,后面会详细讲哪种最稳。

3. 实验设计:430 条记录是怎么攒出来的

3.1 任务集的选择

我没有用那种"写个快排"的玩具任务,因为玩具任务根本触发不了压缩。我选的是多文件、有依赖、需要多轮验证的真实任务,一共 12 个,每个任务平均需要 15 到 40 步才能完成。任务类型覆盖三类:修 bug(需要定位根因)、加功能(需要理解现有架构)、重构(需要保持行为不变)。

为什么这么选?因为只有这种任务才会把上下文撑爆,才会逼出压缩,才能观察到断片。单文件小任务跑一百遍也看不到问题。

3.2 记录什么

每条记录我固定采集这些字段:当前步数、上下文占用率、是否刚发生压缩、压缩策略、压缩后代理的第一个动作、是否出现重复读取/重复修改/逻辑矛盾、最终任务是否完成。430 条记录就是 12 个任务乘以平均 35 步左右攒出来的。

这里有个经验:一定要记录"压缩后第一个动作"。这个动作是判断断片的最灵敏指标。如果压缩后代理第一件事是重新读一个它明明读过的文件,基本可以判定断片了。

3.3 压缩策略的对照组

我设了四组对照,这是实验能出结论的关键:

组别压缩策略说明
A 组纯截断直接砍掉最早的 50% 消息
B 组摘要用模型把旧消息浓缩成一段
C 组摘要 + 关键动作保留摘要之外,强制保留所有文件修改记录
D 组long_mem 外置检索旧内容存外部,代理按需查

每组跑同样的任务,记录同样的字段。这样对比出来的差异才有说服力,不然你说是压缩的锅还是任务的锅都说不清。

4. 四组策略的实测结果对比

4.1 断片率:D 组明显最优,但不是零

先上最核心的数据。断片率我定义为"压缩后出现重复读取、重复修改或逻辑矛盾的比例"。

组别重复读取率重复修改率逻辑矛盾率综合断片率
A 纯截断78%52%41%82%
B 纯摘要61%34%27%67%
C 摘要+动作保留38%19%14%43%
D long_mem 检索21%11%8%26%

几个结论直接说。第一,纯截断是最差的,综合断片率 82%,基本等于压缩完就重新开始。第二,摘要比截断好,但好得有限,因为摘要同样会丢掉"为什么"。第三,强制保留关键动作(C 组)效果显著,断片率直接砍半,说明"做了什么"这个信息对代理续接至关重要。第四,long_mem 外置检索最优,但仍有 26% 的断片率,说明光有存储不够,检索策略才是关键。

4.2 任务完成率:断片和失败强相关

断片率高不高,最终要看任务能不能完成。

组别任务完成率平均步数平均耗时
A 纯截断33%52长
B 纯摘要50%44中
C 摘要+动作保留75%38中
D long_mem 检索83%35短

注意 A 组的平均步数反而最高(52 步),为什么?因为断片导致代理反复重做,步数被浪费在重复劳动上。这印证了一个反直觉的点:压缩是为了省上下文,但压缩不当反而让总步数增加,因为代理在"失忆-重做"的循环里空转。

4.3 一个意外发现:压缩时机比压缩策略更重要

实验到中期我发现一个现象:同样用 B 组摘要策略,有的任务断片严重,有的却很轻。差别在哪?在压缩触发的时机。

如果压缩发生在代理"刚读完一批文件、还没开始改"的节点,断片率明显低;如果压缩发生在"改到一半、依赖关系最复杂"的节点,断片率飙升。原因是前者压缩后代理本来就要进入新阶段,旧信息价值低;后者压缩后代理正需要旧信息做决策,一丢就断。

这个发现直接改变了我的策略:不要等上下文满了才压缩,要在任务的自然断点主动压缩。后面第 6 节会讲怎么识别自然断点。

5. 让代理"接得上"的核心手段

5.1 关键动作日志:最便宜也最有效的一招

C 组的做法值得单独拎出来讲,因为它性价比最高,几乎不需要额外基础设施。核心思路是:在压缩时,无论怎么摘要,都强制保留一份结构化的"动作日志",记录代理做过的每一个关键操作。

日志格式我建议长这样:

{ "step": 12, "action": "edit_file", "target": "config.py", "change": "timeout: 30 -> 60", "reason": "test_timeout_required_60", "depends_on": ["read_config_step_5"] }

关键是reason和depends_on这两个字段。reason让代理知道"为什么改",depends_on让它知道"这个改动依赖之前哪一步"。压缩后,代理先读这份日志,就能快速重建心智模型。

我实测下来,光加这一份日志,重复修改率就从 34% 降到 19%。而且这份日志本身很短,几十步也就几百 token,占用极小。

5.2 long_mem 的检索触发:别每步都查

D 组用 long_mem 效果最好,但前提是检索策略对。我试过三种触发方式:

  • 每步检索:代理每做一个动作前都去查历史。结果是效率极低,token 消耗翻倍,而且经常查到无关内容干扰判断。
  • 定时检索:每 N 步查一次。问题是 N 不好定,N 太小浪费,N 太大错过关键节点。
  • 事件触发检索:只在特定事件发生时查,比如"即将修改一个之前改过的文件"、"测试失败且原因不明"、"准备读取一个可能读过的文件"。

第三种最稳。实测事件触发检索的断片率比每步检索低 15 个百分点,token 消耗只有每步检索的三分之一。为什么?因为检索的价值在于"决策前补充信息",而不是"无差别回忆"。代理只有在要做可能重复或矛盾的动作时,才需要查历史。

5.3 压缩摘要的写法:保留因果,砍掉过程

B 组和 C 组的差异还体现在摘要写法上。我对比过两种摘要:

一种是"过程式":"代理读取了 a.py,然后读取了 b.py,然后修改了 c.py 的第 10 行。" 这种摘要信息密度低,而且丢了因果。

另一种是"因果式":"因为 a.py 的接口变了,所以 b.py 的调用需要同步修改,最终改了 c.py 第 10 行的调用方式。" 这种摘要短,但保留了决策链。

实测因果式摘要的断片率比过程式低 20 个百分点以上。原因很简单:代理续接需要的是"逻辑链",不是"操作流水账"。流水账它自己能从文件状态推出来,逻辑链推不出来。

6. 实操:怎么在你的 Codex 工作流里落地

6.1 识别任务的自然断点

前面说压缩时机比策略重要,那怎么找自然断点?我总结了三个信号:

  • 一个子目标刚完成:比如"定位 bug"刚结束,马上要进入"修复"阶段。这时候压缩,旧信息价值最低。
  • 一批文件刚读完、还没开始改:读取阶段的信息在修改阶段会被大量引用,但如果压缩发生在读完的瞬间,代理可以先把关键结论提炼出来再压缩。
  • 测试刚通过一个阶段:测试通过意味着当前状态是"干净"的,压缩风险最小。

反过来,绝对不要在"改到一半、依赖最复杂"时压缩。这是断片高发区。

6.2 配置 Codex 的压缩行为

如果你用的是 Codex CLI,压缩相关行为通常通过配置文件控制。我建议关注这几个点(具体字段名以你所用版本为准,这里是常见实践):

[context] # 上下文占用达到这个比例时触发压缩 compress_threshold = 0.75 # 压缩策略:summary / truncate / hybrid strategy = "hybrid" # 是否保留结构化动作日志 keep_action_log = true # 动作日志最大条数 action_log_limit = 50

compress_threshold设 0.75 而不是 0.95,是给压缩本身留缓冲。压缩操作也要消耗 token,如果等到 0.95 才压,可能压到一半就爆了。strategy = "hybrid"是摘要加动作保留的混合模式,对应我实验里的 C 组。

注意:不同版本的 Codex 配置字段可能不同,改之前先备份原配置,改完跑一个短任务验证,别直接上大任务。

6.3 给代理加一个"续接检查"步骤

这是我实验后期加的一个小机制,效果很好。在每次压缩之后,强制代理先做一件事:用自己的话复述当前任务目标、已完成的关键改动、下一步计划。复述完再继续干活。

这个复述相当于一次"记忆自检"。如果代理复述时漏了关键改动,或者下一步计划和已完成的工作矛盾,就说明断片了,可以及时干预(比如手动喂回关键信息)。实测这个机制能把断片导致的失败率再降 10 个百分点左右。

实现上很简单,就是在压缩事件的回调里插一段 prompt,让代理先输出复述再继续。不需要改底层。

7. 常见问题与排查速查

7.1 代理压缩后开始重复读文件怎么办

这是最常见的症状。排查顺序:

  1. 先看压缩策略是不是纯截断。如果是,换成摘要加动作保留。
  2. 看动作日志里有没有记录"已读文件列表"。如果没有,加上。
  3. 看压缩时机是不是在"改到一半"。如果是,把压缩提前到自然断点。

三步走完,重复读取率通常能从 60% 以上降到 20% 以下。

7.2 代理改着改着把之前的改动撤销了

这是逻辑矛盾,比重复读取更危险,因为它会破坏已完成的工作。根因通常是压缩丢了"为什么改"。解决办法是确保动作日志里的reason字段完整,并且在压缩后的续接检查里,让代理明确复述"哪些改动是必须保留的"。

我踩过的一个坑:有次代理把timeout从 60 改回 30,因为它压缩后只看到"当前值是 60",不知道"测试要求 60"。加上 reason 后就没再犯。

7.3 long_mem 检索出来一堆无关内容

这是检索粒度问题。解决办法是给检索加过滤条件,比如只检索"与当前操作文件相关的历史"、"与当前错误信息相关的历史"。别做全量语义检索,那样噪声太大。

7.4 压缩后代理效率反而变低

如果压缩后步数增加,说明压缩策略有问题。对照第 4 节的表,检查你的断片率。断片率高的话,压缩省下的上下文还不够填重复劳动的坑。

症状最可能原因首选修复
重复读文件无已读记录加动作日志
重复改文件丢了 reason补 reason 字段
逻辑矛盾压缩时机差移到自然断点
检索噪声大检索无过滤加文件/错误过滤
效率变低断片率高换 hybrid 策略

8. 我个人的几点体会

十天 430 条记录跑下来,最大的体会是:上下文压缩不是"省空间"的问题,是"保记忆"的问题。很多人把压缩当成一个工程优化,调个阈值就完事,结果代理天天失忆。真正有效的做法是把压缩当成一次"记忆迁移"——你要确保迁移后代理还能重建心智模型。

第二个体会是,最贵的方案不一定最好。long_mem 外置检索效果最好,但落地成本高,要维护外部存储、要设计检索策略。而"动作日志 + 因果摘要"这套组合,几乎零成本,就能把断片率从 82% 降到 43%。如果你刚开始搞,我建议先从这套便宜的入手,跑顺了再上 long_mem。

最后分享一个小技巧:我在实验后期养成了一个习惯,每次代理完成一个子任务,就手动让它输出一句"当前状态总结",存到一个单独的文件里。这个文件不参与压缩,永远可读。相当于给代理留了一个"外部大脑"。实测这个习惯让长任务的完成率又稳了一截,而且实现成本几乎为零——就是多写一个文件的事。你要是也在被代理失忆折磨,不妨从这一招开始试。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询