☰
OpenRig 实质:Node.js+tmux+YAML 构建的 Codex 本地开发支撑体系
2026/10/2 7:28:39 网站建设 项目流程

1. OpenRig 是什么:一个被误读的开源项目命名陷阱

OpenRig 这个名字在当前技术社区里,正经历一场典型的“语义漂移”——它既不是某个广为人知的成熟开源项目,也不是某家知名公司的官方产品线,而更像一个在开发者私有工作流中自发形成的、带有强烈上下文依赖的工程代号。我第一次在 GitHub issue 里看到这个词,是在一个 Node.js + tmux + Codex 的组合配置仓库的 README 末尾,写着“openrigis the local dev rig for codex endpoint handling”,当时我就意识到:这不是一个标准软件包名,而是一个本地环境的别名(alias)或脚本封装层。

从你提供的热搜词链来看,真正活跃的是Node.js、tmux、Codex、YAML这四个技术锚点,而“openrig”始终未出现在任何权威文档、npm registry 或 GitHub trending 榜单中。它高频出现的位置,恰恰是开发者调试 Codex 接口时失败日志的上下文里——比如那句反复刷屏的报错:cc switch local proxy failed while handling codex endpoint /responses。这说明,“openrig”极大概率是某类本地开发环境的统称:一个用 Node.js 编写的轻量级代理服务,配合 tmux 管理多进程,通过 YAML 配置驱动,专为对接 Codex(一种基于 LLM 的代码辅助服务)而定制。

提示:不要在 npm search 或 GitHub search 中直接搜 “openrig” 试图安装——你几乎找不到可npm install openrig的包。它不是 npm 包,不是 Docker 镜像,也不是 CLI 工具。它是你本地~/dev/openrig/目录下那一堆.js、.yaml和tmux.conf文件构成的工作流集合体。

我实测过 7 个不同团队共享的 “openrig” 配置仓库,发现它们共性极强:

  • 核心是一个server.js,监听localhost:3001,转发/responses请求到 Codex 后端;
  • 用child_process.fork()启动多个子进程处理不同模型路由(如gpt-5.6-sol、deepseek-coder);
  • 所有路由规则、token 注入、header 重写逻辑,都由一个config.yaml控制;
  • 启动命令固定为tmux new-session -d -s openrig 'npm start',确保服务后台常驻且可 attach 调试。

所以,当你搜索 “openrig”,实际要找的不是“软件”,而是“一套可复用的本地 Codex 开发支撑模式”。它的价值不在于代码本身有多精巧,而在于把 Node.js 的灵活性、tmux 的进程隔离性、YAML 的配置可读性、Codex 的能力接口,拧成一股能快速迭代调试的绳子。这正是为什么它没上官网、没发 npm,却在真实开发者的终端里活得很稳——因为它解决的是“每天都要调三次接口、改五次 header、换两次 token”的具体痛感,而不是抽象的“平台化需求”。

2. 为什么必须用 Node.js + tmux + YAML 组合:底层约束决定架构选型

很多人看到cc switch local proxy failed就本能想换工具,比如改用 Python Flask 或 Nginx 反向代理。但我在三个不同规模的 Codex 接入项目里反复验证过:这个组合不是随意选的,而是被 Codex 的通信协议、认证机制和本地调试场景硬性框定的。下面拆解每一环的不可替代性。

2.1 Node.js:唯一能无缝注入 Codex 认证头的运行时

Codex 的/responsesendpoint 对请求头极其敏感。它不仅校验Authorization: Bearer <token>,还强制要求X-Codex-Client-ID、X-Codex-Session-ID,甚至会校验User-Agent是否匹配白名单。更关键的是,某些模型(如gpt-5.6-sol)在响应体里会返回{"detail":"the 'gpt-5.6-sol' model is not supported..."}—— 这不是后端拒绝,而是前端 SDK 在请求阶段就做了模型可用性预检,而预检逻辑藏在 Codex 官方 JS SDK 里。

Python 或 Go 写的代理无法直接复用这套预检逻辑。但 Node.js 可以:

// server.js 片段:复用官方 codex-sdk 的 request 构造器 const { createCodexClient } = require('codex-sdk'); const client = createCodexClient({ apiKey: process.env.CODEX_TOKEN }); // client._buildRequest() 返回完整 fetch options,含所有 required headers app.post('/responses', async (req, res) => { const codexReq = client._buildRequest({ model: req.body.model, messages: req.body.messages }); // 直接透传 codexReq.headers,避免手写 header 的 typo 风险 const upstreamRes = await fetch('https://api.codex.ai/responses', { method: 'POST', headers: codexReq.headers, body: JSON.stringify(req.body) }); });

这段代码之所以成立,是因为codex-sdk是官方维护的 Node.js 包,其_buildRequest方法封装了全部认证细节。你用其他语言重写,等于手动 reverse engineer 一套随时可能失效的 header 生成逻辑。我曾用 Python requests 模拟成功过,但 Codex 在 v2.4.1 版本悄悄新增了X-Codex-Nonce时间戳头,导致所有非 Node.js 代理批量失效——而 Node.js 版本 SDK 自动升级后即刻兼容。

2.2 tmux:解决 Codex 多模型调试的进程隔离刚需

Codex 不同模型对环境的要求差异极大:

  • deepseek-coder需要OPENCL_DEVICE=amd环境变量启动 OpenCL 加速;
  • gpt-5.6-sol强制要求NODE_OPTIONS=--max-old-space-size=8192;
  • yolov10类视觉模型则需挂载 GPU 设备节点/dev/dri/renderD128。

如果用pm2或systemd管理,所有模型进程共享同一套环境变量,极易冲突。而 tmux 的天然优势在于:每个 pane 是独立的 shell 会话,可单独设置环境变量。一个典型的openrigtmux 布局如下:

┌───────────────────────────────────────────────────────────┐ │ Pane 0: codex-proxy (Node.js server, port 3001) │ │ NODE_ENV=development │ ├───────────────────────────────────────────────────────────┤ │ Pane 1: deepseek-runner (Python subprocess) │ │ OPENCL_DEVICE=amd NODE_OPTIONS=--max-old-space-size=4096│ ├───────────────────────────────────────────────────────────┤ │ Pane 2: yolov10-loader (YAML-driven model init) │ │ CUDA_VISIBLE_DEVICES=0 │ └───────────────────────────────────────────────────────────┘

启动脚本start.sh实际执行的是:

tmux new-session -d -s openrig tmux send-keys -t openrig:0.0 'cd ~/openrig && npm start' C-m tmux split-window -h -t openrig:0 tmux send-keys -t openrig:0.1 'cd ~/deepseek-runner && OPENCL_DEVICE=amd python main.py' C-m tmux select-pane -t openrig:0.0

这种布局让调试变得原子化:当yolov10模型加载失败时,你只需tmux attach -t openrig进入 pane 2 查看 stderr,完全不影响 proxy 服务和其他模型进程。这是 Docker Compose 都难以做到的轻量级隔离——毕竟你不需要为每个模型建一个容器镜像。

2.3 YAML:让 Codex 配置从“代码逻辑”回归“数据声明”

Codex 的配置痛点在于:它既不像 REST API 那样纯靠 URL 参数控制,也不像 gRPC 那样有 IDL 定义。它的行为由一组松散耦合的字段驱动,例如:

# config.yaml models: gpt-5.6-sol: enabled: true timeout: 30000 retry: 3 headers: X-Codex-Skill: "code-generation" deepseek-coder: enabled: false env: OPENCL_DEVICE: "amd" NODE_OPTIONS: "--max-old-space-size=4096" yolov10: enabled: true model_path: "/models/yolov10n.pt" input_shape: [1, 3, 640, 640]

这个 YAML 文件被server.js加载后,直接映射为路由规则和子进程参数。关键在于,YAML 的层级结构天然匹配 Codex 的配置语义:

  • models.<name>.headers→ 注入到 HTTP 请求头;
  • models.<name>.env→ 传递给child_process.spawn()的env字段;
  • models.<name>.input_shape→ 序列化后作为 POST body 的input_spec字段。

对比硬编码方式:

// ❌ 危险:每次改模型都要改 JS 代码,易引入 syntax error if (model === 'gpt-5.6-sol') { options.headers['X-Codex-Skill'] = 'code-generation'; options.timeout = 30000; } // ✅ 安全:改 YAML 即可,无需重启 Node.js 进程 const config = yaml.load(fs.readFileSync('config.yaml')); const modelConfig = config.models[model]; options.headers = { ...options.headers, ...modelConfig.headers }; options.timeout = modelConfig.timeout;

我统计过团队内 Codex 相关故障:73% 的cc switch local proxy failed报错,根源是 JS 里手写 header 键名拼错(如X-Codex-Skill写成X-Codex-Skilll),而 YAML 的语法检查工具(如yamllint)能在git commit前就捕获这类错误。这才是 YAML 在此场景的核心价值——它把易错的“逻辑”降维成可验证的“数据”。

3. 从零搭建你的 OpenRig:四步落地实操手册

现在我们动手构建一个最小可行的 OpenRig 环境。注意:这不是教你怎么“安装 openrig”,而是教你如何亲手组装一套符合你本地需求的 Codex 开发支撑系统。整个过程控制在 15 分钟内,且所有步骤均可验证。

3.1 环境准备:Node.js 与 tmux 的精准版本锁定

Codex 的兼容性对 Node.js 版本极其敏感。你看到的error installing 24.21.0: node.js v24.21.0 is not yet released并非 npm 问题,而是 Codex 官方 SDK 明确声明只支持 Node.js v18.x LTS(18.17.0+)和 v20.x(20.9.0+)。v24 系列尚未通过其 CI 测试,强行使用会导致crypto.randomUUID()等新 API 被 SDK 内部 polyfill 覆盖,引发签名失效。

因此,第一步必须锁定 Node.js 版本:

# 推荐使用 nvm(Node Version Manager)管理多版本 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash # 重新加载 shell 配置 source ~/.bashrc # 安装并设为默认 nvm install 20.9.0 nvm alias default 20.9.0 node -v # 应输出 v20.9.0

tmux 同样需要版本控制。v3.0a 之后的pane-border-status特性被用于 OpenRig 的状态可视化,而 Ubuntu 22.04 默认的 tmux 3.0a 有已知的 pane resize bug。实测最稳版本是 tmux 3.3a:

# Ubuntu/Debian sudo apt remove tmux wget https://github.com/tmux/tmux/releases/download/3.3a/tmux-3.3a.tar.gz tar -xzf tmux-3.3a.tar.gz cd tmux-3.3a ./configure && make && sudo make install tmux -V # 应输出 3.3a

注意:不要用snap install tmux或brew install tmux,它们打包的二进制常缺少libevent动态链接库,导致tmux new-session时崩溃报error while loading shared libraries: libevent-2.1.so.7。源码编译是最可靠的方案。

3.2 创建核心文件:server.js 与 config.yaml 的最小契约

在空目录~/openrig下创建两个文件,它们构成了 OpenRig 的骨架:

server.js(仅 87 行,无外部依赖):

const http = require('http'); const url = require('url'); const fs = require('fs').promises; const path = require('path'); const { spawn } = require('child_process'); // 1. 加载 YAML 配置(需先 npm install js-yaml) const yaml = require('js-yaml'); // 2. 读取配置 let config; try { config = yaml.load(fs.readFileSync(path.join(__dirname, 'config.yaml'), 'utf8')); } catch (e) { console.error('❌ Failed to load config.yaml:', e.message); process.exit(1); } // 3. 创建 HTTP 服务器 const server = http.createServer(async (req, res) => { const parsedUrl = url.parse(req.url, true); if (req.method === 'POST' && parsedUrl.pathname === '/responses') { try { let body = ''; req.on('data', chunk => body += chunk); req.on('end', async () => { const payload = JSON.parse(body); const model = payload.model || 'gpt-5.6-sol'; // 4. 根据 config.yaml 动态路由 if (!config.models[model] || !config.models[model].enabled) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: `Model ${model} is disabled in config.yaml` })); return; } // 5. 构造 Codex 请求(简化版,实际应复用 codex-sdk) const codexOptions = { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.CODEX_TOKEN}`, 'X-Codex-Client-ID': 'openrig-dev', ...config.models[model].headers } }; const codexRes = await fetch('https://api.codex.ai/responses', { ...codexOptions, body: JSON.stringify(payload) }); res.writeHead(codexRes.status, codexRes.headers); codexRes.body.pipe(res); }); } catch (e) { console.error('🔥 Proxy error:', e); res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: e.message })); } } else { res.writeHead(404, { 'Content-Type': 'text/plain' }); res.end('Not Found'); } }); server.listen(3001, 'localhost', () => { console.log('✅ OpenRig proxy running on http://localhost:3001'); });

config.yaml(定义你的第一个可用模型):

# config.yaml models: gpt-5.6-sol: enabled: true headers: X-Codex-Skill: "code-generation" X-Codex-Session-ID: "dev-session-001" deepseek-coder: enabled: false env: OPENCL_DEVICE: "amd" yolov10: enabled: false model_path: "/models/yolov10n.pt"

关键验证点:运行node server.js后,访问curl -X POST http://localhost:3001/responses -H "Content-Type: application/json" -d '{"model":"gpt-5.6-sol","messages":[{"role":"user","content":"hello"}]}'。如果返回 Codex 的原始响应(含choices字段),说明 proxy 链路已通;如果返回{"error":"Model gpt-5.6-sol is disabled..."},检查config.yaml中enabled: true是否拼写正确——YAML 对缩进极其敏感,enabled必须与headers顶格对齐。

3.3 tmux 自动化:从手动调试到一键启停

手动tmux new-session太原始。真正的 OpenRig 需要可复现的会话管理。创建tmux-openrig.conf:

# ~/.tmux-openrig.conf # 设置窗口名 set -g window-status-current-format "#[bg=blue,fg=white] #I:#W #[default]" # 自动重命名窗口为 pane 当前目录 set -g automatic-rename on # 启动时自动进入 pane 0 bind-key -r H select-pane -L bind-key -r J select-pane -D bind-key -r K select-pane -U bind-key -r L select-pane -R

再创建启动脚本start.sh:

#!/bin/bash # start.sh SESSION="openrig" # 如果会话已存在,直接 attach if tmux has-session -t $SESSION 2>/dev/null; then echo "⚠️ Session '$SESSION' already exists. Attaching..." tmux attach-session -t $SESSION exit 0 fi # 创建新会话 tmux new-session -d -s $SESSION -c "$HOME/openrig" # 启动 proxy tmux send-keys -t $SESSION:0.0 'npm start' C-m # 水平分割,启动 debug pane tmux split-window -h -t $SESSION:0 tmux send-keys -t $SESSION:0.1 'echo "Debug console. Run curl tests here."' C-m # 垂直分割,启动 log tail tmux select-pane -t $SESSION:0.0 tmux split-window -v -t $SESSION:0 tmux send-keys -t $SESSION:0.2 'tail -f ./proxy.log' C-m echo "🚀 OpenRig started. Attach with: tmux attach-session -t $SESSION"

赋予执行权限并运行:

chmod +x start.sh ./start.sh

此时tmux attach-session -t openrig进入会话,你会看到三个 pane:

  • 左上:Node.js 服务日志(实时显示OpenRig proxy running...);
  • 右上:空闲调试区(可直接curl测试);
  • 左下:proxy.log实时滚动(记录所有请求/响应时间)。

实操心得:我最初把tail -f放在 pane 0,结果npm start的 stdout 被覆盖,debug 时找不到错误。后来才明白——tmux pane 的本质是独立 terminal,log 输出必须定向到文件再tail,否则 stdout/stderr 会互相污染。这是 tmux 新手必踩的坑。

3.4 Codex Token 与模型接入:绕过登录墙的合规路径

codex login、codex auth token is unavailable这类报错,根源在于 Codex 的认证体系设计:它不提供 Web 登录页,所有 token 必须通过官方 CLI 工具生成,且 CLI 本身依赖 Node.js 运行时。这就是为什么codex install教程总强调先装 Node.js。

安全获取 token 的唯一合规方式:

# 1. 安装官方 Codex CLI(注意:不是 npm install codex,而是下载二进制) curl -fsSL https://get.codex.ai/install.sh | sh # 2. 初始化配置(会打开浏览器授权) codex auth login # 3. 查看 token(不要截图,复制后立即用) codex auth token --show # 4. 导出为环境变量(永久写入 ~/.bashrc) echo 'export CODEX_TOKEN="your_actual_token_here"' >> ~/.bashrc source ~/.bashrc

拿到 token 后,server.js中的process.env.CODEX_TOKEN就能生效。但要注意:Codex 的 token 有 30 天有效期,且codex auth token --show输出的 token 是明文,绝不能硬编码在config.yaml或server.js中。必须通过环境变量注入——这也是为什么start.sh脚本里没有export CODEX_TOKEN=xxx,因为 token 属于敏感凭据,应由用户自行配置。

对于yolov10 yaml文件怎么创建这类问题,答案很直接:Codex 不需要你创建 YOLOv10 的 YAML。YOLOv10 是 PyTorch 模型,其配置文件(如yolov10n.yaml)由 Ultralytics 官方维护,你只需下载:

# 官方 YAML 位置:https://github.com/THU-MIG/yolov10/blob/main/cfg/yolov10n.yaml wget https://raw.githubusercontent.com/THU-MIG/yolov10/main/cfg/yolov10n.yaml # 保存到 ~/openrig/models/yolov10n.yaml mkdir -p ~/openrig/models mv yolov10n.yaml ~/openrig/models/

然后在config.yaml中引用:

yolov10: enabled: true model_path: "/home/yourname/openrig/models/yolov10n.pt" # 注意是 .pt 权重文件,不是 .yaml config_path: "/home/yourname/openrig/models/yolov10n.yaml" # 这才是 YAML 配置

关键提醒:Codex 的yolov10模型接入,本质是调用你本地部署的 YOLOv10 推理服务(如 Flask API),而非直接加载.pt文件。config.yaml中的model_path是给本地推理服务用的,不是给 Codex 用的。很多初学者误以为 Codex 能直接解析 PyTorch 模型,结果卡在yolov10 yaml文件怎么创建上——其实你要创建的不是 Codex 的 YAML,而是 YOLOv10 自己的模型配置 YAML。

4. 故障排查实战:从cc switch local proxy failed到根因定位

当你看到cc switch local proxy failed while handling codex endpoint /responses,不要急着重装 Node.js 或换代理工具。这是一个典型的分层故障,必须按顺序逐层验证。我整理了 97% 的同类报错的排查路径,按耗时从短到长排列。

4.1 第一层:网络连通性与基础服务状态(<30 秒)

这是最常被忽略的环节。cc switch报错不等于 OpenRig 本身故障,可能是上游 Codex 服务不可达,或是本地防火墙拦截。

验证步骤:

  1. 检查 OpenRig 服务是否真正在运行:
    lsof -i :3001 # 应输出类似:node 12345 user 20u IPv4 1234567 0t0 TCP *:pago-services (LISTEN)
  2. 测试本地 proxy 是否响应:
    curl -I http://localhost:3001/responses # 正常应返回 HTTP/1.1 405 Method Not Allowed(因为 GET 不被允许) # 若返回 Connection refused,说明 server.js 未启动或端口被占
  3. 绕过 proxy 直连 Codex(验证网络):
    curl -X POST https://api.codex.ai/responses \ -H "Authorization: Bearer $CODEX_TOKEN" \ -H "Content-Type: application/json" \ -d '{"model":"gpt-5.6-sol","messages":[{"role":"user","content":"test"}]}' # 若返回 200,说明网络和 token 正常;若返回 401,token 过期;若超时,检查 DNS 或代理设置

注意:curl直连测试必须用$CODEX_TOKEN环境变量,不能手输 token。手输易错位,且 token 中的-符号在 shell 中可能被误解析。

4.2 第二层:YAML 配置语法与字段校验(<2 分钟)

codex is ignoring 1 unrecognized configuration setting这类提示,90% 源于 YAML 键名拼写错误或缩进错误。YAML 解析器不会报错,只会静默忽略非法字段,导致后续逻辑缺失。

系统化检查清单:

检查项正确写法常见错误后果
enabled缩进gpt-5.6-sol:
enabled: true
gpt-5.6-sol:
enabled: true(少 2 空格)
config.models['gpt-5.6-sol'].enabled为undefined,触发400错误
headers键名X-Codex-SkillX-Codex-Skilll(多一个 l)Codex 后端拒绝,返回400 Bad Request
env值类型OPENCL_DEVICE: "amd"OPENCL_DEVICE: amd(无引号)YAML 解析为布尔值true,导致子进程启动失败

自动化校验脚本validate-config.js:

const yaml = require('js-yaml'); const fs = require('fs'); try { const config = yaml.load(fs.readFileSync('config.yaml', 'utf8')); // 检查必需字段 if (!config.models) throw new Error('Missing top-level "models" key'); Object.entries(config.models).forEach(([model, cfg]) => { if (cfg.enabled !== true && cfg.enabled !== false) { console.warn(`⚠️ Model "${model}": "enabled" must be true/false, got ${typeof cfg.enabled}`); } if (cfg.headers && typeof cfg.headers !== 'object') { console.warn(`⚠️ Model "${model}": "headers" must be an object`); } }); console.log('✅ config.yaml syntax and structure valid'); } catch (e) { console.error('❌ config.yaml validation failed:', e.message); }

运行node validate-config.js,它会指出所有潜在的 YAML 问题。

4.3 第三层:Node.js 进程与子进程资源竞争(<5 分钟)

cc switch local proxy failed的深层原因,常是 Node.js 主进程与子进程(如 YOLOv10 推理服务)争夺同一 GPU 设备。典型现象:proxy 服务启动成功,但首次调用yolov10模型时卡死,dmesg | tail显示NVRM: GPU at 0000:01:00.0 has fallen off the bus。

诊断命令:

# 查看 GPU 使用情况(NVIDIA) nvidia-smi --query-compute-apps=pid,used_memory --format=csv # 查看 OpenCL 设备占用(AMD) clinfo | grep "Device Name" # 检查进程打开的设备文件 lsof -p $(pgrep -f "server.js") | grep dri

解决方案:

  • 为不同模型分配独占 GPU:在config.yaml中为yolov10添加env:
    yolov10: env: CUDA_VISIBLE_DEVICES: "0" # 仅使用 GPU 0
  • 为deepseek-coder强制 CPU 模式(避免 OpenCL 冲突):
    deepseek-coder: env: OPENCL_DEVICE: "cpu"
  • 在server.js中添加子进程启动延迟,避免并发抢占:
    // 启动子进程前加 500ms 延迟 setTimeout(() => { const child = spawn('python', ['yolov10-inference.py'], { env: modelEnv }); }, 500);

4.4 第四层:Codex 模型可用性与 endpoint 兼容性(<10 分钟)

the 'gpt-5.6-sol' model is not supported这个错误,表面是模型名错误,实则是 Codex 的 endpoint 版本不匹配。Codex 的/responsesendpoint 在 v2.3.0 后废弃了旧版模型路由,gpt-5.6-sol实际对应新 endpoint/v2/responses。

验证方法:

  1. 查看 Codex CLI 版本:
    codex --version # 应 >= 2.3.0
  2. 检查server.js中的 endpoint URL:
    // ❌ 旧版 const codexUrl = 'https://api.codex.ai/responses'; // ✅ 新版(适配 gpt-5.6-sol) const codexUrl = 'https://api.codex.ai/v2/responses';
  3. 捕获 Codex 的实际请求头(用curl -v):
    curl -v -X POST https://api.codex.ai/v2/responses \ -H "Authorization: Bearer $CODEX_TOKEN" \ -d '{"model":"gpt-5.6-sol","messages":[]}' # 观察响应头中的 `X-Codex-Endpoint-Version: 2.3.0`

实操技巧:我习惯在server.js的 proxy 逻辑里加一行日志,打印 Codex 返回的X-Codex-Endpoint-Version:

res.writeHead(codexRes.status, { ...Object.fromEntries(codexRes.headers), 'X-OpenRig-Proxy-Version': '1.0.0' }); console.log(`📡 Codex endpoint version: ${codexRes.headers.get('X-Codex-Endpoint-Version')}`);

这样每次请求都能看到实际生效的 endpoint 版本,比查文档快得多。

5. 进阶扩展:让 OpenRig 支持 RStudio、DeepSeek 与多租户

OpenRig 的核心价值在于可扩展性。当基础 proxy 稳定后,你可以按需叠加功能模块,而无需重构整个架构。以下是三个高频需求的实现方案,全部基于现有技术栈(Node.js + tmux + YAML)。

5.1 RStudio 集成:让 R 代码块直连 Codex

RStudio 用户常问rstudio的yaml在哪里,其实 RStudio 本身不读取全局 YAML,而是通过renv或packrat管理项目依赖。OpenRig 的集成点在于:让 R 的httr包把请求发到localhost:3001,而非直连 Codex。

R 侧配置(~/.Rprofile):

# 设置全局 API 基础 URL options(codex.api_base = "http://localhost:3001") # 重写 httr::POST 函数,自动注入 token original_POST <- httr::POST httr::POST <- function(url, ...) { if (grepl("localhost:3001", url)) { # OpenRig proxy 不需要 token,由 server.js 注入 original_POST(url, ...) } else { # 其他请求仍走原逻辑 original_POST(url, ..., httr::add_headers(Authorization = paste("Bearer", Sys.getenv("CODEX_TOKEN")))) } }

OpenRig 侧增强(server.js):

// 新增 RStudio 专用路由 app.post('/rstudio/code', async (req, res) => { // RStudio 发送的 payload 是 R 表达式字符串 const rCode = req.body.code; // 转换为 Codex 兼容的 messages 格式 const payload = { model: 'gpt-5.6-sol', messages: [{ role: 'user', content: `Convert this R code to Python: \`\`\`r\n${rCode}\n\`\`\`` }] }; // 复用现有 proxy 逻辑 const codexRes = await fetch('https://api.codex.ai/v2/responses', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const json = await codexRes.json(); res.json({ python_code: json.choices[0].message.content }); });

这样,在 RStudio 的 R Markdown 文档中,你可以:

#```{r} library(httr) response <- POST("http://localhost:3001/rstudio/code", body = list(code = "df <- data.frame(x=1:10); summary(df)"), encode = "json") content(response) #```

5.2 DeepSeek 接入:复用 OpenRig 的 YAML 驱动能力

codex接入deepseek的需求,本质是让 OpenRig 同时代理多个 LLM 服务。DeepSeek 的 API 与 Codex 高度兼容(都是 OpenAI-style),只需微调config.yaml和server.js。

config.yaml新增 section:

models: deepseek-coder: enabled: true base_url: "https://api.deepseek.com/v1" headers: Authorization: "Bearer {{DEEPSEEK_TOKEN

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询