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 或 TOML
openrig 选择 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 助手这种需要 SSE(Server-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/completions,openrig 可以在中间做转换。第三是故障隔离,当某个模型端点不可用时,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 LTS,20.x 是 maintenance LTS。如果你机器上还没有 Node.js,去官网下载 LTS 安装包就行。Windows 用户直接下.msi,macOS 用户下.pkg,Linux 用户可以用包管理器或者 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.yaml,openrig 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 启动服务与验证连通性
配置写好后,启动 openrig:
openrig 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 接进 openrig
4.1 Claude Code 的配置方式
Claude Code 通过环境变量来指定 API 端点。在 openrig 启动之后,你需要设置:
export ANTHROPIC_BASE_URL=http://127.0.0.1:8787 export ANTHROPIC_API_KEY=any-valueANTHROPIC_API_KEY这里填什么不重要,因为 openrig 会在转发请求的时候用配置文件里的真实密钥替换掉。但有些版本的 Claude Code 会检查这个变量是否存在,所以不能留空。
如果你用的是 Windows PowerShell:
$env:ANTHROPIC_BASE_URL="http://127.0.0.1:8787" $env:ANTHROPIC_API_KEY="any-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。你需要把端点指向 openrig:
api_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 配置里加一个 provider:
providers: 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是最常见的问题,意思是端口被占用了。先查一下谁在用 8787:
lsof -i :8787macOS 和 Linux 上用lsof,Windows 上用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调到 300000(5 分钟)。如果是格式问题,检查目标提供商的文档,确认它的流式响应格式。
我遇到过一次流式中断是因为本地模型服务在生成到一半时 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或nohup |
6. 进阶用法与个人经验补充
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_PROXY,openrig 可能会把这些代理也应用到本地请求上,导致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里的注释写详细一点,过三个月再回来看,你会感谢当时的自己。