别把 AI 代码审查 API 当同步函数:CI 里最容易漏掉的 5 个状态

0 阅读3分钟

别把 AI 代码审查 API 当同步函数:CI 里最容易漏掉的 5 个状态

GitHub 在 10 月 2 日宣布:Copilot code review 可以通过 REST / GraphQL API 请求,单次请求还能选择 review effort。自动化入口一旦打开,AI 审查就不再是开发者点一下按钮,而是 CI 中一个会重试、并发、过期的异步任务。

最危险的实现,是调用 API 后看到 2xx 就把检查标成成功。它遗漏了五个必须显式处理的状态。

AI 代码审查任务的五状态流转

1. requested:只代表平台接受了请求

请求成功与结果完成之间可能隔着排队和执行。CI 需要先生成内部 job_id,保存仓库、PR、当前 head_sha、规则版本和审查强度,再保存外部回执。

type ReviewJob = {
  id: string
  repo: string
  pr: number
  headSha: string
  policyVersion: string
  effort: "lite" | "balanced"
  state: "requested" | "running" | "completed" | "superseded" | "failed"
}

这样,外部 API 临时超时也不会让任务凭空消失。

2. running:重复事件不能重复创建任务

PR Webhook 会重放,工作流也会人工重跑。幂等键至少要包含:

repo + pr + head_sha + effort + policy_version

数据库给这个键加唯一约束。再次收到相同事件时返回原任务,而不是再发起一次审查。只用 PR 编号不够,因为新提交和新规则都应产生新任务。

3. completed:结果必须绑定代码快照

审查完成时重新读取 PR 的最新 SHA:

if (result.headSha !== pullRequest.headSha) {
  await jobs.markSuperseded(result.jobId)
  return
}

旧结论可以留作证据,但不能再阻塞或放行当前提交。否则慢任务会把新任务的状态覆盖掉,这是典型的“最后返回者获胜”竞态。

4. superseded:过期不是失败

把过期任务记成失败,会制造无意义告警;把它记成成功,又可能误导门禁。superseded 应是独立终态:保留结果,标明对应 SHA,不参与当前合并判断。

如果 PR 更新频繁,还可以设置短暂防抖:新提交到达后等待几十秒再创建任务。但防抖不能替代 SHA 校验。

5. failed:失败要区分“可重试”和“需人工”

网络超时、限流可以指数退避;权限拒绝、配置不支持、覆盖范围未知则不该盲目重试。失败记录至少包含:失败阶段、错误类别、已尝试次数、下次重试时间和是否需要人工介入。

证据包比评论更重要

开发者最终看到的是行内评论,流水线真正需要的是结构化证据:

  • 审查对应的 head_sha;
  • 实际生效的强度,而不是模糊的 default;
  • 规则版本与触发原因;
  • 已检查和跳过的文件;
  • 发现的严重度与位置;
  • 完成、过期、失败或部分完成的终态。

官方更新还提到 Balanced 已成为 Default 对应的默认强度,且不同管理层级可以覆盖设置。因此,“使用 default”不是足够的审计信息,回执里应固化最终解析出的值。

一个最小接入顺序

  1. 先只对高风险目录、跨服务修改或大 PR 触发审查。
  2. 第一阶段保持非阻塞,统计重复率、过期率和失败率。
  3. 固化状态机和证据包,再把明确的阻塞发现接入门禁。
  4. 任何覆盖范围未知或结果过期的情况,回退人工复核。

AI 审查 API 的价值在于可编排,但可编排也意味着必须面对分布式系统的基本问题。先把幂等、快照绑定、终态和回执做好,才谈得上让它稳定进入 CI。

来源

  • GitHub Changelog:Copilot code review: API support and new default effort level(2026-10-02)
  • GitHub Changelog:Dynamic workflows in Copilot CLI and the Copilot app(2026-10-01)