Skip to content
Published at:

第 27 章:场景八:CI/CD 集成

在之前的七个实战场景中,我们都是在本地开发环境中使用 Claude Code——在编辑器里对话、在终端里执行命令、在 Diff 视图中审查变更。这些场景覆盖了个人开发者的日常工作流。但 Claude Code 的能力不止于此:它还可以被嵌入到 CI/CD 流水线中,在无人值守的环境下自动完成代码审查、Issue 分类、报告生成等任务。

本章将带你走进 Claude Code 的自动化场景——把 AI Agent 部署到 CI/CD 流程中,让它成为团队的 24/7 自动化助手。

本章目标:掌握在 CI/CD 环境中集成 Claude Code 的完整方案,包括自动化 PR Review、Issue 分类、非交互模式使用,以及 CI 环境下的最佳实践。

场景描述

你所在的团队维护一个中型 SaaS 项目,技术栈是 TypeScript + React + Node.js,有 20 多位开发者,每天平均有 10 到 15 个 PR 需要 Review。团队只有 3 位 Senior Engineer 负责主要审查工作,Review 队列经常积压,平均等待时间超过 4 小时,有时甚至要等到第二天。

与此同时,GitHub Issues 也在不断增长——每天新增 5 到 8 个 Issue,但没人专门做分类和分配,很多 Bug Report 缺少复现步骤,Feature Request 和问题咨询混在一起,导致重要的 Bug 被淹没。

团队的 Tech Lead 提出了一个想法:**能否让 Claude Code 参与到这些流程中?**不是替代人工,而是做第一道"筛子"——自动检查明显的代码问题、自动分类 Issue,让人类 Reviewer 把精力集中在真正需要深度判断的事情上。

这就是本章要解决的问题。我们将从零开始,搭建一套基于 Claude Code 的 CI/CD 自动化方案。

27.1 Step 1: Claude Code 在 CI 中的角色

在动手写配置之前,必须先明确一个核心原则:Claude Code 在 CI 中是辅助者,不是决策者。它不做最终判断,不做 Merge 决策,不做架构评审。它的定位是"自动化初步筛查",帮人类过滤掉那些机械性的、可以靠规则和模式识别完成的工作。

能力边界

在 CI 环境中,Claude Code 擅长以下任务:

适合 CI 自动化的任务说明
代码风格检查发现与项目规范不一致的写法
常见 Bug 模式识别空指针、未处理的 Promise、竞态条件等
安全漏洞扫描硬编码密钥、SQL 注入、XSS 等常见漏洞
测试覆盖率提醒识别新增代码是否有对应测试
Issue 自动分类判断类型(bug/feature/docs)并打标签
变更摘要生成为 PR 自动生成变更说明

Claude Code 不适合在 CI 中承担的任务:

不适合 CI 自动化的任务原因
业务逻辑正确性判断需要深入理解领域知识
架构设计合理性评估需要全局视角和长期经验
性能瓶颈的精确分析需要实际运行和 profiling 数据
决定是否 Merge这是人的决策权
复杂安全威胁建模需要安全专家的系统性分析

与人工 Review 的分工

一个健康的 CI 流程应该像这样分层:

PR 提交

  ├─→ [自动化层] Claude Code 初步筛查 (5 分钟内)
  │     ├─ 代码风格检查
  │     ├─ 常见 Bug 扫描
  │     ├─ 安全漏洞检测
  │     └─ 测试覆盖率检查

  ├─→ [自动化层] CI 构建与测试 (10 分钟内)
  │     ├─ 编译检查
  │     ├─ 单元测试
  │     └─ Lint 检查

  └─→ [人工层] Senior Engineer 深度 Review (按优先级排程)
        ├─ 业务逻辑审查
        ├─ 架构合理性判断
        └─ 最终 Merge 决策

关键理念:自动化层是非阻塞的(advisory),即使 Claude Code 的 Review 没跑完,也不应该阻止 CI 通过。它产生的评论是参考性质的,供 Reviewer 参考,而非 Merge 的前置条件。

27.2 Step 2: 自动化 PR Review

现在我们来实现第一个自动化场景:每当有新的 PR 提交,Claude Code 自动读取变更内容并发表 Review 评论。

27.2.1 GitHub Actions 基础配置

最简单的集成方式是使用 GitHub Actions。以下是一个基础配置:

yaml
# .github/workflows/claude-review.yml
name: Claude Code Review

on:
  pull_request:
    types: [opened, synchronize, reopened]

jobs:
  review:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write

    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0  # 获取完整历史,确保 diff 正确

      - name: Claude Code PR Review
        uses: anthropics/claude-code-action@v1
        with:
          prompt: |
            请审查这个 Pull Request,重点关注:
            1. 潜在的 Bug 和逻辑错误
            2. 安全漏洞(硬编码密钥、注入风险等)
            3. 代码质量问题(命名、结构、重复代码)
            4. 缺失的错误处理
            5. 测试覆盖情况
            
            请在评论中使用中文,对每个发现的问题提供具体位置和建议修复方案。
          model: claude-sonnet-4-20250514
          max-tokens: 4000

27.2.2 非交互模式的关键配置

CI 环境中没有人在终端前,Claude Code 必须运行在非交互模式下。核心配置参数如下:

参数说明CI 推荐值
--non-interactive禁止任何交互式提示必须开启
--output-format json输出 JSON 格式,便于程序解析推荐
--max-turns限制 Agent 最大执行轮次10-15
--model指定使用的模型sonnet(性价比最优)
--permission-mode权限模式bypass 或精细 allow 列表

在 CLI 中,非交互模式的使用方式:

bash
# 基础非交互模式
claude -p "Review this PR for bugs and security issues" \
  --output-format json \
  --max-turns 10 \
  --model claude-sonnet-4-20250514

# 管道模式:将 diff 内容通过管道传入
git diff origin/main...HEAD | claude -p "Review the following diff for bugs"

# 文件输入模式:从文件读取 prompt
claude -p "$(cat .github/claude-prompts/pr-review.txt)" \
  --output-format json

27.2.3 权限配置

CI 环境中的权限配置需要特别注意——既要让 Claude Code 能完成 Review 工作,又要防止它在无人值守时执行危险操作。

推荐使用精细化的 allow 列表,而非直接使用 bypass 模式:

json
// .claude/settings.json (CI 环境)
{
  "permissions": {
    "allow": [
      "Bash(git diff:*)",
      "Bash(git log:*)",
      "Bash(cat:*)",
      "Read(*)",
      "Glob(*)",
      "Grep(*)"
    ],
    "deny": [
      "Bash(rm:*)",
      "Bash(git push:*)",
      "Bash(git commit:*)",
      "Bash(curl:*)",
      "Bash(wget:*)",
      "Write(*)",
      "Edit(*)"
    ]
  }
}

这个配置的核心思想:

  • 允许只读操作:可以读文件、查看 diff、搜索代码
  • 禁止任何写入:不能编辑文件、不能提交、不能推送
  • 禁止网络操作:不能在 CI 环境中发起额外的网络请求

27.2.4 成本控制

CI 中的每次运行都在花钱,必须严格控制成本:

yaml
# GitHub Actions 中的成本控制示例
- name: Claude Code Review
  uses: anthropics/claude-code-action@v1
  with:
    prompt: "Review this PR for bugs and security issues"
    max-tokens: 4000        # 限制每次 Review 的最大 token 量
    max-turns: 8            # 限制 Agent 思考轮次
    model: claude-haiku-4-5-20250514  # 小 PR 使用轻量模型
    
  # 条件执行:只对大型 PR 使用 Sonnet
  - name: Deep Review (Large PR)
    if: ${{ github.event.pull_request.changed_files > 10 }}
    uses: anthropics/claude-code-action@v1
    with:
      prompt: "Deep review this large PR for bugs and security"
      model: claude-sonnet-4-20250514
      max-tokens: 8000

成本估算参考

PR 规模推荐模型预计 Token 消耗预估成本
小(< 5 文件)Haiku~2000 tokens< $0.02
中(5-20 文件)Sonnet~5000 tokens~$0.05
大(> 20 文件)Sonnet~10000 tokens~$0.10

成本控制最佳实践:为月度 Review 费用设置预算告警。如果团队每天有 15 个 PR,全部使用 Sonnet 深度审查,月成本约 $15-25。这远低于一个 Senior Engineer 一小时的时间成本。

27.2.5 生成 PR 评论

Claude Code 的 Review 结果会自动以评论形式发布到 PR 中。一个典型的 Review 评论结构:

#### 🤖 Claude Code 自动 Review

> 这是 AI 自动生成的初步审查,仅供参考。建议人工确认后再做修改。

**潜在 Bug:**
- `src/auth/login.ts:42` - `user` 可能为 null,缺少空值检查
  建议:在访问 `user.profile` 前添加 `if (!user) return;`

**安全问题:**
- `src/config.ts:15` - API Key 直接硬编码在代码中
  建议:使用环境变量 `process.env.API_KEY`

**代码质量:**
- `src/utils/format.ts:20-35` - 函数过长(15 行),建议拆分为 2 个独立函数
- 变量名 `d` 不够清晰,建议改为 `formattedDate`

---
_由 Claude Code (Sonnet 4) 审查 | Token 消耗: 3420 | 耗时: 12.3s_

27.2.6 完整工作流示例

以下是一个生产可用的完整 PR Review 工作流:

yaml
# .github/workflows/claude-review.yml
name: Claude Code PR Review

on:
  pull_request:
    types: [opened, synchronize, reopened]
    paths-ignore:
      - 'docs/**'
      - '*.md'

concurrency:
  group: claude-review-${{ github.event.pull_request.number }}
  cancel-in-progress: true

jobs:
  claude-review:
    runs-on: ubuntu-latest
    timeout-minutes: 10

    permissions:
      contents: read
      pull-requests: write

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

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

      - name: Install Claude CLI
        run: npm install -g @anthropic-ai/claude-code

      - name: Get PR Diff
        id: diff
        run: |
          git diff origin/${{ github.base_ref }}...HEAD > /tmp/pr.diff
          echo "diff_size=$(wc -l < /tmp/pr.diff)" >> $GITHUB_OUTPUT

      - name: Claude Code Review (Small PR)
        if: ${{ steps.diff.outputs.diff_size < 500 }}
        run: |
          claude -p "$(cat << 'EOF'
          请审查以下 PR 变更。关注:
          1. 潜在的 Bug 和逻辑错误
          2. 安全漏洞
          3. 代码质量问题
          4. 缺失的错误处理
          请用中文输出审查结果,格式为 Markdown。
          EOF
          )" \
            --model claude-haiku-4-5-20250514 \
            --max-tokens 3000 \
            --output-format json \
            --non-interactive \
            < /tmp/pr.diff \
            > /tmp/review.json

      - name: Claude Code Review (Large PR)
        if: ${{ steps.diff.outputs.diff_size >= 500 }}
        run: |
          claude -p "$(cat << 'EOF'
          请深入审查以下大型 PR 变更。关注:
          1. 潜在的 Bug 和逻辑错误
          2. 安全漏洞
          3. 代码质量与架构问题
          4. 缺失的错误处理
          5. 性能隐患
          请用中文输出详细审查结果。
          EOF
          )" \
            --model claude-sonnet-4-20250514 \
            --max-tokens 8000 \
            --output-format json \
            --non-interactive \
            < /tmp/pr.diff \
            > /tmp/review.json

      - name: Post Review Comment
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const review = JSON.parse(fs.readFileSync('/tmp/review.json', 'utf8'));

            const body = `## 🤖 Claude Code 自动 Review

            > 这是 AI 自动生成的初步审查,仅供参考。

            ${review.result || review.content}

            ---
            _自动审查 | 模型: ${review.model || 'Claude'} | Token: ${review.usage?.input_tokens || 0}+${review.usage?.output_tokens || 0}_
            `;

            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: body
            });

27.3 Step 3: 自动化 Issue 分类

PR Review 之外,另一个高价值的 CI 自动化场景是 Issue 分类。手动分类 Issue 是一件枯燥但又不得不做的事——每天花 30 分钟判断 Issue 类型、打标签、分配负责人,累计下来是很大的人力成本。

27.3.1 Issue 分类工作流

yaml
# .github/workflows/claude-issue-triage.yml
name: Claude Code Issue Triage

on:
  issues:
    types: [opened]

jobs:
  triage:
    runs-on: ubuntu-latest
    timeout-minutes: 5

    permissions:
      issues: write

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Claude Code Issue Triage
        uses: anthropics/claude-code-action@v1
        with:
          prompt: |
            分析以下 GitHub Issue,请完成:
            1. 判断类型:bug / feature / documentation / question
            2. 如果是 bug,判断严重程度:critical / major / minor
            3. 根据问题内容,推荐合适的负责人(从 CODEOWNERS 中匹配)
            4. 如果需要更多信息,生成一个友善的追问回复
            
            输出格式(JSON):
            {
              "type": "bug|feature|documentation|question",
              "severity": "critical|major|minor|null",
              "suggested_labels": ["label1", "label2"],
              "suggested_assignee": "username",
              "needs_more_info": true|false,
              "auto_reply": "回复内容"
            }
          max-tokens: 2000
          model: claude-haiku-4-5-20250514

27.3.2 智能标签与分配

Claude Code 读取 Issue 内容后,会根据预定义的规则进行分类:

Issue 分类决策树:

Issue 内容

  ├─ 包含 "报错" / "crash" / "异常" / "不工作"
  │   └─→ type: bug
  │       ├─ 影响核心功能 → severity: critical
  │       ├─ 影响常用功能 → severity: major
  │       └─ 影响边缘功能 → severity: minor

  ├─ 包含 "希望" / "建议" / "能否支持" / "新增"
  │   └─→ type: feature

  ├─ 包含 "文档" / "Wiki" / "说明" / "README"
  │   └─→ type: documentation

  └─ 包含 "怎么" / "如何" / "?"
      └─→ type: question

推荐负责人的逻辑:Claude Code 会读取项目的 CODEOWNERS 文件、最近提交记录、以及 Issue 中提到的文件路径,综合推断最合适的负责人。例如:

  • Issue 提到 src/auth/ → 推荐认证模块的 Owner
  • Issue 提到 src/payment/ → 推荐支付模块的 Owner
  • Bug 严重程度为 critical → 推荐 Tech Lead

27.3.3 自动回复模板

对于信息不完整的 Issue,Claude Code 可以生成友善的追问回复,替维护者节省沟通成本:

🤖 自动回复模板(信息不足的 Bug Report):

---
感谢提交 Issue!为了更好地定位问题,能否补充以下信息:

1. **复现步骤**:请描述从打开应用开始到问题出现的完整操作步骤
2. **预期行为**:你期望发生什么?
3. **实际行为**:实际发生了什么?(包括错误信息截图)
4. **环境信息**:
   - 操作系统版本:
   - 浏览器版本(如适用):
   - 应用版本:

补充这些信息后,我们会尽快排查。感谢你的配合!

---
_这是自动消息。如需人工协助,请 @ 团队成员。_

27.3.4 完整的 Issue Triage 脚本

yaml
# .github/workflows/claude-issue-triage.yml (完整版)
name: Claude Code Issue Triage

on:
  issues:
    types: [opened]

jobs:
  triage:
    runs-on: ubuntu-latest
    timeout-minutes: 5

    permissions:
      issues: write
      contents: read

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Install Dependencies
        run: |
          npm install -g @anthropic-ai/claude-code
          sudo apt-get install -y jq  # JSON 解析工具

      - name: Get Issue Content
        id: issue
        run: |
          echo "title=${{ github.event.issue.title }}" >> $GITHUB_OUTPUT
          echo "body<<ISSUE_BODY" >> $GITHUB_OUTPUT
          echo "${{ github.event.issue.body }}" >> $GITHUB_OUTPUT
          echo "ISSUE_BODY" >> $GITHUB_OUTPUT

      - name: Claude Code Triage
        id: triage
        run: |
          RESULT=$(claude -p "分析这个 GitHub Issue:

          标题: ${{ steps.issue.outputs.title }}
          内容: ${{ steps.issue.outputs.body }}

          请判断类型(bug/feature/documentation/question)和严重程度,
          推荐标签和负责人。输出纯 JSON。" \
            --model claude-haiku-4-5-20250514 \
            --max-tokens 1000 \
            --output-format json \
            --non-interactive)

          echo "type=$(echo $RESULT | jq -r '.type')" >> $GITHUB_OUTPUT
          echo "severity=$(echo $RESULT | jq -r '.severity')" >> $GITHUB_OUTPUT
          echo "labels=$(echo $RESULT | jq -r '.suggested_labels | join(",")')" >> $GITHUB_OUTPUT
          echo "assignee=$(echo $RESULT | jq -r '.suggested_assignee')" >> $GITHUB_OUTPUT
          echo "needs_info=$(echo $RESULT | jq -r '.needs_more_info')" >> $GITHUB_OUTPUT
          echo "reply=$(echo $RESULT | jq -r '.auto_reply')" >> $GITHUB_OUTPUT

      - name: Apply Labels
        uses: actions/github-script@v7
        with:
          script: |
            const labels = '${{ steps.triage.outputs.labels }}'
              .split(',')
              .filter(l => l)
              .map(l => l.trim());

            if (labels.length > 0) {
              await github.rest.issues.addLabels({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: context.issue.number,
                labels: labels
              });
            }

      - name: Assign Issue
        if: ${{ steps.triage.outputs.assignee != 'null' }}
        uses: actions/github-script@v7
        with:
          script: |
            await github.rest.issues.addAssignees({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              assignees: ['${{ steps.triage.outputs.assignee }}']
            });

      - name: Post Auto Reply
        if: ${{ steps.triage.outputs.needs_info == 'true' }}
        uses: actions/github-script@v7
        with:
          script: |
            const reply = `${{ steps.triage.outputs.reply }}`;
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: reply
            });

27.4 Step 4: 非交互模式的使用

非交互模式(Non-interactive Mode)是 Claude Code 在 CI 环境中最核心的运行模式。前面的配置中已经多次出现 --non-interactive,本节深入讲解其原理和最佳实践。

27.4.1 什么是非交互模式

正常情况下,Claude Code 是一个交互式工具——它会提问、等待你的确认、展示 Diff 让你 Accept/Reject。但在 CI 环境中,没有人在屏幕前等待,所有这些交互步骤都会导致流程卡死。

非交互模式改变了 Claude Code 的行为:

行为交互模式非交互模式
权限确认弹出确认对话框根据配置自动 allow/deny
文件编辑展示 Diff 等待 Accept直接输出结果,不修改文件
追问可以反问用户基于已有信息做出最佳判断
输出格式流式 Markdown结构化 JSON

27.4.2 三种非交互调用方式

方式一:CLI 参数模式

最直接的用法,通过 -p 传入 prompt:

bash
claude -p "分析这个代码库的技术栈" \
  --output-format json \
  --max-turns 5 \
  --model claude-sonnet-4-20250514

方式二:管道模式

将内容通过标准输入传入:

bash
# 传入文件内容
cat src/app.ts | claude -p "解释这段代码的功能" --output-format json

# 传入 git diff
git diff HEAD~1 | claude -p "总结这次提交的变更" --output-format json

# 传入构建日志
npm run build 2>&1 | claude -p "分析构建错误的原因" --output-format json

方式三:文件输入模式

将复杂的 prompt 写在文件中,运行时加载:

bash
# 准备 prompt 文件
cat > /tmp/review-prompt.txt << 'EOF'
请审查以下代码变更,关注:
1. 潜在的 Bug
2. 安全问题
3. 性能隐患
4. 与项目现有代码风格的一致性

输出格式:
- 每个问题一行,格式为 "[严重程度] 文件:行号 - 问题描述"
- 严重程度分为: CRITICAL / WARNING / INFO
EOF

# 执行审查
claude -p "$(cat /tmp/review-prompt.txt)" \
  --output-format json \
  < /tmp/pr.diff \
  > /tmp/review-result.json

27.4.3 解析 JSON 输出

在 CI 脚本中,你需要解析 Claude Code 的 JSON 输出。输出结构通常如下:

json
{
  "result": "审查结果文本...",
  "model": "claude-sonnet-4-20250514",
  "usage": {
    "input_tokens": 2340,
    "output_tokens": 1560,
    "cache_creation_input_tokens": 0,
    "cache_read_input_tokens": 0
  },
  "stop_reason": "end_turn",
  "tool_use": [
    {"tool": "Read", "file": "src/auth.ts", "status": "success"},
    {"tool": "Grep", "pattern": "TODO", "status": "success"}
  ]
}

使用 jq 解析的常用命令:

bash
# 提取审查结果文本
RESULT=$(cat /tmp/review-result.json | jq -r '.result')

# 提取 token 用量
INPUT_TOKENS=$(cat /tmp/review-result.json | jq -r '.usage.input_tokens')
OUTPUT_TOKENS=$(cat /tmp/review-result.json | jq -r '.usage.output_tokens')

# 计算总 token
TOTAL=$((INPUT_TOKENS + OUTPUT_TOKENS))
echo "本次审查消耗 $TOTAL tokens"

# 检查是否有工具调用
TOOL_COUNT=$(cat /tmp/review-result.json | jq '.tool_use | length')
echo "使用了 $TOOL_COUNT 个工具"

27.4.4 错误处理

CI 环境中 Claude Code 可能遇到的异常情况及处理策略:

bash
#!/bin/bash
# claude-review.sh - 带错误处理的 Claude Code 调用脚本

set -euo pipefail

MAX_RETRIES=3
RETRY_DELAY=10
TIMEOUT=300  # 5 分钟超时

review_code() {
  local retry=0

  while [ $retry -lt $MAX_RETRIES ]; do
    echo "Attempt $((retry + 1))/$MAX_RETRIES..."

    # 使用 timeout 防止无限等待
    if timeout $TIMEOUT claude -p "$PROMPT" \
      --output-format json \
      --max-tokens 4000 \
      --max-turns 10 \
      --non-interactive \
      < /tmp/pr.diff \
      > /tmp/review.json 2>/tmp/claude-error.log; then

      # 验证 JSON 输出是否有效
      if jq -e . /tmp/review.json > /dev/null 2>&1; then
        echo "Review completed successfully."
        return 0
      else
        echo "Invalid JSON output, retrying..."
      fi
    else
      EXIT_CODE=$?
      echo "Claude Code exited with code $EXIT_CODE"

      # 根据错误类型决定是否重试
      case $EXIT_CODE in
        124)  # timeout
          echo "Timeout after ${TIMEOUT}s"
          ;;
        429)  # rate limited
          echo "Rate limited, waiting ${RETRY_DELAY}s..."
          sleep $RETRY_DELAY
          RETRY_DELAY=$((RETRY_DELAY * 2))  # 指数退避
          ;;
        500|502|503)  # server error
          echo "Server error, retrying..."
          sleep $RETRY_DELAY
          ;;
        *)
          echo "Unexpected error, check /tmp/claude-error.log"
          cat /tmp/claude-error.log
          return 1
          ;;
      esac
    fi

    retry=$((retry + 1))
  done

  echo "All retries exhausted. Review failed."
  return 1
}

# 执行审查,失败时降级为简单模板
if ! review_code; then
  echo "Falling back to template-based review..."
  echo '{"result": "## AI Review Unavailable\n\nClaude Code was unable to complete the review. Please proceed with manual review.", "model": "fallback", "usage": {"input_tokens": 0, "output_tokens": 0}}' > /tmp/review.json
fi

常见错误处理策略总结

错误类型原因处理策略
API 超时请求时间过长设置 timeout,增大或拆分 prompt
Rate Limit (429)请求频率过高指数退避重试,最多 3 次
Server Error (5xx)Anthropic 服务异常等待后重试,超过重试次数则降级
Token 耗尽prompt + 输出超出上限减小 diff 范围,或使用更高效的 prompt
JSON 解析失败输出格式异常重试,或使用 Fallback 模板

27.5 Step 5: CI/CD 最佳实践

经过前面几个场景的实践,本节总结在 CI/CD 环境中使用 Claude Code 的六条核心最佳实践。

实践一:成本控制

在 CI 中,每一次触发都意味着一次 API 调用。如果不加控制,一个高频项目的月度 AI Review 费用可能轻松突破 $100。

控制策略

  1. 按 PR 规模分级使用模型:小 PR 用 Haiku,大 PR 用 Sonnet
  2. 设置跳过条件:文档变更、仅测试变更的 PR 跳过 AI Review
  3. 设置 Token 预算:每次 Review 的 max-tokens 不超过 4000-8000
  4. 月度预算告警:在 CI 脚本中累计 Token 用量,超过预算时发送通知
yaml
# 跳过不需要 AI Review 的场景
- name: Skip AI Review
  if: |
    contains(github.event.pull_request.labels.*.name, 'docs-only') ||
    contains(github.event.pull_request.labels.*.name, 'skip-ai-review')
  run: |
    echo "Skipping AI review for this PR"
    exit 0

实践二:结果验证

AI 的输出不是 100% 可靠的。在 CI 中使用 Claude Code 的输出之前,必须做格式验证。

bash
# 验证审查结果 JSON 结构
validate_review() {
  local file=$1

  # 检查 JSON 有效性
  if ! jq -e . "$file" > /dev/null 2>&1; then
    echo "ERROR: Invalid JSON"
    return 1
  fi

  # 检查必要字段
  if ! jq -e '.result' "$file" > /dev/null 2>&1; then
    echo "ERROR: Missing 'result' field"
    return 1
  fi

  # 检查结果不为空
  local result=$(jq -r '.result' "$file")
  if [ -z "$result" ] || [ "$result" = "null" ]; then
    echo "ERROR: Empty result"
    return 1
  fi

  # 检查结果长度合理(不超过 GitHub 评论限制 65536)
  local len=${#result}
  if [ $len -gt 60000 ]; then
    echo "WARNING: Result too long ($len chars), truncating..."
    jq ".result = (.result[:60000] + \"\n\n... (内容过长已截断)\")" "$file" > "${file}.tmp"
    mv "${file}.tmp" "$file"
  fi

  return 0
}

实践三:非阻塞设计

Claude Code 的 Review 必须是 advisory(参考性) 的,绝不能成为 PR Merge 的阻塞条件。

yaml
# ❌ 错误做法:将 AI Review 设为 Merge 必需检查
# 这会导致 AI 不稳定时阻塞整个团队的开发流程

# ✅ 正确做法:AI Review 与其他 CI 检查并行,总是通过
- name: AI Review (Non-blocking)
  continue-on-error: true  # 关键:失败也不阻塞 CI
  run: |
    claude -p "Review this PR" --output-format json > review.json

- name: Post Review Result
  if: always()  # 无论上一步成功或失败,都继续执行
  run: |
    # 如果有结果就发表,没有就跳过
    if [ -f review.json ]; then
      post_review_comment review.json
    fi

非阻塞设计原则

  • AI Review Job 不与 Required Checks 关联
  • 使用 continue-on-error: true 确保失败不影响 CI 状态
  • 使用 if: always() 确保后处理步骤始终执行

实践四:权限隔离

CI 环境使用的 API Key 应该有最小权限,与个人开发使用的 Key 分离。

bash
# CI 环境变量设置
# 使用独立的 CI 专用 API Key,而非个人 Key
export ANTHROPIC_API_KEY=${{ secrets.CI_CLAUDE_API_KEY }}

# 该 Key 的特性:
# - 独立的用量追踪
# - 独立的速率限制
# - 可以单独轮换而不影响开发者
# - 紧急情况下可以单独撤销

权限隔离清单

环境API Key 类型权限范围
本地开发个人 Key完整权限
CI/CDCI 专用 Key只读 + Review 评论
生产环境独立 Key(如有)严格限制

实践五:日志保留

保存 Claude Code 的完整交互日志,便于调试和审计。

yaml
- name: Claude Code Review with Logging
  run: |
    TIMESTAMP=$(date +%Y%m%d_%H%M%S)
    LOG_DIR="/tmp/claude-logs"
    mkdir -p "$LOG_DIR"

    # 记录输入
    echo "Prompt: $PROMPT" > "$LOG_DIR/input_${TIMESTAMP}.log"
    cp /tmp/pr.diff "$LOG_DIR/diff_${TIMESTAMP}.diff"

    # 执行审查
    claude -p "$PROMPT" \
      --output-format json \
      --non-interactive \
      < /tmp/pr.diff \
      > "$LOG_DIR/output_${TIMESTAMP}.json" \
      2> "$LOG_DIR/error_${TIMESTAMP}.log"

    # 记录 token 用量
    jq '.usage' "$LOG_DIR/output_${TIMESTAMP}.json" > "$LOG_DIR/usage_${TIMESTAMP}.json"

- name: Upload Logs (Optional)
  uses: actions/upload-artifact@v4
  if: always()
  with:
    name: claude-review-logs
    path: /tmp/claude-logs/
    retention-days: 7

实践六:回退机制

当 Claude Code API 不可用时,需要有合理的降级策略。

yaml
- name: AI Review (with Fallback)
  id: review
  continue-on-error: true
  run: |
    # 尝试调用 Claude Code
    if claude -p "Review this PR" --output-format json > review.json 2> error.log; then
      echo "status=success" >> $GITHUB_OUTPUT
    else
      echo "status=degraded" >> $GITHUB_OUTPUT
    fi

- name: Fallback — Template-based Checklist
  if: steps.review.outputs.status == 'degraded'
  run: |
    cat > review.json << 'EOF'
    {
      "result": "## ⚠️ AI Review 暂时不可用\n\n
      由于 Claude API 暂时不可用,本次 PR 未能完成自动审查。\n\n
      **请 Reviewer 手动检查以下事项:**\n\n
      - [ ] 代码风格符合项目规范\n
      - [ ] 所有新增公共 API 有对应测试\n
      - [ ] 错误处理逻辑完整\n
      - [ ] 没有硬编码的密钥或敏感信息\n
      - [ ] 数据库迁移文件正确(如适用)",
      "model": "fallback-template",
      "usage": {"input_tokens": 0, "output_tokens": 0}
    }
    EOF

- name: Post Result (Always)
  if: always()
  run: |
    [ -f review.json ] && post_review_comment review.json

回退层级

Level 1: Claude Code 正常审查(最佳体验)

   ├─ API 不可用

Level 2: 使用备用模型(如 Haiku 替代 Sonnet)

   ├─ 全部 API 不可用

Level 3: 模板化 Checklist(基础保障)

   ├─ 完全无法执行

Level 4: 静默跳过 + 通知 Reviewer

27.6 复盘与技巧总结

三种 CI 集成模式

回顾本章,Claude Code 在 CI/CD 中有三种主要集成模式:

模式触发时机主要用途推荐模型
PR ReviewPR 打开/更新自动审查代码质量和安全问题Sonnet(大 PR)/ Haiku(小 PR)
Issue 分类Issue 创建自动打标签、分配负责人Haiku
自动化报告定时触发/事件触发生成变更日志、发布说明Sonnet

关键配置速查

将本章涉及的所有关键配置汇总成一张速查表:

配置项推荐值作用
--non-interactive必须禁止交互式确认
--output-format json必须输出可解析的 JSON
--max-turns5-15限制 Agent 思考轮次
--max-tokens2000-8000控制单次成本
--modelHaiku/Sonnet 按需成本与质量平衡
timeout-minutes5-10防止 CI 卡死
continue-on-errortrue非阻塞设计
权限模式精细 allow 列表最小权限原则

不适合 CI 自动化的场景

最后,明确 不应该 用 Claude Code 在 CI 中做的事情:

  1. 架构级别的决策:是否需要引入新的设计模式、是否应该拆分微服务——这些需要团队讨论和深度分析
  2. 性能优化判断:真正的性能瓶颈需要 profiling 数据和实际运行环境,Claude Code 只能做表面的模式识别
  3. 复杂的业务逻辑审查:涉及行业特定规则、法律合规要求等,AI 的领域知识可能不足
  4. 决定 Merge 或 Close:这始终是人的决策权

五个常见踩坑点

  1. 忘记设置 continue-on-error → AI Review 的瞬时故障阻塞了整个 CI,团队被迫等待
  2. Token 用量没做限制 → 一个超大 PR 一次消耗了 50000 tokens,月度预算一天用完
  3. 权限给得太多 → CI 环境的 allow 列表包含了 WriteEdit,导致 AI 在无人值守时修改了代码
  4. JSON 输出没有验证 → 解析脚本因为格式异常而崩溃,但日志里只有 parse error,排错困难
  5. API Key 与个人 Key 混用 → 某天个人 Key 被轮换,所有 CI 流程同时挂掉

本章小结

本章是第五篇"实战篇"的最后一章。我们学习了如何将 Claude Code 从个人开发者的桌面工具,转化为团队 CI/CD 流水线中的自动化助手。

核心要点回顾:

  • 角色定位:Claude Code 在 CI 中是辅助者,不是决策者。它做初步筛查,人做最终判断
  • PR Review 自动化:通过 GitHub Actions 集成,自动读取 PR diff 并发表 Review 评论,重点关注 Bug、安全漏洞和代码质量
  • Issue 分类自动化:自动判断 Issue 类型、打标签、推荐负责人,对信息不足的 Issue 生成友善追问
  • 非交互模式:CI 环境的核心运行模式,通过 --non-interactive--output-format json--max-turns 等参数控制行为
  • 六大最佳实践:成本控制、结果验证、非阻塞设计、权限隔离、日志保留、回退机制

从第 20 章到第 27 章,我们走过了 8 个真实开发场景:理解陌生项目、从零搭建新功能、大规模重构、调试排错、Code Review、测试编写、文档生成、以及本章的 CI/CD 集成。每一个场景都展示了 Claude Code 在不同维度上的能力——从理解代码到修改代码,从编写测试到自动化流水线。

在经历了这 8 个真实场景的实战之后,让我们提升一个层次:从"怎么用"上升到"怎么用好"。从下一章开始,我们将进入第六篇"方法论篇",深入学习 AI 编程的底层方法论——Prompt 工程、让 AI 理解你的项目、人机协作模式、以及效率优化策略。这些方法论将帮助你把前五篇学到的所有技能融会贯通,真正从"会用工具"进阶到"AI 时代的优秀开发者"。