一、先说清楚前提
上一篇文章发出去之后,有读者问:既然两者接的都是同一个模型,到底有什么区别?
这个问题我当时回答得比较表面——说「设计哲学不同」,听起来正确但没什么信息量。真正在项目里同时跑过一段时间之后,才意识到这个问题的答案比我想的具体得多。
这篇文章不聊功能对比,不聊参数罗列。只聊一件事:同一个模型,在两个工具里为什么会给出不同的输出。过程中做了一些实测,结论全部来自实际运行结果,不是产品文档推断。
二、实测一:同一段代码,两个工具找出的问题完全不同
我们把一段前端业务代码同时丢给两个工具做审查,prompt 完全一样:
「审查以下代码,找出 3 个潜在问题,每个问题说明:问题描述、具体位置、修复方案。」
两个工具分别给出了自己的答案。
Claude Code 的答案:
- UI 状态管理的逻辑顺序问题 — 代码在切换页面时对 DOM 元素的 class 操作顺序有误,导致某些情况下样式状态和实际不符。问题出在页面切换函数里对元素的 add 和 remove 操作不是原子性的。
- 工具函数缺少类型校验 — 一个用于格式化数字的函数直接调用
.toString(),没有对输入类型做判断。当输入是undefined、null或非数字类型时会抛出TypeError。这个函数被多处调用,一旦传入异常值会影响整个渲染流程。 - 模板属性值未做统一转义 — 代码在拼接 HTML 时,对部分属性值做了转义处理,但对另一些属性值直接拼接。如果被拼接的数据来自外部输入,可能形成注入风险。
Codex 的答案:
- 数据渲染存在 XSS 注入风险(高危) — 多处将用户数据直接插入 innerHTML 或拼接进 HTML 属性,没有做 HTML 实体转义。如果数据来源被污染,可以执行任意 JavaScript 代码。具体位置包括:仓库名称插入、描述文本插入、链接拼接。
- DOM 元素访问缺少空值检查 — 页面切换时直接对
getElementById和querySelector返回的结果调用属性或方法,没有检查元素是否存在。当元素不存在时会抛出TypeError导致页面功能中断。
两者的重叠区域:
只有第三点被同时发现——DOM 操作的安全性。两者都注意到了「直接拼接 HTML 有风险」这个问题,但切入角度不同:Claude Code 说的是「模板属性值未做统一转义」,Codex 直接定性为「XSS 注入漏洞」。
其余问题完全不同,没有任何重叠。
三、实测二:同一段需求,两个工具写出来的代码不一样
为了排除「代码库本身特性」的干扰,我们用一个纯算法任务来验证。这次不是审查现有代码,而是让两个工具分别实现同一个需求:
「写一个 JavaScript 函数,接收一个任务数组,每个任务是一个异步函数,最多同时运行 3 个,所有任务完成后返回结果数组。」
Claude Code 的实现:
async function runAll(tasks, maxConcurrent = 3) {
const results = [];
const queue = tasks.map((t, i) => ({ task: t, index: i }));
const workers = Array.from(
{ length: maxConcurrent },
async () => {
while (queue.length) {
const { task, index } = queue.shift();
results[index] = await task();
}
}
);
await Promise.all(workers);
return results;
}Codex 的实现:
async function runAll(tasks, limit = 3) {
const results = [];
for (let i = 0; i < tasks.length; i += limit) {
const batch = tasks.slice(i, i + limit);
const batchResults = await Promise.all(batch.map(fn => fn()));
results.push(...batchResults);
}
return results;
}两者都能正确解决问题,但思路完全不同:
| 维度 | Claude Code | Codex |
|---|---|---|
| 并发模型 | N 个 worker 竞争消费共享队列 | 固定批次,顺序推进 |
| 任务追加 | 支持运行中途追加新任务 | 任务数量固定,批次之间有等待 |
| 代码行数 | 约 12 行 | 约 7 行 |
| 结果顺序 | 保持原顺序(通过 index 映射) | 保持原顺序(通过 index 映射) |
更深层的差异在于问题建模的方式。
Claude Code 把这个问题建模为「生产者-消费者」问题:创建一个固定大小的 worker 池,每个 worker 从共享队列里取任务执行,谁有空谁拿。这是并发编程里很标准的思路,优点是任务可以随时追加,缺点是结果顺序需要靠 index 来保证。
Codex 把这个问题建模为「分批处理」问题:把任务列表切成固定大小的批次,每批同时跑,跑完再跑下一批。这也是合理的思路,优点是直观,缺点是批次之间必然有空闲的并发窗口。
这不是「对错」的问题,而是同一个问题两种合理的拆解方式。同一个模型,在写代码这个任务上产生了两种不同的编程思维。
四、深层分析:包装方式如何影响了输出
同一个模型,为什么在两个任务上给出了不同方向的结果?
不是模型的问题。是两个工具在包装这个模型时,设定了不同的优先级和上下文策略。
理解层面的差异:主动扩展 vs 依赖输入
Claude Code 默认会主动扫描项目结构,把类型定义、依赖配置、历史上下文纳入理解范围;Codex 依赖用户指令的完整性——你没有告诉它的背景,它不会自己去查。
体现在代码审查任务上:Claude Code 倾向于把「某处代码改动」放进「页面渲染流程」这个更大背景里看,所以先注意到了状态管理的逻辑问题;Codex 聚焦在代码本身的安全模式上,倾向于先扫注入、XSS 这类经典的「代码层面」问题。
这不是能力差异,是注意力的优先级不同。
输出层面的差异:过程输出 vs 结果输出
Claude Code 的输出默认带有推理过程——结论、理由、替代方案一起给;Codex 的输出默认直接给结论或代码块,思考过程被包装掉了,只露出结果。
两种输出风格适合不同的使用者:前者方便你评估方案是否合理,后者方便你直接拿去用。
System Prompt 设定的优先级不同
以上两个差异,最终都来自 System Prompt 的权重配置。Claude Code 的 System Prompt 更倾向于「上下文理解 + 结构化输出」,Codex 的 System Prompt 更倾向于「快速定位 + 直接输出」。
这种包装策略的不同,最终决定了同一个模型面对同一个任务时的「思考方向」。
五、选型建议:按工作场景来
两者没有绝对优劣,只有适合的场景。
选 Claude Code:
- 需要深度理解代码上下文再做修改
- 习惯「方案确认后再动手」的迭代方式
- 代码重构或大型代码库审查(上下文理解能力强)
- 对隐私政策有要求(Anthropic 明确承诺数据不用于训练)
- 需要定时自动化任务(Routines 功能,Codex 没有)
选 Codex:
- 需求明确,追求快速出结果
- 有 CI/CD 自动化需求(
exec模式很适合流水线) - 需要 IDE 集成(VS Code / Cursor / Windsurf 插件)
- 代码安全审计(XSS / 注入类问题更敏感)
- 轻量任务,追求启动速度
一句话总结:
两者都有理解和执行,只是包装方式不同——Claude Code 输出的过程更完整,Codex 输出的结果更直接。用哪个,取决于你需要的是「理解质量」还是「执行速度」。