关注「索引目录」公众号,获取更多干货。
AI代码审查工具号称能发现人工审查员遗漏的问题。但究竟哪一款真正有效呢?我故意在.NET 10代码库中植入了38个bug、安全漏洞和代码异味,然后让三位AI审查员对同一个PR进行审查。以下是结果。
为什么要进行这样的比较?
现在各大平台都提供人工智能代码审查工具:GitHub 有 Copilot,Cursor 有 BugBot,Anthropic 有 Claude。它们都声称能够发现安全问题、漏洞和代码质量问题。但抛开这些营销噱头,我真正想要的是三个实际问题的答案:
- 每个工具实际能发现多少问题?
不是在精心设计的演示环境中,而是在包含关键漏洞和隐蔽代码异味的真实PR环境中。 - 它们在多个审核周期中的表现如何?
第一次审核是一回事。当你修正了发现的问题并重新申请审核时,会发生什么? - 开发者的使用体验如何?
检测率只是一个数字,但这个工具真的能帮助你更有信心地发布产品吗?
为了弄清真相,我设计了一个对照实验。
准备工作
代码库
我搭建了一个名为Demostr8 的全新 .NET 10 解决方案,其中包含两个项目:
- Demostr8.Api
— 一个基于 http://ASP.NET Core 的 Web API,支持 JWT 身份验证、Entity Framework Core、CORS 和 OpenAPI。包含订单和用户控制器、服务层、类型化选项模式以及全局异常中间件。 - Demostr8.Worker
— 一个后台服务,它轮询待处理的订单,并通过外部网关使用 IHttpClientFactory.
生产级代码。规范的 async/await、取消令牌传播、BCrypt 密码哈希、参数化查询、依赖注入——应有尽有。这成为了main分支的基线。
中毒的公关
在一个特性分支(feature/order-processing-improvements)上,我故意在 8 个文件中引入了 38 个问题,旨在使其看起来像是真正的开发人员错误——那种在截止日期压力下容易出现的捷径和疏忽。提交信息?一条完全无辜的"feat: improve order processing and streamline authentication flow"。
这38期内容涵盖四大类:
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
严重程度是经过精心设计的分级。有些问题是致命的(例如,利用sa字符串字面量中的凭据进行 SQL 注入)。另一些问题则比较隐蔽(例如,在 DELETE 操作中返回空值Ok()而不是预期NoContent()值,或者PollingInterval用内联值代替常量30000)。
完整列表
以下是我埋下的所有种子,按类别分组。这是衡量这三种工具效果的评分标准。
安全(18 个问题)
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
漏洞(8 个问题)
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
代码异味(11 个问题)
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
性能(1 个问题)
|
|
|
|
|---|---|---|
|
|
|
|
三个相同的公关稿
同一个分支被推送到三个不同的GitHub仓库,每个仓库都配置了不同的AI审阅器:
|
|
|
|---|---|
|
|
|
|
|
|
|
|
|
同样的代码,同样的差异,三位不同的审阅者,决战即将开始。
第一轮:初试结果
记分牌
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
安全覆盖范围是这三款工具最强的方面,它们都能捕获绝大多数的 SQL 注入、硬编码凭据、身份验证绕过和数据泄露问题。
差异体现在更细微的方面。
按类别检测
|
|
|
|
|
|
|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
安全性:全部合格。Copilot全部通过,18/18。Claude 漏检一个(查询字符串中包含 API 密钥)。BugBot 漏检两个(查询字符串中包含 API 密钥,以及依赖注入单例不匹配)。
代码异味:真正的区别所在。BugBot在第一次检测中仅发现了 9 个代码异味中的 3 个,而 Copilot 和 Claude 都发现了 6 个。诸如错误的 HTTP 状态码、移除ModelState验证以及缺少CancellationToken参数等问题,是区分这些工具的关键所在。
无人接住的(第一轮)
三位审稿人都忽略了三个问题:
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
这三点都属于代码规范问题,而非安全漏洞或正确性错误。但资深人工审核员只需几秒钟就能发现这些问题。
评论风格
除了数值之外,每种工具都有其独特的个性:
- Copilot
发布了 33 条包含代码建议的独立内联评论。内容详尽、细致入微、切实可行。 - 克劳德
发布了 25 条内联评论,外加一份结构化的摘要(包含严重程度分级)、一条“请勿合并”的建议以及一份资质轮换清单。观点鲜明、切合实际、果断。 - BugBot
发布了 22 条评论,通常将相关问题归类在一起。内容简洁明了,信息量少。
第二、三、四轮:复审循环
接下来就更有意思了。在修复了每个工具发现的问题后,我推送了修复程序并重新请求审核。这些工具还能发现更多问题吗?
副驾驶:无情的评论员
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Copilot 持续深入调查。在第二遍测试中,它发现了缺失的ModelState检查项和 DELETE 状态码——这些问题在 PR 包含 38 个问题时被它忽略了。在第三遍测试中,它找到了关键数字。三遍测试均获得满分。
它还提出了 5 个关于UpdateOrderStatusAsync死代码和架构不一致的新观察结果——这是在最初的 38 个发现之外的合理发现。
BugBot:迭代改进器
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BugBot 每次迭代都在进步,在第二轮和第三轮中又发现了 6 个问题。它甚至还发现了一个由自身修复引入的回归问题——修复第 13 号问题的代理使用了 ` <input type="true BadRequest(ModelState)">` 而不是 `<input type="false">` ValidationProblem(ModelState),而 BugBot 标记出了这种不一致之处。这真是令人印象深刻的自我意识。
不过,经过 4 次传球后,传球成功率稳定在 35/38,始终未能追上第 9、15 或 30 名。
克劳德:结构化自动扶梯
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Claude 的表现让我很惊喜。在第二次检查中,它又发现了 3 个问题,并将结论从“禁止合并”改为“需要小幅修复”——明确确认所有严重和高危问题都已解决。在第三次检查中,它发现了最后 3 个问题——包括第一次检查中所有工具都未发现的那个关键问题——并将结论提升至“接近完成”。在第四次检查中,所有修复都已完成,它发出绿灯:“已批准——可以合并”。
与 Copilot 的结果相同,合并成功率均为 38/38,但每一步都体现了合并置信度的提升。它还指出 API 密钥修复(已从查询字符串移至请求体)应使用请求头——这是其他工具均未发现的修复质量问题。即使在最终批准时,它也包含一个非阻塞性的后续建议(在依赖HttpClient注入注册中进行配置),并持续提醒用户轮换 Git 历史记录中的凭据。
多传球记分牌
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
开发者体验问题
副驾驶和克劳德都达到了38/38的命中率。检测结果相同。那么区别在哪?区别在于他们告诉你的方式。
副驾驶:细致入微却不收尾
使用 Copilot 时,每次修复和推送都会触发新一轮的发现。第一轮:修复了 34 个问题。第二轮:又修复了 3 个。第三轮:又修复了一个。感觉就像在和一位越来越吹毛求疵的审校员玩打地鼠游戏。
根本问题在于:没有合并信号。处理完所有发现的问题后,你只能再次请求审核,然后屏息以待。它会不会发现更多问题?不到审核运行,你一无所知。而当它真的发现更多问题时,你又得重新经历一遍。Copilot 从来不会说“这已经足够好,可以合并了”。
BugBot:部分问题已解决,但尚未得出结论
BugBot 也呈现出类似的模式,每次都会发现新的问题。公平地说,GitHub 会在引用的代码发生更改时自动将一些内联注释标记为“已过时”——BugBot 的注释也因此受益,会在已解决的问题上显示“显示已解决”标签。
但它的机制并不一致:一些已修复的问题会被标记为“已过时”,而另一些则不会,即使修复显然已经完成。更重要的是,没有摘要说明哪些问题得到了解决——你必须滚动浏览每个评论才能自行拼凑出修复状态。和 Copilot 一样,BugBot 也从未给出“可以合并”的总体结论。
共同的问题
在实际的团队工作流程中,这两种工具都会产生以下结果:
-
反复评审周期造成的开发人员疲劳 -
合并准备工作尚未获得明确的“绿灯”。 -
下一轮测试是否会暴露出更多问题,目前尚不确定。 - 每一项发现都同样紧迫
——没有区分阻碍因素和锦上添花的因素。
克劳德:检测结果相同,但合并置信度有所提高。
Claude 也达到了 38/38 的水平,但体验却截然不同。与其他工具一样,它会在代码中精确定位到相应位置,并附上详细的内联注释、代码建议和“修复此问题”的链接。
此外,每条评论都标有严重程度(严重、高、中、低),每次审核都包含明确的合并准备情况评估:
- 第一轮(共发现 32 个):
“请勿合并”——10 个严重问题,8 个高危问题,附带凭证轮换清单
- 第二轮检查(新增4项):
“需要小修”——所有严重/高危问题已解决,剩余问题为中/低危
- 第三轮检查(+2 项发现):
“基本完成”——还剩两项小问题,其他所有问题均已确认修复。
- 第四轮审核(0 条新建议):
“已批准 — 准备合并” — 所有问题已解决,仅剩一条非阻塞性后续建议
这种流程让我获得了 Copilot 和 BugBot 从未提供过的东西:确认我的修复确实解决了审查中发现的问题。每次审查,Claude 都会明确地验证哪些之前的问题已经解决,然后再标记新的问题。当状态变为“需要小修”时,我知道那些“严重/高”级别的问题已经确认修复——不仅没有出现在新的评论中,而且还被明确地勾选了。而当最终显示“已批准——准备合并”时,这不仅仅是沉默——而是对所有先前审查中发现的问题都已得到解决的明确确认。
即使在最终审批阶段,Claude 也没有简单地盖章通过。他提出了一项非阻塞性建议(HttpClient在依赖注入注册中配置标头,而不是每次调用都配置),并持续提醒要轮换 Git 历史记录中仍然存在的凭据。这种深思熟虑、注重上下文的反馈正是建立信任的关键。
权衡表
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
判决
最终比分牌上,两名球员并列38/38,一名球员为35。但这些数字并不能反映全貌。
- Copilot在首次检测覆盖率
方面胜出——38 次检测中成功检测出 34 次,初始检测率最高。如果您希望以最少的检测次数获得最多的初步结果,Copilot 是您的理想之选。 - BugBot在回归检测
方面表现出色——它是唯一一款能够检测到自身修复引入的 bug 的工具。对于复杂 PR 的迭代开发而言,这确实非常有价值。但它 35/38 的检测上限意味着总会有一些问题被遗漏。 - Claude在开发者体验方面
胜出——与 Copilot 的得分相同,均为 38/38,但它采用了结构化的严重性分级、每次迭代的合并置信度递增机制,以及超越单纯发现问题的修复质量反馈。它不仅告诉你哪里出了问题,还会告诉你当前所处的位置以及应该优先处理哪些问题。
这三款工具都在第一次扫描中就发现了所有安全漏洞和代码错误。需要多次扫描才能发现的问题都是代码异味和规范问题。这令人安心:对于生产环境中真正重要的问题,这三款工具都能提供可靠的保障。
检测至关重要——你肯定希望审核人员尽可能多地发现问题。但仅仅检测是不够的。你还需要一个清晰的信号,表明你的修复已经完成,PR 可以合并了。Claude 是唯一一款能够同时提供这两项功能的工具。
需要注意的是:Claude 的审查是由 GitHub Actions 工作流驱动的,其中包含结构化的提示,明确指定了审查重点领域,例如 OWASP Top 10、.NET 特有模式和严重性评级(参见附录)。Copilot 和 BugBot 使用的是默认配置,没有自定义指令。这确实是一个合理的比较缺陷——如果 Claude 的提示经过优化,可能会获得优势,尤其是在 .NET 特有问题方面。不过,Copilot 和 BugBot 都支持自定义审查指令(分别通过 `copilot-review-instructions` 和 `copilot-review-instructions` .github/copilot-review-instructions.md).cursor/rules,因此您可以尝试配置它们以生成类似的结构化输出。我尚未对此进行测试,但值得探索。
我可以肯定的是,合并准备进度(禁止合并 -> 已批准)并非提示的一部分——克劳德自行添加了这一步骤。
附录:Claude 代码审查工作流程
以下是使用claude-code-action为 Claude 的审查提供支持的 GitHub Actions 工作流。
name: Claude Code Review
on:
pull_request:
types: [opened, synchronize, ready_for_review, reopened]
jobs:
claude-review:
if: ${{ !github.event.pull_request.draft }}
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
issues: write
id-token: write
actions: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run Claude Code Review
id: claude-review
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
track_progress: true
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}
Review this pull request with focus on:
## Code Quality
- Naming conventions and readability
- DRY violations or unnecessary complexity
- Dead code or commented-out code
## Bugs & Logic
- Null reference risks
- Off-by-one errors or incorrect boundary conditions
- Race conditions or thread safety issues
- Unhandled exceptions or missing error handling
## Security (OWASP Top 10)
- SQL injection or command injection
- Hardcoded secrets or credentials
- Broken access control or missing authorization checks
- Input validation and sanitization
## .NET Specific
- Proper async/await usage (no async void, no missing await)
- IDisposable resources not disposed
- LINQ misuse or performance pitfalls (N+1 queries)
- Correct dependency injection patterns
## Performance
- Unnecessary allocations in hot paths
- Missing pagination on collection endpoints
- Inefficient database queries
Rate issues by severity: CRITICAL, HIGH, MEDIUM, LOW.
Use inline comments for specific code issues.
Post a summary comment with an overall assessment.
claude_args: |
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*)"
免责声明
我与 Anthropic、Cursor 或 GitHub 没有任何关联。我是这三者的付费用户——Claude、Cursor(BugBot)和 GitHub Copilot 都是我日常工作流程中的工具。为了完全透明,我必须说明,这个实验也是使用 Claude Code(Anthropic 的命令行工具)构建、执行和修复的。
我的目标并非评选排行榜上的赢家,而是回答一个实际问题:哪个工具能让我最有信心进行合并?数据本身就说明了一切。
请谨慎看待此结果。每个项目都各不相同——语言、框架、代码库规模和团队惯例都会影响这些工具的性能。一个 Python FastAPI 项目或一个 Go 微服务可能会产生截然不同的结果。此实验是在受控条件下进行的基准测试,并非最终排名。请将其作为起点,然后在正式投入使用前,针对您自己的代码库测试这些工具。
每种工具都有其用武之地。你可能会发现某个工具比我用的更适合你——这完全没问题。这里没有对错之分。最好的工具就是最符合你工作流程,并能让你充满信心交付成果的工具。
关注「索引目录」公众号,获取更多干货。

