XDA 昨天发文,说让 Codex 给 Claude Code 的成品做二审,抓出一堆 Claude 没说的毛病。我在本机照着做了三轮,数字比他还狠。可对照组跑完,结论跟标题不太一样。
✿ ✿ ✿
开篇
先看一段输出,这是今天早上 8 点不到,我终端里的东西:
审查完成:共发现 20 个具体问题;index.html 未修改。 1. 高|第 78–83、114 行|持久化 XSS 2. 高|第 114 行|导入直接覆盖全部书架 3. 高|第 114、66 行|无效结构先持久化、后崩溃 ... model: gpt-5.6-sol tokens used 59,950被审的是一个 128 行的单文件网页,读书清单,能添加、筛选、搜索、导入导出、切深色模式。代码是 Claude 写的,一次写完,打开能用,看着挺像回事。
审它的是 Codex,只读模式,不许改一个字。104 秒,列了 20 条,外加 2 条"低风险补充"。
22 个问题,其中 8 条标了"高"。
这个实验是照着 XDA 昨天(10 月 6 日)的一篇文章做的。但我多做了一步对照,结果让我把原本想好的标题删了。
Claude 交付,Codex 二审
✿ ✿ ✿
XDA 那篇讲了什么
作者 Nolen Jonker 自己不写代码,痛点很典型:Claude Code 做完会告诉你"完成了",文件也能打开,但它不会告诉你哪里不对。
作者举的例子我很有共鸣。做一个落地页,背景动画应该是一片散落的碎片,Claude 说碎片已经生成、页面完成。打开一看,碎片巨大,还带边框,像一堆散落的按钮。来回说了两轮才改对。
更烦的是"顺手改"——明明只让改一个小地方,Claude 会动没提到的东西。
这类问题不报错。Claude 照样汇报成功。
所以作者装了 OpenAI 官方出的一个插件 codex-plugin-cc,在 Claude Code 里直接把活甩给 Codex。作者做了个叫 DVD Shelf 的单文件收藏页,用 Opus 5.5 Medium 写完,再让 Codex"全部审一遍,什么都别改"。
Codex 几秒就回了一串:本地存的数据只要不是干净列表、或者哪条缺了标题,整页崩溃;图标里混着乱码字符;屏幕阅读器会在每个标题前先念一遍装饰用的首字母;点完筛选键盘焦点就丢了;搜索结果数变了,读屏用户听不到。
作者的结论是:Claude 像一个用鼠标、在干净文件上、没放自己数据的人那样做东西。
XDA 作者踩到的那几个坑
✿ ✿ ✿
插件怎么装(和一个小纠正)
插件是 openai/codex-plugin-cc,GitHub 上 3.4 万星,最新版 v1.0.6。要求很低:一个 ChatGPT 账号(免费的也算)或 OpenAI API key,Node.js 18.18 以上。
在 Claude Code 里依次敲:
/plugin marketplace add openai/codex-plugin-cc /plugin install codex@openai-codex /reload-plugins /codex:setup这里有个小纠正。XDA 作者用的是 /codex:rescue 去做审查,但翻 README 会发现,插件其实给了专门的审查命令:
-
/codex:review:标准只读审查,审未提交的改动,或者用 --base main审整条分支,不接受自定义关注点 -
/codex:adversarial-review:可以带一句话关注点,比如"重点挑竞态和数据丢失",专门质疑设计决策 -
/codex:rescue:这个是派活的,让 Codex 去查 bug、试修复
审查的话,用前两个更对路。rescue 也能审,但它是为"让 Codex 去干活、试修复"设计的,拿来做纯审查不如前两个稳妥。
我这次没装插件——插件底层就是调本机的 codex 命令行,我直接用 codex exec --sandbox read-only 跑,效果一样,还能拿到精确的耗时和 token 数。
✿ ✿ ✿
我的实验:三轮来回
第 1 轮:原版代码,Codex 审出 22 条
第一次跑就踩了个坑。不带 --model 时,我的 Codex 配置默认用 gpt-6.1-sol,直接报错:这个模型不支持用 ChatGPT 账号登录的 Codex。加上 --model gpt-5.6-sol 才跑通。
审出来的 22 条,我没全信,挑了能自动验的,用 Playwright 在真浏览器里逐条复现:
- 01
书名填三个空格——前端 required校验能过,trim()之后是空串,封面上赫然印着 undefined - 02
书名写成一段带 onerror的图片标签——脚本真的执行了,1 次 - 03
导入一个内容是 {}的 JSON 文件——控制台报books.filter is not a function,原来的 3 本书被覆盖,刷新之后整页空白,只能手动清浏览器存储 - 04
书架有书,但搜一个不存在的词——页面写着"书架是空的",用户会以为数据丢了 - 05
四个筛选标签, tabIndex全是 -1,键盘根本点不到
5 条全中。这代码要是真发给用户,第 3 条就够写一封道歉邮件了。
五条全部复现
对照组:同样的 prompt,换一个"新 Claude"来审
到这里我差点就写下"Codex 比 Claude 细心"这种结论。
但有个变量没控制住:Codex 是第一次看这段代码,而 Claude 是写这段代码的那个。这俩差的可能不是模型,是位置。
所以我加了个对照:一字不改的审查 prompt,交给一个全新上下文的 Claude 子代理(没参与写代码,只能读文件)。
47 秒,61,532 token。它交回来 28 条:严重 3、高 5、中 9、低 11。
比 Codex 还多 6 条。
我把两份清单逐条对了一遍。核心那几条——XSS、导入覆盖、导入后白屏、存储损坏就启动失败、键盘不可达、空格书名、空状态文案、多标签页互相覆盖、重复 ID——两边都抓到了。各自独有的也有:新 Claude 提了 emoji 开头的书名封面会显示半个字符、导出时没释放临时 URL、深色模式刷新会闪白;Codex 提了浏览器禁用存储时的报错没人接、删除后键盘焦点丢失。
说实话,这个结果让我有点意外,也有点释然。
真正起作用的,是"换一个没写过这段代码的审稿人",而且明确告诉它"去找问题"。 写代码的那个上下文,脑子里装着"我已经做完了"的叙事,很难回头怀疑自己。换个模型能做到这点,换个干净上下文的同一个模型,也能做到。
换的不是模型,是位置
第 2 轮:我修了,Codex 说"有一条没修好"
接下来我(也就是写代码的那个 Claude)按清单修了一轮:加转义、导入前校验结构并二次确认、读存储包 try/catch、筛选改成真按钮、空格书名拦截、ID 改用 UUID、空状态区分"真空"和"没搜到"。diff 是 47 行加、19 行删。
修完再交给 Codex,这次让它只审 diff,每条修复判 FIXED / PARTIAL / NOT FIXED。
42 秒,25,382 token。结论:4 条修好、2 条修了一半、1 条没修好,外加 3 个新引入的回归。
没修好的那条最值得说。我给书名、作者都做了转义,但删除按钮是这么写的:onclick="removeBook('${id}')"——导入文件里的 ID 原样拼进了内联脚本。HTML 转义挡不住这个,浏览器会先把实体解码再执行。我在浏览器里构造了一个 ID 是 ');window.__pwn=1;// 的书,点删除,__pwn 果然变成了 1。
新回归里有一条特别"AI":我把筛选标签从 div 改成 button,没注意全局样式里按钮是白字。结果浏览器里量出来,文字颜色和背景都是 rgb(255,255,255)——白底白字,四个筛选按钮直接隐身。
修一个可访问性问题,顺手造出一个更严重的可访问性问题。这就是 XDA 作者说的"顺手改",只不过这次是我自己干的。
第 3 轮:收口
第三轮改动很小,10 行加 4 行删:导入时一律丢掉外部 ID、重新生成;删除改成事件委托,不再往 onclick 里拼字符串;筛选按钮显式指定文字颜色;主题按钮的 aria-pressed 跟着状态更新。
这一轮 Codex 第一次跑卡住了,十多分钟没输出,我杀掉重跑,29 秒出结果:4 条全部 FIXED,没有中等以上的新问题。
我还是回浏览器复验了一遍:恶意 ID 不再执行(__pwn 为 0),两本同 ID 的书只删掉一本,筛选按钮文字是深灰 rgb(34,34,34)。
有一条我得老实交代:第二轮 Codex 还指出"保存失败时界面照样显示成功",我只改了提示文案,调用方没改。这条现在还挂着。
三轮来回的账本
✿ ✿ ✿
可以直接抄的做法
跑完三轮,我自己的工作流会这么改:
1. 写完别让同一个上下文自审。 开新会话、新子代理,或者换 Codex,三选一都行。关键是审稿人没参与写。我这次实测,新 Claude 28 条、Codex 22 条,差距没大到"非换模型不可"。
2. prompt 里写清"只找问题,什么都别改",并要求给行号和触发场景。 有了"触发场景"这一项,每条都能直接拿去复现,而不是一句"建议加强输入校验"。
3. 审完要复现,别直接全修。 我挑了 5 条自动化复现,5 条全中;但清单里也有"对比度约 3.19:1"这种需要你自己判断要不要管的。
4. 修完必须再审一次 diff。 这是我这次最大的收获:第一轮审出来的问题,第二轮修复又引入了 3 个新问题,其中一个是 XSS 的漏网之鱼。只审一次,等于只审了一半。
5. 交叉模型的价值在第二轮。 第一轮用谁审差别不大,但修复是写代码的那个 Claude 做的,这时候换一个不同模型审 diff,能避开同一种思维惯性——白底白字那种错,就是顺着"div 改 button"的思路一路写下去才犯的。
成本心里也有个数:三轮 Codex 一共约 10.8 万 token,总耗时不到 3 分钟(不算卡住那次)。对一个 128 行的文件来说不算便宜,但比把白屏 bug 发给用户便宜多了。
五条可以直接抄的规矩
✿ ✿ ✿
写在最后
XDA 的标题是"Codex 抓到了 Claude 漏掉的问题"。这话没错,但我觉得容易让人得出"换个更强的模型就好了"的结论。
我跑完的感受是:模型交付的"完成",只是"写的人觉得完成了"。这跟人写代码一样——没有哪个工程师能靠自己读一遍自己的代码就发现所有 bug,所以才有 code review。
AI 写代码,也得有人审,而且审的不能是写的那个。
你现在让 AI 写完代码,会再找一个"审稿人"吗?用的是同一个会话,还是换了一个?