1. 背景与动机

代码审查是保证软件质量的重要环节,但人工审查往往受限于时间与精力。随着 AI 编程助手的发展,利用大模型自动完成初步代码审查已经成为现实。本文将以 OpenAI Codex 为核心,结合 GitHub Actions 与 Python,构建一个能够自动审查 Pull Request 的机器人,覆盖从环境搭建到生产部署的完整流程。

本文面向有一定 Python 基础、熟悉 Git 工作流的中级开发者。难度定位为进阶实战,内容形式为项目实战 + 最佳实践。全文约 3500 字,包含 4 段可运行代码。

2. 技术选型与架构设计

在动手之前,先明确技术栈:

  • Codex CLI:OpenAI 官方命令行工具,用于调用代码审查能力
  • Python 3.10+:编写审查逻辑与结果处理
  • GitHub Actions:自动化触发与结果回写
  • Docker:可选,用于隔离运行环境

整体架构如下:

发现问题

无问题

开发者提交 Pull Request

GitHub Actions 触发

检出代码变更

Codex CLI 执行审查

审查结果

回写评论到 PR

标记通过

3. 环境准备与 Codex 配置

首先安装 Codex CLI 并完成认证:

# 安装 Codex CLI
npm install -g @openai/codex

# 登录并配置 API Key
codex login

# 验证安装
codex --version

配置完成后,创建一个项目配置文件 codex_config.toml,用于指定审查规则:

[model]
model = "gpt-4.1"

[review]
temperature = 0.2
max_tokens = 2000
system_prompt = """
你是一名资深代码审查专家。请从以下维度审查代码:
1. 潜在 Bug 与边界条件
2. 安全漏洞(注入、越权等)
3. 性能问题
4. 代码风格与可维护性
输出格式:按严重程度分级列出问题,并给出修改建议。
"""

4. 编写审查脚本

接下来编写核心审查脚本 review.py。该脚本接收变更文件列表,调用 Codex 进行审查,并输出结构化结果:

import json
import subprocess
import sys
from pathlib import Path


def get_changed_files(base: str, head: str) -> list[str]:
    """获取两个分支之间的变更文件列表"""
    result = subprocess.run(
        ["git", "diff", "--name-only", base, head],
        capture_output=True,
        text=True,
        check=True,
    )
    return [f for f in result.stdout.splitlines() if f.endswith((".py", ".js", ".ts"))]


def run_codex_review(files: list[str]) -> str:
    """调用 Codex CLI 执行代码审查"""
    file_args = " ".join(f'"{f}"' for f in files)
    prompt = (
        f"请审查以下文件的代码变更:{file_args}\n"
        "重点关注逻辑错误、安全问题与性能隐患,按严重程度输出。"
    )
    result = subprocess.run(
        ["codex", "exec", "--json", prompt],
        capture_output=True,
        text=True,
        check=True,
    )
    return result.stdout


def parse_review_output(raw: str) -> dict:
    """解析 Codex 输出为结构化 JSON"""
    try:
        return json.loads(raw)
    except json.JSONDecodeError:
        return {"error": "无法解析审查结果", "raw": raw}


def main() -> None:
    base = sys.argv[1] if len(sys.argv) > 1 else "main"
    head = sys.argv[2] if len(sys.argv) > 2 else "HEAD"

    files = get_changed_files(base, head)
    if not files:
        print(json.dumps({"status": "no_changes"}))
        return

    raw_output = run_codex_review(files)
    result = parse_review_output(raw_output)
    result["files"] = files
    print(json.dumps(result, ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()

5. 接入 GitHub Actions

为了让审查流程自动化,创建 .github/workflows/code-review.yml

name: AI Code Review

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"

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

      - name: Install Codex CLI
        run: npm install -g @openai/codex

      - name: Run review script
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
        run: |
          python review.py origin/main HEAD > review_result.json

      - name: Upload review result
        uses: actions/upload-artifact@v4
        with:
          name: review-result
          path: review_result.json

6. 结果回写与评论发布

审查结果生成后,需要自动回写到 PR 评论区。这里使用 GitHub CLI 完成:

import json
import os
import subprocess


def post_review_comment(result_path: str, pr_number: str) -> None:
    """将审查结果发布为 PR 评论"""
    with open(result_path, "r", encoding="utf-8") as f:
        result = json.load(f)

    if result.get("status") == "no_changes":
        return

    issues = result.get("issues", [])
    if not issues:
        body = "✅ AI 审查未发现明显问题。"
    else:
        lines = ["## 🤖 AI 代码审查结果", ""]
        for issue in issues:
            severity = issue.get("severity", "info")
            emoji = {"critical": "🔴", "warning": "🟡", "info": "🔵"}.get(severity, "⚪")
            lines.append(f"{emoji} **[{severity.upper()}]** {issue.get('file', '')}")
            lines.append(f"  - {issue.get('message', '')}")
            if issue.get("suggestion"):
                lines.append(f"  - 💡 建议:{issue['suggestion']}")
            lines.append("")
        body = "\n".join(lines)

    subprocess.run(
        ["gh", "pr", "comment", pr_number, "--body", body],
        check=True,
        env={**os.environ, "GH_TOKEN": os.environ["GITHUB_TOKEN"]},
    )

7. 踩坑记录与优化建议

在实际部署过程中,我遇到了几个值得记录的问题:

问题一:Codex CLI 输出格式不稳定

早期版本输出有时是纯文本而非 JSON,导致解析失败。解决方案是在 prompt 中明确要求输出 JSON,并在解析失败时降级为文本摘要。

问题二:大文件审查超时

当 PR 涉及大量文件时,单次调用容易超时。优化方案是按文件分批审查,每批不超过 5 个文件,最后合并结果。

问题三:API 成本控制

每次 PR 审查都会消耗 Token。建议在 Actions 中增加触发条件,例如仅当 PR 标题包含特定前缀或文件变更超过阈值时才执行完整审查。

8. 总结

本文从零构建了一个基于 Codex 的自动化代码审查机器人,覆盖了环境配置、审查脚本、CI 集成与结果回写四个环节。核心收获有三点:

  1. AI 审查的价值在于初筛:它能快速发现低级错误与安全隐患,让人工审查聚焦于架构与业务逻辑
  2. 结构化输出是关键:通过约束输出格式,可以无缝对接下游自动化流程
  3. 成本与效率需要平衡:合理设置触发条件与分批策略,才能让 AI 审查真正落地

后续可以进一步扩展的方向包括:接入 Slack 通知、支持多语言审查规则、以及基于历史审查数据微调提示词。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐