3 个配置让 Claude Code Router 稳定跑进 CI/CD:AI 代码审查的 GitHub Actions 实战【免费下载链接】claude-code-routerOne local control plane for every AI agent: route across models, fuse new capabilities, orchestrate tools, and stay fully in control.项目地址: https://gitcode.com/GitHub_Trending/cl/claude-code-router凌晨 3 点,流水线里的 AI 审查任务跑到一半卡死,日志里只有一行EAGAIN: resource temporarily unavailable,手动重跑三次,三次同死。把这类任务搬进 GitHub Actions 等 CI/CD 环境,问题从来不在模型本身,而在进程怎么跑。Claude Code Router(下称 CCR)的定位是本地模型网关:它在127.0.0.1上常驻一个 HTTP 服务,审查任务用一次性的无状态请求打进去,跑完即退出——这正是流水线需要的形态。为什么 AI 审查任务一进流水线就卡死CI 里 AI 任务的死法基本就两种:真超时和假挂起,排查前先分清是哪一种。假挂起最隐蔽,进程不报错、不退出,只是永远停在某个位置,runner 干等直到被超时杀掉。两种典型死法:真超时和假挂起假挂起的根源是交互假设。交互式 CLI 会开 TTY、等键盘输入、渲染 spinner,而 runner 上根本没有键盘,进程就在等输入这一步活埋了自己。你看到的EAGAIN往往也不是致命错误,而是并发任务挤占 runner 的文件描述符后,某个等待读入的操作拿不到资源,进程从此既不推进也不报错。真超时则直白得多:AI 审查一次调用就要几分钟,默认 10 分钟级别的超时配上重试,一个 job 轻松吃掉 runner 大半配额。两种死法指向同一个根因:你在用一个交互式、有状态、长驻的进程形态,去填一个无交互、无状态、用完即走的自动化坑位。非交互模式怎么配:网关长驻,任务一次性解法是把进程模型劈成两半:CCR 网关负责长驻,审查任务负责一次性。ccr start把网关拉成常驻服务,默认监听127.0.0.1:3456,它自己就是一个无交互的 HTTP 服务;审查任务则用claude -p的 print 模式,一条命令、一次请求、跑完退出,两个进程之间只剩一条 localhost 上的 HTTP 调用。网关地址、管理端口和客户端密钥的关系,可以看 服务配置 一节。非交互模式本质上是告诉子进程:别等键盘输入,stdin 我帮你关掉了。CI 里做到这一点只需要三个动作:用-p保证不开 TTY;命令尾部加 /dev/null彻底关闭标准输入;设TERMdumb和CItrue,让终端相关库别尝试渲染。export CItrue TERMdumb claude -p 审查当前 PR 的 diff,输出问题清单 /dev/null密钥别写死:环境变量插值密钥管理靠占位符。把配置文件提交进仓库时,敏感字段一律写$OPENROUTER_API_KEY这种引用,CCR 加载配置时会把$变量名或${变量名}替换成真实环境变量;真实密钥只从 Actions secrets 注入 job 级env,全程不落仓库。⚠️ 这里有个坑:插值发生在配置的初次加载阶段,而 GitHub Actions 的临时 runner 每次都是全新环境,写config.json再启动恰恰是标准流程,所以没感觉;但自托管的持久化机器上,配置迁移过一次之后,别再指望改文件会重新插值一遍。客户端接入网关的三个变量客户端只需要认识网关,不需要认识上游供应商,三件事就够:base URL 指到http://127.0.0.1:3456;API Key 填 CCR 自己签发的客户端 Key(配置文件里的APIKEY字段);上游供应商的 Key 只留在 CCR 配置里。客户端 Key 和上游 Key 是两套东西,别混用,这是最常见的 401 来源。一条完整的 GitHub Actions 工作流怎么写整条流水线就四步:装依赖、种配置并拉起网关、跑审查、输出报告。配置文件以占位符形式提交到.github/ccr-config.json,真实密钥靠环境变量在启动瞬间插值进去。{ API_TIMEOUT_MS: 120000, APIKEY: $CCR_CLIENT_KEY, Providers: [ { name: openrouter, api_base_url: https://openrouter.ai/api/v1, api_key: $OPENROUTER_API_KEY, models: [anthropic/claude-sonnet-4], transformer: { use: [openrouter] } } ], Router: { default: openrouter,anthropic/claude-sonnet-4 } }对应的完整工作流如下,可直接复制:name: AI Code Review on: pull_request jobs: review: runs-on: ubuntu-latest env: CCR_CLIENT_KEY: ${{ secrets.CCR_CLIENT_KEY }} OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} ANTHROPIC_BASE_URL: http://127.0.0.1:3456 ANTHROPIC_API_KEY: ${{ secrets.CCR_CLIENT_KEY }} steps: - uses: actions/checkoutv4 - run: npm i -g musistudio/claude-code-router claude-code - run: cp .github/ccr-config.json ~/.claude-code-router/config.json ccr start - run: claude -p 审查当前 PR 的 diff,输出问题清单这几行里藏的三件事cp和ccr start写在同一个 step 不是偷懒:插值发生在ccr start读取配置的那一刻,job 级env恰好在这个时刻可用,顺序不能反。最后一个 step 里的ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY只影响审查进程,它把网关当唯一上游,上游 Key 从头到尾没进过这个 shell。最后给 job 配一个 15 分钟的超时,超时就让整个 job 失败,用 Actions 自带的 re-run 重来,别在进程内无限重试。超时、重试和路由成本控制怎么调优超时和重试速查超时建议把API_TIMEOUT_MS设为120000:CI 场景下 2 分钟超时比默认的 10 分钟更合理,快速失败比慢速等待便宜。不同场景的推荐值:环境类型推荐 API_TIMEOUT_MS理由交互式开发600000(默认)人在等,允许模型慢慢想CI/CD 流水线120000快速失败,2 分钟通常够用批处理 / 夜间分析1800000任务复杂,但要用并发上限兜底重试策略建议网关管单次,job 管整次:CCR 的 Router 支持失败时回退到备用模型,单次调用层面的抖动交给它;整条任务失败则让 job 退出非零,交给 Actions 重跑,避免进程内重试和 job 重试叠加,把一次审查烧成三次账单。三级路由:实习生、架构师和专家路由策略可以类比成派活:日常审查找实习生(便宜快速的模型),架构级 PR 找架构师(强推理模型),批量机械子任务找流水线工人(最便宜的模型)。CCR 里就对应Router把不同场景映射到不同的供应商,模型,默认路由兜底,自定义规则按请求条件挑模型,规则和回退的实现可以翻 packages/core/src/routing/ 看。 真正省钱的一招是 Subagent 自动路由:Claude Code 主请求派生的 Task / Agent 子请求,CCR 会按你给模型写的 Description 让它们自动改用便宜模型。一次 PR 审查里,主请求走强模型,子请求里大量的搜文件、读代码走低价模型,成本大头直接砍掉。非交互模式解决会不会挂,长驻网关加无状态请求解决挂在哪里,三级路由解决挂一次花多少钱。这三件事齐了,AI 审查在流水线里就从一次玄学变成一条可预期、可重跑、成本可审计的常规动作。【免费下载链接】claude-code-routerOne local control plane for every AI agent: route across models, fuse new capabilities, orchestrate tools, and stay fully in control.项目地址: https://gitcode.com/GitHub_Trending/cl/claude-code-router创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
