我搭了一个AI代码审查机器人,每天自动Review PR——从原理到完整实现,且代码不离开内网
上周发了个PR,半小时没人审。自己看了一遍,有个SQL注入没发现。合了,上线了,被安全团队找上门了。
——这场景不陌生吧?
代码审查有两个老问题:没人审和审不细。前者是人的问题,后者是精力问题。连续审5个PR,第6个你基本就在走形式了。
我搭了一个AI代码审查机器人,接在GitHub上,每次开PR自动审查,几分钟出结果。Bug、安全漏洞、性能问题、代码风格,四个维度逐个扫描。不取代人工审查,但能把”走形式”那部分接过去。
今天把整个搭建过程拆开讲,包括架构设计、核心代码、踩过的坑,还有跟商业方案的对比。代码开源,你clone下来就能跑。
先说清楚:它能做什么、不能做什么
能做的:
-
检测常见Bug模式(空指针、资源泄露、并发问题) -
发现安全漏洞(SQL注入、硬编码密钥、XSS) -
识别性能问题(N+1查询、不必要的循环) -
给出可维护性建议(命名、冗余代码、魔法数字)
不能做的:
-
理解跨文件的复杂业务逻辑 -
判断功能是否符合产品需求 -
替代资深工程师的架构审查
一句话:它是一个不知疲倦的初级审查员,不是资深架构师。
把它当成第一道过滤,人工审查集中在它搞不定的部分。
架构:一条流水线
GitHub PR Event (Webhook / Actions) ↓ 获取 PR Diff (GitHub API) ↓ 解析 Diff → 按文件分组 → 过滤非代码文件 ↓ 逐文件调用 LLM 分析(Bug/安全/性能/可维护性) ↓ 汇总审查结果 → 发布 PR Review Comment
五个步骤,每一步都很明确。重点在中间三步。
第一步:拿到Diff
通过GitHub REST API获取PR的diff。关键细节——请求头要用Accept: application/vnd.github.v3.diff,这样直接返回unified diff文本,不需要处理JSON。
async def get_pr_diff(owner, repo, pr_number): url = f”https://api.github.com/repos/{owner}/{repo}/pulls/{pr_number}” headers = { “Authorization”: f”token {GITHUB_TOKEN}”, “Accept”: “application/vnd.github.v3.diff”, } async with httpx.AsyncClient() as client: resp = await client.get(url, headers=headers) resp.raise_for_status() return resp.text
为什么用异步?因为后面要调LLM API,同步请求会阻塞。FastAPI + httpx的组合在Python生态里最成熟。
第二步:解析Diff
这是最容易踩坑的一步。unified diff的格式看起来简单,但有几个容易忽略的点——
1. a/ 和 b/ 前缀
git diff的输出,文件路径带a/和b/前缀(--- a/src/main.py / +++ b/src/main.py)。但GitHub API返回的diff有时不带。解析时要注意。
2. 行数不一定对
@@ -1,6 +1,8 @@表示原文件从第1行开始共6行,新文件从第1行开始共8行。但有时候count为0(比如纯新增文件),需要处理边界情况。
3. 大diff会撑爆上下文
一个改了50个文件的PR,diff可能有几万行。LLM的上下文窗口装不下,必须分块处理。
我的方案:按文件分组,过滤非代码文件,超大文件跳过。
# 只审查代码文件REVIEW_EXTENSIONS = {“.py”, “.js”, “.ts”, “.java”, “.go”, “.rs”}# 超过500行的文件跳过MAX_DIFF_LINES = 500
过滤非代码文件不是偷懒——审查README.md或package-lock.json的变更没有意义,只会浪费token和产生噪音。
第三步:调用LLM分析
这是核心。prompt设计直接决定审查质量。
我试过三种prompt策略——
策略A:自由审查(”请审查这段代码”) → 结果:泛泛而谈,说了一堆正确的废话
策略B:Checklist式审查(列出检查项,逐项打分) → 结果:太机械,每个文件都差不多,有用的信息被淹没
策略C:维度引导 + 约束条件(最终方案)
审查维度:1. Bug风险:逻辑错误、空指针、资源泄露、并发问题2. 安全问题:SQL注入、XSS、硬编码密钥3. 性能问题:不必要的循环、N+1查询4. 可维护性:命名、冗余、魔法数字约束:– 只指出真正的问题,不要为了审查而审查– 每个问题给具体行号和修改建议– 代码没问题就直接说”LGTM”
“只指出真正的问题”这句话很关键。不加这句,LLM会觉得必须找出问题,然后开始编——把正常代码硬说成有Bug。加了之后,审查的精准度明显提升。
另一个关键参数:temperature=0.3。代码审查需要确定性输出,不是创意写作。低温度让LLM更稳定地输出一致的结果。
⚠️ 踩坑提醒:LLM在代码审查上的F1分数并不高。
Meta 2025年发布的CodeReviewEval benchmark显示,GPT-4o在”发现真实缺陷”任务上F1约0.58。也就是说——它会漏掉约40%的真实Bug,同时误报约40%。
所以:AI审查是第一道防线,不是最后一道。
第四步:发布评论
通过GitHub API创建PR Review。这里有个坑——
Review Comment vs Issue Comment:
-
Issue Comment( POST /issues/{n}/comments):评论挂在PR上,不关联代码行 -
Review Comment( POST /pulls/{n}/reviews):正式的代码审查,可以关联具体行
用Review Comment,因为它在GitHub的PR界面上显示得更正式,有”Approved” / “Changes Requested” / “Comment”三种状态。我选了”Comment”——只提建议,不block PR。让AI有block PR的权力?那是在给自己找麻烦。
第五步:幂等性
同一PR推了新commit,会触发新的synchronize事件。如果不做处理,之前commit的审查评论还会在。两个选择:
- 每次审查都发新评论
(简单,但评论会越积越多) - 更新之前的评论
(需要追踪comment ID)
我选了方案1,在评论里加上commit SHA作标识。
简单可靠,不引入状态管理。
两种部署方式
▪ 方式一:GitHub Actions(推荐零运维方案)
# .github/workflows/review.ymlon: pull_request: types: [opened, synchronize]jobs: review: runs-on: ubuntu-latest steps: – uses: actions/checkout@v4 – run: pip install httpx pydantic – run: python scripts/review.py –owner $OWNER –repo $REPO –pr $PR –commit $SHA env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
优点:不需要服务器,GitHub免费额度够用。
缺点:每次审查要冷启动,大概多10-20秒。
▪ 方式二:Webhook服务器(适合自托管)
pip install -e “.[dev]”python -m src.main # FastAPI跑在8080端口
需要在GitHub仓库的Webhook设置里配你的服务器地址。
优点:响应更快,可以加缓存和限流。
缺点:要维护一台服务器。
我的建议:先用Actions跑起来,审查量大再切Webhook。
用哪个模型?
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
支持任何兼容OpenAI API的模型——改OPENAI_BASE_URL和OPENAI_MODEL两个环境变量就行。
⚠️ 踩坑提醒:别用小模型做代码审查。
7B以下的模型(包括deepseek-r1:1.5b)在代码审查任务上几乎不可用——要么漏检严重,要么把正常代码批成Bug。至少用9B以上的模型,或者直接用API。
跟商业方案比,差在哪?
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
选哪个?
-
3人以下团队,PR不多(<10/天)→ 自建够用 -
10人以上团队,需要稳定可靠 → CodeRabbit免费层或Copilot Review -
代码不能出内网 → 自建 + 本地模型
完整代码
GitHub仓库:https://github.com/helloworldtang/ai-pr-reviewer
clone下来,配好环境变量,跑通7个测试,接上你的仓库。10分钟搞定。
git clone https://github.com/helloworldtang/ai-pr-reviewercd ai-pr-reviewercp .env.example .env # 填入你的配置pip install -e “.[dev]”pytest tests/ -v # 7个测试全过
💡 一句话带走:AI代码审查不是替代人工,是帮你把”走形式”的部分自动化——省下的精力用在真正需要思考的地方。
你们团队做代码审查吗?是人工审还是用工具?最大的痛点是什么?说说你的情况,帮你看看怎么接AI。
参考来源:
-
Meta: “CodeReviewEval: A Benchmark for Automated Code Review using LLMs” (2025) — GPT-4o F1≈0.58 https://arxiv.org/abs/2505.20206 -
GitHub REST API: pulls端点diff格式文档 https://docs.github.com/cn/rest/pulls/pulls#custom-media-types-for-pull-requests -
Anthropic: “Building Effective Agents” — 工具设计原则(专用工具优于通用工具) https://www.anthropic.com/engineering/building-effective-agents -
PR-Agent (Codium-ai): 开源AI审查方案参考 https://github.com/The-PR-Agent/pr-agent
夜雨聆风