实测两周:Codegen 和 Sweep AI 到底能不能用来自动审查代码?
我在两周内,用五个开源 Python 仓库分别跑了 Codegen 和 Sweep AI,想看看这些自主代码审查智能体到底能不能直接放进生产流程。结果比我想象的复杂很多:两个工具都能抓到人类审查员漏掉的真实 Bug,但同时也引入了一些新问题——以我测试的结果来看,我暂时不敢让它们完全自主地跑在 CI 流水线里。下面是具体的观察。
Codegen:基于模式的缺陷检测,能“发货”
Codegen 的思路和市面上那些聊天式 AI 工具完全不同。它不是用自然语言描述去提示大模型,然后指望输出正确,而是先对你的代码库做静态分析,建立起对代码结构的理解,然后再用语言模型根据这个分析结果生成修复。结果是:它比 Cursor 或 Copilot 缺乏创造性,但在自己擅长的领域里更可靠。
我在四个 Python 仓库(代码量从 2400 行到 18000 行)上测试了 Codegen。总共发现了 94 个潜在问题,我手动验证了每一个,其中 71 个是真实 Bug——真阳性率 75.5%。剩下的 23 个是误报,大多出现在使用了动态分发或元类的代码里,Codegen 的静态分析不能完全搞懂。
Codegen 表现最好的缺陷类别是那些“机械可检测”的:
- 空指针解引用和未绑定变量引用:19 个全真阳性,零误报
- 来自未清理字符串格式的 SQL 注入模式:12 个真阳性,2 个误报
- 使用 pickle 做不安全反序列化(没有防护):8 个真阳性,1 个误报
对这些类别,我基本可以信任 Codegen 的输出,把它标记给人类审查员去看,但不会让它自动合并修复。
而 Codegen 的短板在于那些需要“语义理解”而不是模式匹配的 Bug。有一个仓库用方法分发实现了一个复杂的状态机,Codegen 标记了三个潜在空指针问题,但实际那些代码路径根本不会执行——空检查在基类方法里,而那个基类方法从来不会被未初始化就调用。熟悉代码库的人类审查员一眼就能看出来,但 Codegen 只看到了模式,没理解执行流。
我在测试集中测得 Codegen 的“引入新问题率”是 8%——71 个真实修复中有 6 个引入了新 Bug。最常见的问题是变量名遮蔽:Codegen 在函数内引入了一个叫
data的局部变量,而该函数已经有同名的参数,导致原始参数无法访问。修复本身在局部是正确的,但破坏了外部作用域。所以——用 Codegen 修复后一定要跑完整测试套件,尤其要仔细检查涉及变量名改动的 diff。
集成体验对于大多数团队来说可能比技术本身更重要。Codegen 以 GitHub Action 的方式运行:加一个 workflow 文件,它就会在每个 Pull Request 上跑,然后在对的行里贴评论。我在一个已经有 CI 配置的仓库里花了 12 分钟就设置好了。第一次运行在一个修改了 8 个文件的 PR 上生成了 34 条评论——收到这个审查的开发者直接被淹没了。我调了一下配置,让它忽略低严重度问题,并且只评论改动过的行,这样每 PR 平均只出 11 条评论,合理多了。
成本模型也值得了解。Codegen 本身是开源的,GitHub Action 跑在你自己的 CI 基础设施上。但每次分析都需要调用一次 LLM——OpenAI、Anthropic 或者本地模型。我用 GPT-4 配置的 Codegen,每个 PR 的审查成本大约在 0.30 到 1.20 美元之间,取决于 diff 大小和发现问题数量。一个月审查 15 到 20 个 PR,API 账单上大概要多花 15 到 25 美元。这个成本对于在代码上线前抓住 Bug 来说可以接受,但如果整个团队都部署,需要提前算好预算。
Sweep AI:从 Issue 到 Pull Request,只要几分钟
Sweep AI 走的则是另一条路:它不审查现有代码,而是读一个 GitHub Issue 描述,规划实现方案,写出代码,然后直接开一个 Pull Request。这个流程专门处理那些范围明确、模式固定的任务——就是那些维护者可能会标记“Good First Issue”留给新贡献者干的活。
我在五个 Python 仓库上开了 20 个 Issue 来测试 Sweep AI,从简单的依赖更新到需要改动多个文件的特性添加都有。Sweep 成功为其中 18 个 Issue 开了 Pull Request——两个失败是因为 Issue 描述太模糊,Sweep 要求澄清,我认为这不算失败,反而是正确的行为。
在 18 个 PR 中,我直接合并了 11 个(首次成功率 61%)。剩下 7 个需要不同程度的干预:
- 4 个有逻辑错误:语法对,但行为不对。例如一个功能要加一个命令行参数控制日志级别,参数解析对了,但应用的时候日志配置还没初始化,所以参数根本没生效。
- 2 个缺少边界情况处理,我手动补了。
- 1 个重构了一个函数,但会破坏调用它的另一个服务——Sweep 不知道那个服务在另一个仓库里。
61% 的成功率和我自己的感受最接近。对于范围明确、代码库模式一致的任务,Sweep AI 确实省时间。在我的测试中,从发 Issue 到可以审查 PR 平均用时 6 分 20 秒(不包括我写 Issue 和审查 PR 的时间)。对比一下,同样的任务我手动实现平均要花 31 分钟(包括写测试)。Sweep 没有省掉审查时间,但它省掉了实现时间。
Sweep AI 一直让我失望的地方在于“这还不明显吗?”式的改进。如果一个仓库里有一种很啰嗦的错误处理模式,人类开发者做相邻改动时会顺手把它简化,但 Sweep 会原样复制。我让它加一个新 API 端点,它正确地加了端点、请求验证和响应格式化——但旁边端点里的一个 12 行错误处理模式被完全复制过来了,本来可以提取成共享 helper。人类开发者或者更挑剔的 AI 工具会发现这个重复并重构,Sweep 只是忠实地复制模式,不会做判断。
共同的短板:上下文窗口坍缩
两个工具都有一个共同限制,决定了它们的实际可用性:上下文窗口管理。大型仓库文件之间关联很多,每个工具很容易超过它能保持连贯理解的范围。Sweep AI 给一个配置解析 Bug 做的修复单独看没问题,但破坏了四个文件之外的一个集成点——因为依赖链超过了上下文窗口。Codegen 漏掉了一个空指针问题,因为那个可能为空的变量在比它解引用处高两层的辅助函数里初始化——模式跨越的上下文超出了工具能容纳的范围。
我观察到的“文件数甜点”大约是:
- Sweep AI 每个任务涉及 15 到 20 个活跃文件
- Codegen 每个 PR 影响 8 到 12 个直接文件
超过这些阈值,两个工具都会犯人类必须发现和修补的错误。低于阈值,它们能达到“用于初筛”可接受的水平。
语言支持方面,两个工具和宣传也差一点。Codegen 对 Python 支持最好——它的静态分析引擎对 Python 的类型系统和标准库理解得很细,能产出可靠报告。TypeScript 支持能用但不那么完善,异步代码中误报更多。Go 支持存在但分析引擎明显浅很多。Sweep AI 支持同样的语言集,但生成的 Python 代码质量明显高于 TypeScript——Python 中习语用法更正确,PR 描述也更详细更准确。
两个工具对 Rust、C++ 或其他不太主流的语言目前都不推荐用于生产。我好奇地在一个 Ruby 仓库上试了一下 Sweep AI,它生成的代码用了 Python 风格的异常处理语法,根本不能通过 Ruby 解析。这两个工具正在扩展语言支持,但目前最稳的还是 Python。
两周测试后我的建议
Codegen 是我会先加到 CI 流水线里的工具,但要配特定的模式:我把它当成一个建议性审查员——它发评论,但不阻断合并——只用于 Python 和 TypeScript 仓库。75% 的真阳性率(针对模式型 Bug)足够值回 CI 时间和 API 成本。Python 用正常灵敏度,TypeScript 因为异步代码误报率高所以降低灵敏度。我不在 Go 仓库上跑——分析引擎还不够可靠,不值得引入噪音。
Sweep AI 对我来说是给初级开发者用的,而不是给高级开发者用的——这和它营销说的正好相反。高级开发者自己实现任务比写一份能让 Sweep 产出正确代码的详细规范还要快。初级开发者,或者刚接触某个代码库的开发者,则能从 Sweep 读取仓库、遵循现有模式、生成起点实现的能力中受益,他们可以理解和修改这个实现。这个工具最适合的场景是:提 Issue 的人不是手动实现它的人——省下的时间来自委派实现,而不是取代自己的编码。
两个工具组合使用比任何一个单用都更有趣。我用 Sweep AI 生成实现,然后用 Codegen 审查这些实现,然后再合并。这个流水线在 20 个 Sweep 生成的 PR 中额外抓到了 8 个 Bug——这些 Bug 单个工具都抓不到,大多是因为 Sweep 引入的模式被 Codegen 的静态分析规则认作潜在问题。这个流程每 PR 大约要多花 2 到 3 分钟的 CI 时间以及额外的 0.50 到 1.00 美元 API 成本,我觉得为这个额外的安全网是值的。但最终合并决定仍然需要人类来做——以当前这一代工具的能力,我看不出这个需求会很快改变。
