☰
双AI交叉审计代码:Claude Code与Codex生产环境实战
2026/9/28 12:29:56 网站建设 项目流程

20 个模块,两个当前最主流的 AI 编程代理,同时审计同一批生产代码,最后两边都确认存在问题的只有 7 个模块。这个结果我不是意外,而是有点发懵的状态。

事情是这样的:我们一个上线两年多的核心服务准备做一次大版本重构,代码走查靠人肉基本走不过来,几十万行代码,团队就六个人。我当时的想法很直接——既然 Claude Code 和 Codex 都能在仓库里干活,让它们俩互相"交叉验证"一下,先替我们把可疑点筛出来,再让工程师逐个确认。测完我对"AI 审计"这件事的认知发生了挺大的变化,今天这篇就把整个过程、分歧案例和最终沉淀下来的工作流全部摊开讲。

1. 起因:我为什么把整个核心模块拆给两个 AI 做审计

1.1 审计目标不是"找 Bug"而是"找可疑点"

正式动手之前,我先给团队定了个调:AI 审计的产出不是"这行代码错了",而是"这个逻辑值得人工再看一眼"。因为大模型本质上是概率推理引擎,它不可能证明你的代码没有问题,它只能根据训练时见过的缺陷模式,给出一批"可疑点"的候选项。

我们的目标很具体:在三类问题上做初筛——正确性风险(并发、幂等、状态流转)、安全风险(越权、注入、敏感信息泄露)、性能与稳定性风险(N+1 查询、无界缓存、慢 SQL)。风格类问题不在考虑范围内,ESLint 和 Prettier 已经管了。

1.2 为什么选 Claude 和 Codex,而不是其他工具

选 Claude Code 和 Codex 的原因很朴素:它们是当前跑在自己终端里、能真正读整个仓库、能改文件的 Agent 型工具,不是那种粘贴一段代码进去问我"这段代码有什么问题"的网页版。

安装环节其实就有故事可讲。我的开发机是 Windows,跑 Claude Code 时直接弹了Claude's workspace requires the Virtual Machine Platform on Windows的报错,这是因为新版 Claude Code 在 Windows 上依赖虚拟机平台来跑容器沙箱,需要去"启用或关闭 Windows 功能"里勾上"虚拟机平台"然后重启,不是装好就能用。

Codex 那边我用的也是本地 CLI,npm install -g @openai/codex装完后还要注意 PATH,Windows 上很容易报无法将“claude”项识别为 cmdlet这种环境变量问题,本质上是 npm 全局目录没有加到全局 PATH 里。

还有个小插曲:为了统一管理不同模型的 API endpoint,我试过 cc-switch 这类切换工具,结果遇到local proxy failed while handling codex endpoint /responses的报错。排查了一圈,发现是切换后 baseURL 没指向正确的本地代理地址,工具本身没问题,是配置不匹配。所以后面我干脆放弃了切换工具,Claude 和 Codex 各自用官方默认配置,避免引入额外变量。

1.3 两套"眼睛"的分工设计

我先在代码库根目录建了module_audit/文件夹,用来放所有输入输出。审计策略上,两个工具跑的是完全一样的模块清单和 prompt 模板——变量全部控制住,后面对比才有解释力。

也提一个亲测的陷阱:有人喜欢在对话里一句"帮我审计整个项目"就把几十万行代码丢给 AI,实测效果非常差。模型注意力会稀释在全局扫描里,最终给出的都是"注意错误处理""加强校验"这类正确的废话。必须把审计单元切小,按模块或按文件批量喂,输出质量才会真正上来。

2. 统一口径:没有可控变量的对比实验都是玄学

2.1 模块拆解与 Prompt 模板

我把服务按业务边界拆成 20 个模块,每个模块对应一个子目录或一组核心文件。拆分的依据是:模块之间能独立理解、单个模块的代码量保持在 500~2000 行左右、模块边界和现有领域模型对齐。太大的模块拆碎,太小的模块合并。

然后我把审计用的一份系统级 prompt 固定下来,两个 AI 用同一份。Prompt 长这样:

你是资深代码审计工程师。请审计以下模块代码,重点关注: 1. 正确性风险:并发、竞态、幂等性、状态一致性问题 2. 安全风险:越权、注入、敏感信息泄露、不安全反序列化 3. 性能风险:N+1 查询、无界数据增长、阻塞调用、锁粒度 约束条件: - 只报告有具体代码依据的问题,禁止泛泛建议 - 每个问题必须引用具体文件和行号 - 没有发现问题的模块,必须明确回答 PASS - 如果某个改动会破坏现有行为,请显式说明 输出格式: module: [模块名] issues: - severity: critical / warning / info file: [文件路径] line: [行号] issue_type: [bug / security / performance / consistency] description: [问题描述] suggestion: [修复建议]

我实测下来,"必须回答 PASS"和"禁止泛泛建议"这两条约束最能提升报告质量。没有这两个约束,AI 会为了表现自己"认真读了"而硬编出几个低价值问题;加了以后,它宁可少报,也不敢瞎报。

2.2 输出格式与共识判定标准

两边跑完后,我把两份报告合并成一张对比表。合并的时候最麻烦的是"怎么算共识"。

我定的标准是:两个 AI 指向同一模块中同一段代码逻辑、并认定同类风险,才算达成共识。只提到同一个文件名但指向不同函数、或者一个说并发一个说性能但实际指向不同行号,都不算共识。

举个例子,支付模块两个 AI 都提了"回调缺少验签",但是一个指的是外层网关没验签,另一个指的是业务层收到回调消息后没有校验签名,这俩就不算共识,因为一个外层网关其实有验签,另一个业务层的消息确实没验。这种地方人工判断就非常关键,共识判定本身就是在帮我们精确定位理解偏差。

2.3 token 消耗和成本经验

成本上我也报个实数。20 个模块跑下来,Claude Code 输入大约 30 万 token、输出约 4 万 token;Codex 输入约 40 万 token、输出约 5 万 token。差别来源主要是上下文管理机制不同,Claude 会在长上下文里反复读取局部文件,Codex 则倾向于把模块内引用到的关联文件也重新放入上下文。

整体支出换算成 API 费用大概在几美元到十几美元量级,相比人肉代码走查的人力成本,基本可以忽略。但要注意的是:如果你用 Codex 但接了 DeepSeek 这类第三方模型,千万不要拿结果跟官方模型对比。不同模型的上下文行为和工具调用逻辑不一样,审计结论的差异会被模型能力差异污染,对比就没有意义了。

3. 结果概览:20 个模块只交叉出 7 个"共识区"

3.1 三类结果的分布

跑完后我把所有问题分成了三类:

  • 共识区(7 个模块):两个 AI 都独立报告了同类的高危问题,人工复核后全部属实。
  • 单边区(9 个模块):只有一边报告了问题,另一边要么 PASS,要么给的结论完全不同。
  • 盲区(4 个模块):两边都报告了一些问题,但指向的位置和风险类型完全对不上,人工复核后大部分是 AI 各自的幻觉或偏科。

这个分布很有意思:共识区只占总数的三成多,说明当前主流 AI 审计工具在"找可疑点"这件事上远没有到可以互相替代的地步。

3.2 共识区里那些问题长什么样

两个 AI 都确认真实存在的问题,几乎都是"教科书级别"的问题,特征非常典型:具备公认的缺陷模式、有明确的代码上下文、在一个文件内就能看清逻辑,不需要跨服务追踪。

举几个有代表性的:

  • 订单金额计算用了浮点数乘法,精度溢出风险,两边都标了 critical;
  • 优惠券领取接口缺少唯一约束,并发下会重复发放,两边都给出了加唯一索引的建议;
  • 消息队列消费者没有幂等去重,重复投递场景下会重复记账,两边都识别了;
  • 文件上传只校验了 Content-Type 头,没校验文件真实内容,存在伪造上传风险。

所以我的结论是:两个 AI 同时确认的高危问题,可信度非常高,基本可以直接提单。这比任何单个 AI 的报告都可靠得多,相当于两个独立"经验模型"在同一个交叉点上相互验证了。

3.3 单边发现的代表性方向

单边发现的问题能看出两个工具的性格差异。

Claude Code 单边发现的更多集中在:数据流跨文件追踪(比如一个用户 ID 从接口层传到异步任务里期间,没有重新做权限校验)、状态机流转缺了某个分支处理。说明 Claude 在处理"长链条"逻辑时更稳。

Codex 单边发现的更多集中在:某个具体函数里的边界条件处理(比如数组越界、空指针分支没处理)、某个 API 调用的参数校验缺失。说明 Codex 在"单点爆破"上有优势。

这么一来,我不再看它们谁强谁弱的问题了,它们就是两副不同的眼镜,各有各的景深。

4. 分歧案例拆解:四个让我印象最深的"拉锯战"

这一节是全文的重头戏,选四个最有代表性的真实复盘,把代码、两个 AI 的反应、人工复核结论、最终修复方案原原本本摆出来。

4.1 支付回调的幂等性:Codex 报了,Claude 没报

支付回调处理函数简化后长这样:

async function handlePaymentCallback(payload) { const order = await Order.findByOrderNo(payload.orderNo); if (order.paid) { return { success: true, message: "duplicated callback" }; } await Order.updateStatus(order.orderNo, "paid"); await pointService.add(order.userId, order.pointAmount); return { success: true }; }

Codex 标了 critical:先查order.paid再更新的判断和更新不是原子的,同一个订单在并发回调下会同时通过if判断,导致重复加积分。建议改成UPDATE orders SET paid = true WHERE order_no = ? AND paid = false,用更新影响行数做幂等判断。

Claude 在这个模块的报告只提到"回调缺少验签",而这部分其实在网关层有做,所以这条属实的共识度并不高。

人工复核后采纳了 Codex 的方案。加积分动作也往订单表加了一个point_settled字段做幂等标记,并在数据库层加唯一索引兜底。支付这种场景,幂等是"必须靠数据库约束实现,不能靠代码判断实现"的,这是个血泪教训。

4.2 库存扣减的并发:两边都报了,修复方案完全相反

库存扣减的经典写法:

async function deductStock(skuId, count) { const sku = await Sku.findByPk(skuId); if (sku.stock < count) throw new BusinessError("stock insufficient"); sku.stock -= count; await sku.save(); }

两个 AI 都确认这是并发超卖问题,共识成立。但有趣的来了:修复方案完全不同。

Claude 建议用版本号乐观锁:给skus表加version字段,更新时带WHERE version = ?,更新行数为 0 则重试或报错。

Codex 建议引入 Redis 分布式锁,用SETNX锁住 skuId 后再执行读改写。

我最后选了乐观锁和原子 UPDATE 的组合。原因很具体:我们当时的架构里 Redis 的可用性保障还没有做到强一致,锁超时和锁误删会引入新的不一致窗口;而乐观锁的实现成本极低,对库存这种写冲突并不频繁的场景完全够用。

这个案例给了一个重要启发:AI 共识告诉你"这里有问题"是极其有价值的,但 AI 给的修法经常是"通用方案"而不是"你的系统里最合适的方案",需要工程师自己做取舍。

4.3 日志脱敏:Claude 报了,Codex 没报

登录成功的日志:

logger.info("user login success", { userId: user.id, phone: user.phone, idCard: user.idCard });

Claude 标了 warning:日志里打印了手机号和身份证明文,只要日志系统被接入或泄露,就是数据合规事故。建议改成只记录 userId 和脱敏后的手机尾号。

Codex 在同一个模块里报的是另一个 SQL 慢查询问题,日志脱敏完全没有进它的雷达。

人工复核时这条被列为高优先级,因为日志系统是 ELK 链路,一旦日志进了采集器,删除成本极高。这个案例说明了:安全视角的审计和性能视角的审计,在当前 AI 上仍然是两种相当独立的能力,别指望一个工具全部覆盖。

4.4 幽灵问题:Codex 报了一个我查了半天不存在的 Bug

这个是最有价值的反面案例。在用户模块,Codex 报了一个 critical:

时间字段 create_time 存在时区转换错误。代码中使用北京时间字符串直接写入,读取时按 UTC 解析,会导致时间偏差 8 小时。建议统一使用 UTC 存储。

我按 Codex 给的行号翻来覆去找了半天,发现项目里的 ORM 框架在时间持久化时自动做了时区归一化,应用层从来不直接处理时间字符串,这个"时区转换错误"根本不存在。Codex 是看到create_time字段名和时间类型,脑补了一个在别的项目里常见的 Bug 模式。

这个案子告诉我们:AI 报的高危问题里,依然存在幻觉。单边报告必须人工复核,哪怕它给了非常具体的行号和修复建议。反过来,如果某个问题两个 AI 都报了,那幻觉的可能性就大幅下降——所以"双 AI 交叉验证"其实也是在互相抑制幻觉。

5. 为什么同一份代码,两个 AI 会给出不同的审计结论

5.1 训练语料和上下文窗口的差异

Claude 在长上下文、跨文件推理和大段自然语言理解上的训练更充足,这可能跟它在长文档任务上的侧重点有关,所以它比较容易抓住"一个数据从 A 方法流到 B 方法再到 C 方法"的链条问题。

Codex 延续了代码生成模型体系的特点,在函数级、短距离的代码缺陷识别上反应更快,边界条件的覆盖更细。它更像一个"点状扫描器",Claude 更像一个"链状追踪器"。

5.2 审计粒度的差异:函数级 vs 数据流级

看同一份代码,Codex 更关注"这个函数内部有没有写坏",Claude 更关注"这个函数的数据从哪来、往哪去、中间有没有断链"。这导致了双方的漏报方向不同:Codex 容易漏掉跨服务的权限问题,Claude 容易漏掉单个函数内的边界 bug。

这也是为什么我会明确建议:如果你只能用一个 AI 审计,优先选 Claude 看安全和一致性,选 Codex 看函数正确性和性能细节。但现实中最合理的方案还是双跑加交叉验证。

5.3 保守程度与幻觉率的不同

我做的另一个小统计:在人工复核的 56 个单边报告里,Claude 的"确有其事"率大约在六成多,Codex 的"确有其事"率大约在五成上下。Claude 在不确定的时候倾向于降低严重等级,或者在问题描述里加一堆"此处可能引发"的措辞;Codex 倾向于果断下结论,但代价是幻觉问题更刺眼。

两边做了一个很有意思的对比:

维度Claude CodeCodex
优势区跨文件数据流、权限校验链、状态机完整性函数内边界条件、参数校验、单点 bug
长上下文表现稳定,给整个模块也能保持聚焦容易在长上下文后段注意力漂移
严重等级判断偏保守,倾向降级偏果断,容易升级
幻觉风险较低,但会出现"措辞化问题"更高,会编造不存在的具体场景
修复建议偏工程化,考虑兼容性偏快速,直接给最小改动

这张表不是结论,只是我这次实测的一种倾向。模型版本更新很快,你的环境不同结果可能完全不同,但"两套模型不同偏科"这件事,短期内大概率不会变。

6. 我最终沉淀的双 AI 审计工作流

6.1 完整流程:从模块拆解到修复闭环

这次实验跑完,我把流程固化成了团队里的一个标准操作。完整链路是:

  1. 把待审计代码按业务模块拆分成 500~2000 行的审计单元;
  2. 写一份固定审计 prompt,内容覆盖正确性、安全、性能三类风险,并强制要求输出行号和 PASS 结论;
  3. 用 Claude Code 和 Codex 分别对同一批模块并行跑审计;
  4. 把两份结构化输出合并成一张交叉对比表;
  5. 按"共识问题 / 单边问题 / 幻觉问题"分档处理;
  6. 人工复核单边高危问题,确认后进入修复队列;
  7. 修复完成后,让两个 AI 分别对 diff 做一次复检,确认没有引入新问题。

第 7 步很重要,大部分人在审计完之后就收工了,但修复本身也是一次代码变更,AI 审计的价值在这里可以继续发挥。实测下来,复检时 AI 对 diff 的聚焦能力比全量扫描更强,因为它们能看到改动前后对比。

6.2 分级处理策略

我们最终采取的分级策略很直白:

  • 红色项(双 AI 共识 + 高危):直接建工单,不等人工复核,因为共识高危的人工复核确认率接近百分之百;
  • 黄色项(单边报告 + 高危):必须人工复核,同时配合静态分析工具佐证(ESLint 的 no-floating-promises、SonarQube 的规则集、npm audit 的依赖漏洞都是好帮手);
  • 绿色项(单边报告 + 低危):不强制修,记录到技术债清单里,后续统一处理;
  • 灰色项(人工复核确认的幻觉报告):标记后直接丢弃,但不会删记录,方便追溯和评估模型能力变化。

6.3 避坑清单和实操建议

最后是这次全套跑下来我踩过的坑和沉淀下来的建议,每一条都有实际场景支撑:

Prompt 必须完全统一,否则对比没有意义。我第一次跑的时候给 Claude 的 prompt 里多加了"重点关注事务一致性",给 Codex 的没加,结果两边分歧巨大,全部作废重跑。

不要把整个仓库一次性塞进去。有人会觉得"模型上下文窗口越来越大,直接整个项目丢给它不就行了?"实测效果非常差,注意力稀释导致报告全是正确的废话。模块化切片是性价比最高的做法。

AI 说 PASS 不代表真的干净。我们的 20 个模块里有 4 个两边都 PASS 的模块,人工复核时仍然抓出了一个横向越权问题。这说明 AI 审计只能做"哨兵",不能做"裁判"。

修复建议不能直接 merge。前面提到的库存扣减案例就是最好的证例,AI 给出的方案可能完全正确,但未必适配你的系统。AI 的建议应该被当作"提示",而不是"答案"。

保存审计产物,便于追溯。每轮审计的输入 prompt、输出报告、人工复核结论都放在仓库的module_audit/目录下。这不仅是过程资产,后续也可以拿来做模型能力评估,或者喂给下一轮 prompt 做"已知问题清单",减少重复报告。


这次做完整套双 AI 交叉审计,我的一个核心体会是:不要把 AI 审计想成"谁比谁强"的问题,而要想成"它们能互相抑制幻觉、互相补充盲区"的问题。共识项可以大胆信,单边项要带着问号去查,PASS 项永远别轻信。三个臭皮匠顶个诸葛亮,两个 AI 加上一个认真的工程师,顶得上一个非常靠谱的代码走查专家。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询