ChatGPT、Codex实战:任务越做越乱?上下文污染的6个来源与解决方法
刚开始使用Codex时,很多任务其实非常顺。
你给它一个明确Bug:
登录接口返回500,帮我定位原因并修复。
Codex读取几个文件,找到问题,修改代码,跑测试。
整个过程可能非常干净。
但任务一旦变长,情况就开始发生变化。
第一次修改没有解决问题,于是继续调查。
接着读取更多文件。
又发现另一个模块可能相关。
再补充新的要求。
中途改变一次方案。
然后让它顺便处理另一个问题。
几十分钟以后,你可能会发现一个非常熟悉的现象:
Codex好像越来越“听不懂”最开始的要求了。
它开始:
重复读取已经看过的文件;
重新讨论已经确认过的问题;
把旧方案和新方案混在一起;
修改原本明确说过不要修改的模块;
忘记某个阶段已经完成;
甚至重新解决一个早就已经解决的问题。
这时候很容易得出一个结论:
是不是上下文太长以后,模型变笨了?
问题没有这么简单。
Codex本身已经具备面向长任务的上下文压缩、线程、项目、Goals等机制。OpenAI在长时任务实践中也明确指出,真正决定长任务能否保持连贯的,不只是一个“大Prompt”,而是模型所运行的整个Agent Loop;Codex还会通过Compaction压缩已有上下文,让任务能够跨越更长的执行周期。
但是:
能够保存更长的上下文,不等于上下文里的信息始终是正确、相关和有用的。
这就是长任务里另一个非常容易被忽略的问题:
Context Pollution——上下文污染。
这里的“上下文污染”不是OpenAI某个正式错误名称,而是一个很实用的工程描述:
Agent当前能够看到的信息越来越多,但真正与当前决策有关的信息比例越来越低。
最终导致的问题不是:
没有上下文。
而是:
上下文太杂。
一、上下文不是“记忆越多越好”,而是Agent当前的工作现场
很多人第一次理解Context,会把它想象成:
Agent的记忆。
于是自然产生一个逻辑:
记得越多
=
知道得越多
=
表现越好
但工程Agent不是这样工作的。
对于一个具体任务来说,它真正需要的是:
当前目标
+
项目规则
+
相关代码
+
已经确认的事实
+
当前执行状态
+
下一步需要的信息
而不是:
所有历史对话
+
所有读取过的文件
+
所有讨论过的方案
+
所有失败尝试
+
所有临时猜测
+
所有无关需求
两者差别非常大。
可以把Agent上下文理解成开发者桌面。
刚开始:
桌面上只有:
Bug描述
Login.tsx
auth.ts
测试结果
非常容易工作。
随着任务继续:
Bug描述
Login.tsx
auth.ts
router.ts
database.ts
config.ts
20条Terminal输出
3个失败方案
2次需求变化
一些临时讨论
另一个Bug
此时Agent拥有的信息更多了。
但真正的问题是:
Signal / Noise开始下降。
信息数量在增加,
有效信息比例却可能在下降。
所以真正影响Agent长任务稳定性的,并不只是:
Context Window有多大。
而是:
Context里到底装了什么。
二、第一种污染:把已经失效的结论一直留在任务里
这是长任务最典型的问题。
假设一开始我们认为:
登录失败可能是Token过期造成的。
于是Codex围绕Token进行了大量分析。
后来经过测试已经证明:
Token正常
真正问题在Cookie SameSite配置
理论上,后续任务应该以新的事实为基础:
Token问题 → 已排除
Cookie配置 → 当前Root Cause
但历史上下文中仍然保留着大量:
Token猜测
Token分析
Token修改方案
Token相关日志
如果后续又出现一个类似错误,Agent仍然可能重新关注Token。
这就是:
Stale Context——过期上下文。
它最大的危险不是信息错误。
而是:
这个信息曾经是合理的。
因此比明显错误的信息更容易继续影响判断。
更好的方式
当一个关键假设被排除以后,不只是继续往下做。
应该明确更新任务状态:
已确认:
Token正常,不再作为当前排查方向。
当前Root Cause:
Cookie SameSite配置。
后续不要重新修改Token逻辑,
除非出现新的直接证据。
这实际上是在做一件很重要的事情:
Context Garbage Collection。
不是删除历史,
而是明确告诉Agent:
哪些历史已经失效。
三、第二种污染:把“项目长期规则”和“当前任务要求”混在一起
例如一个项目长期存在以下规则:
统一使用pnpm
禁止直接修改生产数据库
修改后必须运行lint和test
公共API需要保持兼容
这些属于:
Durable Context。
它们长期有效。
但今天这个任务可能还有:
只修改Login模块
暂时不要处理UI
不要升级React
这些属于:
Task Context。
任务结束以后,这些限制可能就失效了。
如果所有信息全部放在一个巨大的Prompt里:
项目规范
+
当前需求
+
临时限制
+
测试要求
+
历史决策
+
个人说明
时间长了以后,Agent越来越难区分:
哪些规则是永久的?
哪些只是这一次有效?
OpenAI目前推荐通过AGENTS.md向Codex提供项目级持久指导,并明确建议保持这类说明精简;OpenAI在自身Agent-first工程实践中也总结过一个非常重要的经验:给Codex的是“地图”,而不是一份上千页的说明书。
所以更合理的设计是分层。
Durable Context
放长期规则:
AGENTS.md
项目结构
测试命令
编码规范
禁止事项
Task Context
放当前任务:
当前Bug
允许修改范围
完成标准
当前约束
Runtime Context
只保留执行过程中产生的临时信息:
Terminal结果
当前失败
临时假设
中间Diff
这三种信息的生命周期不同。
把它们混在一起,就是上下文污染的重要来源。
四、第三种污染:任务不断扩张,却始终留在同一个线程
这是Codex特别容易出现的问题。
开始时:
修登录Bug。
完成以后用户继续:
顺便检查一下注册流程。
然后:
再看看用户权限。
接着:
用户权限既然看了,把后台权限也优化一下。
最后:
顺便把TypeScript错误处理掉。
从人类角度看:
这些事情都属于同一个项目。
于是很自然地继续在同一个Thread里做。
但是从Agent任务结构来看:
它们实际上已经变成了:
Task A
登录Bug
Task B
注册流程
Task C
用户权限
Task D
后台权限
Task E
TypeScript修复
而不是:
一个Task。
Codex App目前专门把Agent工作组织为项目下的独立线程,不同Agent可以在独立Thread中并行执行任务,用户再分别查看修改和Diff。
这种设计背后的一个重要思想就是:
Project可以共享,但Task不一定应该共享同一个对话历史。
所以一个非常实用的判断方法是:
如果任务目标没变
继续当前Thread。
例如:
修登录Bug
↓
第一次失败
↓
继续调查
↓
验证
合理。
如果目标已经变了
新开Thread。
例如:
登录Bug已经完成
↓
现在开始优化支付模块
就没有必要继续背着前一个任务的大量历史。
这其实和程序设计里的:
Single Responsibility
非常像。
一个Thread最好也有一个相对明确的责任。
五、第四种污染:不断给Codex追加要求,却没有重新定义“Done”
这是一个更隐蔽的问题。
最初任务:
修复登录Bug。
Done定义很清楚:
登录恢复正常
+
相关测试通过
中途用户增加:
顺便处理错误提示。
然后增加:
登录页面也整理一下。
接着:
再增加一个Loading状态。
于是最终任务已经变成:
Bug Fix
+
Error Handling
+
UI Cleanup
+
Loading State
但Agent原来的Completion Criteria可能仍然围绕:
登录Bug是否修好。
此时容易出现两个极端。
第一种
Bug修好以后,Agent认为:
Done。
但用户觉得:
我后面说的东西还没有做。
第二种
Agent不断继续工作。
因为新的要求越来越多,
它找不到明确结束点。
所以长任务不仅需要维护:
Context。
还需要维护:
Goal。
OpenAI在2026年的Codex实践中已经提供Goals这一类持久目标机制,用于让一个线程跨多个回合持续围绕明确结果工作,并通过完成条件判断任务是否达到目标。
即使不用专门功能,也可以手工维护一个非常简单的状态:
当前目标:
修复登录流程。
完成标准:
1. 登录请求正常;
2. 错误提示正确;
3. Loading状态正确;
4. 相关测试通过。
不属于当前任务:
注册;
权限系统;
UI整体重构。
这样Agent每执行一段时间,都有一个:
North Star。
否则上下文越长,目标反而越容易模糊。
六、第五种污染:失败尝试越来越多,却没有沉淀成“结论”
这是长任务中非常常见的一幕。
Codex尝试:
方案A
失败。
然后尝试:
方案B
失败。
然后:
方案C
部分成功。
再尝试:
方案D
失败。
如果历史只是不断累计:
尝试A
日志A
尝试B
日志B
尝试C
日志C
尝试D
日志D
那么Agent后面必须自己重新理解:
哪些已经证明无效?
哪些仍然可能有效?
这会浪费大量上下文。
更好的方式不是保留完整探索过程作为主要工作状态。
而是在阶段节点形成:
Decision Log。
例如:
已排除:
1. Token过期;
2. API路由错误;
3. 数据库用户不存在。
已确认:
Cookie没有被浏览器保存。
当前方向:
检查SameSite与Secure设置。
不要重复:
Token刷新逻辑。
这样几十条历史消息,被压缩成了几个:
State Facts。
这也是为什么长任务真正重要的不是:
让Agent永远记住所有过程。
而是:
让Agent记住正确的状态。
七、第六种污染:一次性塞太多文件,以为这样最保险
很多开发者担心Codex“不知道项目背景”,于是开始疯狂补上下文:
README
架构文档
数据库Schema
API文档
十几个源文件
测试文件
历史Issue
PR说明
想法是:
我把信息全部给你,你总不会理解错了吧?
结果往往相反。
因为当前任务可能只是:
修改订单按钮的Loading状态。
真正需要的信息也许只有:
OrderButton.tsx
useOrder.ts
对应测试
过量上下文的核心问题不是Context Window一定装不下。
而是:
Attention被稀释。
OpenAI在Agent-first工程实践中专门强调Context Management是复杂Agent任务的核心挑战之一,并总结出“给Agent地图,而不是巨型说明书”的做法;Codex的Skills设计也采用按需加载机制——先暴露技能名称和描述,只有当Agent判断需要时才加载完整SKILL.md,而不是把所有说明一次性塞进上下文。
这背后其实是同一个原则:
Just-in-Time Context。
需要什么,
什么时候再加载什么。
而不是:
Just-in-Case Context。
因为担心以后可能需要,
所以现在全部塞进去。
八、Compaction能解决上下文污染吗?
Codex现在会自动进行Context Compaction。
简单理解就是:
当上下文越来越长时,系统会压缩之前的历史,把关键状态保留下来,让Agent能够继续执行更长的任务。OpenAI明确把Server-side Compaction用于长时间Agent运行,帮助有限Context Window承载更长的任务历史。
这非常重要。
但Compaction并不意味着:
上下文管理已经不需要人管了。
因为Compaction主要解决的是:
历史越来越长
↓
怎样压缩
↓
继续工作
而上下文污染解决的是:
当前信息很多
↓
哪些仍然有效
↓
哪些已经过时
↓
哪些根本不属于当前任务
这是两个不同问题。
例如:
一个错误结论如果一直被当成重要信息,
即使被压缩以后,
它仍然可能继续存在于任务状态中。
所以:
Compaction解决容量问题,Context Management解决信息质量问题。
这也是长任务里非常重要的区别。
九、真正稳定的长任务,需要四层上下文
如果把前面的问题重新整理,我更建议把Codex上下文分成四层。
第一层:Durable Context
长期有效。
例如:
项目结构
编码规范
测试方式
架构边界
安全规则
适合放:
AGENTS.md等项目级配置。
第二层:Task Context
当前任务有效。
例如:
当前Bug
任务范围
禁止修改项
完成标准
任务结束以后可以丢弃。
第三层:Execution State
当前执行进度。
例如:
已经检查什么
已经排除什么
当前Root Cause
当前修改方案
测试结果
这是长任务最需要维护的部分。
第四层:Evidence
用来证明任务完成。
例如:
最终Diff
测试结果
Build结果
未验证项
剩余风险
最终形成:
Durable Context
↓
Task Context
↓
Execution State
↓
Evidence
这比把所有东西放在一个大Prompt里稳定得多。
十、什么时候应该果断开一个新Thread?
一个非常现实的问题:
到底什么时候继续原来的Codex对话,什么时候应该开新任务?
我通常看五个信号。
1. Root Goal已经改变
从:
修登录Bug
变成:
重构权限系统
直接新开。
2. 当前任务已经Done
新的需求即使属于同一个项目,
也可以开新的Thread。
Codex App本身就是按项目组织多个独立Agent线程,以便在不同任务之间切换而不丢失各自上下文。
3. 历史里已经存在大量失效假设
如果你发现Codex频繁重新提到已经排除的问题,
与其继续补充:
我刚才不是说了吗……
不如重新建立一份干净Task Context。
4. 文件范围已经完全变化
前半段:
frontend。
后半段:
database migration。
本质上已经是另一个任务环境。
5. 你自己已经说不清当前线程到底在做什么
这是最好用的判断标准。
如果让你用一句话回答:
这个Thread当前唯一目标是什么?
你自己都需要想半天,
那么这个Thread通常已经太复杂了。
十一、一个更适合Codex长任务的Context Checkpoint
如果任务预计持续比较久,可以每完成一个阶段,就主动生成一次Checkpoint。
例如:
【Current Goal】
修复用户登录后Cookie没有持久化的问题。
【Confirmed Facts】
1. 登录API正常返回200;
2. Token生成正常;
3. 浏览器没有保存Cookie;
4. 问题与数据库无关。
【Changes】
修改 auth/cookie.ts。
【Verification】
unit test通过;
Chrome本地测试通过。
【Remaining】
检查Safari兼容性。
【Do Not Revisit】
Token刷新逻辑;
用户数据库查询。
这几十行内容的价值,可能比继续保留几万Token的探索历史更高。
因为它实际上完成了一次:
State Compression。
不是简单压缩文字。
而是把:
History
变成:
State
这是长任务稳定性的关键。
十二、上下文工程真正解决的不是“记忆”,而是决策质量
所以回到最开始的问题:
为什么Codex任务越做越乱?
很多时候并不是:
模型突然变差。
也不一定只是:
Context Window不够。
更常见的是:
过期信息没有淘汰
+
不同任务混在一个Thread
+
长期规则与临时要求混合
+
失败尝试没有形成结论
+
目标不断变化
+
无关文件持续进入上下文
最终Agent拥有大量信息,
却缺少一份清晰的:
Current State。
所以真正应该优化的不是:
怎么让Codex记住更多东西?
而是:
怎么让它在每一个决策节点,都看到当前真正重要的信息。
这也是为什么未来AI编程越来越值得关注的概念,不只是:
Prompt Engineering。
还包括:
Context Engineering。
Prompt解决的是:
这一刻你怎么跟Agent说。
Context Engineering解决的是:
Agent整个任务生命周期里,应该持续知道什么、忘掉什么、什么时候加载什么。
从Prompt Engineering到Context Engineering
把上一篇的执行问题和这一篇的上下文问题放在一起,其实可以看到Codex工程化正在形成一个更完整的结构:
Environment
↓
Permission
↓
Task
↓
Context
↓
Verification
↓
Evidence
Environment决定:
Agent在哪里工作。
Permission决定:
Agent能做什么。
Task决定:
Agent应该完成什么。
Context决定:
Agent当前基于哪些信息做判断。
Verification决定:
怎么检查结果。
Evidence决定:
怎么证明任务真正完成。
真正长期使用Codex以后,会发现模型本身反而只是这套系统中的一个组件。
模型越来越强以后,
开发者真正需要学习的是:
怎样给Agent建立一个稳定的工作环境和信息环境。
因为一个拥有巨大Context Window、能够运行几个小时的Agent,如果工作状态里一直混着过期结论、无关文件和不断变化的目标,
它只会:
更长时间地在错误上下文里工作。
而一个Context被持续整理、状态被不断更新、任务边界清楚的Agent,
即使面对复杂长任务,
也更容易保持:
目标一致、状态清楚、决策稳定。
这才是Codex从短任务走向Long-Horizon Agent之后,真正需要解决的问题。
更多推荐




所有评论(0)