
1. openrig 到底是个什么东西第一次看到 openrig 这个名字我下意识以为是某个硬件外设的开源项目毕竟 rig 这个词在英文里本意就是“装配、设备”。但翻了一圈社区讨论和仓库结构之后才反应过来它其实是围绕 AI 编程助手生态做的一套本地配置编排工具核心解决的是 Claude Code、Codex 这类命令行 AI 助手在本地跑起来时配置散落、模型切换麻烦、代理转发容易崩的问题。说白了openrig 想干的事情就是把 Claude Code、Codex 这些工具的配置统一收口到一份 YAML 里然后用 Node.js 起一个本地服务负责模型路由、请求转发、配置热加载。你不需要每次换模型都去改一堆环境变量也不用担心 cc switch 切到一半报local proxy failed while handling codex endpoint /responses这种让人头大的错误。它适合谁三类人最值得关注。第一类是同时用 Claude Code 和 Codex 的开发者经常要在两套配置之间来回切第二类是想把本地模型比如通过 LM Studio 跑的模型接进 Claude Code 的人第三类是团队里需要统一管理多个 AI 助手配置、又不想把密钥散落在每个人机器上的技术负责人。如果你只是偶尔用一下某个 AI 助手那 openrig 可能有点重但只要你开始认真把 AI 助手当生产力工具用这套东西的价值就出来了。我自己的场景是白天用 Claude Code 写业务代码晚上用 Codex 跑一些脚本和重构任务中间还要切到本地模型做一些隐私敏感的文本处理。以前每次切换都要手动改配置文件、重启终端偶尔还会因为代理端口冲突导致请求全部失败。openrig 把这一整套流程压缩成了一份 YAML 加一条启动命令这是我愿意花时间研究它的直接原因。2. 核心设计思路与方案选型拆解2.1 为什么是 YAML 而不是 JSON 或 TOMLopenrig 选择 YAML 作为配置格式这个决定背后有很实际的考量。JSON 不支持注释而 AI 助手的配置里有大量需要说明的地方比如某个模型端点的用途、某个密钥的来源、某个超时参数的调整原因。TOML 虽然支持注释但嵌套结构写起来比较啰嗦尤其是当你要配置多个模型提供商、每个提供商下面又有多个模型的时候TOML 的[provider.model]这种写法会让人眼花。YAML 的缩进结构天然适合表达“提供商 → 模型 → 参数”这种层级关系。你可以这样写providers: anthropic: api_key: ${ANTHROPIC_API_KEY} models: claude-sonnet: endpoint: https://api.anthropic.com/v1/messages max_tokens: 8192 local: api_key: not-needed models: qwen-local: endpoint: http://localhost:1234/v1/chat/completions max_tokens: 4096这种结构一眼就能看出层级关系改起来也方便。而且 YAML 支持环境变量插值${ANTHROPIC_API_KEY}这种写法让密钥不用硬编码在文件里这对团队协作来说很重要。我试过用 JSON 管理类似配置光是处理转义和缺少注释这两点就够让人烦躁的。不过 YAML 也有坑最大的问题就是缩进敏感。一个空格和两个空格的差别可能导致整个配置解析失败而且报错信息往往不直观。我的经验是统一用两个空格缩进绝对不要用 Tab并且在编辑器里开启“显示空白字符”功能。另外YAML 里冒号后面必须跟一个空格key:value这种写法在某些解析器里会直接报错。2.2 Node.js 作为运行时是必然选择openrig 用 Node.js 而不是 Python 或 Go这个选择跟它的目标用户群体高度相关。Claude Code 和 Codex 本身就是 Node.js 生态里的工具安装方式基本都是npm install -g。用户既然已经在用这些工具机器上必然有 Node.js 环境openrig 用 Node.js 写就不会引入额外的运行时依赖。从技术角度看Node.js 的事件驱动模型非常适合做代理转发这种 I/O 密集型任务。openrig 的核心工作就是接收请求、根据配置路由到不同的模型端点、把响应流式返回给客户端这整个过程几乎不涉及 CPU 密集计算Node.js 的单线程异步模型处理起来绰绰有余。而且 Node.js 的http和https模块原生支持流式传输对于 AI 助手这种需要 SSEServer-Sent Events流式返回的场景来说实现起来很自然。我实测下来用 Node.js 写的本地代理在 M1 Mac 上处理并发请求时内存占用稳定在 80MB 左右CPU 占用在空闲时几乎为零。这个开销对于一台开发机来说完全可以接受。如果你用 Python 写类似的代理光是启动一个 Flask 或 FastAPI 服务就要吃掉更多内存而且异步流式处理的代码写起来比 Node.js 啰嗦不少。2.3 本地代理转发的核心价值openrig 最核心的功能其实是那个本地代理。为什么需要代理因为 Claude Code 和 Codex 各自有自己的 API 端点配置方式有的通过环境变量有的通过配置文件而且它们对请求格式的要求也不完全一样。openrig 在中间加一层代理把所有请求统一成一种格式然后再根据配置转发到真正的模型端点。这样做的好处有三个。第一是统一入口你只需要告诉 Claude Code 和 Codex 把请求发到http://localhost:PORT剩下的路由逻辑由 openrig 处理。第二是格式转换比如 Codex 用的是/responses端点而某些本地模型只支持/chat/completionsopenrig 可以在中间做转换。第三是故障隔离当某个模型端点不可用时openrig 可以返回一个清晰的错误信息而不是让 Claude Code 或 Codex 抛出一堆看不懂的堆栈。那个热搜词里出现的cc switch local proxy failed while handling codex endpoint /responses错误本质上就是代理层在处理 Codex 的/responses端点时出了问题。常见原因包括代理没有正确识别 Codex 的请求格式、目标端点不支持/responses路径、或者流式响应的分块处理有 bug。openrig 的设计目标之一就是把这些边界情况处理好让用户不用去关心底层细节。3. 从零搭建 openrig 的完整实操流程3.1 环境准备Node.js 安装与版本选择openrig 对 Node.js 版本有要求建议用 LTS 版本。截至我写这篇内容的时候Node.js 22.x 是 active LTS20.x 是 maintenance LTS。如果你机器上还没有 Node.js去官网下载 LTS 安装包就行。Windows 用户直接下.msimacOS 用户下.pkgLinux 用户可以用包管理器或者 nvm。我强烈建议用 nvm 来管理 Node.js 版本因为不同项目可能依赖不同版本。安装 nvm 之后一行命令就能切换nvm install 22 nvm use 22 node -v如果你遇到error installing 24.21.0: node.js v24.21.0 is not yet released or is not available这种错误说明你指定的版本号不存在或者还没发布。Node.js 的版本号是严格按语义化版本来的偶数版本是 LTS奇数版本是当前版。24.x 如果还没到 LTS 阶段用nvm install --lts装最新的 LTS 就行。安装完 Node.js 之后确认 npm 也能正常工作npm -vnpm 一般会随 Node.js 一起安装如果npm -v报错可能是 PATH 没配好。Windows 上重装 Node.js 通常能解决macOS 和 Linux 上检查一下~/.nvm/versions/node/目录下有没有对应的 bin 路径。3.2 openrig 的获取与初始化openrig 目前主要通过 npm 分发安装命令很直接npm install -g openrig如果你不想全局安装也可以用npx openrig直接运行。全局安装的好处是可以在任何目录下直接敲openrig命令坏处是版本管理稍微麻烦一点。我个人的习惯是全局装一个稳定版然后在具体项目里用npx跑最新版做测试。安装完成后运行初始化命令openrig init这个命令会在当前目录下生成一个openrig.yaml模板文件同时创建一个.openrig目录用来存放日志和缓存。模板文件里包含了常用的配置项和注释说明你可以直接改也可以删掉重新写。初始化的时候有个细节要注意如果你当前目录已经有一个openrig.yamlopenrig init会提示你是否覆盖。如果你之前已经配好了千万别手快按了覆盖。我建议在初始化之前先git status看一下确保没有未提交的配置改动。3.3 配置文件详解每个字段到底管什么openrig 的配置文件结构分为几个大块server、providers、routes、logging。我逐个拆开讲。server块控制本地代理服务的行为server: port: 8787 host: 127.0.0.1 timeout: 120000 max_retries: 2port是代理监听的端口默认 8787。如果你机器上 8787 被占用了改成别的比如 8899。host建议保持127.0.0.1这样只有本机可以访问安全性更好。timeout是请求超时时间单位毫秒AI 请求有时候会比较慢设成 120 秒比较稳妥。max_retries是失败重试次数对于网络不稳定的情况很有用但别设太大否则一个坏请求会卡很久。providers块定义模型提供商providers: anthropic: type: anthropic api_key: ${ANTHROPIC_API_KEY} base_url: https://api.anthropic.com openai: type: openai api_key: ${OPENAI_API_KEY} base_url: https://api.openai.com/v1 local: type: openai-compatible api_key: dummy base_url: http://localhost:1234/v1type字段告诉 openrig 用哪种协议跟这个提供商通信。anthropic类型会用 Anthropic 的 Messages API 格式openai类型用 OpenAI 的 Chat Completions 格式openai-compatible用于那些兼容 OpenAI 接口的本地服务比如 LM Studio、Ollama 的 OpenAI 兼容模式。routes块是路由规则决定什么请求发到什么模型routes: - match: claude-* provider: anthropic model: claude-sonnet-4-20250514 - match: gpt-* provider: openai model: gpt-4o - match: local-* provider: local model: qwen2.5-7b-instructmatch支持通配符claude-*会匹配所有以claude-开头的模型名。这样你在 Claude Code 里指定模型名的时候只要前缀对得上openrig 就知道该往哪个提供商转发。logging块控制日志行为logging: level: info file: .openrig/openrig.log max_size: 10MB max_files: 5日志级别建议日常用info排查问题时临时改成debug。日志文件会按大小轮转max_size和max_files控制保留策略避免日志把磁盘占满。3.4 启动服务与验证连通性配置写好后启动 openrigopenrig start如果一切正常你会看到类似这样的输出[openrig] server started on 127.0.0.1:8787 [openrig] loaded 3 providers, 3 routes [openrig] config file: /path/to/openrig.yaml这时候 openrig 已经在后台跑起来了。验证连通性最简单的方法是发一个测试请求curl http://127.0.0.1:8787/health如果返回{status:ok}说明服务正常。然后再测试一下模型路由curl http://127.0.0.1:8787/v1/models这个端点会列出所有可用的模型你可以看到 openrig 根据配置生成的模型列表。如果某个提供商没有出现在列表里检查一下对应的api_key环境变量有没有设置。我踩过的一个坑是在 macOS 上openrig start之后如果直接关掉终端窗口服务也会跟着停。解决办法是用openrig start --daemon让它在后台运行或者用nohup openrig start 。Windows 上可以用start /b openrig start。4. 把 Claude Code 和 Codex 接进 openrig4.1 Claude Code 的配置方式Claude Code 通过环境变量来指定 API 端点。在 openrig 启动之后你需要设置export ANTHROPIC_BASE_URLhttp://127.0.0.1:8787 export ANTHROPIC_API_KEYany-valueANTHROPIC_API_KEY这里填什么不重要因为 openrig 会在转发请求的时候用配置文件里的真实密钥替换掉。但有些版本的 Claude Code 会检查这个变量是否存在所以不能留空。如果你用的是 Windows PowerShell$env:ANTHROPIC_BASE_URLhttp://127.0.0.1:8787 $env:ANTHROPIC_API_KEYany-value设置完之后正常启动 Claude Code 就行。你可以在 Claude Code 里用/status命令确认它连的是哪个端点。如果显示的是http://127.0.0.1:8787说明配置生效了。有个细节要注意Claude Code 有时候会缓存端点配置如果你改了环境变量但没生效试试重启终端或者删掉 Claude Code 的缓存目录通常在~/.claude下面。4.2 Codex 的接入要点Codex 的配置方式跟 Claude Code 不太一样它通常通过配置文件来指定端点。Codex 的配置文件一般在~/.codex/config.yaml或者项目根目录下的.codex.yaml。你需要把端点指向 openrigapi_base: http://127.0.0.1:8787/v1 api_key: any-value model: gpt-4oCodex 用的是/responses端点openrig 需要正确处理这个路径。如果你遇到local proxy failed while handling codex endpoint /responses错误先检查 openrig 的日志tail -f .openrig/openrig.log日志里会显示具体的错误原因。常见的有三种一是目标提供商不支持/responses路径需要在 openrig 里做路径重写二是请求体格式不匹配比如 Codex 发的 JSON 结构跟 OpenAI 标准格式有差异三是流式响应的分块处理有问题导致连接提前关闭。openrig 的routes配置里可以加一个rewrite选项来处理路径重写routes: - match: codex-* provider: openai model: gpt-4o rewrite: from: /responses to: /chat/completions这样当 Codex 请求/responses时openrig 会自动转发到/chat/completions并把请求体转换成 Chat Completions 格式。4.3 接入本地模型的实操细节把本地模型接进 Claude Code 或 Codex 是 openrig 的一个高频使用场景。以 LM Studio 为例先在 LM Studio 里加载一个模型启动本地服务器默认端口 1234然后在 openrig 配置里加一个 providerproviders: lmstudio: type: openai-compatible api_key: dummy base_url: http://localhost:1234/v1 models: - qwen2.5-7b-instruct - llama-3.1-8b-instruct然后在 routes 里加一条routes: - match: local-* provider: lmstudio model: qwen2.5-7b-instruct重启 openrig 之后在 Claude Code 里指定模型为local-qwen请求就会转发到 LM Studio。实测下来7B 级别的模型在 M1 Mac 上响应速度可以接受但复杂任务还是建议用云端模型。这里有个坑LM Studio 的 OpenAI 兼容接口对某些参数的支持不完整比如tools和function_call可能不支持。如果你在 Claude Code 里用了工具调用功能转发到本地模型时可能会报错。解决办法是在 openrig 的 route 配置里加一个strip_params选项把不支持的参数去掉routes: - match: local-* provider: lmstudio model: qwen2.5-7b-instruct strip_params: - tools - tool_choice5. 常见问题与排查技巧实录5.1 代理启动失败与端口冲突openrig start报EADDRINUSE是最常见的问题意思是端口被占用了。先查一下谁在用 8787lsof -i :8787macOS 和 Linux 上用lsofWindows 上用netstat -ano | findstr :8787。找到进程 ID 之后要么杀掉那个进程要么把 openrig 的端口改成别的。我一般倾向于改端口因为占用 8787 的可能是另一个正在用的服务。改端口只需要改openrig.yaml里的server.port然后重启 openrig。如果你同时跑多个 openrig 实例比如一个连云端、一个连本地记得给它们分配不同端口。5.2 模型路由不生效的排查思路配置了 route 但请求还是发到了错误的模型这种情况通常是match规则写错了。openrig 的匹配是从上到下按顺序来的第一个匹配成功的规则会生效。如果你写了routes: - match: * provider: openai model: gpt-4o - match: claude-* provider: anthropic model: claude-sonnet-4-20250514那么所有请求都会匹配第一条*规则第二条永远不会生效。正确的写法是把具体规则放在前面通配规则放在最后。另外模型名的匹配是大小写敏感的。Claude-*和claude-*是不同的。建议统一用小写。5.3 流式响应中断的处理AI 助手的响应通常是流式的如果 openrig 在处理流式响应时中断客户端会看到不完整的输出。常见原因有三个一是server.timeout设得太短长响应还没结束就超时了二是目标提供商的流式格式跟 openrig 预期的不一致三是网络中间有代理或防火墙干扰。排查方法先把logging.level改成debug然后重现问题看日志里有没有stream chunk parse error或connection reset之类的信息。如果是超时问题把timeout调到 3000005 分钟。如果是格式问题检查目标提供商的文档确认它的流式响应格式。我遇到过一次流式中断是因为本地模型服务在生成到一半时 OOM 了日志里显示upstream connection closed unexpectedly。这种情况只能换更小的模型或者加内存。5.4 密钥管理与环境变量陷阱openrig 支持用${VAR_NAME}引用环境变量但有个陷阱如果环境变量没设置openrig 启动时不会报错而是在实际请求时才失败。这会导致你启动服务时一切正常但一发请求就 401。我的做法是在启动 openrig 之前先检查关键环境变量for var in ANTHROPIC_API_KEY OPENAI_API_KEY; do if [ -z ${!var} ]; then echo ERROR: $var is not set exit 1 fi done openrig start另外不要把密钥直接写在openrig.yaml里然后提交到 git。用环境变量或者.env文件并且把.env加到.gitignore里。openrig 支持从.env文件加载环境变量你只需要在启动时加--env-file .env参数。5.5 常见问题速查表问题现象可能原因解决方法EADDRINUSE端口被占用改server.port或杀掉占用进程请求 401环境变量未设置检查${VAR}对应的环境变量路由不生效match规则顺序错误具体规则放前面通配放最后流式响应中断超时太短或上游断开调大timeout检查上游日志Codex/responses报错路径或格式不匹配加rewrite规则做路径重写本地模型工具调用失败模型不支持 tools 参数用strip_params去掉不支持的参数配置解析失败YAML 缩进或冒号问题统一两个空格缩进冒号后加空格服务随终端关闭前台运行用--daemon或nohup6. 进阶用法与个人经验补充6.1 多环境配置切换如果你需要在公司网络和家里网络之间切换或者在不同项目之间用不同的模型配置openrig 支持多配置文件。你可以建几个文件openrig.work.yamlopenrig.home.yamlopenrig.local.yaml启动时用--config指定openrig start --config openrig.work.yaml更进一步你可以用环境变量OPENRIG_CONFIG来指定默认配置文件这样不用每次敲--config。在 shell 的配置文件里加一行export OPENRIG_CONFIG~/openrig/openrig.work.yaml6.2 配置热加载的实操体验openrig 支持配置热加载改完openrig.yaml之后不需要重启服务。但热加载不是万能的server.port和server.host这种底层参数改了必须重启providers和routes的改动可以热加载。我实测下来热加载在大多数情况下工作正常但偶尔会有缓存导致新配置不生效。如果改了配置但行为没变先试试openrig reload命令手动触发重载。如果还不行就老老实实重启。6.3 日志分析与性能调优openrig 的日志里包含了每个请求的耗时、目标提供商、模型名、状态码。定期看一下日志能发现很多问题。比如某个提供商的平均响应时间突然变长可能是对方服务降级了某个模型的错误率升高可能是模型本身有问题。如果你觉得info级别的日志太吵可以改成warn只记录错误和警告。但排查问题时记得临时改回debug否则会漏掉关键信息。性能方面openrig 本身的开销很小瓶颈通常在上游模型服务。如果你发现请求延迟很高先用curl直接请求上游端点对比一下经过 openrig 的延迟。如果差异在 10ms 以内说明 openrig 不是瓶颈。6.4 我踩过的几个坑第一个坑是 YAML 里的布尔值。YAML 会把yes、no、on、off解析成布尔值而不是字符串。如果你某个配置项期望字符串no但写成了no解析出来就是false。解决办法是给可能歧义的值加引号。第二个坑是环境变量插值的嵌套。openrig 不支持${A:-${B}}这种嵌套默认值语法。如果你需要默认值得在 shell 层面处理或者用 openrig 的defaults块。第三个坑是 Windows 路径。在 Windows 上写file: C:\logs\openrig.log会因为反斜杠被转义而出问题。用正斜杠C:/logs/openrig.log或者双反斜杠C:\\logs\\openrig.log。第四个坑是代理环境变量。如果你的机器上设置了HTTP_PROXY或HTTPS_PROXYopenrig 可能会把这些代理也应用到本地请求上导致127.0.0.1的请求被发到代理服务器。解决办法是在 openrig 配置里加no_proxy: 127.0.0.1,localhost或者在启动前unset HTTP_PROXY HTTPS_PROXY。6.5 后续可以扩展的方向openrig 目前主要解决的是配置管理和请求转发但它的架构留了不少扩展空间。比如可以加一个请求缓存层对于相同的 prompt 直接返回缓存结果省 token 也省时间。还可以加一个用量统计模块记录每个模型每天消耗了多少 token方便做成本控制。另外openrig 的 route 匹配目前只支持模型名前缀如果加上基于请求内容的路由比如根据 prompt 长度选择不同模型会更灵活。不过这些都需要改源码适合愿意折腾的人。我个人在实际操作中的体会是openrig 最大的价值不是它现在有多少功能而是它把 AI 助手配置这件事从“每个工具一套配置”变成了“一份 YAML 管所有”。这个思路本身就很值得借鉴哪怕你不用 openrig也可以参考它的配置结构来管理自己的 AI 工具链。最后再分享一个小技巧把openrig.yaml里的注释写详细一点过三个月再回来看你会感谢当时的自己。