---
title: "用 CLI Agent 做代码审查"
wiki: cli
category: "使用模式"
slug: agent-code-review
url: https://learnagent.wiki/cli/cards/agent-code-review
tags: ["code review", "PR review", "Claude Code", "gh CLI", "工作流"]
last_updated: 2026-04-22
reading_time: 16
---

> 代码审查（Code Review）是把"另一个人读一遍你写的代码"这件事制度化。它的目的不是装样子，而是在合并之前抓出三类问题：**会上线就出事的 bug**、**没考虑到的边界情况**、**今天不改将来一定会还回来的技术债**。CLI Agent 做代码审查的核心价值不是替代人，而是把"每次 PR 都跑一遍同样的 12 项检查表"这件事自动化——人类 reviewer 状态好的时候记得 9 项，状态差的时候记得 3 项，CLI Agent 永远是 12 项。

# 用 CLI Agent 做代码审查

## 基础概念

代码审查（Code Review）是把"另一个人读一遍你写的代码"这件事制度化。它的目的不是装样子，而是在合并之前抓出三类问题：**会上线就出事的 bug**、**没考虑到的边界情况**、**今天不改将来一定会还回来的技术债**。CLI Agent 做代码审查的核心价值不是替代人，而是把"每次 PR 都跑一遍同样的 12 项检查表"这件事自动化——人类 reviewer 状态好的时候记得 9 项，状态差的时候记得 3 项，CLI Agent 永远是 12 项。

为什么要在终端里做、而不是直接用平台内置的 AI 审查（GitHub Copilot Code Review、CodeRabbit、Graphite Reviewer 等）？三个原因：

1. **CLI Agent 能读你机器上的全量上下文**——`CLAUDE.md`、本地 `node_modules`、`.env.example`、未提交的草稿、最近 30 条 git log。云端审查只看到推上去的那个 diff，看不到"这个函数其实是上周临时占位准备删的"。
2. **提示词可以现场调**。云端审查的规则要在网页后台改，CLI 直接改 prompt、改 `REVIEW.md`、改 hook，下一秒生效。
3. **不交代码出门**。外审工具要 SaaS、要 GitHub App 权限、要给 OAuth scope；CLI Agent 把代码、diff、提示词都留在你的终端会话里。

它和 SonarQube / Coverity / DeepSource 这类**静态分析**工具也不一样。静态分析是"基于规则匹配"，能稳定抓 null pointer、未初始化、SQL 注入这种语法层面问题；CLI Agent 是"基于语义理解"，能看出"这个函数名叫 `markPaid`，但里面没有写数据库 commit"这种规则匹配抓不到的事。两者互补，不互斥——线上 CI 跑 SonarQube 兜底语法层，本地用 CLI Agent 兜底语义层。

### 核心要素

| 要素 | 作用 |
|------|------|
| **审查目标** | 一个 git diff，可以来自本地 `git diff main...HEAD`、也可以来自远程 PR `gh pr diff <num>` |
| **上下文供给** | `CLAUDE.md` / `REVIEW.md` / 仓库目录树 / 改动文件的相邻代码 / git log；上下文越准，假阳性越少 |
| **提示词模板** | 固定结构：变更概览 → 分文件分点评 → 严重度分级 → 推荐动作。结构稳定才方便后续脚本消费 |
| **严重度分级** | Critical / Major / Minor / Nit 四档（业界主流，Claude Code 官方简化为 Important / Nit / Pre-existing 三档） |
| **产出格式** | 终端 Markdown / JSON 两种：人看 Markdown，CI 消费 JSON 做门禁 |
| **PR 衔接** | 通过 `gh pr comment` / `gh pr review` 把审查结果回写到 GitHub PR 页面 |

### 一次完整审查的流程

```mermaid
sequenceDiagram
    participant Dev as 开发者
    participant CLI as CLI Agent (Claude Code 等)
    participant Git as 本地 git / gh CLI
    participant GH as GitHub PR

    Dev->>CLI: /review 或自定义 review 提示词
    CLI->>Git: gh pr diff 123 / git diff main...HEAD
    Git-->>CLI: 返回 diff + 改动文件列表
    CLI->>Git: 读 CLAUDE.md / REVIEW.md / 相邻代码
    Git-->>CLI: 返回上下文
    Note over CLI: 按提示词模板分析<br/>分文件、分严重度<br/>过滤假阳性
    CLI-->>Dev: 输出 Markdown 审查报告
    Dev->>Dev: 决定是否回写 PR
    Dev->>CLI: /review --comment（可选）
    CLI->>GH: gh pr comment / inline review
    GH-->>Dev: PR 页面出现审查评论
```

注意几件事：

- 这是一个**人在回路**的工作流，不是"Agent 全自动审完直接 merge"。最后一步"决定是否回写 PR"必须由人按。
- 读 `CLAUDE.md` / 相邻代码这一步不能省——少了这一步，Agent 会建议你"加个错误处理吧"，但你这个函数本来就在外层 try/catch 里。
- 严重度分级一定要让 Agent 在产出里写明白，不然你看到 20 条评论分不清哪条是真要修、哪条是 nit，等于没审。

## 基础用法

下面给两个最常用的场景。第一个是"PR 还没推上去，先在本地审一遍"；第二个是"别人开了个 PR，我用 CLI Agent 帮自己提前过一遍"。两个场景共用同一套提示词模板。

### 场景 A：本地 diff 审查（推 PR 之前）

最简单的做法：在仓库根目录起一个 Claude Code 会话，直接喂提示词。

```bash
# 1. 看一眼当前分支相对 main 的改动范围
git diff --stat main...HEAD

# 2. 把 diff 喂给 Claude Code 审一遍（也可以直接在交互模式下贴提示词）
claude -p "$(cat <<'EOF'
请对当前分支相对 main 的改动做一次代码审查，按以下结构输出：

## 1. 变更概览
- 一句话讲清这个 PR 在做什么
- 影响面：动了哪些模块/包
- 风险等级（low / medium / high）

## 2. 分文件审查
对每个改动文件按下面格式输出：

### <文件路径>
- [严重度] <一句话问题描述>
  - 行号：<L<起>-L<止>>
  - 原因：<为什么是问题，引用 CLAUDE.md/规范条款时直接抄原文>
  - 建议：<具体改法，能给 diff 就给 diff>

严重度只用四档：Critical / Major / Minor / Nit
- Critical：合并后会上线出事（数据丢失、鉴权绕过、崩溃）
- Major：影响正确性或可维护性（边界没考虑、命名误导、测试缺失）
- Minor：风格/重构建议
- Nit：可改可不改

## 3. 推荐动作
- 必须修改（blocker 列表）
- 建议修改（major/minor 列表）
- 可忽略（nit 列表）

约束：
- 只看 git diff main...HEAD 范围内的改动
- 不要重复 lint/format 工具能抓的问题
- 没有把握的发现宁可不报，假阳性比漏报代价大
- 引用代码时必须给出文件:行号
EOF
)"
```

预期产出（截选）：

```markdown
## 1. 变更概览
- 给订单接口加上幂等键支持，避免重复下单
- 影响：src/order/service.ts、src/order/repository.ts、对应单测
- 风险等级：medium（涉及钱，但只新增不改老链路）

## 2. 分文件审查
### src/order/service.ts
- [Critical] 幂等键命中后直接返回旧订单，但没校验请求 body 是否一致
  - 行号：L88-L102
  - 原因：CLAUDE.md 第 4.2 条要求"幂等键 + 不同 payload 视为冲突"
  - 建议：命中后比对 payload hash，不一致则返回 409
- [Major] 新加的 `idempotencyKey` 入参没有长度校验
  ...

## 3. 推荐动作
- 必须修改：service.ts L88-L102（幂等冲突检测）
- 建议修改：service.ts L75 长度校验、repository.ts L40 索引补 unique
- 可忽略：测试用例命名风格
```

如果你用的是 Claude Code 而不是其它 CLI，可以直接调官方内置的 `/review` skill，它会跑一套多 agent 并行的审查管线，产出和上面结构基本一致。

### 场景 B：远程 PR 审查（gh CLI + Claude Code 串起来）

把上面的 prompt 包成一个 shell 函数，专门审远程 PR：

```bash
# ~/.bashrc 或 ~/.zshrc
review_pr() {
  local pr_num="$1"
  if [ -z "$pr_num" ]; then
    echo "用法: review_pr <PR 号>" >&2; return 1
  fi

  # 1. 用 gh CLI 拉 PR 元信息和 diff
  local pr_meta diff
  pr_meta=$(gh pr view "$pr_num" --json title,body,author,baseRefName,headRefName,files)
  diff=$(gh pr diff "$pr_num")

  # 2. 把 PR 元信息 + diff 一起喂给 Claude Code
  claude -p "请审查下面这个 PR：

PR 元信息（JSON）：
\`\`\`json
$pr_meta
\`\`\`

完整 diff：
\`\`\`diff
$diff
\`\`\`

按以下结构输出审查结果（结构同本地审查模板）：
1. 变更概览
2. 分文件审查（带严重度 Critical/Major/Minor/Nit）
3. 推荐动作

要求引用 PR 标题/描述里声明的目标，判断改动是否对得上 PR 的初衷。
"
}
```

把审查结果回写到 PR 上，有两种粒度：

```bash
# 粒度 1：作为整段 PR 评论回写（最常用，gh pr comment 原生支持）
review_pr 123 | tee /tmp/review.md
gh pr comment 123 --body-file /tmp/review.md

# 粒度 2：走 review 体系（带 approve / request-changes 状态）
gh pr review 123 --comment --body-file /tmp/review.md     # 只评论不阻拦
gh pr review 123 --request-changes --body "见上文 Critical 项"  # 显式 request changes
gh pr review 123 --approve --body "LGTM, ship it"          # 通过

# 粒度 3：行级 inline 评论（gh CLI 原生不支持，需要 gh extension 或 gh api 直调）
gh extension install agynio/gh-pr-review   # 一次性安装，提供 inline 评论
```

> **官方背景小知识**：Anthropic 也在云端提供托管的 Code Review 服务（仓库装 GitHub App 后，PR 一打开就自动跑），它的产出走"🔴 Important / 🟡 Nit / 🟣 Pre-existing"三色严重度，而且会把每次 review 写到名为 `Claude Code Review` 的 check run 里——可以通过 `gh api repos/OWNER/REPO/check-runs/<id>` 拉到机器可读的 severity tally。本卡聚焦本地 CLI 自助审查，云端托管和本地 CLI 是同一套思路、不同部署形态。

### 让产出可被 CI 消费的 JSON 模板

如果你想做"Critical 数 ≥ 1 就阻断 merge"这类硬门禁，让 Agent 直接产 JSON：

```bash
claude -p "审查 git diff main...HEAD，只输出 JSON，不要任何解释文字。schema 如下：
{
  \"summary\": \"一句话变更说明\",
  \"risk\": \"low|medium|high\",
  \"findings\": [
    {
      \"file\": \"src/foo.ts\",
      \"line_start\": 12,
      \"line_end\": 18,
      \"severity\": \"critical|major|minor|nit\",
      \"category\": \"bug|security|perf|style|test|docs\",
      \"message\": \"问题描述\",
      \"suggestion\": \"具体改法\"
    }
  ]
}" | jq '.findings | map(select(.severity == "critical")) | length'
# 输出 0 → 通过；>0 → CI 退出非 0
```

## 同类工具对比

| 维度 | 人工审查 | IDE 内 AI 审查（Cursor / Copilot Chat） | CLI Agent 审查（本卡） | 平台内置 AI 审查（GitHub Copilot CR / CodeRabbit） |
|------|---------|---------------------------------------|---------------------|--------------------------------------------------|
| 启动成本 | 高（需要 reviewer 排期） | 低（IDE 内一键） | 低（一条命令） | 零（PR 打开自动跑） |
| 上下文范围 | 看人，资深 reviewer 能联想全仓库 | 当前打开文件 + 编辑器索引的范围 | 全仓库 + git history + CLAUDE.md / REVIEW.md | 推到云端的 diff + 部分仓库快照 |
| 规则可定制性 | 写在团队 wiki 里，靠人记 | 改 IDE 设置 | 改提示词 / `REVIEW.md` / hook，立即生效 | 网页后台配规则，改完要等同步 |
| 假阳性控制 | 高（reviewer 自带判断） | 中 | 中-高（可写"宁可漏报不要假阳性"约束） | 低-中（默认追求覆盖率） |
| 产出回写到 PR | 直接评论 | 多数无 | 通过 `gh pr comment` / `gh pr review` 显式回写 | 自动以 bot 身份回写 |
| 隐私 | 高 | 中（看 IDE 厂商策略） | 高（除调模型 API 外不出本机） | 低（代码上云端 SaaS） |
| 适合场景 | 关键合并、架构变更 | 写代码过程中边写边问 | 推 PR 前自审、本地把关、敏感仓库 | 全员仓库的兜底审查、规模化 |

**核心区别一句话**：人工审查抓"判断与品味"，IDE AI 抓"我正在写的这一段对不对"，**CLI Agent 抓"这个 PR 整体能不能合"**，平台内置 AI 抓"所有 PR 都跑一遍的兜底"。这四档不互斥，重要 PR 通常四个都跑一遍。

## 常见误区

| 误区 | 准确理解 |
|------|---------|
| 以为 CLI Agent 审查可以直接全自动 merge | 永远要保留"人按合并键"这一步。Agent 抓得到 80% 的 bug，但漏掉的 20% 里可能藏的是上线就回滚的事故。Agent 是 reviewer，不是 approver |
| Prompt 写"帮我 review 一下" 就开干 | 这种宽泛 prompt 出的几乎都是泛泛而谈的客套话。一定要在 prompt 里指定"产出结构 / 严重度分级 / 假阳性约束 / 引用代码必须带行号"，结构越死，产出越能用 |
| 只喂 diff，不喂上下文 | 只看 diff 等于让 reviewer 蒙眼看代码片段。`CLAUDE.md`、`REVIEW.md`、改动文件的整文件、最近 5 条相关 commit 都要给。Claude Code 内置 `/review` 之所以质量高，就是因为它默认会扫 `CLAUDE.md` 和相邻代码 |
| 漏审 git history | 改动看似无害，但配合最近几次 commit 才看得出问题（例如这次新加的字段刚好和上周删的字段同名）。审查时跑一句 `git log --oneline -20 -- <改动文件>` 喂给 Agent 是低成本高收益的动作 |
| 不分严重度，把所有发现一锅炖 | 没分级的审查报告等于没审。开发者看到 20 条评论会直接 close 掉。强制按 Critical / Major / Minor / Nit 分四档，并在末尾给"必须修 / 建议修 / 可忽略"三组动作清单 |
| 把 CLI Agent 审查替代静态分析 / 测试 | 不是替代关系。Lint / 类型检查 / 单测 / 静态分析这些 CI 该跑还是要跑，CLI Agent 审的是"语义层面 reviewer 才能抓的问题"。让 Agent 抓 lint 能抓的问题是浪费 token |
| 一次喂超大 diff（几千行） | 超过模型上下文窗口或者超出有效注意力范围，产出质量会断崖式下跌。大 PR 应该按文件 / 按 commit 拆分多次审查，最后做一次"跨文件耦合"的总结审查 |

## 优劣势分析

| 优势 | 劣势 |
|------|------|
| **结构稳定**：同一套 prompt 模板每次产出格式一致，下游脚本/CI 可以直接消费 | **token 成本不便宜**：一个中等 PR 的审查动辄几千到几万 token，跑 100 个 PR 是真金白银。Anthropic 官方托管 Code Review 公开报价是每次 PR 平均 $15-25 |
| **能读全量本地上下文**：CLAUDE.md、未提交草稿、git log 都在，云端审查看不到 | **依赖提示词质量**：prompt 写得糙，产出就泛泛而谈。提示词模板需要团队沉淀，不是一次写完不动 |
| **隐私可控**：除调模型 API 外，diff 不出本机；敏感仓库可以走自建 / 本地推理 | **大 PR 表现差**：超过几千行的 diff 会让 Agent 抓不住重点，需要拆分审查再做总结 |
| **规则可即时迭代**：发现假阳性多了就改 `REVIEW.md`，下一次生效 | **难处理跨仓库 / 跨服务的影响**：CLI Agent 默认只看一个仓库，微服务架构下"这个改动会不会影响下游"判断不出来 |
| **和 gh / git 原生工具链无缝衔接**：管道一接，审查结果直接回写 PR | **无 GUI 行级评论**：`gh pr comment` 只能整段回写，行级 inline 要装 `gh extension` 或直调 `gh api` |
| **可组合到自定义 workflow**：可作为 PreToolUse / Stop hook 的一环，做"每次 commit 前自审" | **不能替代人对架构和品味的判断**：Agent 抓得到 bug，抓不到"这个抽象本来就不该存在" |

## 思考题

<details>
<summary>初级：本地 git diff 审查 和 远程 gh pr diff 审查 在产出质量上会有什么差别？为什么？</summary>

**参考答案：**

通常**远程 gh pr diff 审查的产出会更好**，但前提是 prompt 里把 PR 元信息（标题、描述、author、base/head 分支）一起喂给 Agent。原因有两点：

1. **PR 标题和描述提供了"作者声明的目标"**。Agent 可以拿这个目标去验"diff 的实际改动是不是对得上声明"。本地 diff 审查时没有这个声明，Agent 只能从代码本身倒推意图，容易被命名误导。
2. **PR 描述里通常会写"为什么这么改 / 关联了哪个 issue / 已知风险"**。这些信息让 Agent 的判断更贴合上下文。比如 PR 描述写"这是临时 hack，下个 sprint 会重构"，Agent 就不会在这条临时代码上反复挑结构问题。

但反过来，本地 diff 审查也有独家优势：能看到**未提交的工作树状态**和**最近本地 commit**。比如你刚改了一半，跑本地审查能在推之前抓到问题，省一次推-审-改-推循环。

实践上的最佳节奏是：写完先跑本地 diff 审查→修一遍→推上去→再跑一次远程 PR 审查（这次带上 PR 描述）→修第二遍→请人 review。

</details>

<details>
<summary>中级：你的团队想把 CLI Agent 审查接进 CI，做"Critical 数 ≥ 1 就阻断 merge"的硬门禁。这件事可行吗？需要注意哪些坑？</summary>

**参考答案：**

**技术上可行，但默认不建议直接做硬门禁，更稳的做法是软门禁 + 人工 override 通道。**

可行的实现路径：

1. CI 里跑 `claude -p "...只输出 JSON..."` 让 Agent 产 JSON 报告。
2. `jq` 提取 `findings | map(select(.severity == "critical")) | length`。
3. 非 0 则 CI 退出非 0，触发 GitHub branch protection 阻断 merge。

需要避开的坑：

- **假阳性会卡死团队**：Agent 偶尔会把"看似 bug 实则正确"的代码标 Critical。一个误报就让 PR 卡住等人手动 override，开发体验非常差。建议初期只做"提示"不做"阻断"，等三个月观察假阳性率稳定低于 5% 再上硬门禁。
- **token 成本会翻倍**：CI 每次 push 都跑一次审查，月底账单会让人怀疑人生。可以加条件：只在 PR 状态变化（opened / synchronize）时跑，drafts 不跑；或者只对涉及关键目录（auth、payment、migration）的 PR 跑。
- **非确定性问题**：同一个 diff 跑两次结果可能不完全一样。硬门禁要求结果稳定，要么把模型温度设到 0（Claude API 里 `temperature: 0`），要么允许"重跑一次取并集"。
- **必须有 override 通道**：`REVIEW.md` 里写明"在 commit message 加 `[skip-review]` 可绕过"，或在 PR 评论 `@claude review skip` 触发跳过。否则真出现假阳性时只能改 prompt 重跑，整个团队会被堵住。
- **Critical 的定义要团队共识**：默认提示词里 Critical 的定义可能和你团队不一致。必须在 `REVIEW.md` 里写清"在我们仓库，Critical 仅指：1) 数据丢失 2) 鉴权绕过 3) 上线即崩"，越窄越好。

更稳的折衷做法：CI 跑审查 → 输出 JSON → 写到 PR 评论里 → 不阻断 merge。让人看着这份报告决定要不要改、要不要合。这是 Anthropic 官方托管 Code Review 默认的做法（check run 永远是 neutral 结论），值得借鉴。

</details>

<details>
<summary>进阶：把 CLI Agent 审查和静态分析（SonarQube/CodeQL）、人工审查放在同一条流水线里，怎样设计角色边界才能不互相打架？</summary>

**参考答案：**

三者的本质能力不同，分工应该按"抓什么、什么时候抓、抓不到怎么办"来切：

| 角色 | 抓什么 | 何时跑 | 失效兜底 |
|------|-------|--------|---------|
| 静态分析（SonarQube/CodeQL） | 规则可枚举的语法/安全模式（SQL 注入、空指针、未使用变量、CWE Top 25 等） | 每次 push 跑 CI | Agent 审查 + 人工 |
| CLI Agent 审查 | 语义层判断（"函数名和实现不一致"、"边界没考虑"、"违反 CLAUDE.md 中的领域约定"） | PR open / synchronize / 本地推前 | 人工 |
| 人工审查 | 架构、品味、领域判断（"这个抽象不该存在"、"和上周那个改动有冲突"） | 重要 PR / 关键模块 | 无 |

避免打架的几条设计原则：

1. **强制 Agent 不报 lint/静态分析能抓的事**。在提示词里直接写"不要重复 ESLint / mypy / SonarQube 能抓的问题"，Anthropic 官方的 review prompt 里也有同样约束。否则一份审查报告里 80% 是已经被 lint 抓过的废话。
2. **静态分析的产出要让 Agent 看见**。CI 里先跑静态分析，把结果作为上下文喂给 Agent："已知静态分析报了下面这些问题，请勿重复，重点找静态分析覆盖不到的语义层问题。" 这样 Agent 不再做无用功。
3. **人工审查只在 Critical / 架构层介入**。让 Agent 先把 nit 全清完、major 自动建议提交，人类 reviewer 只看 Critical 那几条 + 整体设计。这样 reviewer 的注意力不被稀释。
4. **结果合流到一个 PR 评论里**。三个产出三条评论开发者看不过来。设计一个聚合脚本：拉静态分析 SARIF + Agent JSON + 人工 inline 评论，归并去重，按严重度排序，发一条"统一审查报告"。
5. **失败要透明**。Agent 跑挂了不要装作没事，CI 里显式写"Agent review 跳过：超时"，否则团队会以为审过了，实际没有。Anthropic 官方 Code Review 在挂掉时也会把 check run 结论改为 neutral 但显式写错误信息，是值得学的做法。

最后一条非技术原则：**CLI Agent 审查不能用来 PUA 人类 reviewer**。"Agent 都 LGTM 了你为什么还挑刺"是反模式。Agent 的判断不替代 reviewer 的最终签字权，三者关系是"互相补盲"，不是"上级评下级"。

</details>

## 参考资料

1. Claude Code 官方 Code Review 文档（含触发命令、严重度三色、CLAUDE.md/REVIEW.md 自定义、check run 机器可读输出）：<https://code.claude.com/docs/en/code-review>（查询日期 2026-04-22）
2. Claude Code 官方 `code-review` plugin 仓库（多 agent 并行 review 提示词、产出格式、假阳性过滤策略）：<https://github.com/anthropics/claude-code/blob/main/plugins/code-review/commands/code-review.md>
3. GitHub CLI `gh pr review` 手册（approve / request-changes / comment 三种 review 类型与 flag 用法）：<https://cli.github.com/manual/gh_pr_review>
4. GitHub CLI `gh pr` 全部子命令索引（`pr view` / `pr diff` / `pr comment` / `pr review` / `pr checks`）：<https://cli.github.com/manual/gh_pr>
5. GitHub CLI `gh pr comment` 手册（PR 整段评论的 `--body` / `--body-file` 用法）：<https://cli.github.com/manual/gh_pr_comment>
6. `gh-pr-review` 扩展（CLI 行级 inline review 与 LLM 适配，弥补 `gh pr comment` 不支持行级评论）：<https://github.com/agynio/gh-pr-review>
7. Netlify 工程团队的 Feedback Ladders（业界主流 blocker/critical/major/minor/nit 五档分级实践）：<https://www.netlify.com/blog/2020/03/05/feedback-ladders-how-we-encode-code-reviews-at-netlify/>
8. "Nit" 在 code review 里的语义与使用场景：<https://www.augmentcode.com/guides/what-does-nit-mean-in-code-review>
9. Anthropic Claude Code Security Review GitHub Action（同源思路：用 Claude 审 PR 安全问题，可对照本卡的"普通 review" 流程）：<https://github.com/anthropics/claude-code-security-review>

---
*Source: https://learnagent.wiki/cli/cards/agent-code-review*
*Markdown mirror of https://learnagent.wiki, served as text/markdown for LLM ingestion.*