1. OpenRig 是什么一个被误读的开源项目命名陷阱OpenRig 这个词在当前技术社区里正经历一场典型的“语义漂移”——它既不是官方发布的成熟框架也不是某个知名组织背书的标准化工具而更像是一组散落在 GitHub、Discourse 论坛和零星技术博客中的实践性项目代号。我第一次见到它是在一个用 Node.js 搭建本地 AI 工具链的 Reddit 帖子标题里“OpenRig: my local codex tmux YAML orchestration stack”。当时我就意识到这不是一个产品名而是一个操作范式operational pattern的速记标签。它背后真正指向的是一类面向开发者本地环境的轻量级 AI 协作基础设施用 Node.js 作为胶水层调度核心服务用 tmux 实现多进程会话管理用 YAML 文件定义模型调用链路与参数契约最终对接 Codex注意此处指代的是开源社区对类似 GitHub Copilot 后端能力的泛称非微软官方 Codex API或其替代实现如本地部署的 CodeLlama、StarCoder 或经适配的 DeepSeek-Coder 接口。所谓 “OpenRig”本质是 “Open-source Rig for Local Code Intelligence” 的缩写变体强调其开放、可组装、面向代码智能场景的工程化底座属性。这解释了为什么你在搜索引擎里搜不到权威文档——它没有官网没有 npm 包也没有版本号。你搜到的全是开发者在调试过程中随手打的 tagopenrig出现在 GitHub commit message 里出现在 tmux session 名称里出现在config.yaml的注释行里。它像一把自研的扳手不卖只在修自己那台车时用。也因此所有围绕它的“安装教程”“配置指南”“报错解决”本质上都是某位开发者在复现自己本地工作流时留下的操作快照而非标准化交付物。提示如果你正在搜索 “OpenRig 官网下载” 或 “OpenRig 安装包”请立刻停止。它不存在。你真正需要的是理解这套组合技背后的协作逻辑并亲手把它搭出来。接下来的内容就是我用三周时间踩坑、验证、重构后沉淀下来的完整本地 AI 编程辅助环境搭建手册——不依赖任何中心化服务不调用闭源 API全部基于可验证的开源组件且每一步都附带原理说明与实操验证方法。2. 核心组件解耦Node.js、tmux、YAML 与 Codex 的真实角色分工要真正掌控 OpenRig 类环境必须先打破“把它们当一个整体安装”的思维惯性。这四个关键词不是并列关系而是分层协作的工程契约Node.js 是执行引擎tmux 是进程管家YAML 是配置协议Codex 是能力提供方。它们各自承担不可替代的职责强行合并或跳过任一环节都会导致后续出现“cc switch local proxy failed while handling codex endpoint /responses”这类看似玄学、实则必然的错误。2.1 Node.js不只是运行时更是本地服务的“中央调度器”很多人以为 Node.js 在这里只是跑个index.js其实它承担着三重关键职能协议桥接层Codex 类服务如本地部署的 Ollama CodeLlama通常暴露的是/api/chat或/v1/chat/completions这类 REST 接口而 IDE 插件如 VS Code 的 Continue.dev 或 Cursor期望的是符合 OpenAI 兼容协议的响应格式。Node.js 进程负责做字段映射、stream 分块重组、token 统计注入等转换这是纯前端或纯 CLI 工具无法完成的。状态协调中枢当你在 tmux 中同时运行模型服务、向量数据库如 ChromaDB、代码索引器如 ctags 或 Tree-sitter时Node.js 进程通过内存变量或轻量级 IPC如 Unix socket监听各组件健康状态。一旦检测到codex endpoint不可用它能主动触发重试逻辑或降级策略例如切回本地缓存的提示模板而不是让上层应用直接报错。安全沙箱边界所有外部请求来自 IDE 插件都先抵达 Node.js 服务再由它转发至后端模型。这意味着你可以在 Node.js 层统一做 token 验证、速率限制、输入清洗如过滤恶意 prompt 注入、日志审计——这些功能若放在 tmux 或 YAML 里根本无从实现。我实测对比过直接用 curl 调用本地 Ollama 的/api/chat响应延迟稳定在 80–120ms但接入 Node.js 中间层后平均延迟增加 15–22ms换来的是完整的错误兜底、上下文保持、以及可插拔的预处理钩子比如自动补全缺失的 system prompt。这笔性能账对本地开发而言完全值得。2.2 tmux不是终端复用工具而是生产级进程编排系统把 tmux 当成“多个终端窗口管理器”是最大的认知偏差。在 OpenRig 架构中tmux 扮演的是轻量级容器编排器Container Orchestrator Lite的角色其价值远超screen或nohup。会话即部署单元每个 tmux session 对应一个完整的服务拓扑。例如我常用的openrig-mainsession 包含四个 panePane 0Ollama 服务ollama servePane 1Node.js 调度服务node server.jsPane 2ChromaDB 向量库chroma run --path ./chroma-dataPane 3实时日志聚合tail -f ./logs/*.log这四个进程彼此独立启动、独立重启、独立查看日志但又共享同一套环境变量与工作目录。tmux attach -t openrig-main就等于“进入生产环境控制台”。故障隔离与快速恢复当 Codex endpoint 报错如cc switch local proxy failed问题往往出在某个子进程崩溃。此时无需ps aux | grep全局排查直接Ctrl-bn切到对应 pane按Up键调出上次命令回车重启即可。整个过程 3 秒内完成比 Docker compose down/up 快 5 倍以上。资源可见性保障tmux的Ctrl-bt可以实时查看 CPU/内存占用Ctrl-b:输入list-panes -F #{pane_pid} #{pane_current_path}能精准定位每个进程 PID 和路径。这解决了 Node.js 进程意外退出后难以追溯 root cause 的痛点——很多 “codex login failed” 或 “auth token unavailable” 报错根源其实是 Ollama 进程因内存不足被 OOM killer 杀掉而日志里只显示 “connection refused”。注意不要用tmux new-session -d后台启动就完事。必须为每个 pane 设置autorename自动重命名和remain-on-exit退出后保留 pane否则调试时会丢失上下文。我的.tmux.conf关键配置如下set -g automatic-rename on set -g automatic-rename-format #(basename #S) | #{pane_current_command} set -g remain-on-exit on2.3 YAML不是配置文件而是服务契约的机器可读说明书YAML 在 OpenRig 中绝非简单的 key-value 存储。它是定义服务间交互契约Service Interaction Contract的 DSL领域特定语言。一个典型的openrig-config.yaml文件实际描述的是能力声明哪些模型可用支持哪些参数例如models: - name: codex-local endpoint: http://localhost:11434/api/chat model: codellama:7b max_tokens: 2048 temperature: 0.2 - name: deepseek-coder endpoint: http://localhost:8000/v1/chat/completions model: deepseek-coder:33b max_tokens: 4096路由策略不同代码场景应路由到哪个模型例如routing_rules: - file_pattern: **/*.py model: codex-local system_prompt: You are a Python expert. Prefer async/await and type hints. - file_pattern: **/Cargo.toml model: deepseek-coder system_prompt: You are a Rust expert. Prioritize zero-cost abstractions and unsafe best practices.能力元数据模型是否支持 function calling是否支持 streaming这些信息直接影响 Node.js 调度器的请求构造逻辑。YAML 文件里的一行supports_streaming: true决定了前端能否获得逐字输出的体验。这就是为什么codex is ignoring 1 unrecognized configuration setting这类报错如此常见——不是 YAML 写错了而是你用的 Node.js 调度器版本不识别新加入的字段比如context_window_size或者 tmux 启动的模型服务根本不支持该配置项。YAML 在这里是连接人类意图与机器执行的语义桥梁而非静态参数表。2.4 Codex不是单一产品而是本地代码智能能力的抽象接口必须明确当前社区语境下的 “Codex”早已脱离微软原始定义演变为一个能力接口标准Capability Interface Standard。它代表一类具备以下特征的本地模型服务输入结构化代码上下文当前文件、光标位置、选中文本、相关函数签名输出符合编程语义的补全、解释、重构建议非通用文本生成协议兼容 OpenAI Chat Completion API 的子集messages,model,temperature等字段但可扩展私有字段如code_context因此“接入 Codex” 的本质是让你的本地模型服务Ollama、LM Studio、Text Generation WebUI伪装成 Codex 兼容端点。这需要两步模型适配选择专为代码训练的模型CodeLlama、DeepSeek-Coder、Phi-3、StarCoder2而非通用大模型Llama3、Qwen。我测试过同样 7B 参数CodeLlama 在 Python 补全准确率上比 Llama3 高 37%因为其 tokenizer 和训练数据天然偏向代码 token。API 层封装用 Node.js 或 Python FastAPI 写一个薄层将标准/chat/completions请求转换为底层模型所需的格式如 Ollama 的/api/chat或 vLLM 的/v1/chat/completions。这个薄层就是真正的 “Codex Proxy”。所以当你看到 “codex 安装 windows 桌面版” 或 “codex 破甲” 这类搜索词背后的真实需求是“如何在 Windows 上一键启动一个 Codex 兼容的本地代码模型服务”——答案不是下载某个 exe而是用 Ollama 自定义 YAML Node.js Proxy 组合实现。3. 从零构建 OpenRig一份可验证、可调试、可复现的实操清单现在我们进入最硬核的部分亲手搭建一个最小可行的 OpenRig 环境。本节不提供“一键脚本”因为真正的掌控力来自对每一步意图的理解。所有命令均经过 macOS Sonoma / Ubuntu 22.04 / Windows WSL2 三端验证路径与权限细节均已标注。3.1 环境准备Node.js 版本与依赖的精确控制Node.js 是整个链条的基石版本选择直接决定后续兼容性。当前2024 年 Q3最稳妥的组合是Node.js LTSv20.18.0这是最后一个支持 OpenSSL 1.1.1 的 LTS 版本能完美兼容绝大多数本地模型服务的 HTTPS 客户端如 Ollama 的 Go 客户端。避开 v22 的 OpenSSL 3.0 TLS 1.3 强制要求可省去大量证书配置麻烦。npm 9.x避免使用 npm 10因其默认启用--legacy-peer-deps行为变更可能导致express、axios等关键依赖安装失败。安装步骤以 macOS 为例其他平台同理# 1. 卸载现有 Node.js避免 nvm 与系统自带冲突 brew uninstall node sudo rm -rf /usr/local/bin/node /usr/local/bin/npm /usr/local/lib/node_modules # 2. 使用 nvm 安装指定版本nvm 是跨平台最佳实践 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash # 重启终端后执行 nvm install 20.18.0 nvm use 20.18.0 node -v # 应输出 v20.18.0 npm -v # 应输出 9.9.3 # 3. 创建项目目录并初始化 mkdir ~/openrig cd ~/openrig npm init -y npm install express axios cors dotenv morgan关键经验不要用nodejs.org官网下载的 pkg 安装器。它会把 Node.js 装到/usr/local导致权限问题尤其在 macOS 上需 sudo 才能全局安装包。nvm 安装的 Node.js 完全在用户目录下npm install -g无需 sudo且可随时切换版本。这是我踩过最痛的坑——曾因系统 Node.js 与 nvm Node.js 混用导致cc switch local proxy failed报错持续三天无法定位。3.2 tmux 会话编排定义你的 OpenRig “操作系统”tmux 的配置质量直接决定你每天调试的痛苦指数。以下是经过 200 小时实战验证的最小化.tmux.conf# ~/.tmux.conf # 基础设置 set -g default-shell /bin/zsh set -g default-path ~/openrig # 窗格与会话管理 set -g base-index 1 setw -g pane-base-index 1 set -g renumber-windows on # 键绑定优化更符合 Vim 直觉 unbind C-b set -g prefix C-a bind h select-pane -L bind j select-pane -D bind k select-pane -U bind l select-pane -R # 自动重命名与状态栏 set -g automatic-rename on set -g automatic-rename-format #(basename #S) | #{pane_current_command} set -g status-bg black set -g status-fg white set -g status-left #[fggreen]#S #[fgyellow]#I:#P set -g status-right #[fgcyan]%H:%M #[fgred]%d/%m # 日志与调试 set -g history-limit 5000 set -g remain-on-exit on应用配置并创建 OpenRig 主会话# 重载配置 tmux source-file ~/.tmux.conf # 创建名为 openrig-main 的会话并分割为 4 个 pane tmux new-session -d -s openrig-main tmux split-window -h -t openrig-main tmux split-window -v -t openrig-main tmux split-window -v -t openrig-main # 为每个 pane 命名并执行初始命令 tmux rename-pane -t openrig-main:0.0 ollama tmux send-keys -t openrig-main:0.0 cd ~/openrig ollama serve Enter tmux rename-pane -t openrig-main:0.1 node-server tmux send-keys -t openrig-main:0.1 cd ~/openrig npm start Enter tmux rename-pane -t openrig-main:0.2 chromadb tmux send-keys -t openrig-main:0.2 cd ~/openrig chroma run --path ./chroma-data Enter tmux rename-pane -t openrig-main:0.3 logs tmux send-keys -t openrig-main:0.3 cd ~/openrig tail -f ./logs/*.log Enter # 启动会话 tmux attach -t openrig-main此时你已拥有一个可随时Ctrl-b d分离、tmux attach -t openrig-main重新连接的生产级会话。每个 pane 的标题清晰标明其职责Ctrl-bn/p可快速切换Ctrl-b:输入list-panes可查看所有 pane 状态。3.3 YAML 配置驱动编写你的第一个 openrig-config.yaml在~/openrig/目录下创建config.yaml内容如下已针对 Codex 兼容性与本地模型特性优化# openrig-config.yaml # OpenRig 服务契约定义文件 version: 1.0 # 本地模型服务注册表 models: - name: codex-local # Ollama 服务地址默认 localhost:11434 endpoint: http://localhost:11434/api/chat # 模型名称需提前用 ollama pull 下载 model: codellama:7b # Codex 兼容参数 max_tokens: 2048 temperature: 0.2 top_p: 0.9 # 是否支持流式响应影响前端体验 supports_streaming: true # 模型能力声明供 Node.js 调度器决策 capabilities: - code_completion - code_explanation - code_refactoring - name: deepseek-coder endpoint: http://localhost:8000/v1/chat/completions model: deepseek-coder:33b max_tokens: 4096 temperature: 0.1 supports_streaming: true capabilities: - code_completion - unit_test_generation - docstring_generation # 路由规则根据文件类型选择模型 routing_rules: - file_pattern: **/*.py model: codex-local system_prompt: | You are an expert Python developer. Always use type hints, prefer async/await for I/O, and follow PEP 8. If asked to generate code, output only the code block with no explanation. - file_pattern: **/*.rs model: deepseek-coder system_prompt: | You are an expert Rust developer. Prioritize zero-cost abstractions, proper error handling with Result/Option, and unsafe code only when absolutely necessary and properly documented. - file_pattern: **/package.json model: codex-local system_prompt: | You are a JavaScript/TypeScript expert. Generate valid JSON with correct syntax and semantic versioning. # 全局设置 global: # 默认超时毫秒 timeout_ms: 30000 # 日志级别 log_level: info # 是否启用向量检索增强需 ChromaDB enable_rag: true这个 YAML 文件的关键设计点file_pattern使用 glob 语法VS Code 插件如 Continue.dev会读取当前打开文件的路径匹配此模式后决定调用哪个模型。**/*.py表示所有 Python 文件**/package.json表示任意深度的 package.json。system_prompt内联定义避免外部文件引用保证配置原子性。|符号表示多行字符串保留换行符确保 prompt 格式正确。capabilities字段Node.js 调度器会检查此字段决定是否向该模型发送function_call请求。如果模型不支持如 CodeLlama调度器会自动降级为普通 chat。验证 YAML 有效性# 安装 yaml-validator轻量级 CLI npm install -g yaml-validator # 验证语法与结构 yaml-validator config.yaml # 输出应为✓ Valid YAML3.4 Node.js 调度服务实现 Codex 兼容代理的核心逻辑创建server.js这是整个 OpenRig 的心脏。代码已精简至最小可运行版本但包含所有关键逻辑// server.js const express require(express); const axios require(axios); const cors require(cors); const morgan require(morgan); const fs require(fs).promises; const path require(path); const app express(); const PORT 3000; // 中间件 app.use(cors()); app.use(morgan(combined)); app.use(express.json({ limit: 10mb })); app.use(express.urlencoded({ extended: true })); // 加载配置 let config; try { const configContent await fs.readFile(path.join(__dirname, config.yaml), utf8); // 使用 js-yaml需 npm install js-yaml const yaml require(js-yaml); config yaml.load(configContent); } catch (e) { console.error(❌ Failed to load config.yaml:, e.message); process.exit(1); } // 模型路由映射内存缓存避免每次读 YAML const modelMap new Map(); config.models.forEach(model { modelMap.set(model.name, model); }); // Codex 兼容 /chat/completions 端点 app.post(/v1/chat/completions, async (req, res) { try { const { model: requestedModel, messages, stream false, ...rest } req.body; // 1. 查找匹配的模型配置 const modelConfig modelMap.get(requestedModel); if (!modelConfig) { return res.status(400).json({ error: { message: Model ${requestedModel} not found in config } }); } // 2. 构造下游请求体适配 Ollama / vLLM 等 let downstreamBody; if (modelConfig.endpoint.includes(ollama)) { // Ollama 格式 downstreamBody { model: modelConfig.model, messages: messages.map(msg ({ role: msg.role, content: msg.content })), stream: stream, options: { num_predict: rest.max_tokens || modelConfig.max_tokens, temperature: rest.temperature || modelConfig.temperature, top_p: rest.top_p || modelConfig.top_p } }; } else if (modelConfig.endpoint.includes(v1/chat/completions)) { // vLLM / OpenAI 兼容格式 downstreamBody { model: modelConfig.model, messages, stream, max_tokens: rest.max_tokens || modelConfig.max_tokens, temperature: rest.temperature || modelConfig.temperature, top_p: rest.top_p || modelConfig.top_p }; } else { throw new Error(Unsupported endpoint format: ${modelConfig.endpoint}); } // 3. 转发请求 const downstreamRes await axios.post( modelConfig.endpoint, downstreamBody, { headers: { Content-Type: application/json }, timeout: config.global.timeout_ms } ); // 4. 响应转换Ollama - OpenAI 格式 if (modelConfig.endpoint.includes(ollama)) { const ollamaData downstreamRes.data; if (stream) { // 流式响应处理简化版实际需处理 chunk res.setHeader(Content-Type, text/event-stream); res.write(data: ${JSON.stringify({ id: chatcmpl-${Date.now()}, object: chat.completion.chunk, created: Math.floor(Date.now() / 1000), model: requestedModel, choices: [{ delta: { content: ollamaData.message?.content || }, index: 0 }] })}\n\n); } else { // 非流式响应 res.json({ id: chatcmpl-${Date.now()}, object: chat.completion, created: Math.floor(Date.now() / 1000), model: requestedModel, choices: [{ message: { role: assistant, content: ollamaData.message?.content || }, index: 0, finish_reason: stop }], usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 } }); } } else { res.json(downstreamRes.data); } } catch (error) { console.error(❌ Proxy error:, error.response?.status, error.message); res.status(500).json({ error: { message: Proxy failed: ${error.message}, code: error.response?.status || 500 } }); } }); // 健康检查端点 app.get(/health, (req, res) { res.json({ status: ok, timestamp: new Date().toISOString() }); }); app.listen(PORT, () { console.log(✅ OpenRig Codex Proxy running on http://localhost:${PORT}); console.log( Config loaded: ${config.models.length} models, ${config.routing_rules.length} rules); });启动服务# 安装依赖 npm install js-yaml # 添加启动脚本到 package.json # scripts: { # start: node server.js # } npm start此时访问http://localhost:3000/health应返回{status:ok,...}证明调度服务已就绪。这才是真正的 Codex 兼容端点——它接收标准 OpenAI 请求转发给本地模型并返回标准响应。4. 故障诊断实战解析 “cc switch local proxy failed while handling codex endpoint /responses” 类报错所有关于 OpenRig 的搜索热词如cc switch local proxy failed、codex auth token is unavailable、codex is ignoring 1 unrecognized configuration setting本质上都指向同一个问题服务链路中某个环节的契约断裂。下面我将带你用 tmux 日志 curl 三步法像侦探一样定位每一类报错。4.1 报错溯源四象限按现象分类的排查路径报错现象最可能根源验证命令修复方案cc switch local proxy failed while handling codex endpoint /responsesNode.js 服务未运行或端口被占curl -v http://localhost:3000/healthtmux attach -t openrig-main→Ctrl-b1→ 检查 pane 1 是否在运行npm startcodex auth token is unavailableNode.js 服务运行但未正确读取 config.yamlcat ~/openrig/config.yaml | head -n 5检查 YAML 文件路径是否正确权限是否为644是否有语法错误用yaml-validatorcodex is ignoring 1 unrecognized configuration settingconfig.yaml 中存在 Node.js 调度器不识别的字段grep -n unrecognized ~/openrig/logs/*.log查看日志中具体是哪个字段被忽略对照server.js中的解析逻辑删除或修正该字段error installing 24.21.0: node.js v24.21.0 is not yet released试图安装不存在的 Node.js 版本nvm list-remote | grep v24改用nvm install --lts安装最新 LTS 版本当前为 v20.x关键经验永远不要相信错误消息的第一印象。cc switch local proxy failed听起来像网络问题但 90% 情况下是 Node.js 进程根本没起来。我曾花 2 小时排查防火墙最后发现只是 tmux pane 0 的 Ollama 服务因磁盘满而崩溃导致 pane 1 的 Node.js 在启动时axios.post失败进而整个服务拒绝响应。4.2 tmux 日志实时分析三步定位根因当报错发生时立即执行以下三步在 tmux 会话内Step 1确认服务存活状态# 在任意 pane 按 Ctrl-b 后输入 : # 输入以下命令查看所有 pane 进程 list-panes -F #{pane_pid} #{pane_current_command} #{pane_active}输出示例12345 ollama serve 1 12346 node server.js 1 12347 chroma run --path ./chroma-data 1 12348 tail -f ./logs/*.log 0如果某 pane 的#{pane_active}为0说明该进程已退出。记下其 PID如12345执行ps -p 12345 -o pid,ppid,cmd,etime查看进程存活时间etime。若为0说明刚崩溃若为负数说明 PID 已被回收。Step 2检查对应 pane 的实时输出Ctrl-b0切到 pane 0Ollama按Up键调出ollama serve命令回车重启观察输出是否有Error: listen EADDRINUSE: address already in use :::11434—— 端口被占需lsof -i :11434 \| awk {print $2} \| xargs kill -9Step 3验证 Node.js 服务连通性在 pane 1Node.js中执行curl -X POST http://localhost:3000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: codex-local, messages: [{role: user, content: Hello}] }如果返回{error:{message:Model codex-local not found...}}→ config.yaml 加载失败如果返回curl: (7) Failed to connect to localhost port 3000: Connection refused→ Node.js 进程未运行如果返回{error:{message:Proxy failed: connect ECONNREFUSED 127.0.0.1:11434}}→ Ollama 服务未启动或端口不对4.3 YAML 配置校验避免 “unrecognized setting” 类陷阱codex is ignoring 1 unrecognized configuration setting这类报错根源在于 YAML 字段与 Node.js 解析逻辑不匹配。常见原因及修复字段拼写错误suppors_streaming: true少一个t→ 正确应为supports_streaming字段位置错误将supports_streaming写在global下而非models的某个具体模型下 → Node.js 只在models数组内解析该字段值类型错误max_tokens: 2048字符串→ 应为数字2048否则parseInt(rest.max_tokens)会返回NaN自动化校验脚本保存为validate-config.jsconst fs require(fs).promises; const yaml require(js-yaml); async function validateConfig() { const config yaml.load(await fs.readFile(config.yaml, utf8)); // 检查 models 数组 if (!Array.isArray(config.models)) { throw new Error(config.models must be an array); } config.models.forEach((model, i) { if (!model.name) throw new Error(Model at index ${i} missing name); if (!model.endpoint) throw new Error(Model at index ${i} missing endpoint); if (typeof model.supports_streaming ! boolean) { throw new Error(Model ${model.name} supports_streaming must be boolean); } if (typeof model.max_tokens ! number) { throw new Error(Model ${model.name} max_tokens must be number); } }); console.log(✅ config.yaml validation passed); } validateConfig().catch(console.error);运行node validate-config.js即可提前捕获所有配置陷阱。5. 进阶实战将 OpenRig 接入 VS Code实现真正的本地 Codex 体验搭建好底层服务后最后一步是将其接入日常开发环境。这里以 VS Code 为例演示如何让 Continue.dev 插件无缝使用你的 OpenRig。5.1 Continue.dev 配置绕过云端直连本地Continue.dev 是目前最接近原生 Codex 体验的开源插件。配置它使用本地 OpenRig只需三步安装插件在 VS Code 扩展市场搜索Continue.dev安装并重启。创建.continue/config.json在项目根目录或用户主目录创建此文件{ models: [ { title: OpenRig Codex Local, model: codex-local, provider: openai, apiKey: sk-xxx, // 任意非空字符串OpenRig 不校验 apiBase: http://localhost:3000/v1, completionModel: codex-local, chatModel: codex-local } ], defaultModel: OpenRig Codex Local, context: [ { type: file, fileName: .continue/context.txt } ] }关键点apiBase: http://localhost:3000/v1指向你的 Node.js 代理服务model: codex-local必须与config.yaml中models[0].name完全一致apiKey可填任意值OpenRig 不