文章

Codex 的上下文治理工程:从 Agent Loop 到可观测性

从 Codex 的 Agent Loop、AGENTS.md、Skills、Sandbox、Approvals、Hooks 和 Compaction,看代码 Agent 如何治理每一轮模型应该看到的上下文。

2026/06/08 更新于 2026/06/08
  • Agent
  • Codex
  • 上下文工程
  • AI 产品

Codex 这类代码 Agent 的核心难点,不只是“让模型会写代码”。

更关键的问题是:

在一个长任务里,Agent 每一轮到底应该让模型看到什么?

代码 Agent 不是普通聊天机器人。它会读文件、改文件、运行命令、调用工具、触发测试、请求权限、加载项目规则、使用 Skill、压缩历史、恢复会话,也可能在多轮执行后继续接收新的用户要求。

因此,Codex 的价值不能只理解成“模型能力很强”。更准确地说,它把模型放进了一个工程化的 Agent Loop:

task context

model call

structured tool request

sandboxed execution

tool result

state update

context assembly / compaction

next model call

这篇文章基于 OpenAI 公开 Codex 文档和可观察的工程抽象整理,不讨论未公开内部实现。我的重点不是复述 Codex 功能,而是抽象出一个更通用的问题:

代码 Agent 的上下文治理,应该如何从 prompt 技巧变成系统能力?

上下文窗口不是上下文治理

很多人容易把上下文治理理解成 context window 管理。

模型支持 400k token 或 1M token,好像问题就解决了。

但这只是物理容量,不是治理策略。

对代码 Agent 来说,真正的上下文包括:

  • 用户原始目标;
  • 当前 thread transcript;
  • 已读文件和相关代码片段;
  • 当前 diff;
  • 测试结果和报错日志;
  • shell / tool 调用历史;
  • 项目规则和 AGENTS.md
  • Skill metadata 和被激活的 SKILL.md
  • MCP 工具返回;
  • sandbox 和 approval 状态;
  • config、rules、hooks;
  • 压缩后的任务摘要;
  • 计划、检查点和未完成事项;
  • 用户后续补充约束。

这些内容不可能每一轮都无脑塞进模型。

即使塞得下,也不代表模型会稳定做对。

长上下文会带来几个问题:

  • 成本和延迟上升;
  • 关键证据被低价值历史稀释;
  • 已废弃计划污染当前判断;
  • 旧工具结果和新工作区状态冲突;
  • 项目规则被压缩或挤出注意力;
  • Skill 细节在长任务中逐渐丢失;
  • 任务完成后难以解释“为什么模型当时这么判断”。

所以更合理的区分是:

Agent Context
  应用层维护的候选工作状态

LLM Context
  本轮实际送入模型的输入窗口

Context Assembly
  从 Agent Context 到 LLM Context 的选择、排序、压缩和渲染过程

上下文治理不等于“把 prompt 写长一点”。

它是 Agent Runtime 每一轮必须执行的决策。

Codex 更像结构化 Tool Call Agent Loop

经典 ReAct 可以写成:

Thought → Action → Observation

这个范式很有解释力,但用它描述 Codex 仍然不够。

从工程视角看,Codex 更像:

instructions
  + tools
  + input
  + thread history
  + project guidance
  + skill context
  + workspace evidence
  + sandbox / approval boundary
  → model output items
  → tool execution
  → tool results
  → next input

这里的关键不只是“模型想了什么”,而是系统如何持续维护一个可执行环境。

一次 Codex 式 Agent Loop 至少包含七个动作。

第一,组装上下文。

系统需要决定当前轮要带上哪些指令、文件、错误、diff、Skill、项目规则和历史状态。

第二,调用模型。

模型可能输出自然语言,也可能输出结构化 tool call。

第三,执行工具。

工具可能是文件读取、文件修改、shell 命令、MCP 工具、浏览器或其他外部能力。

第四,观察结果。

工具返回不只是文本,而是下一轮决策的事实材料。

第五,更新状态。

系统需要更新计划、diff、测试结果、权限、错误、未完成事项和当前任务判断。

第六,决定继续还是停止。

如果任务还没完成,下一轮继续;如果完成,给用户总结变更、验证结果和风险。

第七,在必要时压缩历史。

当 thread 变长,系统需要把旧历史压缩成更小的上下文表示,让任务继续推进。

这说明,Codex 的核心不是一条 prompt,而是一个持续运行的控制循环。

上下文来源:不只有聊天历史

代码 Agent 的上下文来源比普通聊天复杂得多。

我会把它分成十类。

来源作用风险
用户目标定义任务方向原始目标可能在多轮后被淡化
对话历史保留用户补充和 Agent 过程长历史会稀释注意力
项目规则注入 repo 规范、命令、约束规则过长会被截断或互相冲突
文件证据支撑代码理解和修改片段过多会污染当前判断
Tool result反馈命令、测试、搜索、MCP 结果原始输出可能冗长且噪声高
Diff / workspace state表示当前实际变更需要和旧计划保持一致
Skill注入特定工作流和验收标准触发不准或细节丢失
Sandbox / approval决定 Agent 能否自主执行过宽危险,过窄低效
Hooks / rules提供确定性检查和生命周期控制配置复杂,需要信任和审计
Compaction summary让长任务继续执行摘要可能丢失关键细节

这些内容的生命周期不同。

AGENTS.md 可能是一类稳定项目规则。

一次 shell 输出可能只是短期证据。

当前 failing test 可能比十轮前的计划更重要。

Skill 的 description 应该长期可发现,但完整 SKILL.md 只有在任务相关时才值得加载。

因此,Agent 不应该只有一个 message history。

它至少需要一个上下文资产模型:

context_item:
  source
  scope
  trust_level
  lifecycle
  evidence_ref
  freshness
  token_cost
  include_reason

否则系统很难解释:为什么这段内容进入了模型,而另一段没有。

AGENTS.md:稳定项目规则层

Codex 官方文档把 AGENTS.md 描述成给 Agent 读取的项目指令文件。

它适合承载:

  • repo 结构;
  • 构建、测试、lint 命令;
  • 工程约定;
  • PR / review 期望;
  • 禁止事项;
  • “done”的判断标准;
  • 子目录特定规则。

这类内容很适合作为稳定上下文。

它不应该每次都由用户重复输入,也不应该埋在一次聊天历史里。

AGENTS.md 也有治理问题。

第一,它有作用域。

全局规则、项目规则、子目录规则不应该同等对待。离当前工作目录更近的规则往往更具体,也更应该影响当前任务。

第二,它有长度限制。

一个过长的项目规则文件会和任务上下文竞争模型注意力。更好的方式是把常用规则放在主文件,把专项规范拆到引用文档或 Skill。

第三,它不是绝对可信的系统指令。

项目文件可能来自仓库,可能被修改,可能包含过时规则,也可能和用户当前任务冲突。成熟的 Agent 产品应该记录 guidance 的来源、版本和作用域。

我的判断是:

AGENTS.md 是代码 Agent 的稳定规则层,但不是全部上下文治理。

它解决的是“项目希望 Agent 长期遵守什么”。

它不解决“当前任务这一轮应该看什么证据”。

Skills:按需加载的工作流上下文包

Skill 是理解 Codex 上下文治理的关键。

官方文档中,Agent Skills 的核心是把任务相关的 instructions、resources 和 optional scripts 打包给 Codex,让 Codex 更可靠地完成重复工作流。

它的关键设计是 progressive disclosure。

Codex 启动时不把所有 Skill 的完整内容都塞进上下文。

它先让模型看到轻量索引:

skill name
skill description
skill path

当任务匹配某个 Skill 后,再加载完整 SKILL.md。如果需要,Agent 再读取 references、assets 或执行 scripts。

这个机制非常重要。

它说明上下文治理不只是压缩历史,也包括能力发现:

先让模型知道“有哪些工作流可用”
再让模型决定“当前任务是否需要某个工作流”
最后只展开“当前确实需要的工作流细节”

一个好的 Skill 不应该是长篇背景知识,而应该提供:

  • 清晰触发条件;
  • 输入、输出和停止条件;
  • 分阶段 workflow;
  • gotchas;
  • 可执行脚本;
  • 验证命令;
  • 输出模板;
  • 失败时如何处理。

Skill 的价值在于,它把组织经验从“每次重新 prompt”变成“可发现、可加载、可验证的工作流资产”。

但 Skill 不是硬状态机。

SKILL.md 进入的是上下文窗口,而不是模型权重。

它能显著提高 Agent 遵循流程的概率,但不能单独保证:

  • 一定触发;
  • 一定不误触发;
  • 一定逐步执行;
  • 一定不被长历史稀释;
  • 一定不会在 compaction 后丢失细节;
  • 一定会完成验证。

所以真正可靠的 Agent workflow 不能只靠 Skill。

更稳的组合是:

Skill
  defines workflow and gotchas

Scripts
  make critical checks deterministic

Rules / Hooks
  enforce lifecycle constraints

Sandbox / Approvals
  define permission boundary

Tests / CI / Review
  verify final output

一句话:

Skill 是让 Agent 使用组织经验的上下文接口;可靠性来自 Skill 和工程控制面的组合。

Sandbox 和 Approvals:权限也是上下文

很多人把 sandbox 和 approval 当成安全功能。

这当然没错。

但从上下文治理角度看,它们还有另一层含义:

Agent 每一轮能做什么,本身就是模型决策时应该知道的任务上下文。

如果 Agent 当前是 read-only,它不应该计划直接修改文件。

如果网络不可用,它不应该假设可以安装依赖或访问远程 API。

如果某个命令需要 approval,它应该知道自己必须停下来请求用户确认,而不是继续假装执行。

Sandbox 定义技术边界。

Approval policy 定义越界时如何停下。

这两者共同决定 Agent 的行动空间。

因此,权限状态应该进入 Task Context:

permissions:
  filesystem: workspace-write
  network: disabled
  approval_policy: on-request
  writable_roots:
    - current_workspace
  requires_approval:
    - outside_workspace_write
    - network_command
    - destructive_tool_call

这不是为了让模型“记住一条安全提示”,而是让它在规划时选择可执行路径。

很多 Agent 失败不是能力问题,而是它制定了一个当前权限下无法执行的计划。

Hooks:上下文治理的可观测入口

Hooks 是 Codex 里非常值得关注的扩展点。

官方文档把 hooks 定义为可以注入 Codex 生命周期的脚本机制。

它们可以用来:

  • 记录会话到日志或分析系统;
  • 扫描 prompt,防止误贴 API key;
  • 自动总结对话形成 persistent memory;
  • 在 turn 停止时运行 validation check;
  • 根据目录定制 prompting;
  • 在 tool use 前后做检查。

这说明,Hooks 不只是自动化小工具。

它们可以成为上下文治理的可观测层。

普通日志记录的是:

  • 用户说了什么;
  • 模型输出了什么;
  • 工具执行了什么;
  • 文件改了什么。

但上下文治理真正需要记录的是:

  • 本轮有哪些候选上下文;
  • 哪些进入了模型;
  • 哪些被排除;
  • 为什么排除;
  • 哪个 Skill 被触发;
  • 哪些 AGENTS.md 规则生效;
  • 哪些工具结果被压缩;
  • compaction 发生在什么时候;
  • 压缩摘要引用了哪些原始事件;
  • 当前权限边界如何影响计划;
  • 哪个验证脚本阻止了完成报告。

如果没有这些记录,Agent 产品就无法解释自己的行为。

用户只能看到最终结果,却看不到系统如何决定“让模型看什么”。

对未来的 Agent 产品来说,context trace 会变得和 tool trace 一样重要。

Compaction:不是总结,而是状态迁移

当任务变长,Codex 会面对一个现实问题:

所有信息都必须放进模型上下文窗口。

如果 thread 太长,系统需要 compact。

很多人会把 compaction 理解成“摘要聊天记录”。

但对代码 Agent 来说,compaction 更像状态迁移:

long raw history

compressed task state

next model calls continue from compressed state

它必须保留的不只是对话内容,而是任务继续执行所需的信息:

  • 原始目标;
  • 当前计划;
  • 已完成步骤;
  • 当前 diff;
  • 失败和修复记录;
  • 未解决问题;
  • 用户约束;
  • 已经批准或拒绝的操作;
  • 相关文件和证据引用;
  • 当前验证状态。

如果 compaction 只生成自然语言摘要,就有几个风险:

  • 把事实和推断混在一起;
  • 丢失原始证据引用;
  • 淡化用户约束;
  • 遗忘失败路径;
  • 让后续模型把摘要当成更高级别指令;
  • 无法 replay 压缩前后的差异。

更好的方式是把 compaction 设计成结构化结果。

例如:

compacted_context:
  original_goal: ...
  current_plan: ...
  completed_steps: ...
  active_files: ...
  current_diff_summary: ...
  failing_tests: ...
  user_constraints: ...
  permissions: ...
  open_questions: ...
  raw_refs:
    - event_id: 42
    - tool_call_id: shell-17

这和 Task Context 的思路一致。

Compaction 不应该只服务 token 节省。

它应该服务任务连续性。

为什么通用 Agent 很难

通用 Agent 的难点不是“能不能接更多工具”。

真正困难的是:

不同任务需要完全不同的上下文秩序。

编码任务最关心:

failing test
current diff
related source file
interface contract
project rule
recent tool result

研究任务最关心:

source credibility
publish date
direct evidence
opposing view
citation trail
uncertainty

设计任务最关心:

user goal
current screen
design system
visual hierarchy
interaction state
accessibility

运维任务最关心:

current incident
recent deployment
logs
metrics
blast radius
rollback plan

它们都可以使用同一个 Agent Runtime。

但它们不应该使用同一种 context policy。

所以一个成熟 Agent 产品可能不是:

one universal agent

而是:

shared agent runtime
  + domain skills
  + task-specific context policy
  + verifiers
  + observability
  + human approval gates

这也是为什么我认为“上下文治理”会成为 Agent 产品的核心中间层。

它不是模型层,也不是 UI 层。

它在 Runtime 和 Product 之间。

任务重演需要 Context Replay

如果要 replay 一个 Agent 任务,只保存最终 diff 不够。

只保存聊天 transcript 也不够。

因为每一轮 LLM input 本身已经是上下文治理的结果。

真正可重演的 Agent 任务,至少需要记录:

  • workspace snapshot;
  • model version;
  • tool schema;
  • Skill version;
  • AGENTS.md version;
  • config / rules / hooks version;
  • context policy version;
  • candidate context list;
  • selected context list;
  • rejected context list;
  • compaction event;
  • final prompt hash;
  • model output;
  • tool call;
  • tool result;
  • state transition。

否则会出现:

workspace 一致
但 context selection 不一致

context selection 一致
但 compaction 不一致

compaction 一致
但 tool result 不一致

tool result 一致
但模型输出不一致

因此,Agent replay 的核心不是 workspace replay,而是 context replay。

这也是 Agent 可观测性未来会越来越重要的原因。

它不仅是 debug 工具,也是:

  • context selector 迭代数据;
  • verifier 训练数据;
  • Skill 触发评估数据;
  • 失败复盘材料;
  • 用户信任机制;
  • 团队流程资产。

对 Agent 产品的启发

从产品经理视角,我从 Codex 的上下文治理里得到几个判断。

第一,Agent 产品不能只展示结果。

用户需要知道 Agent 为什么这么做,它看了什么、忽略了什么、验证了什么、哪里被压缩了。

第二,上下文治理要产品化。

它不应该只是隐藏在 prompt builder 里的实现细节。对高价值任务,产品可以展示任务目标、当前计划、证据、权限、验证结果和未解决风险。

第三,Skill 是组织经验的产品形态。

当团队发现 Agent 重复犯错,不应该只写更长 prompt,而应该沉淀成 Skill、脚本、规则、hook 或测试。

第四,权限边界会影响产品体验。

过紧的 sandbox 会让 Agent 经常中断;过宽的权限会让用户不敢放手。好的产品需要把权限设计成可理解的协作机制,而不是冷冰冰的安全开关。

第五,可观测性是长期壁垒。

谁能更好地记录 context selection、tool result、compaction、approval 和验证链路,谁就更容易持续改进 Agent 的成功率。

对 Plato 的启发

这篇文章也反过来强化了我对 Plato 的判断:

Execution Agent 需要的不只是更强模型,而是一套可维护的 Task Context。

Plato 如果要成为面向产品和执行工作的 Agent workbench,需要把上下文治理显式化。

一个可迭代的方向是:

Event Log
  记录用户、Agent、工具和系统事件

Task Context Builder
  从事件、文件、计划、权限和证据中生成结构化任务状态

Context Policy
  决定不同任务类型下哪些内容优先进入模型

Prompt Renderer
  把 Task Context 渲染成 cache-aware LLM input

Verifier
  检查输出、测试、文档、计划和用户约束

Context Trace UI
  让用户看到 Agent 为什么这么判断

这不是为了把系统做复杂。

而是为了让复杂任务可控。

结论

Codex 的启发不只是“代码 Agent 可以很强”。

更重要的是,它展示了一个成熟 Agent 产品需要的中间层:

Model
  provides reasoning and tool-use ability

Agent Runtime
  executes loop and tools

Context Governance
  decides what model sees and why

Control Plane
  sandbox, approvals, rules, hooks, skills

Observability
  records tool trace and context trace

User Workspace
  provides real files, tests, docs, and feedback

LLM 决定 Agent 能力上限。

上下文治理决定 Agent 稳定性上限。

如果一个 Agent 产品不能回答:

  • 当前轮模型看到了什么;
  • 为什么看这些;
  • 哪些被压缩了;
  • 哪些被排除了;
  • 权限如何影响行动;
  • Skill 如何影响流程;
  • 工具结果如何改变状态;
  • 用户如何追溯和恢复任务;

那么它很难从 demo 走向长期可用。

真正可靠的 Agent,不只是会行动。

它还必须能解释自己的行动条件。

参考资料