一管理Claude Code和Codex的AI編程環(huán)境配置)
1. openrig 到底是個(gè)什么東西第一次看到 openrig 這個(gè)名字很多人會(huì)以為是某個(gè)硬件外設(shè)或者開源機(jī)械臂項(xiàng)目。實(shí)際上結(jié)合它周邊的關(guān)鍵詞——Claude Code、Codex、YAML、Node.js——可以很清楚地判斷出openrig 是一個(gè)圍繞 AI 編程助手生態(tài)構(gòu)建的本地配置與代理編排工具。它的核心價(jià)值在于把 Claude Code、Codex 這類命令行 AI 編程工具的運(yùn)行環(huán)境、模型接入、代理轉(zhuǎn)發(fā)、配置管理統(tǒng)一到一個(gè)可維護(hù)的框架里。說白了你平時(shí)用 Claude Code 寫代碼可能遇到幾個(gè)煩人的問題公司網(wǎng)絡(luò)環(huán)境需要走本地代理、想切換到 DeepSeek 或 GLM 這類第三方模型、多個(gè)項(xiàng)目需要不同的配置、每次換機(jī)器都要重新折騰一遍環(huán)境。openrig 就是來解決這些問題的。它用 YAML 做配置描述用 Node.js 做運(yùn)行時(shí)把 Claude Code 和 Codex 的啟動(dòng)參數(shù)、環(huán)境變量、代理規(guī)則、模型映射全部收攏到一份配置文件里。這篇文章適合誰(shuí)看如果你是剛接觸 Claude Code 或 Codex 的新手想搞清楚怎么在本地把環(huán)境跑通如果你已經(jīng)在用這些工具但每次配置都靠手動(dòng)改環(huán)境變量、記不住參數(shù)如果你需要在多個(gè)模型供應(yīng)商之間切換比如今天用 Claude 官方、明天接 DeepSeek、后天試 GLM——那 openrig 這套思路值得你花時(shí)間研究。我自己的使用場(chǎng)景是這樣的手頭有三臺(tái)開發(fā)機(jī)一臺(tái) macOS 日常開發(fā)一臺(tái) Ubuntu 跑 CI 和長(zhǎng)任務(wù)還有一臺(tái) Windows 偶爾做前端調(diào)試。以前每臺(tái)機(jī)器上 Claude Code 的配置都是散的環(huán)境變量寫在 shell 配置文件里代理設(shè)置靠手動(dòng) export換模型要改好幾個(gè)地方。后來用 openrig 的思路把配置統(tǒng)一成 YAML 之后同步配置就是復(fù)制一個(gè)文件的事。注意openrig 本身不是一個(gè)官方項(xiàng)目它更像是一種配置管理模式的代稱。你在 GitHub 上搜到的同名倉(cāng)庫(kù)可能和本文描述的不完全一致但核心思路是通用的——用結(jié)構(gòu)化配置管理 AI 編程工具的運(yùn)行時(shí)環(huán)境。2. 核心組件拆解YAML、Node.js 與代理層2.1 為什么選 YAML 做配置載體YAML 在這套體系里扮演的是“唯一真相源”的角色。你可能會(huì)問為什么不用 JSON 或者 TOMLJSON 的問題是寫注釋不方便而配置文件恰恰最需要注釋——你得記清楚每個(gè)參數(shù)是干什么的。TOML 雖然可讀性好但嵌套結(jié)構(gòu)表達(dá)起來比較啰嗦。YAML 在可讀性和表達(dá)力之間取得了不錯(cuò)的平衡支持錨點(diǎn)和引用這對(duì)多環(huán)境配置復(fù)用非常關(guān)鍵。一個(gè)典型的 openrig 配置結(jié)構(gòu)大概長(zhǎng)這樣# openrig.yaml version: 1.0 defaults: provider: anthropic proxy: enabled: true host: 127.0.0.1 port: 7890 providers: anthropic: base_url: https://api.anthropic.com api_key_env: ANTHROPIC_API_KEY models: - claude-sonnet-4-20250514 - claude-opus-4-20250514 deepseek: base_url: https://api.deepseek.com/v1 api_key_env: DEEPSEEK_API_KEY models: - deepseek-chat - deepseek-coder glm: base_url: https://open.bigmodel.cn/api/paas/v4 api_key_env: GLM_API_KEY models: - glm-4-plus profiles: work: provider: anthropic proxy: enabled: true personal: provider: deepseek proxy: enabled: false這份配置里providers定義了各個(gè)模型供應(yīng)商的接入信息profiles定義了不同使用場(chǎng)景的組合。你切換工作環(huán)境只需要改defaults.provider或者指定 profile不用去動(dòng)環(huán)境變量。YAML 的錨點(diǎn)功能在這里特別有用。比如你有多個(gè) provider 共享相同的代理設(shè)置可以這樣寫_proxy_default: proxy_default enabled: true host: 127.0.0.1 port: 7890 providers: anthropic: proxy: *proxy_default openai: proxy: *proxy_default這樣改一處就能影響所有引用它的地方避免了復(fù)制粘貼帶來的不一致。2.2 Node.js 在其中的角色Node.js 是 openrig 的運(yùn)行時(shí)基礎(chǔ)。為什么不用 Python 或者 Go因?yàn)?Claude Code 和 Codex 本身就是 Node.js 生態(tài)的工具用 npm 全局安裝的。openrig 作為它們的配置管理層用 Node.js 寫可以無縫調(diào)用這些工具的 API也能直接復(fù)用 npm 的包管理機(jī)制。Node.js 的版本選擇有個(gè)坑要注意。Claude Code 對(duì) Node.js 版本有要求一般建議用 LTS 版本。我實(shí)測(cè)下來Node.js 20.x 和 22.x 都能正常工作但 18.x 在某些新特性上會(huì)報(bào)錯(cuò)。如果你看到類似error installing 24.21.0: node.js v24.21.0 is not yet released這種報(bào)錯(cuò)說明你指定的版本號(hào)根本不存在去 Node.js 官網(wǎng)下載頁(yè)面確認(rèn)一下當(dāng)前 LTS 版本號(hào)。安裝 Node.js 最省事的方式是用版本管理器。macOS 和 Linux 上可以用 nvmWindows 上可以用 nvm-windows 或者直接下安裝包。用 nvm 的好處是可以在不同項(xiàng)目間切換 Node.js 版本# 安裝 nvm 后 nvm install 22 nvm use 22 nvm alias default 22 # 驗(yàn)證 node -v npm -vopenrig 的啟動(dòng)腳本通常是一個(gè) Node.js 腳本它讀取 YAML 配置解析出當(dāng)前 profile 對(duì)應(yīng)的環(huán)境變量然后以正確的參數(shù)啟動(dòng) Claude Code 或 Codex。這個(gè)腳本的核心邏輯大概是const fs require(fs); const yaml require(js-yaml); const { spawn } require(child_process); function loadConfig(path) { const raw fs.readFileSync(path, utf8); return yaml.load(raw); } function buildEnv(config, profileName) { const profile config.profiles[profileName]; const provider config.providers[profile.provider]; const env { ...process.env }; env.OPENRIG_PROVIDER profile.provider; env.OPENRIG_BASE_URL provider.base_url; env.OPENRIG_API_KEY process.env[provider.api_key_env]; if (profile.proxy profile.proxy.enabled) { env.HTTP_PROXY http://${profile.proxy.host}:${profile.proxy.port}; env.HTTPS_PROXY env.HTTP_PROXY; } return env; } const config loadConfig(./openrig.yaml); const env buildEnv(config, process.argv[2] || default); const child spawn(claude, process.argv.slice(3), { env, stdio: inherit });這段代碼的邏輯很直白讀配置、拼環(huán)境變量、啟動(dòng)子進(jìn)程。但就是這種直白的設(shè)計(jì)解決了很多手動(dòng)配置時(shí)的痛點(diǎn)。2.3 代理層的設(shè)計(jì)考量代理層是 openrig 里最容易被忽視但最關(guān)鍵的部分。Claude Code 和 Codex 都需要訪問外部 API而在某些網(wǎng)絡(luò)環(huán)境下直接連接可能不穩(wěn)定或者根本連不上。這時(shí)候就需要一個(gè)本地代理來轉(zhuǎn)發(fā)請(qǐng)求。代理層的設(shè)計(jì)有幾個(gè)要點(diǎn)第一代理只對(duì) AI 工具的流量生效不影響系統(tǒng)全局。你肯定不希望開個(gè)代理把整個(gè)系統(tǒng)的網(wǎng)絡(luò)都繞一遍。openrig 的做法是通過環(huán)境變量HTTP_PROXY和HTTPS_PROXY只注入到子進(jìn)程父進(jìn)程和其他程序不受影響。第二代理要支持按 provider 區(qū)分。有些 provider 需要走代理有些不需要。比如你接 DeepSeek 的國(guó)內(nèi)節(jié)點(diǎn)可能直連就很快走代理反而慢。配置里每個(gè) provider 可以單獨(dú)設(shè)置代理開關(guān)。第三代理失敗要有降級(jí)策略。我遇到過代理進(jìn)程掛了但 Claude Code 還在跑的情況請(qǐng)求全部超時(shí)。后來在 openrig 的啟動(dòng)腳本里加了一個(gè)健康檢查啟動(dòng)前先探測(cè)代理端口是否可達(dá)不可達(dá)就自動(dòng)禁用代理并給出警告。const net require(net); function checkProxy(host, port, timeout 2000) { return new Promise((resolve) { const socket new net.Socket(); socket.setTimeout(timeout); socket.on(connect, () { socket.destroy(); resolve(true); }); socket.on(timeout, () { socket.destroy(); resolve(false); }); socket.on(error, () { resolve(false); }); socket.connect(port, host); }); }這個(gè)健康檢查邏輯很簡(jiǎn)單但能避免很多“為什么請(qǐng)求一直卡住”的困惑。3. 從零搭建 openrig 工作流的完整實(shí)操3.1 環(huán)境準(zhǔn)備與依賴安裝開始之前確認(rèn)你手頭有這些東西一臺(tái)能正常上網(wǎng)的開發(fā)機(jī)、Node.js 環(huán)境、至少一個(gè) AI 模型供應(yīng)商的 API Key。如果你還沒有 API Key先去對(duì)應(yīng)平臺(tái)注冊(cè)申請(qǐng)這里不展開。第一步安裝 Node.js。去 Node.js 官網(wǎng)下載 LTS 版本或者用包管理器# macOS with Homebrew brew install node22 # Ubuntu/Debian curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - sudo apt-get install -y nodejs # Windows # 直接去官網(wǎng)下載 .msi 安裝包雙擊安裝安裝完成后驗(yàn)證node -v # 應(yīng)該輸出 v22.x.x npm -v # 應(yīng)該輸出 10.x.x第二步安裝 Claude Code 和 Codex。這兩個(gè)工具都是 npm 全局包npm install -g anthropic-ai/claude-code npm install -g openai/codex如果你在安裝 Claude Code 時(shí)遇到y(tǒng)our organization has disabled claude subscription access for claude code這類提示說明你的賬號(hào)類型不支持直接使用需要檢查訂閱狀態(tài)或者改用 API Key 方式接入。第三步創(chuàng)建工作目錄和配置文件mkdir -p ~/openrig cd ~/openrig npm init -y npm install js-yaml然后把前面提到的openrig.yaml配置文件放進(jìn)去根據(jù)你自己的 provider 信息修改。3.2 配置文件編寫與參數(shù)詳解配置文件是 openrig 的核心值得花時(shí)間仔細(xì)寫。我把自己用的配置拆解一下每個(gè)參數(shù)都解釋清楚。version: 1.0 # 全局默認(rèn)值所有 profile 繼承這里 defaults: provider: anthropic log_level: info timeout: 120000 # 代理設(shè)置可以被 profile 覆蓋 proxy: enabled: false host: 127.0.0.1 port: 7890 # 不走代理的地址列表 no_proxy: - localhost - 127.0.0.1 - *.local # 模型供應(yīng)商定義 providers: anthropic: base_url: https://api.anthropic.com api_key_env: ANTHROPIC_API_KEY # 請(qǐng)求頭額外字段 headers: anthropic-version: 2023-06-01 models: - id: claude-sonnet-4-20250514 alias: sonnet - id: claude-opus-4-20250514 alias: opus deepseek: base_url: https://api.deepseek.com/v1 api_key_env: DEEPSEEK_API_KEY models: - id: deepseek-chat alias: ds-chat - id: deepseek-coder alias: ds-coder glm: base_url: https://open.bigmodel.cn/api/paas/v4 api_key_env: GLM_API_KEY models: - id: glm-4-plus alias: glm4 # 使用場(chǎng)景配置 profiles: # 日常開發(fā)用 Claude 官方 dev: provider: anthropic model: sonnet proxy: enabled: true # 寫代碼專用用 DeepSeek Coder code: provider: deepseek model: ds-coder proxy: enabled: false # 省錢模式用 GLM budget: provider: glm model: glm4 proxy: enabled: false幾個(gè)關(guān)鍵參數(shù)說明api_key_env指定的是環(huán)境變量名不是 API Key 本身。這樣做的好處是配置文件可以安全地提交到 Git不會(huì)泄露密鑰。你只需要在 shell 里 export 對(duì)應(yīng)的環(huán)境變量就行。models里的alias是給模型起短名方便在命令行里快速指定。比如openrig dev --model opus比openrig dev --model claude-opus-4-20250514好記多了。no_proxy列表里的地址不會(huì)走代理。這個(gè)在本地開發(fā)時(shí)特別有用比如你本地跑了一個(gè)模型服務(wù)肯定不希望請(qǐng)求繞一圈代理再回來。3.3 啟動(dòng)腳本與命令行封裝配置文件寫好了接下來需要一個(gè)啟動(dòng)腳本來讀取配置并啟動(dòng) Claude Code 或 Codex。我寫了一個(gè)比較完整的版本放在~/openrig/bin/openrig.js#!/usr/bin/env node const fs require(fs); const path require(path); const yaml require(js-yaml); const { spawn } require(child_process); const net require(net); const CONFIG_PATH path.join(__dirname, .., openrig.yaml); function loadConfig() { if (!fs.existsSync(CONFIG_PATH)) { console.error(配置文件不存在: ${CONFIG_PATH}); process.exit(1); } return yaml.load(fs.readFileSync(CONFIG_PATH, utf8)); } function checkPort(host, port, timeout 1500) { return new Promise((resolve) { const socket new net.Socket(); socket.setTimeout(timeout); socket.on(connect, () { socket.destroy(); resolve(true); }); socket.on(timeout, () { socket.destroy(); resolve(false); }); socket.on(error, () resolve(false)); socket.connect(port, host); }); } async function buildEnv(config, profileName) { const profile config.profiles[profileName]; if (!profile) { console.error(Profile ${profileName} 不存在); console.error(可用: ${Object.keys(config.profiles).join(, )}); process.exit(1); } const provider config.providers[profile.provider]; const env { ...process.env }; // 注入 provider 信息 env.OPENRIG_PROVIDER profile.provider; env.OPENRIG_BASE_URL provider.base_url; env.OPENRIG_MODEL profile.model || provider.models[0].id; // 注入 API Key const apiKey process.env[provider.api_key_env]; if (!apiKey) { console.warn(警告: 環(huán)境變量 ${provider.api_key_env} 未設(shè)置); } else { env.OPENRIG_API_KEY apiKey; } // 代理配置 const proxyConf { ...config.proxy, ...(profile.proxy || {}) }; if (proxyConf.enabled) { const alive await checkPort(proxyConf.host, proxyConf.port); if (alive) { const proxyUrl http://${proxyConf.host}:${proxyConf.port}; env.HTTP_PROXY proxyUrl; env.HTTPS_PROXY proxyUrl; env.NO_PROXY (proxyConf.no_proxy || []).join(,); console.log(代理已啟用: ${proxyUrl}); } else { console.warn(代理 ${proxyConf.host}:${proxyConf.port} 不可達(dá)已跳過); } } return env; } async function main() { const args process.argv.slice(2); const profileName args[0] || dev; const restArgs args.slice(1); const config loadConfig(); const env await buildEnv(config, profileName); // 決定啟動(dòng)哪個(gè)工具 const tool env.OPENRIG_PROVIDER openai ? codex : claude; console.log(啟動(dòng) ${tool} [profile${profileName}, provider${env.OPENRIG_PROVIDER}]); const child spawn(tool, restArgs, { env, stdio: inherit, shell: process.platform win32 }); child.on(exit, (code) process.exit(code)); } main().catch((err) { console.error(err.message); process.exit(1); });給腳本加執(zhí)行權(quán)限并創(chuàng)建軟鏈接chmod x ~/openrig/bin/openrig.js sudo ln -s ~/openrig/bin/openrig.js /usr/local/bin/openrig現(xiàn)在你可以這樣用了# 用 dev profile 啟動(dòng) Claude Code openrig dev # 用 code profile 啟動(dòng)并傳遞額外參數(shù) openrig code --resume # 查看當(dāng)前配置 openrig dev --help3.4 多環(huán)境同步與版本管理配置寫好后怎么在多臺(tái)機(jī)器之間同步我的做法是把~/openrig目錄做成一個(gè) Git 倉(cāng)庫(kù)但 API Key 不放在配置文件里而是通過環(huán)境變量注入。每臺(tái)機(jī)器上單獨(dú)設(shè)置環(huán)境變量# 加到 ~/.bashrc 或 ~/.zshrc export ANTHROPIC_API_KEYsk-ant-xxxx export DEEPSEEK_API_KEYsk-xxxx export GLM_API_KEYxxxx這樣 Git 倉(cāng)庫(kù)里只有配置結(jié)構(gòu)沒有敏感信息。換機(jī)器的時(shí)候 clone 下來設(shè)置好環(huán)境變量就能用。如果你不想把配置提交到遠(yuǎn)程倉(cāng)庫(kù)也可以用 rsync 或者 Syncthing 在本地網(wǎng)絡(luò)同步。我試過用 Syncthing 同步~/openrig目錄效果不錯(cuò)改一臺(tái)機(jī)器上的配置其他機(jī)器幾秒鐘后就更新了。提示環(huán)境變量里的 API Key 在某些 shell 下可能被其他程序讀取到。如果你對(duì)安全性要求高可以用pass或者系統(tǒng)鑰匙串來管理密鑰然后在啟動(dòng)腳本里動(dòng)態(tài)讀取。4. 常見問題排查與避坑指南4.1 Claude Code 與 Codex 的典型報(bào)錯(cuò)處理在實(shí)際使用中我踩過的坑主要集中在幾個(gè)方面。下面整理成速查表方便對(duì)照排查。報(bào)錯(cuò)信息可能原因解決方法your organization has disabled claude subscription access賬號(hào)訂閱類型不支持改用 API Key 方式或檢查訂閱狀態(tài)cc switch local proxy failed while handling codex endpoint /responses代理轉(zhuǎn)發(fā)規(guī)則不匹配檢查代理配置確認(rèn)/responses路徑被正確轉(zhuǎn)發(fā)the gpt-5.6-sol model is not supported模型名稱錯(cuò)誤或未授權(quán)確認(rèn)模型 ID 拼寫檢查 API Key 權(quán)限error installing 24.21.0: node.js v24.21.0 is not yet releasedNode.js 版本號(hào)不存在去官網(wǎng)確認(rèn)當(dāng)前 LTS 版本號(hào)codex無法加載組織設(shè)置配置文件路徑或權(quán)限問題檢查~/.codex/config.yaml是否存在且可讀請(qǐng)求一直超時(shí)無響應(yīng)代理不可達(dá)或網(wǎng)絡(luò)問題用curl測(cè)試代理端口檢查NO_PROXY設(shè)置關(guān)于cc switch local proxy failed這個(gè)報(bào)錯(cuò)我專門研究過。它的本質(zhì)是代理在處理 Codex 的/responses端點(diǎn)時(shí)轉(zhuǎn)發(fā)規(guī)則沒有覆蓋到這個(gè)路徑。Codex 的 API 路徑和 Claude 不太一樣Claude 用的是/v1/messagesCodex 用的是/responses。如果你的代理規(guī)則只寫了/v1/*那 Codex 的請(qǐng)求就會(huì)漏掉。解決方法是在代理配置里顯式加上/responses路徑的轉(zhuǎn)發(fā)規(guī)則。4.2 模型接入的兼容性問題接入第三方模型時(shí)最大的問題是 API 格式兼容性。Claude Code 和 Codex 各自期望的請(qǐng)求格式不同而第三方模型供應(yīng)商的 API 格式又各有差異。openrig 的代理層需要做格式轉(zhuǎn)換。以 DeepSeek 為例它的 API 格式和 OpenAI 兼容但和 Claude 的格式有差異。如果你直接用 Claude Code 去調(diào) DeepSeek 的接口會(huì)報(bào)格式錯(cuò)誤。解決方法是在代理層做轉(zhuǎn)換// 簡(jiǎn)化的格式轉(zhuǎn)換邏輯 function convertClaudeToOpenAI(claudeRequest) { return { model: claudeRequest.model, messages: claudeRequest.messages.map(msg ({ role: msg.role assistant ? assistant : user, content: typeof msg.content string ? msg.content : msg.content.map(c c.text).join() })), max_tokens: claudeRequest.max_tokens, temperature: claudeRequest.temperature }; }這個(gè)轉(zhuǎn)換邏輯看起來簡(jiǎn)單但實(shí)際要處理的邊界情況很多。比如 Claude 的system字段在 OpenAI 格式里要放到 messages 數(shù)組的第一條stop_sequences要改成stop工具調(diào)用的格式也不一樣。我建議直接用現(xiàn)成的轉(zhuǎn)換庫(kù)比如anthropic-ai/sdk配合openai包做適配不要自己從頭寫。另一個(gè)坑是流式響應(yīng)的處理。Claude 和 OpenAI 的流式格式不同Claude 用event: content_block_deltaOpenAI 用data: {choices:[{delta:...}]}。代理層需要把兩種格式互相轉(zhuǎn)換否則 Claude Code 會(huì)解析不了響應(yīng)。4.3 性能調(diào)優(yōu)與穩(wěn)定性建議跑了一段時(shí)間之后我總結(jié)了幾條調(diào)優(yōu)經(jīng)驗(yàn)第一給代理層加緩存。對(duì)于重復(fù)的請(qǐng)求比如相同的代碼補(bǔ)全請(qǐng)求可以在代理層做短期緩存。我用了一個(gè)簡(jiǎn)單的內(nèi)存緩存TTL 設(shè) 60 秒命中率大概有 15% 左右響應(yīng)速度明顯提升。第二設(shè)置合理的超時(shí)時(shí)間。Claude Code 默認(rèn)的超時(shí)可能比較長(zhǎng)遇到網(wǎng)絡(luò)問題時(shí)體驗(yàn)很差。在 openrig 配置里把timeout設(shè)成 120 秒比較合適太短了長(zhǎng)任務(wù)會(huì)中斷太長(zhǎng)了卡住等得難受。第三日志分級(jí)。開發(fā)階段把log_level設(shè)成debug能看到完整的請(qǐng)求和響應(yīng)。生產(chǎn)使用時(shí)改成warn避免日志文件膨脹。我見過有人忘了改日志級(jí)別跑了一周日志文件幾十個(gè) G。第四定期檢查 API Key 余額。第三方模型供應(yīng)商的余額不足時(shí)報(bào)錯(cuò)信息往往不直觀可能表現(xiàn)為請(qǐng)求超時(shí)或者返回空響應(yīng)。在 openrig 里加一個(gè)余額檢查的定時(shí)任務(wù)余額低于閾值時(shí)發(fā)通知。// 簡(jiǎn)單的余額檢查 async function checkBalance(provider) { const resp await fetch(${provider.base_url}/user/balance, { headers: { Authorization: Bearer ${process.env[provider.api_key_env]} } }); const data await resp.json(); if (data.balance 10) { console.warn(${provider.name} 余額不足: ${data.balance}); } }4.4 跨平臺(tái)使用的注意事項(xiàng)Windows、macOS、Linux 三個(gè)平臺(tái)我都跑過 openrig各有各的坑。Windows 上最大的問題是路徑分隔符和 shell 差異。Node.js 的spawn在 Windows 上默認(rèn)不通過 shell 執(zhí)行導(dǎo)致一些命令找不到。解決方法是在spawn參數(shù)里加shell: true但這樣又可能引入命令注入風(fēng)險(xiǎn)。我的做法是只在 Windows 平臺(tái)加shell: true并且對(duì)傳入的參數(shù)做轉(zhuǎn)義。macOS 上相對(duì)省心但要注意 Apple Silicon 和 Intel 的架構(gòu)差異。有些 npm 包在 M 系列芯片上需要重新編譯如果遇到invalid ELF header之類的報(bào)錯(cuò)刪掉node_modules重新npm install通常能解決。Ubuntu 上的坑主要在權(quán)限和 systemd 集成。如果你想把 openrig 做成開機(jī)自啟的服務(wù)需要寫一個(gè) systemd unit 文件[Unit] DescriptionOpenRig Proxy Service Afternetwork.target [Service] Typesimple Useryouruser WorkingDirectory/home/youruser/openrig ExecStart/usr/bin/node /home/youruser/openrig/bin/proxy.js Restarton-failure EnvironmentNODE_ENVproduction [Install] WantedBymulti-user.target放到/etc/systemd/system/openrig.service然后systemctl enable --now openrig就能開機(jī)自啟了。5. 進(jìn)階玩法把 openrig 用出花來5.1 多模型路由與自動(dòng)降級(jí)openrig 的配置結(jié)構(gòu)天然支持多模型路由。你可以在 profile 里定義一個(gè)模型優(yōu)先級(jí)列表當(dāng)主模型不可用時(shí)自動(dòng)切換到備用模型profiles: resilient: provider: anthropic model: sonnet fallback: - provider: deepseek model: ds-chat - provider: glm model: glm4啟動(dòng)腳本里實(shí)現(xiàn)降級(jí)邏輯先試主模型請(qǐng)求失敗超時(shí)或返回錯(cuò)誤碼就切到下一個(gè)。這個(gè)邏輯用 Node.js 的try/catch加循環(huán)就能實(shí)現(xiàn)但要注意區(qū)分“可重試錯(cuò)誤”和“不可重試錯(cuò)誤”。比如 401 認(rèn)證失敗重試多少次都沒用直接報(bào)錯(cuò)而 429 限流或者 503 服務(wù)不可用就值得重試。我實(shí)測(cè)下來這套降級(jí)機(jī)制在主力模型偶爾抽風(fēng)的時(shí)候特別管用。有一次 Claude 的 API 返回 503openrig 自動(dòng)切到 DeepSeek整個(gè)開發(fā)流程沒有中斷我甚至沒注意到切換發(fā)生了。5.2 與 VS Code 的集成Claude Code 有 VS Code 擴(kuò)展openrig 可以和它配合使用。在 VS Code 的settings.json里配置{ claude-code.environment: { OPENRIG_PROFILE: dev, OPENRIG_CONFIG: /Users/yourname/openrig/openrig.yaml } }這樣在 VS Code 里啟動(dòng) Claude Code 時(shí)它會(huì)讀取 openrig 的配置。不過要注意VS Code 擴(kuò)展啟動(dòng)的進(jìn)程可能不會(huì)繼承你 shell 里的環(huán)境變量所以 API Key 需要在 VS Code 的設(shè)置里單獨(dú)配置或者通過terminal.integrated.env注入。另一個(gè)集成點(diǎn)是用 VS Code 的任務(wù)系統(tǒng)跑 openrig 命令。在.vscode/tasks.json里定義一個(gè)任務(wù){(diào) version: 2.0.0, tasks: [ { label: openrig: dev, type: shell, command: openrig dev, problemMatcher: [] } ] }按CtrlShiftP然后選Tasks: Run Task就能快速啟動(dòng)。5.3 配置模板化與團(tuán)隊(duì)共享如果你在團(tuán)隊(duì)里推廣 openrig可以做一個(gè)配置模板倉(cāng)庫(kù)。把通用的 provider 定義、代理設(shè)置、profile 結(jié)構(gòu)放在模板里團(tuán)隊(duì)成員 clone 之后只需要填自己的 API Key 和個(gè)性化配置。模板倉(cāng)庫(kù)的結(jié)構(gòu)大概是這樣openrig-template/ ├── openrig.yaml # 主配置模板 ├── profiles/ │ ├── dev.yaml # 開發(fā)環(huán)境 │ ├── staging.yaml # 預(yù)發(fā)環(huán)境 │ └── prod.yaml # 生產(chǎn)環(huán)境 ├── bin/ │ └── openrig.js # 啟動(dòng)腳本 ├── package.json └── README.md # 使用說明主配置里用 YAML 的!include指令需要自定義 YAML 類型或者啟動(dòng)腳本里做文件合并把 profiles 目錄下的配置合并進(jìn)來。這樣每個(gè)人只需要維護(hù)自己的 profile 文件公共部分由模板統(tǒng)一管理。團(tuán)隊(duì)共享時(shí)還要注意 API Key 的管理。絕對(duì)不要把 Key 寫進(jìn)配置文件提交到倉(cāng)庫(kù)。可以用.env文件加.gitignore的方式或者用團(tuán)隊(duì)統(tǒng)一的密鑰管理服務(wù)。我見過有人不小心把 Key 提交到公開倉(cāng)庫(kù)幾分鐘內(nèi)就被掃到并盜用了損失不小。5.4 監(jiān)控與日志分析跑了一段時(shí)間后你可能會(huì)想知道哪個(gè)模型用得最多平均響應(yīng)時(shí)間是多少哪些請(qǐng)求經(jīng)常失敗這些數(shù)據(jù)對(duì)優(yōu)化配置很有幫助。在 openrig 的代理層加一個(gè)簡(jiǎn)單的日志記錄把每次請(qǐng)求的元數(shù)據(jù)寫到 JSON Lines 文件function logRequest(entry) { const line JSON.stringify({ timestamp: new Date().toISOString(), provider: entry.provider, model: entry.model, duration: entry.duration, status: entry.status, tokens: entry.tokens }); fs.appendFileSync(openrig.log, line \n); }然后用jq或者寫個(gè)小腳本做分析# 統(tǒng)計(jì)各模型使用次數(shù) cat openrig.log | jq -r .model | sort | uniq -c | sort -rn # 計(jì)算平均響應(yīng)時(shí)間 cat openrig.log | jq -s map(.duration) | add / length這些數(shù)據(jù)幫我發(fā)現(xiàn)了一個(gè)問題我原以為 DeepSeek Coder 在代碼任務(wù)上更快但實(shí)際數(shù)據(jù)顯示 Claude Sonnet 的平均響應(yīng)時(shí)間反而更短。后來調(diào)整了默認(rèn)模型開發(fā)效率提升了不少。6. 我踩過的那些坑說幾個(gè)印象深刻的翻車經(jīng)歷希望能幫你省點(diǎn)時(shí)間。第一個(gè)坑是 YAML 的縮進(jìn)。YAML 對(duì)縮進(jìn)極其敏感用 Tab 還是空格、縮進(jìn)幾個(gè)空格都有講究。我有次從網(wǎng)頁(yè)上復(fù)制了一段配置粘貼進(jìn)去之后一直報(bào)解析錯(cuò)誤查了半天才發(fā)現(xiàn)是混合用了 Tab 和空格。后來在編輯器里設(shè)置了tab_size: 2并且開啟render_whitespace這類問題就少多了。第二個(gè)坑是環(huán)境變量的繼承。openrig 啟動(dòng)子進(jìn)程時(shí)如果直接傳env對(duì)象子進(jìn)程的環(huán)境變量就是完全替換而不是追加。我一開始沒注意導(dǎo)致 Claude Code 找不到PATH連基本命令都執(zhí)行不了。正確的做法是{ ...process.env, ...customEnv }先繼承再覆蓋。第三個(gè)坑是代理的NO_PROXY設(shè)置。我本地跑了一個(gè)模型服務(wù)在localhost:8080但請(qǐng)求一直走代理繞了一圈。后來發(fā)現(xiàn)NO_PROXY里寫的是localhost但實(shí)際請(qǐng)求用的是127.0.0.1兩者在代理規(guī)則里不等價(jià)。把兩個(gè)都加上就好了。第四個(gè)坑是 Node.js 版本升級(jí)導(dǎo)致的兼容性問題。有次我把 Node.js 從 20 升到 22結(jié)果js-yaml包報(bào)了個(gè)奇怪的錯(cuò)誤。查了才知道是包版本太老不支持新的 Node.js API。升級(jí)js-yaml到最新版就解決了。所以升級(jí) Node.js 大版本時(shí)記得把依賴包也更新一遍。第五個(gè)坑是 API Key 的權(quán)限范圍。有些平臺(tái)的 API Key 可以設(shè)置權(quán)限范圍比如只讀、只寫、或者限定模型。我申請(qǐng)了一個(gè) Key 用來測(cè)試結(jié)果一直報(bào) 403后來發(fā)現(xiàn)是申請(qǐng)時(shí)沒勾選對(duì)應(yīng)的模型權(quán)限。這個(gè)坑不常見但遇到了很難排查因?yàn)閳?bào)錯(cuò)信息不會(huì)告訴你具體缺哪個(gè)權(quán)限。這些經(jīng)驗(yàn)歸結(jié)起來就是一句話配置管理這件事細(xì)節(jié)決定成敗。openrig 的思路是把所有細(xì)節(jié)顯式化、結(jié)構(gòu)化讓你能一眼看到全貌而不是散落在各個(gè) shell 配置文件和環(huán)境變量里。剛開始搭建的時(shí)候多花點(diǎn)時(shí)間后面用起來就省心了。