在敏捷开发和持续交付(CI/CD)的快节奏下,代码审查(Code Review, CR)往往成为了研发团队的瓶颈。

人工 CR 耗时费力,且由于评审者精力有限,常常流于形式(如只看代码风格而忽略了潜在的并发或安全漏洞)。传统的静态扫描工具(如 SonarQube、ESLint)虽然速度快,但它们只能基于预设的规则行事,无法理解业务逻辑,更无法提出架构级别的重构建议

大语言模型(LLM)的出现,为这一痛点提供了革命性的解决方案。本文将手把手教你如何将 LLM 深度集成到 CI/CD 流水线中,构建一个不知疲倦、火眼金睛的 AI Code Reviewer。

1. 为什么需要 AI Code Review?

相比于传统静态扫描,LLM 在代码审查上的核心优势在于其强大的上下文理解能力语义推理能力

  • 发现深层逻辑漏洞:AI 可以识别出“在循环中频繁查询数据库”这种性能反模式,而静态工具通常很难跨文件追踪数据流。
  • 业务语义检查:AI 能理解变量命名和注释的意图,指出“虽然代码没有语法错误,但处理退款逻辑时没有校验订单状态”这类业务层面的缺陷。
  • 建设性的重构建议:不仅指出问题,AI 还能直接提供修改后的代码片段。

2. AI Code Review 的核心架构设计

要构建一个自动化的 AI 审查机器人,其工作流通常如下:

graph LR Dev["Developer"] -->|Push PR| Git["GitHub/GitLab"] Git -->|Trigger Webhook| CI["CI/CD Pipeline (e.g., GitHub Actions)"] CI -->|1. Fetch Diff| Diff["Git Diff Extract"] Diff -->|2. Build Context| Prompt["Context Assembly & Prompting"] Prompt -->|3. API Call| LLM["OpenAI / Claude API"] LLM -->|4. Parse Response| CI CI -->|5. Post Comments| Git

关键挑战:上下文的构建 (Context Assembly)

大模型虽然聪明,但它的输入窗口(Context Window)是有限的,且按 Token 计费。如果你把整个仓库的代码都扔给它,不仅极其昂贵,还会导致它在长上下文中“迷失”。

最佳实践:基于 Git Diff 的精确切片

我们不应该提交整个文件,而是只提取本次 Pull Request 中修改的部分(Git Diff),并适当附加几行上下文(Context Lines)。

3. 实战:使用 GitHub Actions 构建自动化审查机器人

下面我们将通过一个真实的 GitHub Actions 脚本,展示如何拦截 PR 并调用 LLM 进行审查。

3.1 编写 GitHub Actions 工作流文件

在你的项目根目录下创建 .github/workflows/ai-code-review.yml

yaml
name: AI Code Review

on:
  pull_request:
    types: [opened, synchronize] # 当 PR 被创建或更新时触发

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0 # 获取完整的 git 历史,以便生成精确的 diff

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: npm install axios @actions/github @actions/core

      - name: Run AI Review Script
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
        run: node scripts/ai-reviewer.js

3.2 编写核心的审查脚本 (ai-reviewer.js)

在这个脚本中,我们将获取 PR 的变更文件,将 Diff 内容发送给 LLM,并将审查意见回写到 GitHub 的评论区。你可以使用 QubitTool 的 代码比对查看器 来辅助调试生成的 Diff 格式是否正确。

javascript
const github = require('@actions/github');
const core = require('@actions/core');
const axios = require('axios');

async function run() {
  try {
    const token = process.env.GITHUB_TOKEN;
    const openaiKey = process.env.OPENAI_API_KEY;
    const octokit = github.getOctokit(token);
    const context = github.context;

    if (context.eventName !== 'pull_request') return;

    const prNumber = context.payload.pull_request.number;
    const owner = context.repo.owner;
    const repo = context.repo.repo;

    // 1. 获取 PR 的所有文件变更 (Diff)
    const { data: files } = await octokit.rest.pulls.listFiles({
      owner,
      repo,
      pull_number: prNumber,
    });

    for (const file of files) {
      // 忽略锁文件、图片或过大的变更
      if (file.filename.endsWith('.lock') || file.changes > 500) continue;

      const diffContent = file.patch;
      if (!diffContent) continue;

      // 2. 构建 Prompt,要求 LLM 进行审查
      const prompt = `
你是一个资深的软件架构师。请审查以下代码变更(Git Diff 格式),指出潜在的 Bug、性能问题或安全隐患。
如果代码没有明显问题,请回复 "LGTM"。否则,请提供具体的修改建议。

文件名: ${file.filename}
变更内容:
\`\`\`diff
${diffContent}
\`\`\`
      `;

      // 3. 调用 OpenAI API
      const response = await axios.post(
        'https://api.openai.com/v1/chat/completions',
        {
          model: 'gpt-4-turbo-preview',
          messages: [{ role: 'user', content: prompt }],
          temperature: 0.2,
        },
        {
          headers: {
            'Authorization': `Bearer ${openaiKey}`,
            'Content-Type': 'application/json',
          },
        }
      );

      const reviewComment = response.data.choices[0].message.content;

      // 4. 将审查意见作为 PR 评论发布
      if (reviewComment && reviewComment.trim() !== "LGTM") {
        await octokit.rest.pulls.createReviewComment({
          owner,
          repo,
          pull_number: prNumber,
          body: `🤖 **AI Reviewer**:\n\n${reviewComment}`,
          commit_id: context.payload.pull_request.head.sha,
          path: file.filename,
          position: 1, // 简化示例,实际应根据 diff 计算具体的行号
        });
      }
    }
  } catch (error) {
    core.setFailed(error.message);
  }
}

run();

4. 进阶:自动化生成缺失的单元测试

除了指出问题,LLM 还可以直接产生生产力。我们可以扩展上面的 CI 脚本,当检测到核心业务逻辑被修改,但没有对应的 .test.js_spec.py 文件更新时,自动触发另一个流程:

测试生成 Prompt 示例:

text
作为 QA 工程师,请为以下新增的函数编写完整的单元测试(使用 Jest 框架)。
要求:
1. 必须覆盖所有边界条件(如空输入、极大值)。
2. 必须模拟(Mock)外部依赖。
3. 请只输出测试代码本身。

[新增函数代码]

通过这种方式,AI 不仅能防范烂代码合入主干,还能主动提高项目的测试覆盖率。

5. FAQ 常见问题解答

Q: AI 经常提出一些“吹毛求疵”的建议(如建议把 var 改为 let),导致评论区极其嘈杂,如何解决? A: 这是初期接入 AI Review 时最常见的问题。解决方案是在 System Prompt 中设定强约束,例如:“只报告可能导致运行时错误、严重性能下降或安全漏洞的严重问题。忽略代码风格(如缩进、变量声明方式)等微小细节。”

Q: 公司的代码包含敏感业务逻辑,不能发给公网的 OpenAI,怎么办? A: 可以结合本系列的前一篇文章《Ollama 高级实战指南》,在公司内网部署开源模型(如 Qwen2.5-Coder),将 CI 脚本中的 API 端点指向内网的 Ollama 即可。

总结

将 LLM 深度集成到 CI/CD 流水线中,是研发团队向“AI 原生工程”迈出的关键一步。一个配置得当的 AI Code Reviewer,就像是一个 24 小时在线、精通各种最佳实践的资深架构师,能够显著降低技术债务,提升代码质量。现在就开始在你的下一个项目中尝试吧!