生成式人工智能在软件开发中的应用——Bug检测与代码审查

30 阅读22分钟

想象一下,公司支付给软件工程师的薪资都是最高的,这些工程师负责开发支撑公司收入的产品,但最终由于生产环境中出现代价高昂的缺陷,导致收入损失。这是任何企业主最害怕的噩梦,可悲的是,这种情况每天都在发生。软件已经自动化了整个行业,取代了漫长的手工流程,并创造了许多以前不可能实现的新方式。然而,当缺陷削弱了产品的核心功能时,自动化就难以发挥应有的效力。

为缓解这一根本性问题,近年来诞生了多个职位名称以保障质量,例如 QA 工程师、QA 分析师和测试工程师。与此同时,也制定了多种流程来在代码部署到生产环境之前发现缺陷。主要可归纳为两大类:

  • 代码审查
    这是开发阶段进行的流程,团队成员在代码正式上线前互相审查代码。一些团队会规定合并代码前,必须由最少数量的成员审查并批准 Pull Request(PR)。

  • 质量保证
    这是开发结束后、代码推送到生产环境前的最后一道“守门人”流程。通过在与生产环境高度相似的测试环境中进行手工或自动化测试,模拟用户行为,以捕捉任何可能在代码审查中遗漏的缺陷。

当任何一个流程发现缺陷、性能问题、安全漏洞或其他故障时,代码会被回退——即返回给开发该代码的软件工程师,并附上需要修正的具体问题说明。

这些流程对任何软件开发团队都至关重要,但往往非常耗时且缺乏确定性,容易造成瓶颈,且并未完全实现防止缺陷进入生产环境的目标。正因如此,随着 AI 工具的出现,业界开始大力推动代码审查的自动化,加快缺陷检测的速度并提高确定性。如今,成千上万的软件工程团队已经开始使用基于 AI 的自动代码审查工具。

AI 代码审查工具的类型

本章评测的 AI 工具主要分为三大类,在软件开发中的使用方式略有不同。有些工具提供多种功能类型。

  • IDE 集成工具
    这类工具直接集成在软件开发环境中,如 Visual Studio Code、IntelliJ IDEA 或 Eclipse。开发者编写代码时,工具实时反馈错误、高亮问题、建议改进,并在 IDE 内直接提供文档链接。在这里介绍的三种工具类型中,只有 IDE 集成工具能在代码本地保存时立即反馈问题。即时反馈帮助开发者现场识别并修复问题,提高代码质量,减少后续大量审查的需求。

  • 基于 Git 的工具
    这类工具集成在版本控制系统中,如 GitHub、GitLab 或 Bitbucket,运行于 Git 工作流中。与 IDE 工具不同,基于 Git 的工具无法通过本地保存触发,只能在 Git 工作流中的操作触发。你可以设置它们在推送代码到仓库或创建、合并 Pull Request(PR)时自动审查代码。这些工具根据预定义规则和标准检查代码,可在代码库所有分支强制执行编码规范。它们通常以 PR 评论或持续集成(CI)流水线报告形式提供反馈,确保代码在合并主分支前符合质量要求。

  • 浏览器工具
    这类工具通过网页浏览器访问,通常集成在线版本控制平台,如 GitHub、GitLab 和 Bitbucket。与基于 Git 的工具类似,只能通过 Git 工作流触发,无法响应本地变更。你可以使用浏览器工具在线自动审查 PR 或代码合并。提交 PR 后,工具会检查代码中的错误、风格违规和安全漏洞,并通过浏览器的网页界面反馈结果。我认为这三种工具中此类最不方便,因为它要求你使用除熟悉的 IDE 和版本控制工具外的额外平台。

此外,还应区分以下几类工具:

  • 代码风格检查工具(Linters)
    这类工具最简单,主要用于强制执行编码规范和风格。它们扫描代码以识别语法错误、风格不一致及基础编程错误。比如针对 JavaScript 的 ESLint 和 Python 的 Pylint,通常集成于开发环境中,实时反馈诸如缩进、括号位置、行长等问题。

  • 静态分析工具
    这类工具通过不执行代码的方式深入分析,检测潜在缺陷、安全漏洞和性能问题。静态分析工具如 SonarQube 能理解控制流、数据流和变量作用域,能够发现复杂问题,比如内存泄漏和并发问题。它们常集成在 CI/CD 流水线中,帮助维护项目代码健康。

  • AI 驱动的代码分析工具
    这类工具利用机器学习分析大量项目的编码模式,识别复杂问题并提出改进建议。AI 分析工具如 DeepCode 和 Codacy 提供上下文感知的建议,能预测代码变更的影响,并基于海量数据集提供优化方案。

鉴于本书范围限制,我仅介绍最后一类工具,即 AI 驱动的代码分析工具。

应用场景

数以百万计已经使用 AI 工具进行自动代码审查和缺陷检测的软件工程师发现,这些工具在多种日常使用场景中带来了显著的好处,包括:

  • 培养软件工程师
    自动代码审查工具为软件工程师,尤其是初级工程师,提供了一个全天候的“搭档程序员”,指出缺陷、给出建议,最重要的是提供建议背后的上下文和原因分析。这是一个极佳的技能提升工具。相比团队成员的传统代码审查,自动化工具能带来更频繁的反馈循环,增加学习语言、框架或算法的机会。对于初级开发者以及刚接触新技术栈或框架的工程师尤其有益,因为经验不足更易犯错。代码审查中,错误会被回退,并附上帮助开发者理解错误、避免重犯的说明。

  • 提升软件开发速度
    自动化代码审查减少了 PR 被回退的次数,同时极大缩短了代码编写与问题被发现之间的时间。每次代码变更时的自动审查能及时发现漏洞和改进点,帮助开发者立即修复。这消除了推送有缺陷代码、再被团队成员发现并回退的循环——这种多次回退循环浪费个人开发者时间,延误功能上线。

  • 减少技术债务
    代码审查中,安全漏洞和性能问题常常被忽视,因为它们通常不会影响功能,而功能是代码审查的最大关注点。即使被发现,这些问题也很少作为回退原因处理,而是被标记为“可选修复”,实际上把漏洞或问题加入了技术债务堆积中。技术债务通常长期积累,直到不可持续,需要对代码库进行大规模重构。

  • 加深代码审查深度
    本章提及的大多数代码审查工具重点关注安全漏洞,通常会检测出代码中 OWASP 前十漏洞的出现,并给出解决建议。团队代码审查很少能达到这样的深度;这些漏洞往往只在专业安全审计或渗透测试报告中被发现(如果被发现的话)。使用这些工具可以让团队更早发现安全漏洞。

保留人工审查

对自动化代码审查工具的一个常见批评是,它们可能会让团队成员(人类)减少或延迟进行代码审查。公平地说,早在 AI 工具出现之前,代码审查在许多团队中就已经是一项令人头疼的工作。软件工程师经常忘记审查同事的 Pull Request,或者为了让功能上线而草率地留下“lgtm”(“looks good to me”的缩写)之类的正面评价。

AI 工具为代码审查过程带来了极大的即时性,这让软件工程师放心他们的代码质量有保障,但同时也让他们觉得审查同事代码的紧迫感降低,认为 AI 工具已经替他们完成了这项工作。

我认为这是一个非常合理的批评。AI 代码审查无法替代人工审查,尤其是由对功能技术和业务用例都非常了解的资深工程师进行的审查。这正是 AI 代码审查明显缺失的部分——AI 工具无法理解被审查代码背后的上下文和某些代码片段的意图。这可能导致它提出无关的建议,或者漏掉那些对人类审查者来说显而易见的上下文相关问题。这也是为什么即使使用自动代码审查,也绝不能跳过人工代码审查的关键原因。

另外值得注意的是,这些自动化代码审查工具的市场宣传语言,与上一章介绍的代码生成工具的宣传用语截然不同。尽管这些产品确实采用了 AI 算法(例如 Codacy),但本章讨论的工具中很少(甚至几乎没有)在市场文案中强调 AI。

这有两个原因。其一,许多工具在 AI 流行之前已经在市场上存在多年;其二,许多工具将自己定位为 AI 生成代码问题的补充保障。例如 Sonar 承诺降低风险,确保代码质量,并最大化 AI 与人工代码的价值。官网宣传写道:“为了最大化生成式 AI 在编码中的优势,开发团队需要健壮的 DevOps 流程、报告和聚焦代码质量、安全与可靠性的度量指标。”

评估流程

为了筛选出本章重点介绍的工具,我评估了 20 多款自动化代码审查工具。所有被涵盖的工具均符合以下标准:

  • 拥有专业项目背景和实力团队支持;
  • 生成的代码质量达到较高标准;
  • 提供一定程度的免费或试用功能;
  • 截至撰写时(2025 年中),拥有较高的用户采纳率。

为了选择和对比本章中的 AI 工具,我编写了一个简单的 JavaScript 程序,并在代码中故意引入了四个问题。完整代码可在本书的 GitHub 仓库中“Chapter 3”文件夹找到。示例 3-1 给出了最相关的代码片段,并对四个问题做了注释说明。我将完全相同的代码分别提交给本章评测的所有工具,随后讨论各工具的检测结果。

示例 3-1 代码片段(代码审查工具测试用):

app.post('/submit', (req, res) => {
   const requestData = req.body;

   // 1. SQL 注入漏洞
   const sqlQuery = `SELECT * FROM users 
                     WHERE username = '${requestData.username}'`;
   db.all(sqlQuery, [], (err, rows) => {
       if (err) {
           console.error('执行 SQL 查询出错:', err.message);
           res.status(500).send('数据库操作错误');
       } else {
           console.log('查询结果:', rows);
           res.send('数据处理完成,SQL 查询结果:' + JSON.stringify(rows));
       }
   });

   // 2. 跨站脚本攻击(XSS)漏洞
   const responseHtml = `
       <html>
           <body>
               <h1>用户资料</h1>
               <div>${requestData.userInput}</div> <!-- 用户输入直接渲染到 HTML -->
           </body>
       </html>
   `;
   console.log('生成的用户 HTML:', responseHtml);

   // 3. 事件监听器可能的内存泄漏
   const listeners = [];
   for (let i = 0; i < 100; i++) {
       listeners.push(() => console.log('事件监听器', i));
   }
   console.log('创建的监听器数量:', listeners.length);

   // 4. 低效循环
   let sum = 0;
   for (let i = 0; i < 100000; i++) {
       sum += i;
   }
   console.log('0 到 99999 的和:', sum);
});

以下是对每个故意引入错误的简要说明及其在代码审查中被发现的重要性:

  • SQL 注入漏洞
    该漏洞源于直接将用户输入拼接进 SQL 查询字符串,而未进行任何验证或清理。在示例代码中,变量 requestData.username 被直接嵌入 SQL 语句。攻击者可以构造恶意输入,操控 SQL 逻辑执行未授权操作,例如访问、修改或删除数据。比如,输入 ' OR '1'='1 会使查询返回系统中所有用户,导致数据泄露。

  • 跨站脚本攻击(XSS)
    XSS 发生在应用将不可信的数据(通常来自用户输入)未经验证或转义直接插入网页内容中。在代码中,requestData.userInput 被直接包含在返回客户端的 HTML 结构中。如果用户输入含恶意 JavaScript,浏览器会执行该脚本,可能导致会话劫持、个人信息窃取或恶意重定向。

  • 内存泄漏
    Web 应用中的内存泄漏是指不再需要的内存未被释放。示例中循环创建大量事件监听器,但未移除。每个监听器都保持闭包,持续占用内存。长时间运行的应用(如服务器)中,这种累积会耗尽资源,导致性能下降甚至崩溃。

  • 低效循环
    示例中的循环以低效方式执行大量迭代,计算从 0 到 99,999 的整数和。每次迭代都执行算术操作并更新局部变量,虽操作简单但重复冗余。该行为不仅浪费 CPU 资源,还可能阻塞 Node.js 的事件循环,延迟其他请求处理。

接下来,让我们深入了解我尝试过的表现最佳的 AI 代码审查工具。

Codacy

Codacy 是一家总部位于葡萄牙的初创公司,2012 年推出了自动化代码审查工具。多年来,该产品不断发展,现已成为市场领先的解决方案。根据其官网介绍,Codacy 利用 AI “帮助开发者识别并修复代码中的问题,提高代码质量,减少技术债务,支持 40 多种编程语言,并与 GitHub、Bitbucket 和 GitLab 实现无缝集成”。

Codacy 的 AI 工具会分析代码中潜在的错误、风格违规、安全漏洞和性能问题,并为软件工程师提供改进建议。该工具能够从过去的审查中学习,适应每个开发团队的具体标准和实践。

通过自动化代码审查流程,Codacy 帮助开发者更多地专注于功能开发而非问题修复,从而加快开发周期,提升代码可维护性。

实际案例

我使用 GitHub 账号注册了 Codacy,并在本章前面展示的代码上运行了该工具(完整代码可在本书的 GitHub 仓库中查看)。
Codacy 正确识别出了第一个问题——SQL 注入漏洞,并将其严重等级标记为“Critical”(严重),这是其评级中的最高级别,如图 3-1 所示。

image.png

Codacy 提供了一个可展开的区域,详细解释了错误的性质、危险原因以及解决方法(见图 3-2)。

image.png

Codacy 也正确识别出了第二个问题——XSS 漏洞,并将其严重等级标记为“中等”(见图 3-3 和图 3-4)。

image.png

如图 3-4 所示,Codacy 对该 XSS 漏洞进行了清晰的解释。

image.png

Codacy 的分析未能识别出第 3 和第 4 个问题,这两个问题更多涉及性能而非安全。

所有这些反馈都是我连接 GitHub 账号并选择想要分析的仓库后,Codacy 网站立即提供的。然而,当我在同一仓库上打开一个 Pull Request(PR)时,Codacy 会在仓库内执行第二轮分析。

它识别的大部分错误与之前分析中发现的问题一致,这符合预期,因为代码相同。但在 GitHub 上,Codacy 还会针对每个问题提供“提交建议”(commit suggestion)及简要说明,使软件工程师可以非常方便地一键接受建议并合并 PR(见图 3-5)。

image.png

基于以上所有理由,我给 Codacy 的工具评分为 8/10。它成功发现了两个安全问题,但未能检测出两个性能问题。对于检测到的问题,Codacy 提供了非常全面的解释和可接受的修复建议,且可以一键应用于实际仓库。

DeepCode(隶属于 Snyk)

DeepCode 最初是一家位于瑞士苏黎世的独立初创公司,由苏黎世联邦理工大学(ETH Zurich)衍生而来。2020 年 9 月,被网络安全巨头 Snyk 收购。此后,产品先以“DeepCode by Snyk”名义推出,近期改名为“DeepCode AI”,并已整合进 Snyk 更广泛的产品与服务套件中。

正如 Snyk 2020 年描述的,DeepCode 拥有“先进且可解释的机器学习语义代码分析技术。其扫描速度比其他方案快 10 至 50 倍,使开发流程支持实时工作流,并通过定制机器学习平台大幅减少假阴性和假阳性,快速从海量代码中学习。”

DeepCode 通过机器学习算法,从数百万公开开源的软件开发仓库中学习。这一庞大数据集使 DeepCode 能提供高度准确的建议,并发现人类审查者可能忽略的潜在问题。

DeepCode 可在 IDE 中使用,也能直接集成在 Git 仓库。它能即时指出安全漏洞,表现为 IDE 中的工具提示警告或仓库中 Pull Request 的评论。官网介绍:

它结合了符号 AI 与生成式 AI、多种机器学习方法,以及顶尖安全研究员的专业知识,实现精准的漏洞检测和技术债务管理。DeepCode AI 专为安全设计,支持 11 种编程语言和超过 2500 万条数据流案例,高效发现并修复漏洞。这项 AI 技术通过一键修复安全问题和全面的应用覆盖,提高开发者生产力,同时通过数百万开源项目的训练数据确保 AI 的可信度。DeepCode AI 以其采用多模型和安全特定训练集的混合方法,在应用安全防护中独树一帜。

实际案例

正如我对 Codacy 所做的那样,我使用 GitHub 账号注册了 Snyk/DeepCode,并在本书仓库中的示例 3-1 代码上运行了该工具。
DeepCode 正确识别出了第一个问题——SQL 注入漏洞,并将其标记为 “H”(高危),这是其评级系统中的最高等级。它还给出了一个评分(见图 3-6),尽管我未能找到该评分具体含义的详细说明。该问题的得分为 830,是我的代码中获得的最高分。

image.png

Snyk/DeepCode 为每个错误提供两个可展开的区域。其中一个区域对问题进行了更深入的解释,类似于在浏览器界面中呈现的堆栈跟踪(见图 3-7)。

image.png

第二个可展开区域提供了解决该问题的建议(见图 3-8),并指出应避免使用将用户输入参数直接拼接成字符串的 SQL 语句。这是防御性编程中的最佳实践。

image.png

这些建议是“原封不动”地来自训练数据中的开源仓库。就透明度而言,这非常好,因为软件工程师总是希望了解代码的来源。然而,这也增加了解决问题时的认知负担,因为这些仅是为帮助开发者修复问题而提供的建议方案,而非可以一键采纳的最终解决方案。

尽管在问题 1 上给出了如此详尽的细节,DeepCode 并未发现问题 2、3 和 4。不过它确实在我使用的一些库(node_modules 目录内)中发现了一些低严重度的问题,这些与本书的练习无关。

我给 DeepCode 评分为 6/10。它发现了两个安全问题中的一个,但未发现任何性能问题。对于已发现的问题,DeepCode 提供了非常全面的解释;但相比 Codacy 和 CodeRabbit,DeepCode 在每个问题的辅助修复建议上表现不足。DeepCode 提供问题的信息,但没有提供可以一键轻松采纳的修复方案。

CodeRabbit

CodeRabbit 是一款于 2023 年 9 月推出的自动化代码审查平台,正值生成式 AI 热潮期间。它迅速获得了广泛关注,尤其是在 Twitter/X 上,一些科技影响者对该产品进行了深入评测并在其网络中推广(这里有一个例子)。截至撰写时(2025 年中),CodeRabbit 的官方用户数尚未公开。

CodeRabbit 利用 AI 技术提升代码审查的质量、性能和效率,通过在仓库的评论中给出代码建议。

实际案例

与其他工具一样,我用 GitHub 账号注册了 CodeRabbit,授权它访问我的账号,并选择了要分析的仓库。与 Codacy 和 DeepCode 不同,CodeRabbit 不会静态分析仓库中已有的代码,而是需要打开一个 Pull Request,随后 CodeRabbit 会在该 PR 中发表评论,提出代码审查项和建议。CodeRabbit 将其定位为一种更具交互性的工具,旨在模拟团队成员在 GitHub 上打开 PR 后数秒内发表评论的场景。然而,我在 CodeRabbit 网站上的使用体验远不及本章其他竞争对手的工具。

CodeRabbit 正确识别出了问题 1,即 SQL 注入漏洞(见图 3-9)。它未提供严重等级的指示,所有报告的问题在这方面看起来都相同。它准确指出了出错的代码片段,并简要说明了为何该代码存在漏洞。我相信大多数软件工程师会喜欢这种简洁的界面,因为这正是他们从审查自己 PR 的同事那里获得的反馈类型。

image.png

除了说明外,CodeRabbit 还提供了一个名为“可提交建议”(Committable suggestion)的可展开区域,里面包含了针对该问题的修复建议(见图 3-10)。虽然 CodeRabbit 会明显提醒用户仔细审查所提供的解决方案,但提交修复仅需轻松点击一次即可完成。

image.png

CodeRabbit 也检测出了问题 2,即 XSS 漏洞(见图 3-11),但和其他分析过的工具一样,CodeRabbit 未能发现性能问题 3 和 4。

image.png

因此,我给 CodeRabbit 评分为 7/10。它发现了两个安全问题,但未能发现任何性能问题。它对发现的其中一个问题提出了解决方案,但对另一个问题则没有。相比另外两款工具,它对问题的解释也比较肤浅。最后,它缺乏一个网站界面,无法让用户深入研究问题并查看代码库历史变更和改进情况,而这是其他工具所具备的功能。

工具比较

这三款 AI 代码审查工具在阻止我合并 Pull Request(PR)时采取了不同的策略,如图 3-12 所示:

  • Codacy 会阻止 PR 合并,直到我修复它识别出的问题(公平地说,我可以使用它提供的修复建议完成修改);
  • Snyk/DeepCode 即使发现问题,也不会阻止 PR 合并;
  • CodeRabbit 仅发布评论,不执行实际检查,因此无论发现多少问题,都不会阻止 PR 合并。

image.png

如果让我选择一款工具,Codacy 会是我的首选。正如表 3-1 所示,它得分最高。

表 3-1 AI 代码审查工具概览

工具使用场景测试表现
Codacy浏览器 + 仓库8 / 10
Snyk/DeepCode浏览器 + 仓库6 / 10
CodeRabbit仓库7 / 10

总结

多年来,代码审查一直是我所在软件开发团队面临的最大挫折之一。人们天生更倾向于接受分配给自己的新任务,而不是暂停手头的工作去审查同事的 Pull Request(PR)。这种默认行为导致功能向质量保障(QA)环节的流转延迟,最终影响上线。同时,这也造成了为了赶进度而以低于理想的代码审查水平快速推进某些紧急功能的情况,导致生产环境出现缺陷。总体来看,这种普遍的代码审查挫折最大受害者是团队士气,成员常感到频繁切换工作上下文,难以集中精力。

早在近期生成式 AI 热潮之前,我所在团队就已开始使用多种自动化代码审查形式,如代码风格检查(linters)、静态代码分析和测试覆盖率仪表盘。任何拥有健全工程规范的团队大概率也采取了类似做法。

然而,经过 15 年行业经验,我发现近期的工具进化为这些工具注入了更深层次的价值——尤其是它们与软件开发流程的无缝集成,以及一键采纳建议修复的功能。拥有一个全天候在线、能对代码问题提供深思熟虑反馈的强大代码审查助手,对任何人都是巨大的帮助。作为曾经的软件工程师,这简直是梦想成真。

不过,我认为软件工程师应首先将这些工具视为学习机会。它们会犯错,工具本身也会在显著位置给出警告,我只能强调这一点。务必让人工进行审查和测试这些建议的修复。和代码生成工具一样,我建议在审查这些工具提出的任何代码或修复建议时保持高度谨慎。将代码真正理解并拥有后,再提交 PR 或合并至主分支。