ChatGPT、Codex实战:任务越做越乱?上下文污染的6个来源与解决方法

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之后,真正需要解决的问题。