ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Headless 模式跑 Claude Code:-p 输出 JSON 接入 GitHub Actions 的配置清单

Headless 模式跑 Claude Code:-p 输出 JSON 接入 GitHub Actions 的配置清单 1. 为什么要把 Claude Code 塞进 GitHub Actions先说结论Claude Code 的 Headless 模式本质上是把「坐在终端前和 AI 来回对话」这件事压缩成「喂一个 prompt吐一段结构化结果」。它没有交互界面但代码分析、工具调用、推理能力一个不少。触发它的开关就是-p等价于--print意思是「把结果打印出来就行别开交互界面」。这个能力放到 CI 里价值极大。你想想每次 PR 提交如果有个机器人自动跑一遍代码审查、把问题按严重程度分类、再把结果写成 JSON 让后续步骤消费团队里就没人需要手动点开 diff 逐行看了。GitHub Actions 正好是干这个的天然场所——它本来就是事件驱动、无头执行的环境和 Headless 模式的气质完全吻合。但很多人第一次接的时候会卡在几个地方-p和--output-format json到底怎么组合、密钥怎么安全注入、JSON 输出里哪个字段才是真正的回复文本、下游jq解析时报Cannot index是怎么回事。这篇就按「本地先跑通 → 再搬进流水线」的顺序把配置清单和排障点一次讲清楚。适合谁看已经在用 Claude Code 交互模式、想把它自动化进 CI 的后端/DevOps 同学或者你正在搭 AI 驱动的代码审查流水线需要一个能稳定解析的输出格式。核心检索词就三个Claude Code Headless、-p参数、GitHub Actions JSON 输出。我试过把交互模式硬塞进脚本结果就是进程挂在那里等输入CI 直接超时。Headless 模式解决的正是这个根本矛盾——从「持续对话」变成「单次执行」。2. 前置准备TaoToken 接入与 Claude Code 安装在写 workflow 之前得先让 Claude Code 能在一个非交互环境里正常发请求。这里涉及三样东西一个可用的 API 端点、一个 Key、以及 Claude Code 本体。TaoToken 提供的就是这个接入层。官网在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 端点是 https://taotoken.net/api 。你需要先在控制台生成一个 API Key这个 Key 后面会作为 GitHub Secret 注入绝对不要写死在 YAML 里。安装 Claude Code 本身Node 环境下一个命令就够npm install -g anthropic-ai/claude-code装完之后Claude Code 需要知道往哪儿发请求、用哪个 Key。它读取的是环境变量。本地测试时你可以临时导出export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_API_KEYsk-你的key注意ANTHROPIC_BASE_URL不要带末尾斜杠也不要带/v1之类的路径后缀Claude Code 会自己拼接。这一点踩过坑多写一个斜杠会导致 404报错信息还很不直观。验证安装和配置是否生效跑一个最小的 Headless 请求claude -p 回复 ok 两个字 --output-format json如果返回一段 JSON里面有result字段且内容是「ok」说明链路通了。如果报 401八成是 Key 没生效或者环境变量名写错如果报连接错误检查ANTHROPIC_BASE_URL是否可达。关于模型 IDClaude Code 默认会用一个内置的模型名。如果你在 TaoToken 侧需要指定具体模型可以通过ANTHROPIC_MODEL环境变量覆盖。三件套记牢Base URL、Key、Model ID缺一个都可能跑不起来。这一步在本地做完你才有底气把它搬进 Actions——因为 CI 里出问题排查成本高得多本地先确认基础链路是省时间的做法。3. 可复制的 GitHub Actions workflow 配置现在进入正题。下面这份 workflow 是完整可复制的放在.github/workflows/claude-review.yml。它做三件事检出代码、安装 Claude Code、用-p跑一次审查并把 JSON 结果存成 artifact。name: Claude Headless Review on: pull_request: types: [opened, synchronize] jobs: review: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkoutv4 with: fetch-depth: 0 - name: Setup Node uses: actions/setup-nodev4 with: node-version: 20 - name: Install Claude Code run: npm install -g anthropic-ai/claude-code - name: Run headless review env: ANTHROPIC_BASE_URL: ${{ secrets.ANTHROPIC_BASE_URL }} ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} run: | git diff origin/${{ github.base_ref }}...HEAD /tmp/pr.diff claude -p 审查以下 diff按 Critical/Warning/Suggestion 分类输出简洁结论 \ --output-format json \ --max-turns 3 \ --allowedTools Read \ /tmp/pr.diff /tmp/review.json - name: Parse result run: | jq -r .result /tmp/review.json - name: Upload artifact uses: actions/upload-artifactv4 with: name: claude-review path: /tmp/review.json几个关键点拆开说。--output-format json让 Claude Code 输出一个 JSON 对象而不是纯文本。这个对象里除了result真正的回复文本还有耗时、token 用量、成本等元数据。CI 里几乎总是该用 JSON因为你要程序化消费它。--max-turns 3是安全阀。Headless 模式下没人盯着如果不限制轮次Claude 可能反复调用工具直到烧掉大量 token。单文件或单次 diff 审查3 轮通常够用。--allowedTools Read限制它能用的工具。在无人监管的 CI 环境里这是第一道防线——你不想让它在流水线里执行写操作或跑任意命令。密钥注入走secrets。在仓库 Settings → Secrets and variables → Actions 里加两个ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY。YAML 里通过${{ secrets.XXX }}引用这样 Key 不会出现在日志里。如果你用的是 Cline MCP 或 Codex 那套配置体系思路一样三件套 Base URL Key Model ID 都要在对应配置文件里写全。Claude Code 这边就是上面两个环境变量加可选的ANTHROPIC_MODEL。fetch-depth: 0是为了让git diff能拿到完整的 base 分支历史否则浅克隆会导致 diff 为空。4. 验证请求与成功结果解析配置写完怎么确认它真的跑通了分两步本地一次流水线一次。本地验证直接模拟 CI 里的命令git diff HEAD~1 /tmp/pr.diff claude -p 审查以下 diff --output-format json /tmp/pr.diff /tmp/review.json jq -r .result /tmp/review.json如果jq能打印出审查文本说明输出结构符合预期。你可以进一步看元数据jq {cost: .total_cost_usd, tokens: .usage} /tmp/review.json流水线验证推一个 PR 上去在 Actions 页面看这次 run。成功的话Parse result这一步的日志里会直接打印审查结论artifact 里能下载到完整的review.json。一个典型的成功 JSON 长这样字段名以实际返回为准{ type: result, subtype: success, result: Critical: 无\nWarning: 第 12 行缺少输入校验\nSuggestion: 建议提取重复逻辑, total_cost_usd: 0.0031, usage: { input_tokens: 1200, output_tokens: 180 } }下游消费的关键就是.result。如果你想把结论发到 PR 评论可以用gh命令jq -r .result /tmp/review.json | gh pr comment ${{ github.event.number }} --body-file -这样一条从 diff 到评论的链路就闭环了。注意--body-file -从 stdin 读避免长文本转义问题。验证阶段最容易忽略的是「空 diff」。如果 PR 只改了二进制文件或没实际变更/tmp/pr.diff是空的Claude 会返回一个空结果或报错。稳妥做法是加个判断if [ -s /tmp/pr.diff ]; then claude -p ... --output-format json /tmp/pr.diff /tmp/review.json else echo {result:no changes} /tmp/review.json fi5. 常见报错排查对照这一节按真实报错来。Headless 模式在 CI 里翻车基本集中在下面几类。401 Unauthorized。最常见。原因通常是 Secret 没配、名字拼错、或者 Key 已失效。排查顺序先在 Actions 日志里确认环境变量是否被正确注入不要打印 Key 本身打印它的长度即可再本地用同一个 Key 跑一次。如果本地通、CI 不通就是 Secret 引用的问题。local proxy failed / connection refused。这类是网络层。检查ANTHROPIC_BASE_URL是否写对、是否多了斜杠或路径。CI runner 的出网策略也可能拦截确认 runner 能访问该域名。Cannot index / reading choices。这个报错通常出现在下游jq解析时说明你拿到的 JSON 结构和预期不符。可能是 Claude Code 返回了错误对象而不是成功对象.result字段不存在。先cat /tmp/review.json看原始内容再决定解析路径。别一上来就jq -r .result先确认结构。OAuth / authentication error。如果你之前用交互模式登录过本地可能存了 OAuth 凭证和 CI 里的 API Key 模式冲突。CI 环境是干净的一般不会有这问题本地测试时如果报 OAuth 相关错误检查是否有残留的凭证文件干扰必要时清掉再用环境变量。进程挂起直到超时。这是忘了加-p的典型症状。没有-pClaude Code 会进入交互模式等输入CI 里没人输入就一直挂着。确认命令里-p存在。输出为空但退出码为 0。检查 stdin 是否真的有内容。管道上游命令失败时stdin 可能是空的Claude 收到空输入返回空结果。加set -o pipefail让上游失败能传导出来。把这几类对照着看基本能覆盖 90% 的接入问题。核心心法先看原始输出再谈解析先本地复现再查 CI。6. 把 Headless 能力接到你的工作流里跑通之后你会发现 Headless 模式的想象空间比想象中大。除了 PR 审查还能做批量文件分析、提交信息规范化、甚至把散落的 TODO 自动转成 Issue 格式。它的设计哲学是 Unix 那套「小工具、大组合」——Claude Code 站在管道中间接收上游数据处理后传给下游。如果你要长期在 CI 里跑这类任务建议把 Key 管理和用量监控做起来。TaoToken 的 API Keys 页面可以生成和管理密钥接入文档里有各语言的调用示例地址分别是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 和 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。想先在网页里验证模型输出是否符合预期可以用模型对话页面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 快速试。如果这套 Headless 审查要跑在很多仓库、频率也高那 Coding Plan 会更划算适合长期编码和 Agent 类任务入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 。控制台在 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite 可以看用量和成本。最后给个实用技巧把审查规范写进项目根目录的CLAUDE.md。无论是本地脚本还是 Actions 里的 Claude都会读它。一份配置统一所有环节的审查标准比在每个 workflow 里重复写 prompt 干净得多。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进