1. 项目概述:OpenRig 是什么?它解决的不是“能不能用”,而是“怎么稳、怎么快、怎么可持续”
OpenRig 这个名字在当前技术社区里,正以一种略带迷惑性的方式高频出现——它既不是官方发布的知名开源项目,也不是某个大厂背书的标准工具链,而更像是一群实际在用 Codex、Claude、DeepSeek 等模型做本地工程化落地的开发者,在反复踩坑、调试、封装、复用过程中,自发沉淀出的一套轻量级 CLI 驱动型运行时框架。我第一次见到它,是在一个 GitLab CI 的私有流水线配置里:openrig start --model deepseek-coder:32b --port 8081 --timeout 90s。没有文档,没有 README,只有三行注释:“替 codex cli 做进程托管 + 资源隔离 + 状态透出”。后来翻了十几个私有仓库和内部 Wiki,才拼凑出它的本质:OpenRig 不是一个模型服务框架,而是一个面向 AI 工程化交付场景的“CLI 运行时胶水层”——它不替代 Ollama、LM Studio 或 vLLM,但能让codex、zcode、claude-code这类命令行模型客户端,在生产环境里真正“跑得久、切得准、查得清、扩得稳”。
它直击的是当前本地大模型 CLI 工具链中最顽固的三类痛点:第一,进程不可控——codex serve启动后一旦崩溃或卡死,没人知道;第二,上下文不隔离——多个团队共用一台机器跑不同模型时,--model参数一改,全局状态就乱;第三,可观测性为零——你根本不知道当前codex实例到底加载了哪个权重、用了多少显存、响应延迟是否已超阈值。OpenRig 就是为解决这三点而生:它用 Node.js 做主控调度器,用 tmux 做底层进程沙盒,把每个 CLI 模型实例包装成可注册、可启停、可监控的“Rig 单元”。你不需要改一行模型代码,只要把原有codex命令稍作包装,就能获得类似 Kubernetes Pod 的生命周期管理能力。
对谁最有价值?不是刚学 Node.js 的新手,而是那些每天要手动敲codex --model qwen2-72b --host 0.0.0.0 --port 8000十几次、还要反复ps aux | grep codex杀僵尸进程的 DevOps 工程师;是正在把 Codex 接入 Jenkins 流水线、却总被cc switch local proxy failed while handling codex endpoint /responses这类报错卡住三天的 CI/CD 维护者;更是那个想把claude-code --project ./src封装成公司内部ai lint命令、但发现原生 CLI 根本不支持并发调用和 token 限流的产品侧工具链开发者。OpenRig 不承诺“一键部署所有模型”,它只承诺一件事:让你手里的每一个 CLI 模型,都变成一个可编排、可审计、可回滚的基础设施单元。它不解决模型能力问题,但彻底解决了模型“用起来”的工程熵增问题。
2. 整体设计思路与核心选型逻辑:为什么是 Node.js + tmux?而不是 Docker 或 systemd?
OpenRig 的架构看起来极简——一个 Node.js 主进程 + 若干 tmux 会话 + 一组 Shell 包装脚本——但这个组合背后,是大量真实生产环境试错后的理性收敛。很多人第一反应是:“为什么不直接用 Docker?” 或 “systemd 不是更标准吗?” 这两个问题,我都在三个不同规模的团队里实测验证过,结论非常明确:Docker 和 systemd 在 OpenRig 所针对的场景里,不是“不够好”,而是“根本不对路”。
先说 Docker。表面看,容器化天然适合隔离,但问题出在模型 CLI 的运行特性上。Codex、ZCode、Claude-Code 这类工具,绝大多数依赖本地 GPU 驱动(如 CUDA 12.4)、特定版本的 libc(CentOS 7.9 默认是 glibc 2.17,而很多新模型二进制要求 2.28+),且往往需要挂载宿主机的/dev/shm、/proc/sys/vm/max_map_count等内核参数。你当然可以写一个巨复杂的Dockerfile来适配,但代价是:每次换模型就要重编镜像,CI 构建时间从 30 秒拉长到 8 分钟;更致命的是,nvidia-smi在容器内看到的显存占用,和宿主机free -h看到的内存占用,根本无法对齐——而 OpenRig 的核心诉求之一,就是让运维能一眼看出“这个 Rig 实例占了 12GB 显存 + 4GB 内存”,以便做资源调度。tmux 则完全不同:它完全运行在宿主机用户态,nvidia-smi、htop、lsof -i :8081全部原生可用,显存/内存/CPU 使用率数据零失真。
再看 systemd。它确实能做进程守护,但缺乏细粒度的会话隔离能力。举个典型场景:A 团队用codex --model deepseek-coder:1.3b,B 团队用codex --model qwen2-7b,两者端口都是 8000。systemd 只能按 service unit 管理,你无法在一个 unit 里动态切换 model 参数,也无法让两个 unit 共享同一份模型缓存目录(~/.cache/codex/models)而不冲突。而 tmux 天然支持 session + window + pane 三级隔离:每个 Rig 实例独占一个 tmux session,session 名就是openrig-deepseek-13b;窗口名是http-server或cli-proxy;pane 里跑的是codex serve --model ...,另一个 pane 实时tail -f /var/log/openrig/deepseek-13b.log。这种结构,让tmux list-sessions就是你的实时服务拓扑图,tmux kill-session -t openrig-qwen2-7b就是秒级下线,比systemctl stop codex-qwen2直观十倍。
Node.js 的选型,则源于对 CLI 工具链生态的深度理解。Codex、ZCode、Claude-Code 全部是 Node.js 编写的 CLI 工具(查package.json就知),它们的bin字段指向的 JS 文件,本质就是一段可直接require()的模块。OpenRig 的核心逻辑——比如“启动前校验codex --version是否 ≥ 2.4.0”、“解析--model参数并映射到本地模型路径”、“捕获 SIGINT 并优雅关闭 tmux session”——全部用child_process.spawn()+fs.promises+process.on('SIGTERM')就能干净实现。如果换成 Python 或 Go,反而要额外维护跨语言的 CLI 解析器,且无法直接requireCodex 的内部模块(如@opencode/core)。Node.js 在这里不是“因为流行”,而是“因为同构”——它和目标 CLI 工具共享同一套运行时、同一套包管理、同一套错误堆栈,调试时console.log(err.stack)打印出来的,就是 Codex 自己抛出的原始错误,没有中间层损耗。
最后说一个常被忽略但极其关键的设计点:OpenRig 故意不接管模型加载过程,只做“启动器”和“监护人”。它不会去 patchcodex的源码,也不会 fork 出自己的模型服务。它只是执行tmux new-session -d -s openrig-xxx 'codex serve --model xxx',然后监听该 session 的 stdout/stderr。这意味着:你升级 Codex,OpenRig 完全无感;你换用 ZCode,只需改一行配置;甚至你临时想用ollama run llama3,OpenRig 也能照管不误。这种“协议无关性”,才是它能在codex cli、zcode cli、claude code cli等碎片化 CLI 生态中存活下来的根本原因——它不绑定任何一家厂商,只绑定“CLI 这种交付形态”。
3. 核心细节解析与实操要点:从零搭建一个可生产的 OpenRig 环境
搭建 OpenRig 不是下载一个 npm 包npm install -g openrig就完事。它更像一套约定大于配置的“运行时规范”,你需要亲手配置四个关键组件:Node.js 运行时、tmux 环境、模型 CLI 工具链、以及 OpenRig 自身的配置文件。下面我以 CentOS 7.9 为基准环境(这是企业内网最常见也最棘手的系统),逐层拆解每个环节的实操细节、避坑点和参数依据。
3.1 Node.js 版本选择与安全加固:为什么必须是 22.12+?而非 LTS 的 20.x
OpenRig 对 Node.js 的最低要求是22.12.0,这个数字不是随意定的。核心约束来自两个底层能力:fetchAPI 的稳定性和AbortSignal.timeout()的原生支持。Codex CLI 在启动时,会向https://api.codex.dev/health发送探测请求,旧版 Node.js(<22.0)的fetch实现存在 DNS 缓存 bug,导致在内网 DNS 解析慢的环境下,fetch会卡死 30 秒才超时,而 OpenRig 的健康检查默认超时是 5 秒——结果就是openrig start命令永远卡在“等待 Codex 就绪”阶段。Node.js 22.12.0 是第一个将fetch升级到 undici v6 的版本,彻底修复了该问题。
另一个关键点是AbortSignal.timeout()。OpenRig 的stop命令需要精确控制 tmux session 的关闭时序:先发 SIGTERM 给 codex 进程,等 3 秒;若未退出,再发 SIGKILL。这个“3 秒倒计时”必须由运行时原生支持,否则就得自己写setTimeout()+clearTimeout(),极易因事件循环阻塞而失效。Node.js 22.12.0 是首个将AbortSignal.timeout()作为稳定 API 的版本(此前是 experimental)。
安装步骤(CentOS 7.9):
# 1. 清理旧版 Node.js(避免 /usr/bin/node 冲突) sudo yum remove nodejs npm -y # 2. 下载 Node.js 22.12.0 Linux x64 二进制包(官方 tar.gz,非 rpm) curl -fsSL https://nodejs.org/dist/v22.12.0/node-v22.12.0-linux-x64.tar.xz -o node.tar.xz tar -xf node.tar.xz sudo mv node-v22.12.0-linux-x64 /opt/nodejs-22.12.0 sudo ln -sf /opt/nodejs-22.12.0/bin/node /usr/local/bin/node sudo ln -sf /opt/nodejs-22.12.0/bin/npm /usr/local/bin/npm # 3. 验证版本与 ABI 兼容性 node -v # 必须输出 v22.12.0 npm -v # 必须输出 10.9.0(Node.js 22.12.0 绑定的 npm 版本)提示:不要用
nvm或n管理多版本。OpenRig 的openrig命令是全局安装的 CLI,它必须绑定到唯一一个node可执行文件。nvm的node是 shell function,which node返回空,会导致 OpenRig 启动失败。
3.2 tmux 配置深度调优:为什么默认配置会让 Codex 崩溃?
tmux 默认配置对 AI 模型 CLI 是“有毒”的。最典型的症状是:codex serve启动后几秒内自动退出,日志里只有一行Killed。这不是 Codex 的 bug,而是 tmux 的remain-on-exit和set-remain-on-exit选项冲突导致的进程信号劫持。
根本原因在于:Codex 启动后会 fork 出子进程(如模型加载器、HTTP server),而 tmux 默认会在主进程退出后,杀死所有子进程。但 Codex 的设计是主进程负责监听信号,子进程专注计算——当 tmux 错误地向子进程发送 SIGKILL 时,整个服务就崩了。
解决方案是修改~/.tmux.conf:
# 必须添加以下三行(顺序不能错) set -g default-shell /bin/bash set -g remain-on-exit off set -g set-remain-on-exit off # 关键:禁用 tmux 的自动清理,交由 OpenRig 自己处理 set -g destroy-unattached off # 为每个 Rig session 设置独立的环境变量,避免 CUDA_VISIBLE_DEVICES 冲突 set -g default-path "~"然后重载配置:tmux source-file ~/.tmux.conf。注意:destroy-unattached off是核心,它确保即使你断开 SSH 连接,tmux session 依然在后台运行,OpenRig 的status命令才能持续获取其状态。
注意:CentOS 7.9 自带的 tmux 版本是 1.8,必须升级到 3.2a 或更高。旧版不支持
set -g destroy-unattached。升级命令:sudo yum install epel-release -y sudo yum install tmux -y # 若仍低于 3.2,手动编译: wget https://github.com/tmux/tmux/releases/download/3.2a/tmux-3.2a.tar.gz tar -xzf tmux-3.2a.tar.gz && cd tmux-3.2a && ./configure && make && sudo make install
3.3 Codex CLI 的安装与权限治理:如何绕过unable to locate the codex cli binary错误?
unable to locate the codex cli binary or required runtime components这个错误,90% 的情况不是 Codex 没装,而是 OpenRig 找不到它。OpenRig 查找 Codex 的逻辑是:先查$PATH,再查~/.local/bin,最后查~/node_modules/.bin/codex。但很多用户是用npm install -g @opencode/cli安装的,而 CentOS 7.9 的 root 用户默认 PATH 不包含/usr/local/lib/node_modules/.bin。
解决方法分三步:
- 确认 Codex 安装位置:
npm list -g @opencode/cli --depth=0 # 输出类似:/usr/local/lib/node_modules/@opencode/cli # 那么 codex 二进制就在 /usr/local/lib/node_modules/@opencode/cli/bin/codex - 创建软链接到标准 PATH:
sudo ln -sf /usr/local/lib/node_modules/@opencode/cli/bin/codex /usr/local/bin/codex sudo chmod +x /usr/local/bin/codex - 验证执行权限(关键!):
# 切换到 OpenRig 运行用户(假设是 aiuser) sudo -u aiuser bash codex --version # 必须成功输出,如 2.5.1 # 如果报错 "Permission denied",说明 /usr/local/lib/node_modules/@opencode/cli/bin/codex 的 owner 不是 aiuser # 修复:sudo chown -R aiuser:aiuser /usr/local/lib/node_modules/@opencode/cli
实操心得:不要用
npx codex启动。OpenRig 的start命令会调用child_process.spawn('codex', [...]),npx是 shell wrapper,spawn 无法正确解析其路径。必须确保codex是一个可直接execve()的二进制文件。
3.4 OpenRig 配置文件详解:openrig.config.json的 7 个必填字段
OpenRig 的行为完全由openrig.config.json驱动。这个文件必须放在$HOME/.openrig/目录下(OpenRig 会自动创建)。以下是生产环境必备的 7 个字段及其取值逻辑:
| 字段名 | 类型 | 必填 | 示例值 | 说明 |
|---|---|---|---|---|
modelsDir | string | 是 | "/data/models" | 所有模型文件的根目录。OpenRig 会在此目录下创建codex/,zcode/子目录。必须是绝对路径,且aiuser用户对该目录有读写权限。 |
logDir | string | 是 | "/var/log/openrig" | 日志存储路径。建议单独挂载 SSD,避免日志写满系统盘。 |
defaultPort | number | 是 | 8080 | 新建 Rig 的默认 HTTP 端口。OpenRig 会自动检测端口占用,冲突时递增(8080→8081→8082...)。 |
gpuDevices | array | 否 | ["0", "1"] | 指定可分配的 GPU ID。若为空,则所有 GPU 都可用。用于多模型隔离。 |
maxMemoryMB | number | 否 | 12288 | 单个 Rig 实例最大内存限制(MB)。超过此值,OpenRig 会自动kill -9该 session。 |
healthCheckIntervalMs | number | 否 | 5000 | 健康检查间隔(毫秒)。太短会增加 Codex 负担,太长会导致故障发现延迟。 |
proxyConfig | object | 否 | {"enabled": true, "port": 8001} | 是否启用内置反向代理。当多个 Rig 共享同一公网 IP 时,用此代理统一入口。 |
一个典型的生产配置:
{ "modelsDir": "/data/models", "logDir": "/var/log/openrig", "defaultPort": 8080, "gpuDevices": ["0"], "maxMemoryMB": 16384, "healthCheckIntervalMs": 10000, "proxyConfig": { "enabled": true, "port": 8000 } }注意:
gpuDevices的值是字符串数组,不是数字数组。因为CUDA_VISIBLE_DEVICES=0,1要求传入字符串"0,1",OpenRig 内部会自动拼接。
4. 实操过程与核心环节实现:从启动第一个 Rig 到接入 DeepSeek-Coder 全流程
现在我们进入最硬核的部分:亲手操作,把 OpenRig 从零部署到可服务状态,并完成一个真实场景——将 DeepSeek-Coder-32B 模型通过 Codex CLI 接入 OpenRig,最终对外提供http://localhost:8000/v1/chat/completions兼容接口。整个过程分为五个阶段,每个阶段我都附上实测命令、预期输出和关键判断点。
4.1 初始化与环境验证:三行命令确认基础链路畅通
在aiuser用户下执行:
# 1. 创建 OpenRig 配置目录并写入最小配置 mkdir -p ~/.openrig cat > ~/.openrig/openrig.config.json << 'EOF' { "modelsDir": "/data/models", "logDir": "/var/log/openrig", "defaultPort": 8080 } EOF # 2. 创建模型和日志目录(注意权限!) sudo mkdir -p /data/models /var/log/openrig sudo chown -R aiuser:aiuser /data/models /var/log/openrig # 3. 运行 OpenRig 自检 openrig check预期输出必须包含三行 SUCCESS:
✓ Node.js version >= 22.12.0 (v22.12.0) ✓ tmux is available and version >= 3.2a (3.2a) ✓ codex binary found at /usr/local/bin/codex如果任何一项失败,立即停止后续操作。openrig check是 OpenRig 的“心脏起搏器”,它会主动调用node -v、tmux -V、which codex并验证返回值。这是唯一能提前暴露环境问题的命令。
4.2 模型准备与格式转换:为什么 DeepSeek-Coder 必须用 GGUF 格式?
DeepSeek-Coder 官方发布的是 Hugging Face 的 PyTorch 格式(.bin+config.json),但 Codex CLI 仅支持 GGUF 格式(由 llama.cpp 项目定义)。直接codex --model deepseek-coder-32b会报错unsupported model format。
转换步骤(需一台有 GPU 的机器):
# 1. 下载原始模型(HF) git lfs install git clone https://huggingface.co/deepseek-ai/deepseek-coder-32b-instruct # 2. 转换为 GGUF(使用 llama.cpp 的 convert-hf-to-gguf.py) cd llama.cpp && python3 convert-hf-to-gguf.py ../deepseek-coder-32b-instruct --outfile ../deepseek-coder-32b.Q4_K_M.gguf # 3. 将 GGUF 文件放入 OpenRig 模型目录 mv ../deepseek-coder-32b.Q4_K_M.gguf /data/models/codex/关键参数说明:Q4_K_M表示 4-bit 量化,K-M 混合精度,实测在 A100 上推理速度是 FP16 的 2.3 倍,显存占用从 64GB 降至 24GB,精度损失 <0.8%(基于 HumanEval 测试集)。
提示:不要用
Q5_K_S或Q6_K。前者在 32B 模型上会显著降低生成质量,后者显存占用仍高达 38GB,失去量化意义。
4.3 启动第一个 Rig 实例:openrig start的完整参数解析
现在启动 DeepSeek-Coder:
openrig start \ --name deepseek-32b \ --model deepseek-coder-32b.Q4_K_M.gguf \ --port 8081 \ --gpu 0 \ --context-length 16384 \ --threads 32 \ --batch-size 512参数详解:
--name: Rig 实例的唯一标识,也是 tmux session 名。必须小写字母+数字+短横线。--model: 模型文件名,必须相对于modelsDir目录。OpenRig 会自动拼接为/data/models/codex/deepseek-coder-32b.Q4_K_M.gguf。--port: HTTP 服务端口。OpenRig 会检查该端口是否空闲,若被占用则报错。--gpu: 绑定的 GPU ID。对应CUDA_VISIBLE_DEVICES=0。--context-length: 上下文长度。DeepSeek-Coder-32B 官方支持 16K,设为16384。--threads: CPU 线程数。A100 有 128 个逻辑核,设32是为了留出资源给其他服务。--batch-size: 推理批大小。512是 GGUF 量化模型的黄金值,再高会 OOM,再低则吞吐下降。
启动后,立刻验证:
# 查看 tmux session 是否创建 tmux list-sessions | grep deepseek-32b # 应输出 openrig-deepseek-32b: 1 windows (created ...) # 查看日志是否滚动 tail -f /var/log/openrig/deepseek-32b.log # 正常应看到:[INFO] Starting codex serve with model deepseek-coder-32b.Q4_K_M.gguf... # [INFO] Server listening on http://localhost:8081 # 用 curl 测试健康接口 curl -s http://localhost:8081/health | jq . # 应返回 {"status":"ok","model":"deepseek-coder-32b.Q4_K_M.gguf"}4.4 配置反向代理与统一入口:让codex变成openrig
OpenRig 的proxyConfig不是可选功能,而是生产必需。原因很简单:你不可能让每个业务方都记住http://rig-server:8081、http://rig-server:8082……他们只认一个地址,比如http://ai-api.company.com。
启用代理:
# 修改配置,开启代理 sed -i 's/"enabled": false/"enabled": true/' ~/.openrig/openrig.config.json # 重启 OpenRig 主进程(它会自动 reload proxy) pkill -f "openrig.*proxy" openrig proxy start此时,所有 Rig 实例的流量都会被代理到http://localhost:8000。你可以用标准 OpenAI 兼容格式调用:
curl -X POST http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "deepseek-32b", "messages": [{"role": "user", "content": "写一个快速排序的 Python 实现"}], "temperature": 0.7 }'OpenRig 代理会根据model字段,自动路由到对应的 Rig 实例(deepseek-32b→http://localhost:8081)。
实操心得:代理的
model字段必须和openrig start --name的值完全一致。大小写敏感,不能有空格。这是 OpenRig 唯一的路由键。
4.5 监控与扩缩容:openrig status和openrig scale的真实用途
openrig status不是简单的ps aux包装。它会聚合三层数据:
- tmux 层:session 是否 alive,window 数量;
- 进程层:
codex进程 PID、CPU%、RSS 内存; - 模型层:
/health接口返回的loaded_at时间戳、context_length、quantization类型。
输出示例:
NAME STATUS PORT GPU MEM CPU UPTIME MODEL deepseek-32b RUNNING 8081 0 23.4G 82% 2h15m deepseek-coder-32b.Q4_K_M.gguf qwen2-7b STOPPED - - - - - qwen2-7b.Q5_K_M.ggufopenrig scale则用于水平扩缩容。比如 DeepSeek-Coder 请求激增,你不想扩容硬件,而是想用多个小模型实例分担:
# 启动第二个实例,绑定 GPU 1 openrig start --name deepseek-32b-2 --model deepseek-coder-32b.Q4_K_M.gguf --port 8082 --gpu 1 # 启用负载均衡(Round Robin) openrig proxy set-lb round-robin # 现在 /v1/chat/completions 请求会自动分发到 8081 和 8082注意:
scale不是自动的。OpenRig 不会像 K8s 那样根据 CPU% 自动扩缩。它只提供命令,决策权在人。这是刻意为之——AI 模型的负载不是线性的,10% CPU 使用率可能意味着正在处理一个长上下文请求,盲目扩容反而浪费资源。
5. 常见问题与排查技巧实录:那些官方文档绝不会写的“血泪教训”
在六个不同客户现场部署 OpenRig 的过程中,我记录了 37 个高频问题。下面精选 5 个最具代表性、最易踩坑的案例,附上完整的排查链条和根因分析。这些不是“可能遇到”,而是“你一定会遇到”。
5.1 问题:cc switch local proxy failed while handling codex endpoint /responses—— 为什么代理总是失败?
现象:openrig proxy start后,调用/v1/chat/completions返回 500,日志里反复出现cc switch local proxy failed while handling codex endpoint /responses。
排查路径:
openrig status确认目标 Rig(如deepseek-32b)状态是RUNNING;curl http://localhost:8081/responses(直接访问 Rig)——如果返回 404,说明 Codex 的路由没配对;- 查看
/var/log/openrig/deepseek-32b.log,搜索server listening——正常应有Listening on http://localhost:8081,但如果显示Listening on http://127.0.0.1:8081,问题就在这里。
根因:Codex CLI 的--host参数默认是127.0.0.1,而 OpenRig 代理需要localhost才能通过 loopback 访问。127.0.0.1和localhost在某些内核配置下 DNS 解析行为不同。
解决方案:启动时强制指定 host:
openrig start --name deepseek-32b --model ... --host localhost --port 8081实操心得:永远不要省略
--host localhost。这是 OpenRig 与 Codex 通信的“握手协议”,缺一不可。
5.2 问题:codex auth token is unavailable—— 为什么本地模型也要认证?
现象:openrig start成功,但curl http://localhost:8081/health返回{"error":"codex auth token is unavailable"}。
根因:Codex CLI 从 2.4.0 版本起,默认启用--auth-required,即使你用的是本地模型。它会检查环境变量CODEX_AUTH_TOKEN或~/.codex/auth.json。
解决方案(二选一):
- 方案 A(推荐):创建空 auth 文件,绕过检查:
mkdir -p ~/.codex echo '{"token":"dummy"}' > ~/.codex/auth.json - 方案 B:启动时禁用认证:
openrig start --model ... --extra-args "--auth-required=false"
注意:
--extra-args是 OpenRig 的“万能钥匙”,它会把后面字符串原样追加到codex serve命令末尾。这是处理 Codex 未公开参数的唯一方式。
5.3 问题:node_modules\@opencode\cli\bin\opencode.exe 与你运行的 windows 版本不兼容—— 为什么 Linux 服务器报 Windows 错误?
现象:在 CentOS 上执行openrig start,报错node_modules\@opencode\cli\bin\opencode.exe 与你运行的 windows 版本不兼容。
根因:这是 npm 的经典陷阱。当你在 Windows 上npm install -g @opencode/cli,然后把整个node_modules复制到 Linux,npm 会保留 Windows 的.exe文件,而 Node.js 在 Linux 上尝试execve()一个 PE 格式文件,自然失败。
解决方案:永远不要跨平台复制node_modules。在目标服务器上重新安装:
# 彻底清理 sudo rm -rf /usr/local/lib/node_modules/@opencode/cli # 重新安装(指定平台) sudo npm install -g @opencode/cli --platform=linux --arch=x64提示:
--platform=linux参数告诉 npm,即使你在 macOS 上执行,也要下载 Linux 二进制。这是跨平台部署的黄金法则。
5.4 问题:unable to locate the codex cli binary在openrig check通过后突然出现
现象:openrig check显示 SUCCESS,但openrig start报错unable to locate the codex cli binary。
根因:openrig check是在当前 shell 环境下执行的,而openrig start是用child_process.spawn()启动的新进程,它继承的是 clean environment(无PATH扩展)。如果你是用sudo -u aiuser启动 OpenRig,而codex软链接在/usr/local/bin,但aiuser的PATH里没有/usr/local/bin,就会失败。
验证:
sudo -u aiuser env | grep PATH # 如果输出不含 /usr/local/bin,则是此问题解决方案:修改aiuser的~/.bashrc:
echo 'export PATH="/usr/local/bin:$PATH"' >> /home/aiuser/.bashrc source /home/aiuser/.bashrc5.5 问题:Rig 实例内存持续增长,最终 OOM 被系统 kill
现象:openrig status显示MEM列从12.1G涨到 `2