ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

openrig:本地AI编码环境编排与代理配置实战

openrig:本地AI编码环境编排与代理配置实战 1. 从 openrig 说起一个被名字耽误的本地 AI 编码环境编排工具第一次看到openrig这个名字我下意识以为是某种开源硬件机架项目毕竟 rig 在英文里最常出现在矿机架、电台设备、测试台架这些场景。直到我在几个折腾 Claude Code 和 Codex 的社群里反复看到它被提起才意识到这是一个把本地 AI 编码工具链装配起来的编排层。说白了它解决的是一个非常具体的痛点当你同时想用 Claude Code、Codex CLI 这类终端里的 AI 编码助手又想让它们统一走本地模型或者第三方兼容端点时配置会迅速变成一团乱麻。openrig的核心价值在于装配这个词。它不生产模型也不替代 Claude Code 或 Codex 本身它做的事情是把 Node.js 运行时、YAML 配置文件、模型端点、代理转发这几块拼图用一套声明式的方式固定下来。你可以把它理解成一个接线盒左边接的是你本地的 LM Studio、Ollama 或者任何兼容 OpenAI 接口的服务右边接的是 Claude Code、Codex 这些客户端中间那堆环境变量、base_url、模型名映射、超时重试的琐事全部交给 openrig 的配置去管。我之所以愿意花时间写这个项目是因为过去半年里我帮至少七八个朋友处理过Claude Code 连不上本地模型Codex 报 organization has disabled subscription accesscc switch local proxy failed while handling codex endpoint /responses这类问题。这些报错看起来五花八门根子上其实是同一类问题客户端、代理、模型端点三者的协议和配置没有对齐。openrig 试图用一份 YAML 把这件事讲清楚这个思路我认为是对的值得展开聊聊。这篇文章适合三类人一是刚装完 Node.js、准备上手 Claude Code 或 Codex 的新手想知道这些工具之间到底怎么串起来二是已经在用但被各种代理报错折磨的中级用户想搞清楚/responses端点、模型名映射这些细节三是想自己搭一套可复现本地 AI 编码环境的人希望有一份能直接抄的配置模板。下面我会从设计思路、核心细节、实操流程到排错一层层拆开讲。2. 整体设计思路为什么是 YAML 加 Node.js 这套组合2.1 声明式配置为什么比一堆环境变量靠谱在 openrig 出现之前绝大多数人配置 Claude Code 或 Codex 的方式是这样的打开终端export ANTHROPIC_BASE_URL...export OPENAI_API_KEY...再设几个*_MODEL变量然后祈祷客户端读的是对的那个。这套做法在只用一个工具、一个模型的时候没问题但一旦你要在 Claude Code 和 Codex 之间切换或者今天用本地 LM Studio、明天换成第三方兼容端点环境变量就会互相污染。我自己就踩过这个坑明明改的是 Codex 的配置结果 Claude Code 也跟着变了行为排查了半天才发现是 shell 里残留的 export。YAML 的好处是它把配置从运行时状态里剥离出来了。一份openrig.yaml描述的是我想要的环境长什么样而不是我现在 export 了什么。这种声明式的思路在基础设施领域早就被验证过Terraform、Docker Compose、Kubernetes 都是这个路子。openrig 把它搬到本地 AI 编码工具链上逻辑是一致的你描述期望状态工具负责把实际状态对齐过去。具体到字段设计一份典型的 openrig 配置大概会包含这几块运行时声明Node.js 版本、包管理器、客户端声明Claude Code、Codex 各自的启动参数、端点声明本地或远程的 base_url、API key 引用、模型名映射、以及代理层声明是否需要本地转发、监听端口、路径重写规则。这种分层的好处是当你遇到 cc switch local proxy failed while handling codex endpoint /responses 这种报错时你能立刻定位到是代理层的路径重写出了问题而不是在一堆环境变量里大海捞针。2.2 Node.js 在这套体系里扮演什么角色很多人问 node.js 是干什么的在这个场景下答案很直接Claude Code 和 Codex CLI 本身都是 Node.js 写的命令行工具它们的安装、运行、依赖管理都依赖 Node 运行时。所以 openrig 把 Node.js 作为第一等公民来声明是有道理的。你装 Claude Code 的时候执行npm install -g anthropic-ai/claude-code装 Codex 的时候执行对应的 npm 包安装命令背后都是 Node 生态。这里有个新手特别容易踩的坑Node.js 版本。热搜里那条 error installing 24.21.0: node.js v24.21.0 is not yet released or is not available 就是典型症状——你照着某个教程抄了个版本号结果那个版本根本不存在或者还没发布。我的建议是永远用 LTS 版本去 node.js 官网下载页选那个标着 LTS 的或者用 nvm 管理。openrig 的配置里如果能声明node: lts/*这种语义化版本就能避免这类问题。另一个细节是全局安装路径和权限。在 Ubuntu 上直接npm install -g经常遇到 EACCES 权限错误很多人第一反应是加 sudo这其实是个坏习惯会把全局包装到 root 名下后续升级各种麻烦。正确做法是配置 npm 的 prefix 到用户目录或者干脆用 nvm让每个 Node 版本有自己的全局包空间。openrig 如果要做环境隔离这一层是绕不开的。2.3 代理层那个最容易出事的中间件Claude Code 和 Codex 各自说各自的方言。Claude Code 走的是 Anthropic 的 Messages API 格式Codex 走的是 OpenAI 的接口格式其中/responses端点是新版 Codex 用的。当你想让它们都指向同一个本地模型服务时就需要一个代理层做协议转换和路径重写。热搜里那条 cc switch local proxy failed while handling codex endpoint /responses 说的就是这个代理层在处理 Codex 的/responses请求时挂了。代理层出问题的原因通常有三类一是路径重写规则不对客户端请求/responses代理转发成了/v1/responses或者干脆没转发对二是请求体格式不兼容Codex 发的 JSON 结构本地模型服务不认识三是流式响应处理有问题SSE 流被代理截断或者缓冲了。openrig 如果要在配置里声明代理规则就必须把这三点都考虑进去否则用户还是会遇到同样的报错。我个人的经验是代理层能不用就不用能用官方支持的直连方式就别加中间件。但如果确实需要比如本地模型只暴露 OpenAI 兼容接口而你想用 Claude Code那代理的配置就要写得非常明确尤其是路径映射和超时设置。下面我会给出一份具体的配置模板。3. 核心细节解析配置字段、模型映射与端点对齐3.1 一份可复现的 openrig.yaml 骨架先给一份我实际用过的配置骨架字段名我按常见约定来写你可以根据自己用的 openrig 版本微调。这份配置的目标是让 Claude Code 和 Codex 都能通过一个本地代理访问 LM Studio 里跑的本地模型。# openrig.yaml runtime: node: lts/* packageManager: npm clients: claude-code: enabled: true env: ANTHROPIC_BASE_URL: http://127.0.0.1:8787 ANTHROPIC_API_KEY: local-key ANTHROPIC_MODEL: local-large codex: enabled: true env: OPENAI_BASE_URL: http://127.0.0.1:8787/v1 OPENAI_API_KEY: local-key OPENAI_MODEL: local-large proxy: listen: 127.0.0.1:8787 upstream: http://127.0.0.1:1234/v1 routes: - from: /v1/responses to: /v1/chat/completions - from: /v1/messages to: /v1/chat/completions timeoutMs: 120000 stream: true models: aliases: local-large: qwen2.5-coder-32b-instruct local-small: qwen2.5-coder-7b-instruct这份配置里几个关键点值得展开。runtime.node用lts/*而不是写死版本号就是为了避开前面说的版本不存在问题。clients下面每个客户端有自己的 env 块互不干扰这是声明式配置相对环境变量的核心优势。proxy.routes是路径重写的核心把 Codex 的/v1/responses和 Claude Code 的/v1/messages都映射到本地模型服务认识的/v1/chat/completions。models.aliases做的是模型名映射客户端里写local-large实际转发时替换成 LM Studio 里真实的模型标识。3.2 模型名映射为什么是刚需很多人不理解为什么需要模型别名这一层直接用真实模型名不行吗行但会很痛苦。原因有几个第一不同客户端的模型名校验规则不一样Claude Code 可能只认它认识的几个名字你写个qwen2.5-coder-32b-instruct它可能直接拒绝第二本地模型的真实标识经常变今天叫qwen2.5-coder-32b-instruct明天你换了个量化版本可能叫qwen2.5-coder-32b-instruct-q4_k_m如果客户端配置里写死了每次换模型都要改客户端第三别名让你可以在不改客户端的前提下切换后端模型这对做对比测试特别有用。映射的实现方式通常是在代理层做请求体的字符串替换或者更稳妥的做法是解析 JSON、改model字段、再序列化。字符串替换快但容易误伤比如请求体里别的地方也出现了模型名。解析 JSON 更安全但多一层开销。openrig 如果要做这件事我建议用 JSON 解析的方式稳。3.3 端点对齐/responses和/messages的区别这是最容易让人懵的地方。Claude Code 用的是 Anthropic 的 Messages API端点是/v1/messages请求体里有个messages数组角色是user和assistant系统提示单独放在system字段。Codex 新版用的是 OpenAI 的 Responses API端点是/v1/responses请求体结构又不一样。而本地模型服务LM Studio、Ollama 的 OpenAI 兼容层通常只实现了/v1/chat/completions也就是经典的 Chat Completions 格式。所以代理层要做的是双向翻译把/v1/messages的请求体转成/v1/chat/completions能懂的格式把/v1/responses的请求体也转过去然后把响应再转回来。这个转换不是简单的字段改名涉及系统提示的位置、工具调用tool calls的格式、流式响应的 chunk 结构等。热搜里 cc switch local proxy failed while handling codex endpoint /responses 大概率就是转换逻辑在/responses这条路径上没覆盖全。我的建议是如果你的代理工具对/responses支持不完整可以先在 Codex 配置里把它降级到用 Chat Completions 端点。Codex 通常支持通过配置指定用哪个 API 格式具体字段名查一下你那个版本的文档。这样能绕开很多转换 bug。4. 实操过程从零搭一套能跑的本地 AI 编码环境4.1 第一步把 Node.js 装对Ubuntu 上我推荐用 nvm别用 apt 里的 nodejs 包版本太旧。安装 nvm 的命令是curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash装完重开终端然后nvm install --lts nvm use --lts node -v npm -vWindows 用户直接去 node.js 官网下载 LTS 的 msi 安装包一路下一步就行。装完在 PowerShell 里node -v验证。这里注意如果你之前用管理员权限装过 Node可能会有路径冲突建议先在添加或删除程序里把旧的卸干净。macOS 用户可以用 Homebrewbrew install nodelts或者同样用 nvm。我个人在所有平台都用 nvm因为切换版本太方便了做多项目的时候不用来回卸载重装。4.2 第二步装 Claude Code 和 CodexClaude Code 的安装npm install -g anthropic-ai/claude-codeCodex 的安装命令根据你用的版本不同常见的是npm install -g openai/codex装完分别跑claude --version和codex --version确认。如果报 command not found八成是 npm 全局 bin 目录没在 PATH 里。用npm config get prefix看看全局路径然后把它下面的 bin 目录加到 PATH。这里插一句关于 your organization has disabled claude subscription access for claude code 这个报错。这个错误通常出现在你用组织账号登录、而组织管理员关闭了 Claude Code 访问权限的情况下。解决办法要么是找管理员开权限要么是改用 API key 方式而不是订阅登录。在 openrig 的配置里我倾向于直接用 API key 模式可控性更强。4.3 第三步起本地模型服务以 LM Studio 为例装好后在界面里下载一个编码能力强的模型比如 Qwen2.5-Coder 系列。然后在 LM Studio 的 Local Server 标签页里启动服务默认监听http://127.0.0.1:1234OpenAI 兼容端点是/v1。启动后可以用 curl 测一下curl http://127.0.0.1:1234/v1/models能返回模型列表就说明服务正常。记下返回里的模型 id填到 openrig 配置的models.aliases里。如果你用的是 Ollama命令是ollama serve默认端口 11434OpenAI 兼容端点是/v1。Ollama 的好处是命令行管理方便ollama pull qwen2.5-coder:32b就能拉模型。4.4 第四步配置代理并启动代理这块如果你用的 openrig 自带代理功能直接在 YAML 里配好proxy段然后openrig up就行。如果 openrig 只是个配置管理器代理需要单独起那可以用一个轻量的 Node 脚本或者现成的转换工具。我这里给一个最小化的 Node 代理示例用 Express 写展示路径重写和模型名替换的核心逻辑const express require(express); const fetch require(node-fetch); const app express(); app.use(express.json({ limit: 10mb })); const UPSTREAM http://127.0.0.1:1234/v1; const ALIASES { local-large: qwen2.5-coder-32b-instruct, local-small: qwen2.5-coder-7b-instruct }; app.post([/v1/messages, /v1/responses], async (req, res) { const body { ...req.body }; if (body.model ALIASES[body.model]) { body.model ALIASES[body.model]; } // 把 Anthropic 风格的 system 字段合并进 messages if (body.system !body.messages.find(m m.role system)) { body.messages.unshift({ role: system, content: body.system }); delete body.system; } const upstream await fetch(${UPSTREAM}/chat/completions, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify(body) }); res.status(upstream.status); upstream.body.pipe(res); }); app.listen(8787, 127.0.0.1, () { console.log(proxy on 127.0.0.1:8787); });这段代码是示意性的真实场景下你还要处理流式响应的格式转换、错误码映射、工具调用字段的翻译。但它展示了核心思路接收客户端的请求改模型名合并系统提示转发到上游把响应流回传。4.5 第五步验证端到端代理起来后先单独测代理curl -X POST http://127.0.0.1:8787/v1/messages \ -H Content-Type: application/json \ -d {model:local-large,messages:[{role:user,content:hi}]}能返回内容就说明代理通了。然后启动 Claude Code随便问一句看它能不能正常回复。再启动 Codex 测一遍。两个都通了这套环境就算搭起来了。5. 常见问题与排查技巧实录5.1 报错速查表报错信息大概率原因排查方向cc switch local proxy failed while handling codex endpoint /responses代理未处理/responses路径或请求体转换失败检查代理路由是否包含/responses看代理日志里请求体结构your organization has disabled claude subscription access for claude code组织账号权限被关闭改用 API key 模式或联系管理员error installing 24.21.0: node.js v24.21.0 is not yet released版本号不存在改用 LTS 版本用 nvm 管理codex 无法加载组织设置登录态或配置文件损坏清除~/.codex下的缓存重新登录模型返回 404 model not found模型名映射缺失或写错用/v1/models确认真实模型 id检查 aliases流式响应卡住不输出代理缓冲了 SSE 流关闭代理的响应缓冲确保 pipe 直通5.2 几个我踩过的坑第一个坑是代理的超时设置。本地大模型推理慢尤其是 32B 级别的模型一个复杂请求跑一两分钟很正常。如果代理默认超时是 30 秒你会看到请求莫名其妙中断还以为是模型崩了。把超时设到 120 秒甚至更长timeoutMs: 120000就是这个意思。第二个坑是流式响应的缓冲。很多 HTTP 框架默认会缓冲响应体再一次性发出这对普通请求没问题但对 SSE 流式响应是灾难——客户端会一直等直到整个响应生成完才收到体验极差。解决方法是确保代理层用 pipe 直通或者显式关闭缓冲。第三个坑是模型名大小写。有些本地服务对模型名大小写敏感Qwen2.5-Coder和qwen2.5-coder会被当成两个模型。映射的时候一定要用/v1/models返回的原始字符串别手打。第四个坑是并发。本地模型服务通常并发能力有限Claude Code 和 Codex 同时跑可能互相抢资源导致两个都变慢甚至超时。如果机器配置一般建议一次只开一个客户端或者给代理加个简单的请求队列。5.3 关于 VS Code 集成很多人想在 VS Code 里直接用 Claude Code。官方有 Claude Code for VS Code 扩展装完后它会在集成终端里调用 claude 命令。这时候 openrig 配的环境变量能不能被继承就很重要了。我的做法是在 VS Code 的 settings.json 里显式配置终端环境变量或者干脆在项目根目录放一个.env文件让扩展去读。Ubuntu 上如果遇到扩展找不到 claude 命令检查一下 VS Code 启动时的 PATH 是不是包含了 nvm 的路径GUI 启动的应用经常读不到 shell 的 PATH这是个经典坑。6. 一些延伸想法和实际体会openrig 这类工具的价值我觉得不在于它省了多少配置步骤而在于它把本地 AI 编码环境这件事从一堆散落的命令和变量变成了一份可版本控制的配置文件。你可以把openrig.yaml提交到 git换台机器 clone 下来就能复现同样的环境这对团队协作和知识沉淀的意义很大。我在实际使用中最大的体会是代理层越薄越好。能直连就直连能少一层转换就少一层。每多一层就多一个出问题的地方而且报错信息往往被层层包裹排查成本指数上升。如果非要加代理就把日志打全请求体、响应体、路径重写前后都记下来出问题的时候能一眼看出是哪一层的事。另外本地模型和云端模型的能力差距还是客观存在的。本地跑 7B 模型做代码补全够用但复杂重构还是得靠更大的模型。openrig 的别名机制让你可以随时切换我的习惯是日常补全用本地小模型遇到难题手动切到强模型这样既省成本又保证质量。这个切换策略比死磕一个模型要实用得多。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进