跳转至

Claude Code 与 Codex Agent 设计对照

这一章不比较“哪个产品更好”,只比较两个 agent runtime 在相同设计问题上的不同取法。读这类系统时,重点不是记住对象名,而是看它们如何处理一组反复出现的工程矛盾:模型不可靠但要推进任务,工具有副作用但要让模型使用,上下文有限但任务很长,权限要严格但体验不能完全阻塞。

共同问题

Coding agent 的主矛盾是:模型负责决策,本地 runtime 负责执行。模型能生成计划、文本和工具调用,但不能直接运行命令、读写文件、批准权限或修改长期记忆。runtime 必须把模型输出变成可验证、可审计、可恢复的本地动作。

flowchart LR Intent[模型意图] --> Runtime[本地 runtime] Runtime --> Validate[结构校验] Validate --> Permission[权限与隔离] Permission --> Execute[工具执行] Execute --> Observation[结果观察] Observation --> Intent

这个闭环里最容易出问题的地方有四个。第一,模型会输出不完整、过长或语义错误的工具参数;第二,工具执行结果可能很大、失败或被权限拒绝;第三,用户可能在任务中途插入新要求或中断;第四,长任务会超过上下文窗口,需要压缩但不能丢关键事实。Claude Code 和 Codex 的机制都围绕这些问题展开。

主循环的取法

Claude Code 更像一个 query loop 驱动的 runtime。入口把请求交给 QueryEngine,query loop 每次采样前重新整理消息、工具、上下文和恢复策略。模型返回 tool_use 后,runtime 执行工具并把 tool_result 作为下一次采样输入。它强调在单个用户任务内持续“采样、执行、回填、再采样”,并把 fallback、stop hook、auto compact、streaming tool execution 放在 loop 内处理。

Codex 更强调 Session 对 turn 的调度。用户输入先进入 Session 队列,Session 决定是启动新 turn、注入 active turn、处理中断、等待审批还是执行 compact。regular task 再负责推进一次 turn 内的模型和工具循环。它的设计重点是把会话级顺序、pending input、审批响应和 active task 生命周期统一管理。

两者解决的是同一个问题:agent 不是一次请求,而是一个可被用户和工具不断打断的长流程。差别在于控制中心的位置。Claude Code 的分析重点落在 query loop 如何不断重建下一次采样;Codex 的分析重点落在 Session 如何维护 turn 边界和操作队列。

设计点 Claude Code Codex Agent
控制中心 QueryEngine + query loop Session loop + regular task
用户追加输入 作为后续采样上下文并入任务 pending input 进入 active turn 或新 turn
完成判断 无 tool_use 后再过 stop hook、恢复、预算检查 turn complete 前确认工具、pending input、事件和历史收束
中断处理 abort 模型流或工具,并补齐必要 tool_result interrupt 进入 Session 队列,取消 active task

上下文与记忆

两套系统都把上下文分成多层,而不是把所有材料拼成一个 prompt。任务历史提供当前事实,项目规则提供约束,工具/skill 提供能力说明,长期记忆提供跨会话经验,compact 摘要负责压缩旧历史,resume/fork 负责从持久化记录恢复现场。

Claude Code 的记忆设计更突出文件型规则和动态注入。CLAUDE.md、规则目录、@include、路径条件、skill 发现、read-file attachment 和 compact 后的文件恢复共同决定模型看到什么。它适合分析“模型在本地项目里如何获得足够工作现场”。

Codex 的记忆设计更突出 history、rollout、context baseline 和 memory read/write 的分层。初始上下文建立基线,后续 turn 注入 diff;compact 可以重写 working history;长期 memory 写入从主流程中异步派生。它适合分析“长会话如何在可恢复记录和模型工作集之间转换”。

共同取舍是:上下文越完整,token 成本和污染风险越高;上下文越稀疏,模型越容易重复操作或误判现场。好的 agent runtime 不追求最大上下文,而是追求可解释的上下文编排。

工具与 Skill

两者都把“模型可见能力”和“本地可执行能力”分开。模型看到的是工具 schema 或 skill 摘要;本地持有的是 handler、权限检查、hook、sandbox 和结果映射。这个分离是 agent 安全和可维护性的基础。

Claude Code 的 skill 更像 prompt command:它可以展开 prompt、设置 allowed tools、指定模型/effort、触发 forked agent,也可以通过路径动态发现。它强调 skill 如何改变任务方法,而不是直接扩大执行权限。

Codex 的 skill 更偏“任务说明按需注入”:基础上下文中可见摘要,显式触发后才读取完整 SKILL.md,并处理依赖。工具层则通过 ToolRouter 同时维护模型可见 specs 和本地 handler registry,支持 MCP、dynamic tools 和 deferred exposure。

共同设计原则是:不要让 skill 直接变成隐式权限,不要让 tool schema 代替 handler 校验,不要把所有工具全量暴露给模型。工具暴露面、执行权限和任务方法应该分别控制。

权限与安全

Claude Code 和 Codex 的安全边界都在 runtime,而不是 prompt。模型可以请求命令、patch、文件读写或外部工具,但是否执行由本地权限系统决定。权限拒绝也会作为 tool_result 回到模型,成为下一步推理的输入。

Claude Code 的权限链路强调规则、hook、permission mode、canUseTool 和 sandbox runtime 的组合。hook 可以参与决策,但 hook allow 不能越过 deny rule、安全检查和交互要求。sandbox 会把文件系统、网络和敏感路径限制落实到命令环境。

Codex 的权限链路强调 permission profile、approval policy、ExecPolicy、patch safety、sandbox 和 guardian。permission profile 定义能力上限,approval policy 定义交互策略,ExecPolicy 和 patch safety 把 shell 与 patch 从“任意字符串/文本”解释成有风险等级的动作。

共同取舍是:权限越自动,用户体验越顺滑,但风险越高;权限越保守,系统越安全,但 agent 容易被频繁审批打断。成熟 runtime 会把风险拆细:只读、工作区写入、网络、越界写入、后台进程、删除、权限升级分别处理,而不是用一个总开关。

可观测性与恢复

两者都把事件和持久化视为核心机制。agent 运行中会产生模型文本、reasoning、tool call、工具进度、权限请求、输出截断、compact boundary、usage 和错误恢复。UI 看到的是这些事件的投影;runtime 依赖这些记录恢复任务。

Claude Code 通过 transcript JSONL、parent uuid、compact boundary、subagent transcript 和 AppState 恢复会话。Codex 通过 rollout、thread store、state db、event stream 和 turn context 恢复历史与上下文基线。

共同原则是:UI 日志、模型 history、持久化记录不是同一个东西。UI 需要可读,模型需要结构合法,恢复需要因果完整。把三者混成一个数组,短 demo 可以跑,长任务会在 compact、resume、fork、interrupt 和权限审批时失控。

设计结论

从 Claude Code 和 Codex 可以抽出几条通用设计规则:

  1. Agent loop 要以“观察结果后继续决策”为核心,而不是一次性规划所有步骤。
  2. 模型输出只表达意图,本地 runtime 必须独立校验、授权和执行。
  3. 工具 spec、handler、权限、sandbox、结果回填要分层设计。
  4. 上下文系统要编排历史、规则、能力、记忆和 compact,而不是简单拼 prompt。
  5. 长任务必须有事件流和持久化恢复,否则中断、压缩和 fork 都不可控。
  6. Skill 应该影响工作方法,不应该偷偷扩大执行权限。
  7. 权限拒绝和工具失败要回到模型上下文,让模型能基于真实约束调整方案。

这类系统的难点不在于“接一个模型 API”,而在于把不稳定的模型决策放进稳定的本地控制系统里。Claude Code 和 Codex 的具体实现不同,但都在解决同一组 agent runtime 设计问题。