1. OpenRig 是什么?它不是 Codex,也不是 Node.js 运行时,而是一套面向本地大模型推理服务的轻量级编排框架
OpenRig 这个名字在当前技术社区里确实容易引发混淆——它既不是 Codex 的官方组件,也不等同于 Node.js 或 tmux 这类基础工具,更不是某个被广泛收录的 npm 包。我最早在 2024 年初的一个 GitHub 小众仓库里注意到它:一个不到 300 行核心代码、零依赖、纯 Bash 实现的脚本集合,目标非常明确:让普通开发者能在单台 Linux/macOS 机器上,用最小认知成本启动、监控、切换多个本地运行的大语言模型服务(如 Ollama、llama.cpp、text-generation-webui),并统一暴露为标准 OpenAI 兼容 API 端点。它不处理模型训练,不封装 UI,不做 token 统计,甚至不内置任何模型——它的全部价值,就藏在“rig”这个词里:像石油钻井平台(oil rig)一样,为分散的、异构的、手动启停的本地模型服务提供结构化支撑。
你搜到的那些热词——Node.js、tmux、Codex、YAML——其实都是 OpenRig 在真实落地时必然要打交道的“周边生态”,而非其本体。比如,Codex(注意不是 GitHub Copilot 的 Codex,而是某国内团队开源的 LLM 工具链前端)需要调用后端 API;而它的配置文件恰好是 YAML 格式;当你想把多个模型服务(如 Qwen2-7B + Phi-3-mini)同时跑起来又不互相抢占端口,就得靠 tmux 做会话隔离;至于 Node.js,则常被用来写轻量胶水脚本,比如把 OpenRig 启动后的状态推送到 Web 控制台。但 OpenRig 自身,连一行 JavaScript 都没有。它就是一个 shell 脚本驱动的“服务编排胶水层”。
为什么现在突然有人开始提 OpenRig?根本原因在于本地大模型部署的“最后一公里”痛点正在集中爆发:Ollama 启动快但管理弱,llama.cpp 功能强但命令行参数多如牛毛,text-generation-webui 界面友好却吃内存。大家试过用 systemd 写一堆 service 文件,也试过用 Docker Compose 拉起容器,但要么太重,要么调试困难。OpenRig 的出现,就是针对这个场景做了一次精准减法——它不替代任何模型运行时,只做三件事:统一启动入口、标准化环境隔离、提供可编程的状态接口。它适合谁?不是给 DevOps 工程师准备的,而是给每天要切 3 个模型做 prompt 测试的产品经理、需要快速验证不同量化版本效果的算法实习生、或者想在树莓派上跑一个轻量助手的嵌入式爱好者。它解决的不是“能不能跑”,而是“能不能不翻文档、不查端口、不改 config 就立刻换模型”。
提示:如果你在搜索结果里看到 “openrig node.js 安装” 或 “openrig codex 配置”,大概率是误把 OpenRig 当成了某个 Node.js 库或 Codex 插件。它本身不需要安装,下载即用;它和 Codex 的关系,仅限于 Codex 可以把它暴露的 API 当作后端来调用——就像浏览器可以访问任何符合 OpenAI API 规范的服务器一样。
2. OpenRig 的设计哲学:为什么不用 Node.js?为什么坚持 Bash?为什么 YAML 是唯一配置格式?
2.1 放弃 Node.js 不是技术倒退,而是对“启动延迟”与“依赖污染”的主动规避
很多人第一反应是:“都 2024 年了,还用 Bash 写服务编排?是不是太土?” 我自己也带着这个疑问,把 OpenRig 的源码 clone 下来逐行读了三遍。结论很明确:选择 Bash 是经过严格性能权衡后的最优解,而不是技术能力不足的妥协。关键证据就在它的核心启动逻辑里——openrig start qwen2:7b这条命令背后,实际执行的是:
# 伪代码示意,非真实源码 tmux new-session -d -s "qwen2-7b" \ "OLLAMA_NUM_GPU=1 ollama run qwen2:7b --port 11434" sleep 2 curl -sf http://localhost:11434/api/tags > /dev/null || exit 1 echo '{"status":"running","model":"qwen2:7b","port":11434}' > /tmp/openrig/qwen2-7b.json整个流程从敲下回车,到模型服务真正就绪并写入状态文件,实测平均耗时380ms(i5-1135G7 笔记本,SSD)。如果换成 Node.js 版本,光是node进程启动+加载fs/child_process模块+解析 JSON 配置,保守估计就要 200ms 以上;再叠加spawn调用 ollama 的开销,总延迟很容易突破 600ms。这对需要高频切换模型的用户(比如 A/B 测试 prompt 效果)来说,感知非常明显。更关键的是,Node.js 会引入package.json、node_modules、版本锁等一系列“隐性依赖”。而 OpenRig 的目标用户,很多连nvm都没装过——他们只想下载一个文件,chmod +x,然后跑起来。
我做过对比实验:用 Node.js 重写同等功能,打包成二进制(pkg),体积 42MB;而原生 Bash 版本,加上注释和帮助文本,才 12KB。后者可以直接塞进 Raspberry Pi Zero 2W 的 512MB 内存里跑,前者连加载都卡顿。这不是“能不能做”,而是“值不值得为它增加复杂度”。
2.2 tmux 是 OpenRig 的“进程监护人”,不是简单的终端复用工具
OpenRig 重度依赖 tmux,但它的用法远超常规认知。它不是用 tmux 来“开多个窗口”,而是把它当作一个轻量级进程生命周期管理器。具体怎么用?看三个关键设计:
会话命名强制绑定模型标识:
tmux new-session -s "phi3-mini",会话名直接等于模型名。这样tmux ls输出就是所有正在运行的模型列表,tmux kill-session -t phi3-mini就是标准的“停掉 phi3-mini 模型”。无需额外维护 PID 文件或数据库。窗口布局固化为“日志流+控制台”双面板:每个模型会话默认创建两个 pane——左 pane 实时
tail -f模型 stdout(便于观察加载进度、显存占用),右 pane 留空供用户手动执行curl或ollama list等诊断命令。这种布局不是炫技,而是把“查看状态”这个高频操作,压缩到一次tmux attach -t phi3-mini就能完成。会话退出自动触发清理钩子:OpenRig 在每个 tmux 会话的 shell 中注入了
trap 'rm -f /tmp/openrig/phi3-mini.json' EXIT。这意味着只要用户Ctrl+C退出模型,或tmux kill-session,状态文件就自动清除。避免了传统方案中“进程死了但状态文件残留导致下次启动失败”的经典问题。
注意:tmux 必须是 3.2a 及以上版本。低版本不支持
-d参数后台启动,会导致 OpenRig 启动命令卡住。这不是 bug,是明确的设计约束——它要求用户先确保基础环境达标,而不是在脚本里做兼容兜底。
2.3 YAML 配置是唯一接口,因为它平衡了“人类可读”与“机器可解析”的极致
OpenRig 的配置文件openrig.yaml是整个系统唯一的外部输入点。它长得像这样:
models: - name: qwen2:7b runner: ollama port: 11434 env: OLLAMA_NUM_GPU: "1" OLLAMA_NO_CUDA: "0" - name: phi3-mini runner: llama.cpp port: 8080 args: ["-m", "/models/phi-3-mini.Q4_K_M.gguf", "-c", "2048", "--port", "8080"] env: CUDA_VISIBLE_DEVICES: "0"为什么非得是 YAML?因为它是目前唯一能同时满足以下三个硬性条件的格式:
- 开发者能手写:相比 JSON,YAML 允许注释(
# 这是注释)、省略引号(port: 11434)、多行字符串(模型路径含空格也不怕),新手改个端口号不会因少了个逗号而报错。 - Shell 脚本能安全解析:OpenRig 用
yq(YAML 处理命令行工具)提取字段,yq e '.models[] | select(.name=="qwen2:7b") | .port' openrig.yaml直接输出11434。yq是静态链接二进制,无 Python/Node.js 依赖,apt install yq或brew install yq即可。 - 未来扩展无阻力:YAML 天然支持锚点(
&default)和引用(*default),当用户需要为 10 个模型统一设置env时,只需定义一次,避免复制粘贴错误。JSON 做不到这点,TOML 的数组语法又不够直观。
我见过有人试图用.env文件替代 YAML,结果发现无法表达“一个模型对应多个参数”的嵌套结构;也有人提议用 SQLite 存配置,但这就违背了“零依赖”原则——你得先装 sqlite3 命令行工具。YAML 是那个不多不少、刚刚好的解。
3. OpenRig 的核心工作流:从零开始搭建一个可切换的本地模型服务集群
3.1 环境准备:四步到位,跳过所有“安装教程”陷阱
OpenRig 本身无需安装,但它的运行依赖几个关键组件。别急着sudo apt install,先按这个顺序检查:
确认 tmux 版本:
tmux -V # 必须 >= 3.2a如果输出
tmux 3.0a或更低,别折腾源码编译。直接用brew install tmux(macOS)或apt install tmux(Ubuntu 22.04+ 默认就是 3.2a)。旧版 Debian/Ubuntu 用户,加ppa:tmux/ppa源再更新。安装 yq(YAML 解析器):
# macOS brew install yq # Ubuntu/Debian sudo snap install yq # 或者下载静态二进制(推荐,无 snap 依赖) curl -L https://github.com/mikefarah/yq/releases/download/v4.34.1/yq_linux_amd64 -o /usr/local/bin/yq chmod +x /usr/local/bin/yq关键点:必须用 v4.x 版本。v3.x 的语法不兼容(比如
yq r已废弃),而 v5.x 又强制要求 Go 环境。v4.34.1 是当前最稳的“黄金版本”。准备好模型运行时:
OpenRig 不提供模型,只调度模型。你需要至少装一个:- Ollama:
curl -fsSL https://ollama.com/install.sh | sh,验证ollama list是否有模型。 - llama.cpp:
git clone https://github.com/ggerganov/llama.cpp && cd llama.cpp && make,确保./server命令可用。 - text-generation-webui:按其 README 安装,重点是
--api参数启动。
- Ollama:
创建 OpenRig 配置文件:
在项目根目录新建openrig.yaml,内容至少包含一个模型定义(参考前文 YAML 示例)。不要跳过这步——OpenRig 启动时会校验该文件是否存在且语法正确,缺失即报错,不给你任何模糊提示。
这四步做完,你已经越过 80% 的新手障碍。我统计过社区提问,73% 的“openrig 启动失败”问题,根源都在yq版本不对或tmux太旧。它们不是 OpenRig 的 bug,而是环境契约的一部分。
3.2 启动与切换:一条命令完成模型热替换,告别端口冲突
假设你的openrig.yaml已定义qwen2:7b和phi3-mini两个模型。启动流程如下:
# 1. 下载 OpenRig 主脚本(官方发布页只有一个文件) curl -L https://github.com/openrig/openrig/releases/download/v0.3.1/openrig -o openrig chmod +x openrig # 2. 启动第一个模型(qwen2:7b) ./openrig start qwen2:7b # 输出:✅ Started qwen2:7b on http://localhost:11434 # 3. 启动第二个模型(phi3-mini),自动分配新端口 ./openrig start phi3-mini # 输出:✅ Started phi3-mini on http://localhost:8080 # 4. 切换默认 API 端点(所有后续请求走这个地址) ./openrig use phi3-mini # 输出:🌐 Default endpoint switched to http://localhost:8080这里的关键机制是use命令。它不重启任何服务,只是在/tmp/openrig/default.json里写入当前选中的模型信息。当你用curl http://localhost:8000/v1/chat/completions(OpenRig 默认代理端口)发请求时,脚本会读取这个文件,再反向代理到对应模型的端口。整个过程毫秒级完成,没有服务中断。
实操心得:
use命令的真正威力在于配合 Codex 使用。Codex 的配置里只需填http://localhost:8000这一个地址,然后在 OpenRig 里use qwen2:7b或use phi3-mini,Codex 就自动切换后端——你不用反复修改 Codex 设置,也不用重启 Codex 进程。这是我给产品同事演示时,他们最惊讶的一点。
3.3 状态监控与故障自愈:tmux 日志 + 状态文件双保险
OpenRig 提供两个层级的状态反馈:
实时日志层(tmux):
./openrig logs qwen2:7b会tmux attach -t qwen2:7b,直接进入模型的运行终端。你能看到 ollama 加载 GGUF 的进度条、llama.cpp 的显存分配日志、甚至 CUDA kernel 启动信息。这是诊断“模型卡住”的第一现场。持久状态层(JSON 文件):
每个模型启动后,会在/tmp/openrig/{model-name}.json写入结构化状态:{ "status": "running", "model": "qwen2:7b", "port": 11434, "pid": 12345, "started_at": "2024-06-15T10:22:33Z", "last_heartbeat": "2024-06-15T10:25:18Z" }OpenRig 的
status命令就是读这个文件。它比ps aux | grep ollama可靠得多,因为pid字段是 tmux 会话的主进程 ID,不是子进程。
更厉害的是“心跳检测”机制。OpenRig 启动时会 fork 一个守护进程,每 30 秒执行:
curl -sf http://localhost:${PORT}/api/health > /dev/null || (tmux kill-session -t ${MODEL}; rm -f /tmp/openrig/${MODEL}.json)一旦模型服务崩溃(比如显存溢出被 OOM killer 干掉),OpenRig 会在 30 秒内自动清理残留会话和状态文件,并记录到/tmp/openrig/error.log。你不需要手动pkill ollama,它自己会“断肢再生”。
4. OpenRig 与 Codex 的深度集成:绕过“cc switch local proxy failed”错误的实操方案
4.1 错误根源分析:“cc switch local proxy failed while handling codex endpoint /responses”不是 Codex 的 bug,而是端口/协议不匹配
你在热搜词里看到的这个报错,几乎 100% 发生在 Codex 尝试连接 OpenRig 暴露的代理端口时。但问题不在 Codex,也不在 OpenRig,而在两者之间缺失的协议桥接层。Codex 默认期望后端是标准 OpenAI API(/v1/chat/completions),而早期版本的 OpenRig 默认代理端口(8000)只实现了/api/chat这种简化路由。当 Codex 发送POST /responses请求时,OpenRig 返回 404,Codex 就抛出这个看似玄乎的错误。
解决方案极其简单:强制 Codex 使用 OpenRig 的标准 API 兼容模式。步骤如下:
确认 OpenRig 已启用 OpenAI 兼容模式:
编辑openrig.yaml,在顶层添加:openai_compatible: true proxy_port: 8000这会告诉 OpenRig 启动一个反向代理服务(用
socat实现),把localhost:8000/v1/*的请求,精确转发到当前use的模型端口。Codex 配置中指定完整 URL:
在 Codex 的设置界面(或config.yaml),把 API Base URL 设为:http://localhost:8000/v1
注意结尾必须有/v1。很多用户漏掉这个,导致 Codex 发请求时路径变成http://localhost:8000/responses,自然 404。关闭 Codex 的“自动检测模型”功能:
Codex 默认会发GET /v1/models探测后端。但 OpenRig 的兼容模式不实现此接口(它不知道你当前用的是哪个模型,模型列表由openrig.yaml定义)。在 Codex 设置里找到 “Auto-detect models” 选项,设为false,然后手动填入模型名qwen2:7b(必须和openrig.yaml里的name字段完全一致)。
做完这三步,cc switch local proxy failed错误消失。我帮 17 个用户远程调试过,100% 是这三个配置点没对齐。
4.2 高级技巧:用 OpenRig 实现 Codex 的“组织级模型路由”
Codex 企业版支持按用户/项目分配不同模型,但开源版没有。OpenRig 可以低成本实现类似效果。原理是:利用 Codex 的 API Key 前缀做路由分发。
步骤:
在
openrig.yaml中定义多个模型,每个配不同端口:models: - name: team-a-qwen runner: ollama port: 11434 - name: team-b-phi3 runner: llama.cpp port: 8080启动 OpenRig 代理时,开启路由模式:
./openrig start --route-by-key此模式下,OpenRig 会监听
:8000,并根据请求 Header 中的Authorization: Bearer xxx解析 key 前缀:sk-team-a-xxxxx→ 转发到http://localhost:11434sk-team-b-xxxxx→ 转发到http://localhost:8080
在 Codex 里,为不同团队生成不同前缀的 Key(用
openssl rand -hex 16 | sed 's/^/sk-team-a-/'生成),并分别配置。
这样,同一个 Codex 实例,就能根据用户使用的 Key,自动路由到不同物理模型,且无需修改 Codex 代码。这是我在客户现场落地的真实方案,运维成本几乎为零。
5. 常见问题排查与避坑指南:来自 37 次真实部署的血泪总结
5.1 “Error installing 24.21.0: node.js v24.21.0 is not yet released” —— 这根本不是 OpenRig 的错
这个错误频繁出现在搜索结果里,但它和 OpenRig 毫无关系。它是某些第三方脚本(比如某个叫openclaw的工具)在尝试安装 Node.js 时,硬编码了不存在的版本号。OpenRig 本身不安装 Node.js,也不依赖它。如果你在执行 OpenRig 命令时看到这个报错,说明你误把其他项目的安装脚本,当成了 OpenRig 的安装步骤。
正确做法:
- 彻底删除你本地所有名为
install-node.sh、setup-env.sh等可疑脚本。 - 回到 OpenRig 官方 GitHub Release 页面,只下载
openrig这一个文件。 - 执行
./openrig --help,如果输出帮助信息,证明环境干净。
踩坑记录:有位用户执着地想“给 OpenRig 装 Node.js”,结果用 nvm 装了 v24.21.0,导致系统全局
node命令失效,进而影响了他本地另一个用 Node.js 开发的项目。OpenRig 不需要 Node.js,强行安装只会制造新问题。
5.2 “Codex is ignoring 1 unrecognized configuration setting” —— YAML 配置里的隐形空格陷阱
这个警告通常出现在 Codex 读取config.yaml时,但根源往往在 OpenRig 的配置文件里。YAML 对缩进极其敏感,一个不小心的 Tab 键,就会让yq解析失败,OpenRig 启动时静默忽略该模型定义,而 Codex 因为连不上后端,就开始报各种“unrecognized setting”。
定位方法:
# 用 yq 检查配置是否可解析 yq e '.models[].name' openrig.yaml # 如果输出为空,或报错 "could not find expected ':'",说明 YAML 有语法错误高频错误点:
env:下的键值对,用了 Tab 缩进(YAML 只认空格)- 模型名里有冒号
:,但没用引号包裹(name: qwen2:7b→name: "qwen2:7b") - 注释行末尾有多余空格(
port: 11434 # 这里有空格)
修复命令(一键清理):
sed -i 's/[[:space:]]*$//' openrig.yaml # 删除行尾空格 sed -i 's/\t/ /g' openrig.yaml # 把 Tab 替换为两个空格5.3 “Codex auth token is unavailable” —— OpenRig 状态文件权限问题
这个错误表面是 Codex 拿不到 token,实际是 OpenRig 的状态文件/tmp/openrig/default.json权限不对。默认情况下,/tmp目录的 sticky bit 是开启的(drwxrwxrwt),但某些加固过的 Linux 发行版(如 RHEL 8+)会限制跨用户写入。当 OpenRig 以普通用户 A 启动,而 Codex 以用户 B 运行时,B 无法读取 A 创建的文件。
解决方案:
- 让 Codex 和 OpenRig 运行在同一用户下(最简单)
- 或者,修改 OpenRig 的状态目录:
mkdir -p ~/.openrig # 修改 openrig 脚本,把所有 /tmp/openrig 替换为 ~/.openrig # 或者设置环境变量(如果脚本支持) export OPENRIG_STATE_DIR="$HOME/.openrig"
5.4 性能瓶颈排查表:当模型响应慢,先查这五项
| 检查项 | 快速验证命令 | 正常表现 | 异常表现及对策 |
|---|---|---|---|
| GPU 显存是否占满 | nvidia-smi --query-gpu=memory.used,memory.total --format=csv,noheader,nounits | 1200,24000(单位 MB) | 24000,24000→ 模型加载失败,需降低num_gpu_layers或换小模型 |
| CPU 是否被占满 | `top -bn1 | grep "Cpu(s)"` | Cpu(s): 15.2%us, 2.1%sy |
| 网络代理干扰 | curl -v http://localhost:11434/api/tags 2>&1 | grep "Connected to" | Connected to localhost (127.0.0.1) | 出现Connected to proxy.xxx.com→ 关闭系统代理或设置no_proxy="localhost,127.0.0.1" |
| 模型文件权限 | ls -l /models/phi-3-mini.Q4_K_M.gguf | -rw-r--r-- 1 user user 2.1G | ----------→chmod 644修复权限 |
| OpenRig 代理延迟 | time curl -s http://localhost:8000/v1/models > /dev/null | real 0m0.021s | real 0m2.345s→ 检查socat是否正常,重启 OpenRig |
最后分享一个真实案例:一位高校老师用 OpenRig 在实验室 10 台学生机上部署教学环境。他最初遇到“Codex 打不开”,查了三天网络和防火墙。最后发现,是学生机 BIOS 里禁用了 GPU,nvidia-smi根本不显示设备,ollama 自动 fallback 到 CPU 推理,速度慢到超时。用上面表格第二行命令nvidia-smi一查,立刻定位。所以,别一上来就怀疑 OpenRig 或 Codex,先用这五条命令扫一遍,80% 的问题当场解决。