Claude Code 在 CI/CD 里翻车了:一个真实项目的坑
把 Claude Code 接入 GitLab CI 后遇到的 token 过期、stdin 阻塞、输出格式不稳定和并发限流问题,以及最终的解决方案。
# Claude Code 在 CI/CD 里翻车了:一个真实项目的坑
上周把 Claude Code 接入 GitLab CI,想着自动化 code review 能省不少事。结果部署当天,Pipeline 直接红成一片。
初衷很简单
项目是个 Node.js 的微服务集群,PR 进来后跑 lint、test,再加一轮 AI review。之前用 GitHub Actions + Copilot 写过类似的,这次迁移到 GitLab 就想着用 Claude Code 替代。
配置看起来挺 straightforward:
# .gitlab-ci.yml
ai-review:
stage: review
image: node:20
script:
- npm ci
- npx @anthropic-ai/claude-code review --model sonnet
only:
- merge_requests
第一个坑:token 过期比想象中还快
Claude Code 的 auth token 默认 24 小时过期。我们的 CI runner 是共享的,前一个 job 占着 token,下一个 job 进来直接 401。
解决方案是把 token 存成 GitLab CI variable,然后在每个 job 里重新 auth:
export ANTHROPIC_AUTH_TOKEN=$CI_ANTHROPIC_TOKEN
claude auth refresh
但刷新之后再跑 review,发现 token 被 runner 的 env 覆盖了。最后还是用了 service account 的方式,给 Claude Code 配了一个专用 API key,绕过了 auth token 机制。
第二个坑:stdin 阻塞
Claude Code 在 CI 里跑 review 时,它会尝试读 stdin 来等待用户输入。但 CI 环境没有 TTY,它卡在那儿不动,直到 timeout。
加 --no-stdin 参数能解决,但官方文档里这个 flag 藏在 changelog 的角落里,差点以为是我用错了版本。
claude code review --model sonnet --no-stdin --output json
第三个坑:输出格式不稳定
我们期望拿到 JSON 格式的 review 结果,好让它自动评论到 MR 上。但 Claude Code 的输出格式在不同 model 版本之间变化很大。
Sonnet 4 输出的是带 markdown 的代码块,Sonnet 3.5 输出的是纯文本。更糟糕的是,同一个版本在不同 PR 规模下,输出长度差异巨大——50 行改动和 500 行改动,review 结果的质量完全不在一个层级。
最后我们退回到用 Anthropic API 直接调用,自己拼 prompt 和解析输出。虽然少了 Claude Code 的交互体验,但在 CI 里稳定可靠更重要。
第四个坑:并发限制
我们的 GitLab runner 同时跑 4 个 job,每个 job 都调 Claude API。短时间内请求量飙升,触发了 API 的 rate limit。
错误信息是 429 Too Many Requests,但 Claude 的 rate limit 是按 org 级别的,不是按 account。我们升级了 plan 才解决。
建议
如果你也在 CI 里用 Claude Code:
2. **加 --no-stdin**,否则 CI 环境会卡住
3. **用 API 代替 CLI**,CLI 的输出格式不稳定,API 更可控
4. **评估并发需求**,shared runner 的 rate limit 很容易被触发
最后说一句,Claude Code 做本地开发体验很好,但 CI/CD 场景下它还不够成熟。等它把 --no-stdin 写进正式文档之前,我建议先绕道。