☰
openrig:本地AI编码环境编排与代理配置实战
2026/10/3 18:07:51 网站建设 项目流程

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 access""cc 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 -v

Windows 用户直接去 node.js 官网下载 LTS 的 msi 安装包,一路下一步就行。装完在 PowerShell 里node -v验证。这里注意,如果你之前用管理员权限装过 Node,可能会有路径冲突,建议先在"添加或删除程序"里把旧的卸干净。

macOS 用户可以用 Homebrew:brew install node@lts,或者同样用 nvm。我个人在所有平台都用 nvm,因为切换版本太方便了,做多项目的时候不用来回卸载重装。

4.2 第二步:装 Claude Code 和 Codex

Claude Code 的安装:

npm install -g @anthropic-ai/claude-code

Codex 的安装命令根据你用的版本不同,常见的是:

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:1234,OpenAI 兼容端点是/v1。启动后可以用 curl 测一下:

curl http://127.0.0.1:1234/v1/models

能返回模型列表就说明服务正常。记下返回里的模型 id,填到 openrig 配置的models.aliases里。

如果你用的是 Ollama,命令是ollama serve,默认端口 11434,OpenAI 兼容端点是/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 的别名机制让你可以随时切换,我的习惯是日常补全用本地小模型,遇到难题手动切到强模型,这样既省成本又保证质量。这个切换策略,比死磕一个模型要实用得多。

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

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

立即咨询