AI 代码审查机器人
构建 GitHub/GitLab 机器人,用显式规则、落地上下文和质量追踪审查 PR。
设计与审查策略
选择模型、从团队历史定义审查规则、设计 PR 评论格式。
为什么
AI 审查者的价值在规则而非模型。无显式规则(函数最大长度、禁用 API、安全模式),LLM 给泛泛'考虑...'评论,开发者忽略。精确规则加落地上下文(diff + 相关代码)产出可执行审查,被解决而非被驳回。
何时使用
连接机器人之前。花 1 周从团队实际审查评论历史定义 10-20 条规则。
如何做
1. 挖掘审查历史
- 从 GitHub/GitLab 导出 6 个月 PR 审查评论
- 按主题聚类:安全、性能、命名、错误处理、测试
- 前 10-20 个高频主题成为规则
2. 规则写成结构化检查
- 每条规则:{ id, description, severity, check(diff, context) -> Finding[] }
- 例:no-console-log -> 标记 src/ 中新增的 console.log
- 静态规则(regex/AST)与 LLM 辅助规则(语义)混合
3. 选择模型
- gpt-4o-mini 做分类(便宜、快、规则检查够用)
- Claude 做细致审查(安全推理、架构反馈)
- 缓存规则结果;仅需语义判断的规则调 LLM
4. 设计评论格式
- 每发现一条评论,作为可审查行评论(非文字墙)
- 格式:[Rule: id] 严重度图标 + 1 句问题 + 建议修复
- 按文件分组发现;每 PR 限 5 条评论避免噪音
5. 定义审查触发
- PR 打开 + 新推送时(重新审查 diff)
- 跳过草稿和机器人 PR(renovate、dependabot)
- 用 .ai-reviewer.yml 做每仓库规则覆盖
示例
// 结构化规则
const rules = [
{
id: "no-console-log",
description: "生产代码中无 console.log",
severity: "warn",
check(diff) {
return diff.addedLines
.filter(l => l.code.match(/console.log(/))
.map(l => ({ file: l.file, line: l.number,
message: "移除 console.log 或用 logger" }));
},
},
{
id: "unhandled-async",
description: "异步调用无 try/catch 或 .catch",
severity: "error",
async check(diff, context) {
// LLM 辅助:让 Claude 找未处理的 await
return await claude.findUnhandledAwaits(diff, context);
},
},
];
// .ai-reviewer.yml(每仓库覆盖)
rules:
no-console-log: off # 此仓库是 CLI,日志没问题
unhandled-async: error
max_comments_per_pr: 5
常见问题
- ⚠无规则——LLM 每个 PR 发泛泛'考虑加注释',开发者一周内就驳回
- ⚠发文字墙而非行评论——开发者无法执行 20 行文章,略过漏真问题
- ⚠审查机器人 PR(dependabot)——机器人在依赖机器人 PR 上发评论,造成无限评论循环
最佳实践
- ✓挖团队 6 个月审查评论定义规则——机器人应执行团队标准而非通用标准
- ✓发现作为可审查行评论发布,每 PR 限 5 条——信噪比决定开发者是否读机器人
- ✓webhook 处理中跳过草稿 PR 和机器人作者 PR,避免噪音和评论循环
实现与 PR 集成
构建 webhook、diff 解析和评论发布,配限流和落地。
为什么
webhook 循环是机器人失败之处——每次推送发评论刷屏 PR、不限流撞 API 上限、发未落地评论(不关联具体行)让开发者忽略机器人。每 PR 批量审查,只评论变更行。
何时使用
规则在样本 diff 上产出好发现后。连接 webhook,先在测试仓库运行再指向主仓库。
如何做
1. 建 webhook 接收器
- GitHub App(比机器人账号权限更细,首选)
- Webhook:pull_request(opened、synchronize)+ pull_request_review
- 用 X-Hub-Signature-256 验证 webhook 签名
2. 解析 diff
- GET /repos/:owner/:repo/pulls/:number/files(分页)
- 每文件:提取新增行及行号
- 经 .gitattributes 跳过生成文件(*.min.js、*.lock、dist/)
3. 跑规则收集发现
- 先跑静态规则(快、无 LLM 成本)
- LLM 辅助规则批量:一个 prompt 含所有相关 diff + 上下文
- 每发现落地到 diff 中具体 (file, line)
4. 发可审查评论
- POST /repos/.../pulls/:number/comments 带 position(diff 中行)
- 用 GitHub Review API(POST /reviews)批量评论为一次审查
- 除非 error 严重度规则触发,标记审查为 COMMENT(非 REQUEST_CHANGES)
5. 处理限流和重试
- GitHub:App 每小时 5000 请求;接近限流时排队审查
- LLM:按 (rule_id, diff_hash) 缓存发现,重推时跳过重审
- 幂等:发新评论前删除机器人旧评论
示例
// Webhook 处理(GitHub App)
app.webhooks.on("pull_request.opened", async ({ payload }) => {
if (payload.pull_request.draft) return; // 跳过草稿
if (payload.pull_request.user.login.includes("[bot]")) return; // 跳过机器人
const diff = await github.getDiff(payload); // 分页文件
const findings = [];
for (const rule of rules) {
findings.push(...await rule.check(diff, { repo: payload.repository }));
}
const top = findings.slice(0, 5); // 限 5 条
// 作为单次审查带行评论发布
await github.rest.pulls.createReview({
owner, repo, pull_number: pr.number,
event: findings.some(f => f.severity === "error") ? "REQUEST_CHANGES" : "COMMENT",
comments: top.map(f => ({ path: f.file, line: f.line, body:
`[${f.ruleId}] ${f.severity === "error" ? "🚫" : "⚠️"} ${f.message}` })),
});
});
常见问题
- ⚠每次推送都发不去重——10 提交 PR 收 10 相同审查,刷屏时间线
- ⚠未落地评论(无行位置)——作为通用 PR 评论发布,开发者无法内联解决
- ⚠审查中途撞 GitHub API 限流——机器人静默失败,PR 完全无审查
最佳实践
- ✓按 (rule_id, diff_hash) 缓存发现,发前删旧机器人评论——使重推幂等
- ✓用 GitHub Review API 将所有评论批量为一次审查事件,非逐条评论
- ✓接近 API 限流时排队审查,从队列(BullMQ + Redis)处理而非静默失败
部署与调优
部署为 serverless 函数或容器,追踪审查质量,每周调优规则。
为什么
AI 审查者静默退化——模型更新改评论风格,或新代码模式触发误报。不追踪'评论解决 vs 驳回'和每周规则审查,机器人信噪比下降直到开发者禁用。
何时使用
机器人在真实 PR 发评论时。第一天起追踪质量指标,每周据数据调优规则。
如何做
1. 部署 webhook 接收器
- Cloud Run 或 Fly.io:含 GitHub App 的容器,PR 间缩到零
- min-instances = 0(成本:按审查付费),max = 5(处理 PR 打开风暴)
- GitHub App 私钥存密钥管理器
2. 追踪审查质量指标
- 每条评论存 { rule_id, pr, posted_at, resolved_at, dismissed }
- resolved = 开发者修复问题;dismissed = 开发者点"解决"未修复
- 看板:每规则解决率、每规则驳回率、每周总评论数
3. 每周调优规则
- 看板:驳回率 > 50% 的规则噪音大——收紧或移除
- 一个月无发现的规则可能过期——检查代码库是否已演进
- 从近期手动审查评论中加现有规则未覆盖的新规则
4. 安全处理模型更新
- 固定模型版本(gpt-4o-2024-08-06)避免更新静默改行为
- 模型升级时:在 50 个历史 PR 上重跑机器人并 diff 发现
- 新模型驳回多 > 20% 则回滚
5. 收集开发者反馈
- 每条机器人评论加 thumbs-up / thumbs-down 反应
- 月度调查:"机器人有帮助吗?"1-5 分
- 均分低于 3 则暂停机器人做全规则审查
示例
// 部署到 Cloud Run(缩到零)
// Dockerfile -> gcloud run deploy ai-reviewer --source . --min-instances 0 --max-instances 5
// 质量追踪(Postgres)
await db.comments.insert({
rule_id, pr_number, repo, posted_at: new Date(),
status: "open", // -> "resolved" | "dismissed"
});
// 每周质量报告(定时任务)
const rules = await db.query(`
SELECT rule_id,
AVG(CASE WHEN status = 'resolved' THEN 1 ELSE 0 END) AS resolve_rate,
AVG(CASE WHEN status = 'dismissed' THEN 1 ELSE 0 END) AS dismiss_rate
FROM comments WHERE posted_at > now() - interval '7 days'
GROUP BY rule_id
`);
// 任一规则 dismiss_rate > 0.5 则告警 Slack——太吵,需调优
常见问题
- ⚠无质量追踪——机器人发数月,驳回率爬到 80%,开发者静音无人察觉
- ⚠模型未固定——静默更新改评论语气,误报飙升,信任一夜蒸发
- ⚠无开发者反馈渠道——开发者觉得烦但无法信号,静默禁用
最佳实践
- ✓第一天起按规则追踪解决 vs 驳回率——驳回率是机器人信任的先行指标
- ✓固定模型版本,升级前在 50 历史 PR 重跑——行为变更触生产前捕获
- ✓每条评论加 thumbs-down 反应并月度调查——有用度低于 3/5 则暂停审查规则