在 CI 里跑 Claude Code 这件事,我折腾了整整两天才跑通。把过程中踩过的坑、验证过的配置、还有实际生产环境中跑了一个多月的经验整理出来,希望能帮你少走弯路。
1. 为什么要用 claude-code-action
先说清楚这个东西解决什么问题。claude-code-action是一个 GitHub Action,让 Claude Code CLI 直接跑在 GitHub Actions 的 runner 上。核心用途是两大类:一是自动给 PR 做 code review,二是让 Claude 在 CI 环境里自动改代码、跑测试、提交 PR。
我最初的需求很简单:团队代码 review 人手不够,希望有个 AI 能先过一遍,把明显的问题挑出来,但不需要它真的改代码。后来加了一个更进阶的用法:让它自动修 lint 错误、自动补测试,跑完直接开一个 PR。
为什么不是本地跑?本地跑有一个致命问题——不可复现。Claude 在本地改了什么、什么时候跑的、用的什么模型版本,这些都没有记录。放到 CI 里就不一样了:每一次执行都有日志、有时间戳、有可追溯的上下文。这在团队协作里非常重要,尤其是多个开发者共用同一个 GitHub 仓库时,你总得知道这个 AI 到底干了什么。
再说一下为什么这个 action 比自己在 workflow 里裸调 CLI 更靠谱。直接写claude -p "review this diff"这种命令会遇到几个坑:认证 token 怎么传、工作目录怎么切、JSON 输出怎么接、失败重试怎么办。这些 claude-code-action 已经都处理好了,有输入参数可以控制,有输出可以直接后续步骤复用。省掉的这些时间,足够你多配三个 workflow。
2. 环境准备与前置条件
2.1 必要的权限与密钥
用这个 action 之前,先把 GitHub 侧的权限理清楚。
第一件事是确保 workflow 有权限。在 repository settings 里,Actions > General > Workflow permissions需要设置为Read and write permissions,否则 action 即使启动了,也没法创建 PR、没法提交 code review comment。这个权限设置是很隐蔽的一个坑,我见过不少人配置完全正确,就是跑起来之后 GitHub API 返回 403,排查到最后发现是仓库本身的 workflow 权限没开。
第二件事是 API key。如果你用的是 Claude API,你需要一个ANTHROPIC_API_KEY存在 GitHub Secrets 里。如果你用的是 Claude Code 的订阅账号(比如 Pro 或者 Max),那你需要CLAUDE_CODE_OAUTH_TOKEN,这个 token 可以通过在本地登录 Claude Code 后,从~/.claude/credentials.json里找到。两者在生产环境里我建议都用 API key,因为 OAuth token 有设备绑定和有效期,跑一跑突然失效会让你欲哭无泪。
2.2 最小配置示例
一个最简的 workflow 长这样:
name: Claude Code Review on: pull_request: types: [opened, synchronize] jobs: review: runs-on: ubuntu-latest permissions: contents: write pull-requests: write steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: anthropics/claude-code-action@v1 with: claude-code-auth-token: ${{ secrets.ANTHROPIC_API_KEY }} prompt: "Review this pull request. Identify bugs, security issues, and style problems. Return results as a JSON object with a 'comments' array."这里有两个细节值得注意。fetch-depth: 0很重要,它让 checkout 拿到完整的 git 历史,这样 Claude 才能正确理解 diff 的上下文。如果不加这一行,Claude Code 看到的可能只有最新的一个 commit,review 质量会大打折扣。permissions块也要显式声明,GitHub 默认的权限是只读,不写这一块就只能看不能写。
2.3 模型选择与参数配置
claude-code-action本身不直接暴露模型参数,但你可以通过环境变量控制。最常用的是ANTHROPIC_MODEL,比如设成claude-sonnet-4-20250514。
经验之谈:review 任务用默认模型就够,因为 review 是一次性的分析任务,token 用量可控;但自动修代码、开 PR 这类多轮 agentic 任务,建议显式指定更强的模型,并加上max-think-tokens这类参数。我自己在项目里跑自动修 bug 任务时发现,默认配置的模型有时候在复杂代码路径上会“偷懒”,给定一个看似合理但根本没修对的方案。换成指定模型并给了更大的思考空间之后,正确率明显提升。
参数层面的调优后面详述,先把 workflow 跑起来。
3. 核心玩法:三种典型场景
3.1 场景一:PR 自动 Code Review
这是最简单的用法,也是我认为价值密度最高的用法。让 Claude 在每次 PR 变更时自动分析代码,然后把意见作为 review comment 提交到 PR 上。
- uses: anthropics/claude-code-action@v1 with: claude-code-auth-token: ${{ secrets.ANTHROPIC_API_KEY }} prompt: | You are a senior software engineer. Review this PR carefully. Focus on: 1. Logic errors and edge cases 2. Security vulnerabilities 3. Performance issues 4. Code style consistency For each issue, provide: - File path and line number - Severity (critical / major / minor) - Explanation of the problem - Suggested fix Format the output as YAML for easy parsing.直接跑这个配置,Claude 的分析结果会出现在 workflow 的日志输出里,不会自动变成 PR comment。如果你想要它直接发到 PR 上,需要加一个后续步骤来处理输出。
- uses: anthropics/claude-code-action@v1 id: review with: claude-code-auth-token: ${{ secrets.ANTHROPIC_API_KEY }} prompt: "Review the PR and provide a summary of issues." output: "review-result.md" - name: Post Review Comment run: | gh pr comment ${{ github.event.pull_request.number }} --body-file review-result.md env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}这里用到了 action 的output参数,它会把 Claude 的输出写入一个文件,后面的步骤直接读取这个文件。一开始我没发现这个参数,走了一个弯路:用${{ steps.review.outputs.output }}去拿结果,发现拿到的只是文件名,不是内容。后来看了源码才知道,这个 action 会把内容写进指定的文件,你需要自己再读出来。
3.2 场景二:自动修代码并开 PR
这个玩法的核心思路是:给 Claude 一个明确的任务,让它直接改代码、跑测试(可选)、然后提交到一个新分支并开 PR。
name: Auto Fix Lint Issues on: schedule: - cron: '0 2 * * *' # 每天凌晨两点 workflow_dispatch: # 支持手动触发 jobs: autofix: runs-on: ubuntu-latest permissions: contents: write pull-requests: write steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Run Claude Code Auto Fix uses: anthropics/claude-code-action@v1 with: claude-code-auth-token: ${{ secrets.ANTHROPIC_API_KEY }} prompt: | Run the linter with: npm run lint If there are lint errors, fix them. Then commit and push the changes to a new branch called 'autofix/lint'. Finally, open a pull request against the main branch with title "chore: auto-fix lint issues".这个赛季的关键是你必须给 Claude 的权限足够大。除了之前提到的contents: write,还需要注意actions: write权限(用于触发一些后续 action),而且 Claude 在 CI 里默认是交互模式,你必须在 prompt 后面给它加一个明确的指示,比如 "Do not ask the user for confirmation, just do it"。否则 workflow 会挂在那里等输入。
在实际项目中跑这个方案,最大的痛点是 Claude 改完代码后,提交到 GitHub 的过程容易出问题。正常的做法是把 GitHub CLI(gh)预装在 runner 上,但 Claude 有时候会因为 git 用户没有配置而报错。在 prompt 里提前告诉它“先配置git config user.name和user.email,然后再 commit”,可以避免大部分这种问题。
跑这个任务我踩过一个具体的坑:Claude 改完代码后执行git push时,仓库的状态不是预期的,于是它自作聪明地做了git pull --rebase,结果产生了大量冲突。原因是 main 分支在任务执行期间被其他人更新了。后来我在 prompt 里加了“don't pull or merge,only push to a fresh branch”,并且让 action 可以拿到浅克隆(shallow clone),分支创建后直接强推(force push),问题就消失了。
3.3 场景三:接收外部输入做定向任务
这个更适合团队内部构建“AI 自动化流水线”,比如把 GitHub Issue 作为任务源,让 Claude 去处理。
name: Issue Auto-Responder on: issues: types: [opened] jobs: respond: runs-on: ubuntu-latest permissions: issues: write steps: - uses: actions/checkout@v4 - uses: anthropics/claude-code-action@v1 with: claude-code-auth-token: ${{ secrets.ANTHROPIC_API_KEY }} prompt: | A new issue has been opened: "${{ github.event.issue.title }}" The issue body is: ${{ github.event.issue.body }} 1. Analyze the issue and determine if it's a bug report, feature request, or question. 2. If it's a bug report, check if the codebase has code related to the issue description. 3. Output a response with: - Classification - Initial analysis - Suggested next steps Do not modify any files. Just output the analysis.这个玩法适合给开源项目搭建自动化的 Issue triage 机器人。我自己在一个组织内部用过类似配置,效果是:Issue 一开,几分钟内就有一个初步的分析报告,包括问题分类、疑似相关代码位置、建议的修复方向。维护者拿到这个报告后再决定要不要深入处理,效率提升非常明显。
4. 输入输出机制与数据复用
4.1 输入参数详解
我扒了一遍 claude-code-action 的源码,把常用的输入参数整理成表:
| 参数名 | 作用 | 备注 |
|---|---|---|
claude-code-auth-token | 认证 token | API Key 或 OAuth Token |
prompt | 给 Claude 的任务描述 | 支持多行字符串 |
output | 将输出保存到指定文件 | 为空时输出到 stdout |
working-directory | 指定 Claude 的工作路径 | 默认为仓库根目录 |
args | 传给claude命令的额外参数 | 用逗号分隔 |
github-token | 用于 GitHub API 操作 | 默认使用GITHUB_TOKEN |
debug | 是否输出调试信息 | 选true时会有详细走查 |
args这个参数是通往高级玩法的钥匙。我需要给 Claude 指定模型时,就是用args: "--model,claude-sonnet-4-20250514"这样传的。查看当前支持的所有模型可以用claude model命令在本地查看。
实际使用中working-directory也很实用。如果你想在 monorepo 里只处理某个子项目,把工作目录指进去,Claude 就只会看到那个子目录,不会被其他无关代码干扰。这在上下文窗口有限的情况下很有意义。
4.2 输出复用技巧
Claude Code CLI 有一个 JSON 输出模式,这在做自动化时特别好用。你可以在 prompt 里要求它输出 JSON,然后把产出文件交给后续步骤处理。
- name: Generate Test Report uses: anthropics/claude-code-action@v1 id: gen_tests with: claude-code-auth-token: ${{ secrets.ANTHROPIC_API_KEY }} prompt: | Look at the file src/utils/string.ts. Generate unit tests for all functions in this file. Use vitest syntax. Write the tests to tests/string.test.ts. output: "tests-created.txt" - name: Verify Tests Pass run: npm test - name: Commit Tests run: | git add tests/ git diff --cached --stat这里有一个小技巧:不一定非要用output参数生成的文件,也可以直接在后一步读 stdout——但 stdout 也可能包含其他信息(比如 Claude 的辅助话语),不适合直接当结构化数据用。我把output参数学到的规范用起来后,后续步骤可靠了许多。
5. 实际项目中的参数调优与成本控制
5.1 控制 Token 消耗的实战经验
AI 自动化的一个隐性问题就是成本。让 Claude Code 在 CI 里自主干活,如果不做任何约束,同一个任务可能吃掉几百 k 的 token,费用对小型团队来说并不轻。
我的控制策略有两种:
第一,在 prompt 里限制范围。比如“只 review 这个 PR 中新增的代码,跳过已有逻辑”,直接把分析范围压缩到 diff 而不是整个仓库。这个简单的一句话,能让 token 消耗下降 50% 以上。
第二,利用args参数限制输出长度和思考预算:
with: claude-code-auth-token: ${{ secrets.ANTHROPIC_API_KEY }} args: "--max-turns,8,--max-output-tokens,1024" prompt: "Fix all lint errors in src/ directory. Do not ask questions. Just do it."max-turns限制 Claude 在任务中可以执行的工具调用次数,max-output-tokens限制每次回复的长度。这两个参数加上之后,就算任务规划失控,也不会无限消耗下去。
这里我个人的实测数据:跑一个 200 行变更的 PR review,不限制时平均消耗约 45k token;加上--max-turns,6和--max-output-tokens,1024后,基本稳定在 28k 左右,而且 review 质量没有明显下降。如果你的场景是“每天定时修复”,再加一个条件判断:只有在 diff 文件数大于某个阈值时才执行 Claude,进一步降低空跑的成本。
5.2 并发与超时设置
Claude Code 执行任务不是瞬间完成的,复杂任务可能在几分钟到十几分钟之间。GitHub Actions 默认 job 超时是 6 小时,但对 AI 任务不要给这么长。并非所有人都意识到,任务挂住时你也是在烧 token 的。
我的做法是设置timeout-minutes: 30。如果 30 分钟没有跑完,基本可以断定任务设计或者 prompt 描述出了问题,把整个 job 杀掉更合理。
并发控制上,限制条件是同一个仓库同一时间只能有一个 AI 任务在跑,否则两个 Claude 同时改代码,会产生 git 冲突。在 workflow 里加 concurrency 块:
concurrency: group: claude-code-${{ github.ref }} cancel-in-progress: true为简便起见我把cancel-in-progress关掉了,因为取消进行中的任务实际上会造成 token 的浪费——已经烧掉的 API 费用是不会退的。如果希望后来的任务等待而不是取消前面,不要设置这个字段即可。
5.3 失败重试策略
AI 执行任务本身就带不确定性,同一个 prompt 跑 10 次可能会有 1 次跑偏。不要让 workflow 因为一次失败就报红。
我给一万步的 workflow 配置了continue-on-error: true,让主流程继续跑,但在最后加一个“判断 Claude 任务是否成功”的步骤,仅在该步骤输出警告而不是让整个 CI 失败。这样主要目的(让 AI 完成大部分工作)依然成立,剩下的边缘情况再人工处理。
对于自动开 PR 的任务,因为 push 失败需要重新跑,我会用更保守的策略。要是那次跑的结果没有达到预期,我宁可人工重跑,也不想让 workflow 自动疯狂重试——因为重试一次就是一笔 API 费用。
6. 常见错误与排查手册
6.1 认证失败(401 / 403)
这个坑出现频率最高。配置正确的前提下,最常见的原因是 Secrets 名字打错了。我建议先去仓库的 Actions 日志里看具体报错信息:
- 如果看到
Authentication failed,检查 secrets 是否以正确名字存在。 - 如果看到
403 Forbidden,大概率是 workflow 权限设置成了 read-only。
在 Actions 设置里把Workflow permissions改为读写权限,是最快的解决方案。
另外,如果你的 API Key 是在 Anthropic Console 创建的,确认它有正确的预算和权限。免费额度用完了也会出现认证失败,这个报错很具有迷惑性。
6.2 Claude 执行过程中卡住不动
在日志里如果看到 Claude 输出停在某个工具调用,没有后续进展,可能有三个原因:
- 模型在做长思考,需要更长轮次。加大
max-turns或者直接提高timeout-minutes。 - 任务的 prompt 里带有“ask me if you need help”之类的语句,导致 Claude 在等待输入。使用非交互模式时,在 prompt 里同时加上 “You should not ask the user for additional input. Make reasonable assumptions and complete the task.”。
- 仓库 checkout 不完整导致 Claude 找不到文件。确认
fetch-depth: 0。
6.3 Push 失败 / 无法写入分支
这类问题比较直白,多做几个检查:
- 是否给了 action 对仓库的写权限(
contents: write)。 - 是否设置了
GITHUB_TOKEN或者自定义的 token。切记:如果使用默认的GITHUB_TOKEN,这个 token 只在当前 job 内有效,并且仓库的 Actions 权限须为允许写。 - 如果仓库启用了 branch protection,默认的
GITHUB_TOKEN无法直接 push 到受保护的 main 分支。这种情况最常见且最易误导人,解决方案是创建一个带 push 权限的 Personal Access Token,把它存在 Secrets 里,再在 workflow 的 env 中引用。
6.4 生成的代码质量不稳定
我的体感是,这个不稳定并不是模型能力的问题,更多是任务描述不清晰导致的。有一次我让它“写一个函数判断字符串是否是回文”,它写出了递归 + 栈 + 正则去特殊字符的版本,明显过度包装了。
此后我在所有 prompt 开头都会加上“Write the simplest possible production code. Do not over-engineer. Do not add extra features.”这类限制定语,代码质量稳定很多。
还有一个实用技巧是:在 prompt 里规定“只改目标问题,不要重构其他代码”。否则你能看到它顺手帮你把文件里 10 年前的旧写法全换了一遍——让你胆战心惊。
7. 生产环境的实战经验总结
这套配置在我们团队已经稳定跑了一个半月,每天凌晨自动修 lint、自动补测试、自动清理 TODO 注释。从我观察到的产出看,收益有几个方面:
一是 PR review 的覆盖率大幅提升。以前人工 review 很容易漏掉小问题,现在 Claude 在代码合并之前总能先抓住几处逻辑问题。虽然质量比不上顶级工程师,但是“永不休眠”这一点,是人力无法替代的。
二是自动化修 lint 这类重复劳动,确实释放了我不少时间。每天醒来看到 auto-fix PR 已经开好,commit 清晰,描述明确,只需花五分钟看下 diff 就能合并。
但你也要清楚它的边界。Claude Code Action 目前不适合做需要强领域知识的任务,比如“这个第三方 SDK 的最佳实践是什么”这类问题,它的回答质量浮动较大。对大型仓库的全局重构,也不推荐让它在 CI 里自主行动,上下文和代码库的边界把握很容易失控。
最后给一个我在使用中沉淀下来的配置清单,仅供参考:
- uses: anthropics/claude-code-action@v1 with: claude-code-auth-token: ${{ secrets.ANTHROPIC_API_KEY }} prompt: | You are working in a production codebase. 1. Read the provided context carefully. 2. Make the minimal changes to satisfy the request. 3. Do not ask for confirmation. 4. Check your work with git diff. 5. Only commit if the change is complete. output: "result.md" args: "--max-turns,10,--max-output-tokens,2048" working-directory: "src/svc"这个动作配合一个“通知 Slack 或者飞书群”的后续步骤,就是一套完整的 AI 自动化闭环。配置不复杂,做到稳定运行靠的是耐心调试和不断的 prompt 迭代。
实际上,往后加一步——用gh pr create --title "AI autofix: 日期" --body "由 Claude Code Action 自动提交"创建 PR,这套 CI 的能力就圆满了。跑起来之后你会发现,不只是 review,很多以前想做的自动化又多了另一种可能性。