资讯动态

让 Claude 半夜自己审 PR:Headless 模式 + GitHub Actions 实测

发布时间:2026/9/29 2:15:03 来源:尧图企业网站定制
一、问题交互式 Claude 没法挂到流水线上人工 Code Review 跟不上 PR 速度交互式调用 Claude 又没法自动化怎么办我们团队前阵子被这事卡住——夜里合了十几条 PR第二天早会一堆谁来 Review的尴尬。顺便一提我维护的雷达鸭 App收录中国一人公司赚钱案例华为应用市场 微信小程序Uni-app arkTS UniCloud攒到一定体量后PR 审查负担也压上来了这才逼着我去翻 Claude Code 的 Headless 模式。核心转变一句话把人确认换成参数约束。交互式下工具要不要执行、文件要不要改都是人按回车Headless 下所有决策都靠参数预先约束好Claude 自己跑完输出结果。最朴素的调用# 最基本的 Headless 调用claude-p分析 src/ 目录的安全漏洞# 等价的完整形式claude--print分析 src/ 目录的安全漏洞-p就是--print的短写跑完直接退出不进交互式 REPL。这就是无人值守的起点。二、4 维参数把交互式的确认翻译成约束Headless 不是简单加个-p而是要把交互式里那些隐式约定全显式化。Claude Code 给了 4 个维度# 维度一输出格式claude-p列出主要问题--output-format text# 纯文本人看claude-p审查 PR--output-format json# 结构化机器解析claude-p分析代码--output-format stream-json# 流式实时监控# 维度二成本与规模护栏claude-p审查代码--max-turns5# 最多 5 轮工具调用claude-p分析日志--max-budget-usd0.50# 单次硬上限 0.5 美元# 维度三安全边界claude-p审查代码变更--allowedToolsRead,Grep,Glob# 只读最安全claude-p生成文档--disallowedToolsBash# 黑名单禁 Bashclaude-p检查 git 历史\--allowedToolsRead,Grep,Glob,Bash(git log *),Bash(git diff *)# 细粒度白名单# 维度四执行控制claude-p检查代码格式--modelclaude-haiku-4-5 claude-p安全漏洞分析--modelclaude-sonnet-4-6 claude-p代码审查--modelclaude-sonnet-4-6 --fallback-model haiku# 主模型过载自动切text输出适合人看json给 CI 后续步骤消费stream-json一行一个事件适合长任务实时盯。我们做 PR 审查统一用json因为后面要用jq提取result字段、用total_cost_usd算账。json输出长这样{type:result,subtype:success,session_id:550e8400-e29b-41d4-a716-446655440000,is_error:false,duration_ms:12345,num_turns:5,total_cost_usd:0.0342,usage:{input_tokens:5000,output_tokens:1500,cache_read_input_tokens:3000},result:发现 2 个 Critical 问题\n1. SQL 注入风险...}session_id留着后面会话管理用total_cost_usd直接是这次审查花了几美分。我们跑了两周平均一条 PR 审查成本在 0.03~0.08 美元之间——比之前请同事加班喝的咖啡便宜多了。三、Unix 管道Claude 当命令行工具用Headless 模式下 Claude 就是个标准 stdin/stdout 程序能塞进任何 Unix 管道# 分析日志文件catserver.log|claude-p找出所有 500 错误并总结根因# 分析 git 变更gitdiffHEAD~1|claude-p总结这次提交的变更格式为 Conventional Commits# Claude 分析 → jq 提取 → 发邮件claude-p检查是否有安全漏洞--output-format json|\jq-r.result|\mail-s安全扫描报告securitycompany.com# grep 预过滤 → Claude 深度分析grep-rTODOsrc/|claude-p将这些 TODO 按优先级分类末尾那个例子是我们日常在用的——先grep把范围收窄再喂给 Claude 分类比让 Claude 自己Grep整个仓库省 token 也省时间。四、GitHub Actions 两种接法官方给了两条路。方式一官方 Action起步首选# .github/workflows/claude-review.ymlname:Claude PR Reviewon:pull_request:types:[opened,synchronize,reopened]issue_comment:types:[created]# 同一 PR 的新提交取消旧的运行——避免浪费concurrency:group:${{github.workflow}}-${{github.event.pull_request.number}}cancel-in-progress:truejobs:review:runs-on:ubuntu-latestif:|github.event_name pull_request || contains(github.event.comment.body, claude)permissions:contents:readpull-requests:writeissues:writesteps:-uses:actions/checkoutv4with:fetch-depth:0# 完整历史用于 diff 分析-uses:anthropics/claude-code-actionv1with:anthropic_api_key:${{secrets.ANTHROPIC_API_KEY}}prompt:|审查这个 PR 的代码变更重点检查 1. 安全漏洞SQL 注入、XSS、敏感信息硬编码 2. 未处理的错误情况和边界条件 3. 性能问题N1 查询、内存泄漏风险claude_args:---allowedTools Read,Grep,Glob--max-turns 10--model claude-sonnet-4-6十几行 YAML 跑起来PR 一开自动评论。concurrency那段必加——同一 PR 连推几个 commit旧的运行会被自动取消不然账单会很难看。方式二直接 CLI精细控制需要自己处理变更文件列表、自己写评论、自己卡门禁的场景用直接 CLIname:Advanced AI Reviewon:pull_request:types:[opened,synchronize]paths:[src/**]# 只在 src 目录变更时运行concurrency:group:${{github.workflow}}-${{github.event.pull_request.number}}cancel-in-progress:truejobs:review:runs-on:ubuntu-latestpermissions:contents:readpull-requests:writesteps:-uses:actions/checkoutv4with:fetch-depth:0-uses:actions/setup-nodev4with:node-version:20-name:Install Claude Coderun:npm install-g anthropic-ai/claude-code-name:Get changed filesid:changedrun:|FILES$(git diff --name-only origin/${{ github.base_ref }}...HEAD) echo files$(echo $FILES | tr \n ) $GITHUB_OUTPUT echo count$(echo $FILES | wc -l) $GITHUB_OUTPUT-name:Run Claude Reviewid:reviewenv:ANTHROPIC_API_KEY:${{secrets.ANTHROPIC_API_KEY}}CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:1run:|claude -p 审查以下 PR 变更文件 ${{ steps.changed.outputs.files }}重点检查安全漏洞、逻辑错误、性能问题。 对每个问题给出文件名和行号。 \--output-format json \--max-turns 10 \--max-budget-usd 0.50 \--model claude-sonnet-4-6 \--allowedTools Read,Grep,Globreview.json RESULT$(jq-r .result review.json) COST$(jq-r .total_cost_usd review.json) echo cost$COST$GITHUB_OUTPUT echo resultEOF$GITHUB_OUTPUT echo $RESULT$GITHUB_OUTPUT echo EOF$GITHUB_OUTPUT-name:Post Review Commentuses:actions/github-scriptv7with:script:|const cost ${{ steps.review.outputs.cost }}; const result ${{ steps.review.outputs.result }}; await github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: ## Claude Code Review\n\n${result}\n\n---\n*Cost: $${cost} | Automated by Claude Code* });-name:Gate on critical issuesrun:|RESULT${{ steps.review.outputs.result }} if echo $RESULT | grep -qi critical; then echo ::error::Critical issues found exit 1 fi末尾那段Gate on critical issues是真有用的——评审里出现critical字样直接让 CI 失败比让人盯着看评论靠谱。两种方式的取舍起步用方式一几分钟接上要卡门禁、要拿total_cost_usd做账、要把结果写到外部系统就上方式二。我们团队最终留了方式二因为要把每次审查成本塞进 Grafana。五、多阶段 CI 管道分析 → 修复 → 验证单步审查只是开始。真正省事的是把 Claude 拆成多个 job按阶段跑、按模型分级name:Multi-Stage AI Pipelineon:pull_request:types:[opened,synchronize]jobs:# 阶段一快速格式检查用便宜的模型lint-check:runs-on:ubuntu-lateststeps:-uses:actions/checkoutv4-name:Format Checkenv:ANTHROPIC_API_KEY:${{secrets.ANTHROPIC_API_KEY}}CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:1run:|npx anthropic-ai/claude-code -p 检查 src/ 下的代码是否符合项目编码规范 \ --model claude-haiku-4-5 \ --max-turns 3 \ --max-budget-usd 0.05 \ --allowedTools Read,Grep,Glob \ --output-format text# 阶段二深度安全审查用最强模型security-scan:runs-on:ubuntu-latestneeds:lint-check# 格式检查通过后再做安全扫描steps:-uses:actions/checkoutv4-name:Security Scanenv:ANTHROPIC_API_KEY:${{secrets.ANTHROPIC_API_KEY}}CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:1run:|npx anthropic-ai/claude-code -p 深度安全扫描重点检查 OWASP Top 10 \ --model claude-sonnet-4-6 \ --append-system-prompt 你是应用安全专家只关注安全漏洞。 \ --max-turns 10 \ --max-budget-usd 1.00 \ --allowedTools Read,Grep,Glob \ --output-format json \ --json-schema {type:object,properties:{vulnerabilities:{type:array,items:{type:object,properties:{severity:{type:string},description:{type:string},file:{type:string}},required:[severity,description]}}},required:[vulnerabilities]} \ security-report.json阶段一用 Haiku便宜、快阶段二才上 Sonnet贵、准。needs: lint-check让安全扫描等格式检查通过再跑——格式都过不了的 PR 没必要烧 Sonnet 的钱。这种分级模型 阶段依赖组合下来我们一条 PR 的平均成本从单一 Sonnet 全量审查的 ~0.15 美元压到了 ~0.06 美元。六、流式输出和会话管理流式输出盯长任务stream-json一行一个事件配while read能实时看 Claude 在干啥claude-p分析整个 src/ 目录的架构问题\--output-format stream-json\--allowedToolsRead,Grep,Glob|whileread-rline;doTYPE$(echo$line|jq-r.type // )case$TYPEinsystem)echo[INIT] 模型:$(echo$line|jq-r.model // unknown);;assistant)TEXT$(echo$line|jq-r.message.content[0].text // );[-n$TEXT]echo[CLAUDE]$TEXT;;result)COST$(echo$line|jq-r.total_cost_usd // 0);TURNS$(echo$line|jq-r.num_turns // 0);echo[DONE] 完成$TURNS轮费用: \$$COST;;esacdone我们把这个管道接到 CI 日志里长任务不再是黑盒等 5 分钟——能实时看到 Claude 读到哪个文件、下了什么结论。会话管理跨步骤复用上下文多阶段管道每个 job 是独立容器默认上下文丢光。--resume接session_id能把上一轮分析接上# 第一次调用分析代码结构RESULT$(claude-p分析 src/ 的模块依赖关系\--output-format json\--allowedToolsRead,Grep,Glob)# 提取 session_idSESSION_ID$(echo$RESULT|jq-r.session_id)# 第二次调用在上一轮分析的基础上继续claude-p基于刚才的分析指出循环依赖问题\--resume$SESSION_ID\--output-format text# 继续当前目录最近的会话不需要知道 session_idclaude-p继续刚才的分析--continue# 创建分支会话保留原始会话不变claude-p如果改用微服务架构呢--resume$SESSION_ID--fork-session# 禁用会话持久化适合完全无状态的 CI 场景claude-p一次性分析--no-session-persistence--continue不用记session_id直接续最近的--fork-session适合假设性提问——分支会话不影响主线。完全无状态的 CI 用--no-session-persistence跑完不落盘。七、五层安全防线让 Claude 半夜自己跑最让人睡不着的就是它会不会偷偷rm -rf。书里给的五层防线我们一层没少层一最小权限——--allowedTools把工具收成白名单审查任务只给Read,Grep,Glob连Edit都不给。层二Secrets 管理——API Key 一律走${{ secrets.ANTHROPIC_API_KEY }}绝不硬编码。硬编码会原样出现在 Actions 日志里谁都能看。层三容器隔离——只读文件系统 无网络jobs:review:runs-on:ubuntu-latestcontainer:image:node:20options:--read-only--tmpfs /tmp--network none--network none直接断网Claude 想外传数据也没出口。层四成本防护——路径过滤 并发限制 单次预算兜底on:pull_request:paths:-src/**-!src/**/*.test.*# 排除测试文件concurrency:group:claude-${{github.event.pull_request.number}}cancel-in-progress:true加上--max-budget-usd 0.50单次跑超 0.5 美元自动停。层五审计日志——JSON 输出天然带审计字段tee落盘claude-p任务--output-format json|tee-a/var/log/claude-audit.jsonl事后谁、什么时候、花了多少钱、跑了多少轮全在日志里。八、CI 环境变量与完整模板CI 里这几个环境变量必设ANTHROPIC_API_KEYsk-ant-...# API 密钥CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC1# 一个变量关掉自动更新、遥测、错误上报DISABLE_AUTOUPDATER1# 禁用自动更新CI 中必须DISABLE_TELEMETRY1# 禁用遥测DISABLE_ERROR_REPORTING1# 禁用错误上报BASH_DEFAULT_TIMEOUT_MS120000# Bash 默认超时 2 分钟CLAUDE_CODE_MAX_OUTPUT_TOKENS32000# 最大输出 tokenCLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC1这个一定要加——不然 CI 跑着跑着 Claude 自己开始检查更新日志里一堆噪音。一个能直接抄的完整模板-name:Run Claude Analysisenv:ANTHROPIC_API_KEY:${{secrets.ANTHROPIC_API_KEY}}CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:1BASH_DEFAULT_TIMEOUT_MS:300000run:|npx anthropic-ai/claude-code -p $PROMPT \ --output-format json \ --max-turns 10 \ --max-budget-usd 1.00 \ --allowedTools Read,Grep,Glob \ --model claude-sonnet-4-6 \ --fallback-model haiku \ --append-system-prompt 遵循项目 CLAUDE.md 中的审查规范。--fallback-model haiku是个容易被忽略的小细节——主模型过载时自动切 Haiku不至于让整条管道挂在 429 上。九、判断跑了两周我们的结论是Headless 模式不是凑合用的替代品是 CI 集成的正解。交互式适合人盯着改代码Headless 适合挂流水线——两个场景两套约束逻辑。反正我们以后的 PR 审查默认走 Claude GitHub Actions人只看 critical 项。半夜合的 PR第二天早会前报告已经躺在评论里了。关于作者雷达鸭 App 独立开发者10 年软件开发经验软件设计师、人工智能应用工程师专注鸿蒙 ArkTS Web 前端探索 AI 自动化。版权声明本文采用 MIT 协议开源转载请注明出处。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑