
上个月我把公司里积压的 16 个业务模块同时丢给 Claude Code 和 OpenAI Codex 做了一次代码审计最后统计结论时发现两个模型只在 4 个模块上给出了基本一致的判断。11 个模块上意见相左还有 1 个两边都放过了——后来人工复查时正好在那里面炸出一个线上隐患。这篇文章就讲清楚这次对比审计的完整过程怎么设计可复用的双 AI 审计流程、怎么判定“达成共识”、分歧背后到底反映了什么、实际操作中有哪些坑以及最终如何把两边的结论合并成一张可执行的修复清单。如果你正在犹豫该选 Claude 还是 Codex 来做代码审查或者已经用上了但不知道结果到底该信几分这篇应该能给你一个比较落地的参考。1. 为什么同时让两个 AI 去审同一批模块1.1 这次实验的起因模块积压与单模型盲区起因其实很朴素。团队里有一批历史模块因为迭代节奏太快长期没有做过系统性 review。它们分布在订单、支付回调、库存、消息队列消费、缓存更新这些核心链路里代码量不算大但每个都藏着一堆“看起来能跑、边界情况必炸”的隐患。人工逐个 review 的话一个模块至少要预留半天还不算返工沟通的时间16 个模块排下去差不多要一个月。当时正好 Claude Code 和 Codex 的 CLI 都开始普及我就想试试能不能用 AI 做第一轮粗筛。但这里有个很现实的问题我信不过任何一个模型的单方结论。LLM 做代码审查有一个典型毛病就是它对自己没把握的地方也倾向于编一个“很像那么回事”的建议单独跑一遍输出看着头头是道实际有一半是幻觉。所以我决定换个思路把两套独立的模型都跑一遍然后只对它们的结论做交叉比对。两个模型如果出现一致判断说明这个问题的模式很可能在训练数据里出现过足够多次可信度会高很多如果结论不一致那正好给我指出需要人工重点核对的位置。这个思路的核心假设是两个模型基于不同训练分布系统性的盲区不太可能完全重叠。后来复盘时我发现这个假设基本成立但“达成共识”和“正确”之间也并不是等号这部分后面会展开说。1.2 Claude Code 和 Codex 的定位差异既然要做双模型对比首先得了解这两个工具各自擅长什么。Claude Code 是 Anthropic 出的终端编程代理安装之后可以直接在命令行里指定目录和文件让它递归扫描整个模块。它的上下文窗口做得比较宽适合一次性消化一个完整模块然后输出长篇的分点审计意见。OpenAI 的 Codex CLI 则更像个执行型 agent任务拆解和后续修改建议给得很具体常常会直接给出一段修复用的 patch。我个人的体感是Claude Code 更像一个“按清单逐项排查的审计员”而 Codex 更像“先画数据流再找断点的开发”。两者对比情况如下维度Claude CodeOpenAI Codex接入方式CLI / 桌面端可指定目录CLI / 云端任务支持 exec 模式长上下文扫描能力强适合整模块阅读中上任务太长可能截断问题归类习惯偏风险清单式经常给低危建议偏数据流推演突出可运行性修复建议文字描述为主偶尔给补丁经常给可直接落地的 patch典型短板容易把“潜在风险”当成“必然问题”上下文不足时会中断或跳过深层问题放着这两个工具的差异不用只拿其中一个做“权威结论”就浪费了对比的价值。真正有用的做法是让它们各跑各的再靠人工把两边的结果合并、分类、去重、定级。这个流程跑通之后我最大的感受是AI 审计的产出不是“结论”而是“线索”线索越多你离真实缺陷越近。2. 审计前的准备怎么让两边的结果可以横向比较2.1 固定输入同一份代码、同一条规则、同一个输出模板做对比实验最忌讳的就是给两个模型不同的指令。如果 Claude Code 拿到的任务是“检查安全性”Codex 拿到的任务是“检查代码风格”那两边结果南辕北辙你根本没法判断分歧到底来自模型能力还是来自任务本身。所以我在开始之前先写了一套固定的审计提示词所有模块都原样复用。这套提示词我后来用了几轮效果比较稳定你是一名资深代码审计工程师。请审计当前工作目录下的指定模块。 审计范围${MODULE_PATH} 审计重点 1. 安全漏洞注入、越权、敏感信息泄露、签名校验缺失 2. 运行时错误空指针、越界、类型误用、未处理异常 3. 资源问题连接泄漏、文件句柄未关闭、并发竞态 4. 逻辑缺陷状态机缺分支、边界条件错误、幂等缺失 5. 死代码与明显可维护性风险 输出要求 - 对每个发现按“严重/中等/轻微”给出评级 - 标明出现位置文件:行号 - 用一句话描述问题再用一句话给出修复建议 - 如果某个类别确实没有问题请明确写“未发现” - 不要为了凑数而编造问题你可能注意到了最后两句是有讲究的。LLM 在收到“按这些维度审查”的指令时会有一种迎合倾向哪怕代码真的没问题它也倾向于从每个维度里硬找出两三个“潜在风险”以免显得自己没用。明确允许它输出“未发现”能显著减少这种空转告警也让两边结果的对比更干净。2.2 审计模块怎么挑模块选择也不能随意。我踩过一次坑第一次实验时把一个 8000 多行的服务整个丢给 Claude Code结果它只盯着前几百行看后面的逻辑基本没有覆盖。后来我把策略调整为“按边界清晰的模块逐个审计”效果立刻好了很多。挑选模块我遵循三个原则边界要清晰能明确看出入口和出口比如某个 HTTP handler、某个消费者函数、某个独立状态机。不要把互相耦合的多个服务混成一个任务。行数控制单个模块控制在 200 到 1500 行之间。太小没有审计价值太大则容易被模型截断或泛泛而谈。核心链路优先优先选那些改动后影响面大的模块比如支付回调、库存扣减、消息队列消费而不是纯展示页面或 CRUD 接口。这次实验我最终选了 16 个模块覆盖订单状态机、支付回调、库存扣减、缓存更新、配置热加载、用户鉴权、日志脱敏、文件上传、报表聚合、定时任务调度、连接池封装、第三方回调解析等。每个模块的代码都固定在同一个 commit hash 上确保两个模型看到的内容完全一致。2.3 “达成共识”的判定标准统计之前必须先定义什么叫“达成共识”。否则凭感觉说“差不多一致”后面做数据统计时一定会吵架。我的判定标准是这样的两个模型在同一模块的同一位置文件、函数或行号段提出了同一类问题且严重级别一致或只差一级才算共识。举例来说Claude 说“订单状态机的 switch 缺 default 分支评级严重”Codex 说“状态机存在未定义状态转移建议增加兜底分支评级严重”这类就算共识。如果两边都提了问题但指的是两个不同的点比如一个讲 SQL 注入、另一个讲日志格式那不算共识算两条独立发现。按这个标准我最终的统计结果大致如下共识类型模块数量典型表现双方共识问题4状态机缺 default、库存并发扣减、消息重复消费、硬编码密钥Claude 单边告警5配置加载缺少错误处理、日志脱敏正则边界Codex 单边告警6缓存更新非原子、context 未透传双方均未发现1支付回调未校验签名人工复查时发现这里最扎眼的就是最后一行两个 AI 都没发现问题但人工复查时偏偏在一个最不该出问题的模块里找到了严重缺陷。这说明“共识”是一个高置信信号但绝对不是“已通过审计”的证明。后面我会专门讲怎么应对这种双漏报。3. 审计结果复盘共识和分歧都藏在哪3.1 共识问题有什么共性先看两边意见一致的那 4 个模块。我逐个做了人工复核结论是所有共识项都真实成立没有误报。这符合预期因为这些问题的模式在公开代码库里出现频率太高了属于“模型见过答案”的范畴。举两个典型的例子。第一个是库存扣减模块。Claude Code 和 Codex 都指出当前实现是“先 SELECT 当前库存再在 Java 里判断是否充足最后 UPDATE 扣减”这个三步操作不是原子的并发请求下必然出现超卖。修复建议也都一致改成 UPDATE 语句里加库存条件或者用数据库行锁保证原子性。这个判断完全正确属于很经典的并发竞态人工 review 时也一定会抓。第二个是消息队列消费模块。两个模型都报了同一个问题没有消费幂等。如果消息被重复投递消费者会把同一条记录再写一次库。在 MQ 的 at-least-once 语义下这是必须处理的场景。两个 AI 能同时抓到这一点说明这类问题已经成了训练数据里的“标准答案”。总结下来共识问题往往满足两个特征一是错误模式非常经典二是代码中有明显的“教科书式反面写法”。AI 判断这类问题最准也最适合交给它们做第一轮筛查。但这里有个反向坑如果一个模块的代码质量极差、低级错误特别多AI 反而容易只顾着报显而易见的低级问题忽略了更隐蔽的业务逻辑缺陷。所以当你发现 AI 输出一大堆“空指针、资源未关闭”之类的告警时别急着开心这可能意味着模型只是在背题没有真正理解业务流。3.2 分歧案例谁说对了谁在臆测11 个模块存在分歧这才是实验里最有信息量的部分。我把两边都报过、但结论不同的案例都捞出来逐个对照代码和测试结果最后发现两边的命中率并不对称。先说 Claude Code 对、Codex 漏掉的例子。日志脱敏模块里Claude 指出正则匹配手机号时没有做长度边界校验导致在特定文本里会把中间 11 位数字误判成手机号。我复现了一下确实存在误脱敏。Codex 没报这个问题它反而把重点放在正则性能上建议用预编译 Pattern。性能建议本身没错但相比“误脱敏导致线上数据被错误打码”优先级显然低了一档。再说 Codex 对、Claude 漏掉的例子。缓存更新模块里Codex 指出 Redis 的读改写操作不是原子的并发场景下可能出现写覆盖推荐用 Lua 脚本或分布式锁。Claude 没有报这个点它提的是一条低危建议说缓存过期时间写死、应该改成可配置。人工核实时发现Codex 抓到的问题对系统影响更大因为缓存里的展示数据在高峰流量下被反复覆盖一直存在偶发数据不一致。Claude 的建议只是优化项不修也不会出事。这两组案例让我意识到两边的“注意点”差异很大。Claude 更擅长按风险清单逐项扫所以安全、资源类的常规问题覆盖率高Codex 更擅长沿着数据流推演所以并发、状态一致性问题更敏锐。它们的分歧不是简单的谁强谁弱更像是两种审计视角的互补。3.3 间接共识双方各报一半指向同一个根因除了直接共识和单边告警我还发现了一类特别有意思的情况我管它叫“间接共识”。表现是两个 AI 报的问题文字完全不同位置也不同但人工深挖之后发现它们其实是同一个根因的两个症状。最典型的是连接池封装模块。Claude 报的是连接超时时间写死缺少配置入口。Codex 报的是context 没有从业务层透传到数据库调用层导致超时控制失效。看表象这是两个问题一个说配置、一个说 context 传递。但我把代码翻了一遍后发现根因其实是同一个统一 DB 封装层没有暴露超时参数业务层传入的 context 在封装层内部被丢弃了写死的超时时间也只是封装层内部的一个常量。这种“间接共识”比直接共识更有价值因为它意味着两个模型从不同路径逼近了同一个缺陷只是各自停在了离根因不远的不同位置。如果你只按字面结论去修修完“配置项”或者修完“context 透传”问题都能缓解一半但都没法根治。所以在合并审计结果时千万不要机械地按问题 ID 去重而是要做一次根因归并把相关的告警串联成一组再统一处理。这一步目前只能靠人AI 给不了你。4. 双模型审计实操环境、命令、留档4.1 环境搭建和 CLI 安装讲完方法论再说实际操作。Claude Code 和 Codex 的安装方式都不复杂核心命令分别是 Claude Code 的 npm 全局安装和 Codex CLI 的 npm 全局安装装完直接敲命令进交互模式。但安装过程中有几个高频报错我把这一年里被问得最多的坑整理成了一张速查表报错现象可能原因处理建议claude 不是内部或外部命令npm 全局 bin 目录未加入 PATH或 Node 版本过低检查 node -v建议 18确认 npm config get prefix 对应目录在 PATH 里Windows 下提示 Claudes workspace requires the Virtual Machine Platform虚拟机平台功能未启用控制面板-程序-启用或关闭 Windows 功能勾选“虚拟机平台”和“Windows Hypervisor Platform”重启Codex Windows 安装未完成安装脚本执行时权限不足管理员身份运行终端清理 npm 缓存后重装检查安装日志具体卡在哪个脚本调用本地端点时报错比如 /responses 处理失败本地服务未启动、鉴权失效或网络配置异常确认登录态有效API Key 配置正确检查本地服务日志不要直接在生产环境反复试错任务跑到一半提示上下文不足输出被截断单个任务塞入的代码量太大拆成更小的模块开启输出重定向到文件避免依赖终端滚动缓冲区安装完记得先跑一个最小样例确认模型能正常读取当前目录下代码再上正式模块。我见过不少人上来就丢整个仓库跑了两小时然后发现模型从第一步就理解错了目录结构纯浪费时间。4.2 审计过程的编排跑审计时我强烈建议一次只喂一个模块不要批量塞。这个坑我前面提过一次这里再强调一遍因为它是影响审计质量的头号因素。具体操作流程是这样的先切到目标分支、固定到某个 commit然后分别用两个工具执行审计任务。为了避免交互模式里的随意性我使用一次性输出模式直接把结果打印到标准输出并重定向到文件。两个工具都支持类似的非交互调用方式把提示词作为参数传进去即可。git checkout main git pull cd src/order claude --print -p 请审计当前目录下的 src/order 模块按约定输出... audit-order-claude.md cd src/order codex exec 请审计当前目录下的 src/order 模块按约定输出... audit-order-codex.md有一点需要注意每个工具的参数名和用法会随版本迭代变化上面给的是思路不是永久有效的官方文档。真正要紧的是把整条命令固化成一个脚本让后续每次审计都跑同一套流程不要这次手敲、下次改参数否则结果不可比。另外一个细节是审计过程中不要让两个工具并行跑同一个仓库的写操作。它们都可能建议你改代码如果你在交互模式里顺手让它们改了就会污染代码基线后面根本没法判断谁对谁错。我把两个工具都固定为只读模式只让它输出意见禁止写文件。4.3 审计日志怎么留档与回溯审计结果如果不留档等于白跑。这里说的留档不只是把终端输出复制到一个 txt 里而是要有结构化、可检索、可回溯的证据链。我每个模块都会保存三份文件原始 AI 输出、汇总后的 CSV 表、人工复核备注。CSV 表大致是这个结构模块名,工具,严重级别,文件,行号,问题简述,根因归类,是否确认,修复状态,备注 order-state,claude,严重,src/order/state.go,48,状态机缺default分支,状态机逻辑,是,已修复,与codex结论一致 order-state,codex,严重,src/order/state.go,52,未定义状态转移,状态机逻辑,是,已修复,与claude结论一致 inventory,claude,严重,src/inventory/deduct.go,77,先查后扣存在竞态,并发安全,是,已修复,与codex结论一致这套 CSV 后续可以直接导入项目管理工具也可以按季度做回归对比。团队里如果有“审计日志留存 180 天”这类要求用这个方式最省事原始输出文件按模块归档汇总表单独维护180 天后还能对照旧的 commit 重新跑一轮看看之前的告警是不是真的修干净了。这里我要特别提醒一个坑AI 模型会升级升级后对同一份代码的判断可能完全不同。所以归档时一定要把两个信息也记录下来——模型版本和提示词版本。否则三个月后你跑出不一样的结果根本说不清是代码变了还是模型变了。我在文件里固定加一行元信息记下工具名、版本号、commit hash、审计时间后续复盘时全靠它定位。5. 这次用下来的体会以及怎么把它固化进日常流程5.1 双 AI 审计的正确打开方式并集而不是交集很多人第一次做双模型对比时会天然把“共识”当成唯一可信结论觉得两边都报了才算问题。我实测下来这个想法需要修正。直接共识确实是高置信信号但它只能覆盖那些“教科书式”的错误真正决定审计上限的是单边告警和双漏报的处理方式。我的建议是把两个模型的告警合并成并集再按优先级人工筛。具体顺序可以这么排双方共识的严重问题最高优先级直接进入修复排期。一方报出且人工能复现的问题第二优先级安排开发修复。一方报出但当前无法复现的问题记入待办清单不要丢也不要一上来就修。很多问题需要特定并发量或特定数据才能触发现。两边都没报、但人工 review 发现的问题这是最重要的复盘素材回头分析为什么漏把同类模式补进下一轮提示词。我测完这批模块后真正让我觉得钱花得值的地方恰恰不是那些共识问题而是单边告警里被另一方遗漏的隐藏 bug。比如缓存更新模块的竞态问题要不是 Codex 报出来Claude 的单方结论会让我以为这个模块只有配置优化项差点把一个真实缺陷放过去。5.2 如何把 AI 审计固化成日常机制做完这一轮实验后我把双 AI 审计固定成了团队发版前的一道轻量关卡。流程很简单每个迭代对变更模块跑一次双模型审计生成 CSV 汇总表维护人只需要处理“共识问题 人工可复现的单边问题”其余记录在案。这套流程不会替代人工 code review但它能把人工 review 的注意力集中在真正有风险的位置上整体效率反而更高。提示词也不是写死就完事。我会根据上一轮的双漏报案例不断迭代提示词把团队踩过的坑直接写进去。比如第一轮两个 AI 都没报“支付回调未校验签名”我就在提示词里补了一句“支付回调必须校验签名且不能只校验来源 IP”。下一轮同样的模块再跑两个模型都把这个点列成了严重问题。AI 审计本质上是一个可训练的流程你喂给它什么历史经验它就回报你什么水平的判断。这套方法也不只适用于 Web 业务模块。嵌入式方向同样可以跑比如 INA226 电流监测驱动、HC05 蓝牙模块的初始化状态机、ESP8266 的 AT 指令解析这类代码里面最容易出问题的就是状态机缺分支、超时未处理、字节序转换错误恰好是 LLM 比较擅长识别的模式。唯一要注意的是嵌入式代码经常依赖外部 datasheet 里的寄存器语义模型对具体型号的底层细节未必有把握一旦涉及这类内容必须人工翻开手册核对不能盲信 AI 的输出。5.3 一点真实经验作为收尾最后说点个人体会。这次双模型审计跑下来我最深的感受是不要迷信共识更不要迷信分歧“同时对同一段代码下判断”这个动作本身就是最有价值的。因为两边意见不一样你才会被迫回到代码里重新核对数据流、状态机和边界条件而那次人工核对的过程往往比 AI 直接告诉你“哪里有问题”更能帮你建立对模块的真实认知。AI 在这个流程里的角色更像一个不知疲倦、偶尔靠谱的实习生它能给你铺开一堆待复查的线索但最终拍板、核对、修复的还是你自己。如果要给后来者一个最实用的建议那就是从一开始就把整个审计过程设置成可复现、可追溯的流程固定代码版本、固定提示词模板、固定输出格式、保存原始日志。你不需要在终端前面盯着模型一行行跑把命令写好、把结果落盘去做别的事回头直接看 CSV。等这轮跑完你会发现最有价值的不是“它找到了几个 bug”而是你手里多了一套无论换哪个模型、换哪个项目都能快速起跑的代码体检工具。