跳到正文
码上手 coding.chengyu.dev

无头模式与 CI:让 Claude 在流水线里干活

不开交互界面,用 claude -p 把 Claude Code 当成一个命令行工具嵌进脚本和 CI;掌握输出格式、权限与 --bare,接入 GitHub Actions 自动评审 PR,并了解什么时候该换成 Agent SDK。

约 30 分钟 进阶 Claude CodeGitHub Actions 核实于 2026-10-25

学完这一课,你能

  • 能用 claude -p 配合 --output-format 和 --json-schema 在脚本里拿到可解析的结果
  • 能说清无头模式下权限怎么生效,以及为什么 CI 里推荐 --bare
  • 能用 claude-code-action 或纯脚本两种方式,在 GitHub Actions 里自动评审 PR
  • 能判断一个自动化需求该用 claude -p 还是 Agent SDK

团队五个人,每天十几个 PR。真正细看的评审只能顾上核心模块,其余的大多是扫一眼就点通过。结果上线后才发现:某个接口漏了 await,某个配置里明文写了测试环境的密码。

如果每个 PR 一提交,就有一个 Claude 先过一遍、把明显的问题写成评论,人类评审就能把精力留给真正需要判断的地方。这一课就做这件事:让 Claude Code 脱离交互界面,在脚本和 CI 里自动运行。

无头模式:claude -p

给 claude 加上 -p(全称 --print),它就不再打开交互界面,而是执行完一次任务、把结果打印到标准输出后退出,像 grep、jq 一样可以放进管道和脚本。成功时退出码为 0,失败时非 0,脚本可以据此判断。

它会读标准输入,所以最自然的用法是「把东西喂给它」:

# 把构建日志喂进去,把解释写进文件
cat build.log | claude -p "用三句话说明这次构建失败的根本原因" > why.txt

# 根据暂存区的改动生成一条中文提交信息
git diff --cached | claude -p "根据这段 diff 写一条符合 Conventional Commits 的提交信息,只输出这一行"

输出格式用 --output-format 控制:

格式 得到什么 适合
text(默认) 纯文本 直接给人看、写进文件
json 一个 JSON 对象,正文在 result,另有 session_id、费用估算 total_cost_usd 等元数据 脚本解析、记录花费
stream-json 每行一个 JSON 事件,实时输出(需加 --verbose) 自己做界面、实时展示进度

需要固定结构时,再加 --json-schema 传入一个 JSON Schema,结果会出现在 structured_output 字段里。比如把一批用户反馈分类:

cat feedback.txt | claude -p "把每条反馈归类为 bug、需求或咨询" \
  --output-format json \
  --json-schema '{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"text":{"type":"string"},"kind":{"type":"string","enum":["bug","需求","咨询"]}},"required":["text","kind"]}}},"required":["items"]}' \
  | jq '.structured_output.items'

如果 Claude 拒绝了任务或没能产出合法结构,structured_output 字段会缺失,脚本使用前要先判断它在不在。

多轮任务可以用 --continue 接着最近一次对话,或者先从 JSON 里取出 session_id,再用 --resume 指定接哪一次。

无头模式下的权限

交互模式里,Claude 遇到需要批准的操作会停下来问你。无头模式没人可问,规则是这样的:

  • 不设置权限模式时,-p 运行在 Manual 模式(也就是默认模式,v2.1.302 起明确如此),需要批准的调用一律被拒绝。读取工作目录里的文件这类本就不需要批准的操作照常进行。
  • 用 --allowedTools 预先放行,语法和权限规则一样(见第 3 课)。例如 --allowedTools "Read,Bash(git diff *),Bash(git log *)"。注意 Bash(git diff *) 里星号前的空格不能省,否则 git diff-index 也会被匹配。
  • 也可以用 --permission-mode 设一个整体基线:acceptEdits 自动接受文件编辑,dontAsk 拒绝所有本该询问的调用,适合锁得很死的 CI。
  • 给它设上限:--max-turns 限制轮数,--max-budget-usd 限制估算花费,CI 里两个都建议加。

接入 GitHub Actions

官方提供了 anthropics/claude-code-action,它基于 Agent SDK,在 GitHub 的工作流里运行 Claude Code。最快的接入方式是在本地仓库里启动 claude,运行 /install-github-app:它会安装 Claude GitHub App、把凭据存成仓库 secret、推一个带工作流文件的分支并帮你打开 PR,合并即生效。前提是装好并登录了 GitHub CLI(gh auth login)、你对仓库有管理员权限,且仓库在 github.com 上。

想手动配置,就三步:安装 Claude GitHub App;在仓库 secret 里放 ANTHROPIC_API_KEY(API 计费),或用 claude setup-token 生成的 CLAUDE_CODE_OAUTH_TOKEN(用订阅额度);把工作流文件放进 .github/workflows/。

这个 Action 有两种工作方式,取决于你有没有写 prompt:

模式 触发条件 结果在哪
交互模式(不写 prompt) 有人在 issue 或 PR 评论里 @claude 在原 issue 或 PR 下回复评论
自动化模式(写了 prompt) 工作流事件本身,如 PR 打开、定时任务 默认在工作流日志里,提示词要求且有发评论的工具时才会发到 PR

其他常用参数:claude_args 透传任意命令行参数(如 --max-turns、--model、--allowedTools),settings 传入 settings JSON,trigger_phrase 改触发词。还在用 @beta 的旧工作流要迁到 @v1:去掉 mode,把 direct_prompt 改成 prompt,把 max_turns、model 这类选项挪进 claude_args。

实操:在 CI 里自动评审 PR

方案 A:官方 Action + 代码评审插件(推荐 GitHub 用户)

这是官方示例里的做法:安装 code-review 插件,在 PR 打开或更新时运行它的评审 Skill,把问题以行内评论的形式发在 PR 上。新建 .github/workflows/claude-review.yml:

name: Claude 代码评审
on:
  pull_request:
    types: [opened, synchronize, ready_for_review, reopened]
jobs:
  review:
    runs-on: ubuntu-latest
    timeout-minutes: 15          # 防止跑飞
    permissions:
      contents: read
      pull-requests: read
      issues: read
      id-token: write            # Action 用 GitHub App 认证时需要
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 1
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          plugin_marketplaces: "https://github.com/anthropics/claude-code.git"
          plugins: "code-review@claude-code-plugins"
          prompt: "/code-review:code-review --comment ${{ github.repository }}/pull/${{ github.event.pull_request.number }}"
          claude_args: '--allowedTools "mcp__github_inline_comment__create_inline_comment"'

--comment 决定评审发到 PR 上,去掉它就只写进运行日志;claude_args 那一行不能删,Action 只有在 --allowedTools 点名时才会启动发行内评论的工具。草稿 PR、已关闭的 PR 和已有 Claude 评论的 PR 会被跳过。如果你连工作流都不想维护,官方还有一个托管的 Code Review 功能可以了解。

方案 B:纯脚本版(想完全掌控提示词,或用在其他 CI)

核心思路:让 Claude 只负责产出文字,发评论这一步交给脚本。Claude 手里没有任何写权限,即使 diff 里藏了恶意指令,它也做不了什么。

name: AI 评审(脚本版)
on:
  pull_request:
    types: [opened, synchronize]
permissions:
  contents: read
  pull-requests: write
concurrency:
  group: ai-review-${{ github.event.pull_request.number }}
  cancel-in-progress: true       # 连续推送时只保留最新一次
jobs:
  review:
    # 只评审本仓库分支发起的 PR;fork 来的 PR 拿不到 secrets
    if: github.event.pull_request.head.repo.full_name == github.repository
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v6
      - name: 安装 Claude Code
        run: |
          curl -fsSL https://claude.ai/install.sh | bash
          echo "$HOME/.local/bin" >> "$GITHUB_PATH"
      - name: 生成评审并发评论
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          GH_TOKEN: ${{ github.token }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
        run: |
          gh pr diff "$PR_NUMBER" > pr.diff
          claude --bare -p "你是资深代码评审。下面是一个 PR 的 diff,请用中文列出:1. 可能的 bug 和安全问题(附文件和行号);2. 明显的性能问题;3. 缺失的测试。没有问题就回复「未发现明显问题」。不要逐行复述 diff。" \
            --max-turns 5 --max-budget-usd 1 \
            --output-format json < pr.diff > review.json
          jq -r '.result' review.json > review.md
          gh pr comment "$PR_NUMBER" --body-file review.md

几个设计上的讲究:

  • PR 编号通过 env 传进脚本,而不是把 github.event.pull_request.title 这类别人能控制的文字直接拼进 run,避免命令注入。
  • --bare 让 PR 里如果夹带了 .claude/settings.json 或 .mcp.json,也不会被加载执行。
  • --max-turns、--max-budget-usd、timeout-minutes、concurrency 四道闸,防止一个 PR 烧掉一大笔钱。
  • 换成 GitLab CI 或公司内部的 Jenkins,只要把 gh pr diff 和 gh pr comment 换成对应平台的命令,主体不用改。
GitHub Actions — AI 评审(脚本版)
$ curl -fsSL https://claude.ai/install.sh | bash
# 安装输出省略
$ gh pr diff 128 > pr.diff
$ claude --bare -p "你是资深代码评审……" --max-turns 5 --output-format json < pr.diff > review.json
$ jq -r '.result' review.json
1. src/api/order.ts:42 调用 fetchStock() 时缺少 await,库存校验会被跳过
2. config/test.yaml:7 明文写入了数据库密码,建议改为读取环境变量
3. 新增的 calcDiscount() 没有对应的单元测试
$ gh pr comment 128 --body-file review.md
# 输出为示意,实际内容取决于你的 diff
让 Claude Code 为你的仓库搭好 AI 评审流水线 Claude Code

请为这个仓库添加一个 GitHub Actions 工作流,在 PR 打开和更新时用 claude -p 自动评审,要求:

  1. 文件放在 .github/workflows/ai-review.yml,参考「方案 B 纯脚本版」的结构:用 –bare,Claude 只输出文字,发评论由 gh pr comment 完成;
  2. 评审提示词结合这个仓库的技术栈来写(先读 package.json 或其他依赖文件判断),用中文输出,按「必须修 / 建议修 / 可以考虑」三级分类;
  3. 只对本仓库分支发起的 PR 运行,加上 timeout-minutes、concurrency、–max-turns 和 –max-budget-usd;
  4. 不要把任何 PR 标题、正文之类的外部文字直接拼进 run 脚本;
  5. 写完后告诉我需要在仓库 Settings 里添加哪个 secret,以及怎么开一个测试 PR 验证。不要替我提交或推送。

Agent SDK:需要更多控制时

claude -p 适合「一问一答」式的自动化。如果你要把 Claude Code 的能力嵌进自己的 Python 或 TypeScript 程序,比如做一个内部的「工单自动修复机器人」,需要在每次工具调用时自己决定放不放行、把过程实时显示在自己的界面上,就该用 Agent SDK。它提供和 Claude Code 相同的工具、智能体循环和上下文管理,并支持 Hooks、子智能体、MCP、权限和会话。

安装:Python 用 pip install claude-agent-sdk,TypeScript 用 npm install @anthropic-ai/claude-agent-sdk。最小的 Python 例子:

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage

async def main():
    async for message in query(
        prompt="检查 utils/date.py 中可能导致崩溃的时区处理问题并修复",
        options=ClaudeAgentOptions(
            allowed_tools=["Read", "Edit", "Glob"],
            permission_mode="acceptEdits",
        ),
    ):
        if isinstance(message, ResultMessage):
            print("完成:", message.subtype)

asyncio.run(main())

query 返回一个异步迭代器,Claude 每思考一步、每调用一次工具,你都会收到一条消息。认证用 Claude Console 的 API key;官方明确规定,未经许可,第三方开发者不能在自己的产品里让用户用 claude.ai 账号登录或使用其订阅额度。选择上可以这样记:脚本和 CI 用 claude -p,要做成产品或需要精细控制时用 SDK。

小测

你在 CI 里运行 claude -p 「修复 lint 错误」,没有加任何权限相关参数。日志显示 Claude 想编辑文件,但最后什么都没改。最可能的原因是?

小测

一个开源项目想用 Claude 自动评审外部贡献者的 PR。下面哪个做法风险最大?

动手清单

0/5

参考来源

工具更新很快,若与官方文档不一致,以官方为准。

学完了吗?

标记完成会记录在本机浏览器,计入你的学习进度和连续天数。

Esc

输入关键词开始搜索,例如「CLAUDE.md」「MCP」「部署」