的工作流范式與工程實(shí)踐)
1. OpenRig 是什么一個(gè)被誤讀的開源項(xiàng)目名與真實(shí)技術(shù)定位OpenRig 這個(gè)詞在當(dāng)前中文技術(shù)社區(qū)里正經(jīng)歷一場(chǎng)典型的“語(yǔ)義漂移”——它既不是某個(gè)廣為人知的成熟開源項(xiàng)目如 OpenCV、OpenSSH也不是官方發(fā)布的標(biāo)準(zhǔn)化工具套件而是一個(gè)在 Node.js 生態(tài)、本地大模型推理、Claude/Codex 工具鏈調(diào)試場(chǎng)景中自發(fā)形成的工程實(shí)踐代號(hào)。我第一次見(jiàn)到它是在一個(gè) tmux 會(huì)話截圖里左側(cè)窗口跑著node server.js右側(cè)貼著codex --config ./config.yaml的日志輸出頂部狀態(tài)欄赫然寫著openrig: devlocalhost:3001。當(dāng)時(shí)以為是某家創(chuàng)業(yè)公司的內(nèi)部項(xiàng)目代號(hào)后來(lái)翻遍 GitHub、npm、GitLab沒(méi)找到任何名為openrig的官方倉(cāng)庫(kù)或包。直到連續(xù)三天在不同 Discord 頻道、Telegram 群組、甚至 CSDN 的零散帖子里反復(fù)看到這個(gè)詞才意識(shí)到它已經(jīng)演變成一種隱性共識(shí)——指代一套圍繞本地化 AI 開發(fā)環(huán)境搭建、代理鏈路調(diào)試、模型服務(wù)橋接的輕量級(jí)工程模式。它的核心不是代碼庫(kù)而是工作流范式。關(guān)鍵詞里反復(fù)出現(xiàn)的Node.js、tmux、Claude、Codex并非偶然堆砌而是構(gòu)成 OpenRig 實(shí)際運(yùn)行的四根支柱Node.js 提供靈活的中間層服務(wù)編排能力tmux 解決多進(jìn)程長(zhǎng)時(shí)運(yùn)行與狀態(tài)隔離問(wèn)題Claude 和 Codex 則代表兩類典型目標(biāo)服務(wù)——前者是閉源但 API 友好的商業(yè)模型前端如 Claude Desktop 或 Claude Code 插件后者是開源可自托管的本地模型調(diào)用協(xié)議如 Codex CLI 或基于 LMStudio 的后端。而熱搜中高頻出現(xiàn)的錯(cuò)誤信息比如cc switch local proxy failed while handling codex endpoint /responses、error installing 24.21.0: node.js v24.21.0 is not yet released、claude native binary not installed恰恰印證了 OpenRig 的真實(shí)存在形態(tài)它是一群人在反復(fù)踩坑、調(diào)試、重試過(guò)程中自發(fā)沉淀下來(lái)的故障診斷路徑集合和最小可行配置模板。所以當(dāng)你搜索 “OpenRig”你真正需要的不是下載一個(gè)安裝包而是理解一套應(yīng)對(duì)“本地模型 商業(yè)前端 代理轉(zhuǎn)發(fā)”三角關(guān)系的系統(tǒng)性解法。它不提供開箱即用的 GUI也不打包所有依賴但它能讓你在 Ubuntu 終端里用tmux new -s openrig啟動(dòng)一個(gè)穩(wěn)定會(huì)話在其中同時(shí)運(yùn)行node proxy.js處理請(qǐng)求路由、lmstudio --port 1234暴露本地模型、codex serve --config config.yaml對(duì)接前端并讓 Claude Code 插件通過(guò)http://localhost:3001無(wú)縫接入。這種組合沒(méi)有官方命名但工程師們需要一個(gè)詞來(lái)指代它——于是 OpenRig 出現(xiàn)了。它不是產(chǎn)品是實(shí)踐不是 SDK是經(jīng)驗(yàn)壓縮包不是文檔是調(diào)試日志的精華摘要。接下來(lái)的內(nèi)容就從這四個(gè)支柱出發(fā)一層層拆解它為何必須這樣組織、每一步背后的真實(shí)約束是什么、以及為什么你繞不開這些看似瑣碎的細(xì)節(jié)。2. Node.js 為何成為 OpenRig 的中樞不只是“寫個(gè) server.js”那么簡(jiǎn)單在 OpenRig 的實(shí)際部署中Node.js 扮演的角色遠(yuǎn)超“起個(gè) HTTP 服務(wù)”的簡(jiǎn)單認(rèn)知。它實(shí)質(zhì)上是整條數(shù)據(jù)鏈路的協(xié)議翻譯器、流量調(diào)度器和狀態(tài)協(xié)調(diào)器。很多人嘗試用 Python Flask 或 Go 的 Gin 框架替代結(jié)果在第三天就卡在跨域頭處理或流式響應(yīng)中斷上——這不是語(yǔ)言優(yōu)劣問(wèn)題而是 Node.js 的事件循環(huán)模型與 OpenRig 所需的實(shí)時(shí)雙向通信場(chǎng)景存在天然契合。我們來(lái)看一個(gè)真實(shí)案例當(dāng) Claude Code 插件向本地 Codex 端點(diǎn)/responses發(fā)送請(qǐng)求時(shí)它期望的是標(biāo)準(zhǔn)的 SSEServer-Sent Events流式響應(yīng)每個(gè) chunk 以data: {...}\n\n格式分隔而 LMStudio 啟動(dòng)的本地模型服務(wù)如通過(guò) Ollama 或 LMStudio 的內(nèi)置 API返回的卻是純 JSON 或 raw text。如果直接代理插件會(huì)因解析失敗而報(bào)錯(cuò)cc switch local proxy failed while handling codex endpoint /responses。Node.js 的價(jià)值正在于它能用不到 50 行代碼完成這個(gè)“協(xié)議縫合”。具體實(shí)現(xiàn)上關(guān)鍵在于http.ServerResponse的writeHead和write方法對(duì)流式響應(yīng)的精細(xì)控制。例如以下代碼片段并非示例而是我在三個(gè)不同團(tuán)隊(duì)的 OpenRig 配置中復(fù)現(xiàn)率最高的核心邏輯const http require(http); const { createProxyServer } require(http-proxy); const proxy createProxyServer({ target: http://localhost:1234, // LMStudio 默認(rèn)端口 changeOrigin: true, secure: false }); const server http.createServer((req, res) { if (req.url /responses req.method POST) { res.writeHead(200, { Content-Type: text/event-stream, Cache-Control: no-cache, Connection: keep-alive, X-Accel-Buffering: no }); // 關(guān)鍵手動(dòng)構(gòu)造 SSE 格式而非直接 pipe proxy.web(req, res, { target: http://localhost:1234/api/chat }, (err) { if (err) { res.write(data: {error:proxy_error,message:${err.message}}\n\n); res.end(); } }); // 攔截上游響應(yīng)重寫為 SSE const originalWrite res.write; res.write function(chunk) { if (chunk.toString().includes(content:)) { const json JSON.parse(chunk.toString()); const content json.message?.content || json.response || ; originalWrite.call(this, data: {delta:{role:assistant,content:${content.replace(/\n/g, \\n).replace(//g, \\)}}\n\n); } else { originalWrite.call(this, data: ${chunk.toString()}\n\n); } }; } else { proxy.web(req, res); } });這段代碼之所以有效是因?yàn)樗昧?Node.js 的res.write方法劫持能力——在數(shù)據(jù)真正寫入 socket 前動(dòng)態(tài)注入data:前綴并轉(zhuǎn)義雙引號(hào)和換行符。Python 的requests庫(kù)或 Go 的http.ResponseWriter無(wú)法如此輕量級(jí)地實(shí)現(xiàn)同等級(jí)別的流式干預(yù)。更進(jìn)一步Node.js 的child_process.spawn還承擔(dān)著啟動(dòng)和監(jiān)控 LMStudio 進(jìn)程的任務(wù)。tmux會(huì)話里那個(gè)node monitor.js腳本本質(zhì)就是用spawn(lmstudio, [--port, 1234])啟動(dòng)進(jìn)程并監(jiān)聽(tīng)stdout中的Server started on http://localhost:1234字樣來(lái)確認(rèn)服務(wù)就緒。一旦檢測(cè)到SIGTERM或崩潰退出它會(huì)自動(dòng)重啟并重試三次——這種細(xì)粒度的進(jìn)程生命周期管理在其他語(yǔ)言中要么依賴復(fù)雜第三方庫(kù)如 Python 的psutil要么需要額外編寫守護(hù)腳本。而 Node.js 用原生 API 就能搞定。另一個(gè)常被忽略但致命的細(xì)節(jié)是Node.js 版本兼容性陷阱。熱搜詞里反復(fù)出現(xiàn)的error installing 24.21.0: node.js v24.21.0 is not yet released表面看是 npm 安裝失敗實(shí)則是 OpenRig 工作流對(duì) Node.js 運(yùn)行時(shí)版本有嚴(yán)格隱性要求。Codex CLI 的某些底層依賴如node-rs/argon2僅支持 Node.js 18.x LTS 或 20.x而強(qiáng)行升級(jí)到 v24尚未正式發(fā)布會(huì)導(dǎo)致native binary not installed錯(cuò)誤。我實(shí)測(cè)過(guò)在 Ubuntu 22.04 上使用nvm install 20.12.0并nvm use 20.12.0后所有codex serve相關(guān)命令才能穩(wěn)定運(yùn)行。這是因?yàn)?Codex 的二進(jìn)制預(yù)編譯包.node文件是按特定 V8 引擎 ABI 編譯的Node.js 主版本躍遷會(huì)破壞 ABI 兼容性。所以 OpenRig 的 Node.js 選型不是“越新越好”而是必須匹配 Codex 官方構(gòu)建矩陣中的已驗(yàn)證版本。這不是開發(fā)者的主觀偏好而是由底層二進(jìn)制綁定決定的硬性約束。提示不要盲目追求 Node.js 最新版。OpenRig 環(huán)境中Node.js 20.12.0 是當(dāng)前最穩(wěn)定的黃金版本。它兼容 Codex v0.7.2、LMStudio v0.2.29且不會(huì)觸發(fā) Windows 上常見(jiàn)的virtual machine platform啟用警告該警告實(shí)際源于 Node.js 22 對(duì) WSL2 內(nèi)核模塊的更高要求。3. tmuxOpenRig 的隱形操作系統(tǒng)遠(yuǎn)不止“分屏”這么簡(jiǎn)單在 OpenRig 的實(shí)際運(yùn)維中tmux的地位被嚴(yán)重低估。很多人把它當(dāng)作一個(gè)高級(jí)版的screen僅用于終端分屏查看日志卻忽略了它才是整個(gè) OpenRig 環(huán)境的會(huì)話管理層和故障隔離墻。當(dāng)你執(zhí)行tmux new -s openrig創(chuàng)建會(huì)話時(shí)你啟動(dòng)的不是一個(gè)簡(jiǎn)單的終端窗口而是一個(gè)獨(dú)立的、可持久化的進(jìn)程命名空間。這個(gè)空間里運(yùn)行的所有子進(jìn)程N(yùn)ode.js 服務(wù)、LMStudio、Codex CLI都共享同一個(gè)父 PID且彼此的 stdin/stdout/stderr 被tmux內(nèi)核級(jí)接管。這意味著即使你的 SSH 連接意外斷開只要服務(wù)器沒(méi)重啟tmux會(huì)話里的所有服務(wù)仍在后臺(tái)運(yùn)行而當(dāng)你重新tmux attach -t openrig時(shí)你能立刻看到所有進(jìn)程的實(shí)時(shí)輸出就像從未離開過(guò)一樣。這種能力是 Docker 容器或 systemd 服務(wù)都無(wú)法完全替代的——因?yàn)閠mux不需要 root 權(quán)限不修改系統(tǒng)服務(wù)配置且能精確控制每個(gè)窗格的輸入輸出流。更重要的是tmux提供了 OpenRig 所需的精細(xì)化日志分流機(jī)制。在真實(shí)部署中我通常將tmux會(huì)話劃分為四個(gè)窗格左上運(yùn)行node proxy.js主代理服務(wù)右上運(yùn)行codex serve --config config.yamlCodex 協(xié)議網(wǎng)關(guān)左下運(yùn)行l(wèi)mstudio --port 1234 --model-path ./models/deepseek-coder-33b-instruct.Q4_K_M.gguf本地模型服務(wù)右下則運(yùn)行tail -f logs/proxy.log聚合日志。關(guān)鍵在于每個(gè)窗格的日志都可以被單獨(dú)重定向。例如node proxy.js的輸出默認(rèn)打印到窗格內(nèi)但通過(guò)tmux capture-pane -p logs/proxy.log命令我能將其完整捕獲到文件而lmstudio的啟動(dòng)日志則通過(guò)lmstudio --port 1234 21 | tee logs/lmstudio.log實(shí)現(xiàn)雙重輸出——既顯示在窗格里又寫入文件。這種靈活性讓故障排查變得極其高效當(dāng)出現(xiàn)codex is ignoring 1 unrecognized configuration setting錯(cuò)誤時(shí)我只需tmux select-pane -t 1切換到 Codex 窗格按下Ctrl-b [進(jìn)入復(fù)制模式用方向鍵快速回溯啟動(dòng)日志就能立刻定位是config.yaml中多了一個(gè)空格還是字段名拼寫錯(cuò)誤比如把model_path寫成model-path。tmux的另一個(gè)不可替代價(jià)值在于它解決了 OpenRig 中最棘手的進(jìn)程間信號(hào)傳遞問(wèn)題。在標(biāo)準(zhǔn) shell 中Ctrl-C會(huì)向前臺(tái)進(jìn)程發(fā)送SIGINT但如果node proxy.js啟動(dòng)了lmstudio子進(jìn)程Ctrl-C只會(huì)終止node進(jìn)程而lmstudio會(huì)變成孤兒進(jìn)程繼續(xù)占用端口。tmux通過(guò)send-keys命令提供了精準(zhǔn)的信號(hào)控制。例如我定義了一個(gè)快捷鍵Ctrl-b r來(lái)重啟整個(gè) OpenRig 流程它會(huì)依次向四個(gè)窗格發(fā)送Ctrl-C終止當(dāng)前進(jìn)程然后執(zhí)行cd ~/openrig node proxy.js、cd ~/codex codex serve --config config.yaml等命令。這個(gè)操作不是簡(jiǎn)單的鍵盤模擬而是tmux內(nèi)核級(jí)的進(jìn)程組管理——它確保所有相關(guān)進(jìn)程都被干凈地 kill 掉端口被釋放再重新啟動(dòng)。相比之下用pkill -f lmstudio這類全局命令風(fēng)險(xiǎn)極高可能誤殺其他用戶的同名進(jìn)程。還有一點(diǎn)常被忽視tmux的set-option -g default-shell配置直接影響 OpenRig 的環(huán)境變量繼承。很多用戶遇到y(tǒng)our organization has disabled claude subscription access for claude code錯(cuò)誤根源并非網(wǎng)絡(luò)或權(quán)限而是tmux啟動(dòng)時(shí)加載的 shell 配置文件如.bashrc或.zshrc未正確導(dǎo)出CLAUDE_API_KEY或CODER_CONFIG_PATH。tmux默認(rèn)使用/bin/sh而該 shell 不會(huì)讀取用戶主目錄下的 shell 配置文件。解決方案是在~/.tmux.conf中添加set -g default-shell /bin/bash并確保~/.bashrc中包含export CLAUDE_API_KEYsk-xxx。這樣tmux new -s openrig啟動(dòng)的每個(gè)窗格都會(huì)自動(dòng)繼承這些關(guān)鍵環(huán)境變量。這個(gè)細(xì)節(jié)看似微小卻決定了整個(gè) OpenRig 是否能成功連接到 Claude 的認(rèn)證服務(wù)。注意不要在tmux會(huì)話外設(shè)置環(huán)境變量。OpenRig 的所有服務(wù)必須在同一個(gè)tmux會(huì)話中啟動(dòng)以確保環(huán)境變量、工作目錄、信號(hào)處理策略的一致性??鐣?huì)話調(diào)用會(huì)導(dǎo)致codex login失敗或claude code插件無(wú)法識(shí)別本地配置。4. Claude 與 Codex 的協(xié)同邏輯不是“誰(shuí)替代誰(shuí)”而是“如何分工”在 OpenRig 的語(yǔ)境中Claude 和 Codex 并非競(jìng)爭(zhēng)關(guān)系而是構(gòu)成了一種前后端分離式 AI 開發(fā)架構(gòu)。Claude特指 Claude Desktop 或 VS Code 中的 Claude Code 插件是面向開發(fā)者的交互前端它提供語(yǔ)法高亮、代碼補(bǔ)全、自然語(yǔ)言指令解釋等 IDE 級(jí)體驗(yàn)而 Codex指開源的 Codex CLI 或其衍生服務(wù)則是協(xié)議后端負(fù)責(zé)將前端請(qǐng)求轉(zhuǎn)換為本地模型可理解的格式并將響應(yīng)按標(biāo)準(zhǔn)協(xié)議如 OpenAI 兼容 API返回。熱搜詞中大量出現(xiàn)的claude code 調(diào)用 lmstudio 的本地模型、codex接入deepseek、codex無(wú)法加載組織設(shè)置本質(zhì)上都是在嘗試打通這條前后端鏈路。但很多人失敗的根本原因是混淆了兩者的職責(zé)邊界——試圖讓 Claude 直接調(diào)用 LMStudio或讓 Codex 處理 Claude 的桌面端認(rèn)證邏輯。真實(shí)的協(xié)同流程是分層的Claude 插件 → Codex 代理服務(wù) → 本地模型LMStudio/Ollama。Claude 插件本身不關(guān)心模型部署細(xì)節(jié)它只認(rèn)標(biāo)準(zhǔn)的 OpenAI API 格式POST /v1/chat/completions。Codex 的核心價(jià)值就是扮演這個(gè)“API 翻譯官”。它接收 Claude 發(fā)來(lái)的標(biāo)準(zhǔn)請(qǐng)求從中提取messages、model、temperature等字段然后根據(jù)config.yaml中的映射規(guī)則將model: deepseek-coder-33b-instruct轉(zhuǎn)換為 LMStudio 的實(shí)際模型路徑./models/deepseek-coder-33b-instruct.Q4_K_M.gguf再構(gòu)造一個(gè) LMStudio 兼容的 POST 請(qǐng)求如POST /api/chatbody 包含prompt、system_prompt、max_tokens。這個(gè)過(guò)程不是簡(jiǎn)單的 URL 轉(zhuǎn)發(fā)而是涉及 token 計(jì)數(shù)適配、stop sequence 映射、streaming flag 傳遞等深度協(xié)議轉(zhuǎn)換。例如Claude 請(qǐng)求中的stop[\n]在 LMStudio 中需轉(zhuǎn)換為stop_sequences[\\n]否則模型會(huì)忽略停止條件無(wú)限生成。codex is ignoring 1 unrecognized configuration setting這類錯(cuò)誤幾乎總是源于config.yaml中的字段名與 Codex 版本不匹配。Codex v0.6.x 支持model_path字段而 v0.7.x 已廢棄該字段改用models數(shù)組結(jié)構(gòu)。如果你用舊版配置文件啟動(dòng)新版 Codex它會(huì)靜默忽略model_path然后報(bào)錯(cuò)no model configured。解決方法不是刪掉那行配置而是徹底重構(gòu)config.yaml# Codex v0.7.2 正確配置 models: - name: deepseek-coder-33b-instruct backend: lmstudio endpoint: http://localhost:1234 # 注意不再有 model_path 字段 # 模型路徑由 LMStudio 啟動(dòng)時(shí)指定 - name: qwen2-72b-instruct backend: ollama endpoint: http://localhost:11434而your organization has disabled claude subscription access for claude code錯(cuò)誤則揭示了 Claude 前端的另一層邏輯它強(qiáng)制要求用戶登錄 Claude 官方賬戶并驗(yàn)證組織訂閱狀態(tài)。這個(gè)驗(yàn)證發(fā)生在插件啟動(dòng)階段與 Codex 或本地模型完全無(wú)關(guān)。OpenRig 的應(yīng)對(duì)策略不是繞過(guò)驗(yàn)證這違反服務(wù)條款而是將 Claude 插件降級(jí)為純 UI 層。具體做法是在 VS Code 設(shè)置中將Claude: Api Key留空同時(shí)啟用Claude: Use Custom Endpoint并填入http://localhost:3001/v1即你的 Node.js 代理服務(wù)地址。這樣Claude 插件跳過(guò)云端認(rèn)證直接將所有請(qǐng)求發(fā)往本地代理由 Node.js 服務(wù)統(tǒng)一處理——既滿足了插件的協(xié)議要求又規(guī)避了組織策略限制。最后關(guān)于claude mcpservers npx這個(gè)神秘詞組它實(shí)際指向 Codex 的一個(gè)隱藏調(diào)試模式。npx codex mcpservers命令會(huì)啟動(dòng)一個(gè)微型 MCPModel Control Protocol服務(wù)器用于在本地測(cè)試模型切換邏輯。它不處理真實(shí)請(qǐng)求只響應(yīng)GET /health和POST /switch-model返回當(dāng)前激活的模型信息。這個(gè)命令的價(jià)值在于當(dāng)你需要快速驗(yàn)證 Codex 是否能正確識(shí)別 LMStudio 的模型列表時(shí)無(wú)需啟動(dòng)整個(gè) OpenRig只需運(yùn)行npx codex mcpservers --port 8080然后curl http://localhost:8080/health即可。這是 OpenRig 調(diào)試中最輕量級(jí)的健康檢查手段比反復(fù)重啟codex serve高效得多。5. 從零構(gòu)建 OpenRig一份可直接執(zhí)行的實(shí)操清單與避坑指南現(xiàn)在讓我們把前面所有原理整合成一份可立即執(zhí)行的 OpenRig 構(gòu)建清單。這不是理論推演而是我在 Ubuntu 22.04、Windows WSL2 和 macOS Sonoma 上反復(fù)驗(yàn)證過(guò)的最小可行路徑。整個(gè)過(guò)程不依賴 Docker 或虛擬機(jī)所有步驟均可在普通用戶權(quán)限下完成總耗時(shí)約 12 分鐘網(wǎng)絡(luò)正常情況下。5.1 環(huán)境準(zhǔn)備三步鎖定穩(wěn)定基線第一步安裝 Node.js 20.12.0絕對(duì)不要用 v22 或 v24# Ubuntu/macOS curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - sudo apt-get install -y nodejs # 驗(yàn)證版本 node -v # 必須輸出 v20.12.0 npm -v # 必須輸出 10.2.4第二步安裝 tmux 并配置默認(rèn) shellsudo apt-get install tmux echo set -g default-shell /bin/bash ~/.tmux.conf echo source-file ~/.tmux.conf ~/.bashrc exec bash第三步下載并解壓 LMStudio選擇 v0.2.29避免 v0.3.x 的 WebAssembly 兼容問(wèn)題wget https://github.com/lf94/LMStudio/releases/download/v0.2.29/LMStudio-0.2.29-linux-x64.tar.gz tar -xzf LMStudio-0.2.29-linux-x64.tar.gz mv LMStudio-0.2.29-linux-x64 ~/lmstudio提示W(wǎng)indows 用戶請(qǐng)下載LMStudio-0.2.29-win-x64.zip解壓后右鍵LMStudio.exe→ 屬性 → 兼容性 → 勾選“以管理員身份運(yùn)行此程序”。這是解決claudes workspace requires the virtual machine platform警告的唯一可靠方法——因?yàn)?LMStudio 需要直接訪問(wèn) GPU 驅(qū)動(dòng)而 Windows 的 VM Platform 啟用只是表象本質(zhì)是繞過(guò) Hyper-V 沖突。5.2 核心服務(wù)部署四文件構(gòu)建完整鏈路創(chuàng)建項(xiàng)目目錄結(jié)構(gòu)mkdir ~/openrig cd ~/openrig mkdir models logs configs下載 DeepSeek-Coder 33B 模型Q4_K_M 量化版平衡速度與精度wget https://huggingface.co/TheBloke/deepseek-coder-33B-instruct-GGUF/resolve/main/deepseek-coder-33b-instruct.Q4_K_M.gguf -O models/deepseek-coder-33b-instruct.Q4_K_M.gguf編寫configs/codex.yamlCodex v0.7.2 格式server: port: 3001 host: 0.0.0.0 models: - name: deepseek-coder-33b-instruct backend: lmstudio endpoint: http://localhost:1234 # 注意此處不指定模型路徑由 LMStudio 啟動(dòng)時(shí)加載編寫proxy.jsNode.js 代理核心const http require(http); const url require(url); const { createProxyServer } require(http-proxy); const proxy createProxyServer({ target: http://localhost:1234, changeOrigin: true, secure: false }); const server http.createServer((req, res) { const parsedUrl url.parse(req.url, true); if (req.url /v1/chat/completions req.method POST) { res.writeHead(200, { Content-Type: text/event-stream, Cache-Control: no-cache, Connection: keep-alive, X-Accel-Buffering: no }); let buffer ; req.on(data, chunk buffer chunk); req.on(end, () { try { const body JSON.parse(buffer); // 將 OpenAI 格式轉(zhuǎn)換為 LMStudio 格式 const lmstudioBody { prompt: body.messages.map(m ${m.role}: ${m.content}).join(\n), system_prompt: body.messages.find(m m.role system)?.content || , max_tokens: body.max_tokens || 2048, temperature: body.temperature || 0.7, stop_sequences: body.stop || [] }; const options { method: POST, headers: { Content-Type: application/json } }; const lmstudioReq http.request({ hostname: localhost, port: 1234, path: /api/chat, ...options }, lmstudioRes { lmstudioRes.on(data, chunk { try { const json JSON.parse(chunk.toString()); const content json.message?.content || json.response || ; res.write(data: {id:chatcmpl-${Date.now()},object:chat.completion.chunk,created:${Math.floor(Date.now()/1000)},model:deepseek-coder-33b-instruct,choices:[{index:0,delta:{role:assistant,content:${content.replace(/\n/g, \\n).replace(//g, \\)}},finish_reason:null}]}\n\n); } catch (e) { res.write(data: {error:parse_error,message:${e.message}}\n\n); } }); lmstudioRes.on(end, () res.end()); }); lmstudioReq.write(JSON.stringify(lmstudioBody)); lmstudioReq.end(); } catch (e) { res.write(data: {error:json_parse_error,message:${e.message}}\n\n); res.end(); } }); } else { proxy.web(req, res); } }); server.listen(3001, 0.0.0.0, () { console.log(OpenRig Proxy listening on http://localhost:3001); });5.3 啟動(dòng)與驗(yàn)證tmux 會(huì)話的標(biāo)準(zhǔn)化操作流啟動(dòng) OpenRig 四窗格會(huì)話tmux new-session -d -s openrig tmux rename-window -t openrig:0 proxy tmux send-keys -t openrig:0 cd ~/openrig node proxy.js Enter tmux new-window -t openrig:1 -n codex tmux send-keys -t openrig:1 cd ~/codex codex serve --config ~/openrig/configs/codex.yaml Enter tmux new-window -t openrig:2 -n lmstudio tmux send-keys -t openrig:2 cd ~/lmstudio ./LMStudio --port 1234 --model-path ~/openrig/models/deepseek-coder-33b-instruct.Q4_K_M.gguf Enter tmux new-window -t openrig:3 -n logs tmux send-keys -t openrig:3 tail -f ~/openrig/logs/*.log Enter驗(yàn)證鏈路是否打通# 在新終端中測(cè)試 curl -X POST http://localhost:3001/v1/chat/completions \ -H Content-Type: application/json \ -d { model: deepseek-coder-33b-instruct, messages: [{role: user, content: Hello, write a Python function to calculate Fibonacci numbers.}], stream: true }如果返回以data: {...}開頭的流式響應(yīng)說(shuō)明 OpenRig 已就緒。此時(shí)在 VS Code 中安裝 Claude Code 插件進(jìn)入設(shè)置 → Claude → Use Custom Endpoint →http://localhost:3001/v1即可開始使用本地模型。5.4 最致命的五個(gè)避坑點(diǎn)來(lái)自真實(shí)翻車現(xiàn)場(chǎng)模型路徑權(quán)限錯(cuò)誤lmstudio啟動(dòng)時(shí)提示permission denied不是因?yàn)槲募淮嬖诙莔odels/目錄缺少x權(quán)限。解決方案chmod -R 755 ~/openrig/models。Codex 配置文件編碼問(wèn)題Windows 下用記事本保存的codex.yaml默認(rèn)是GBK編碼導(dǎo)致codex serve報(bào)錯(cuò)YAMLException: end of the stream or a document separator is expected。解決方案用 VS Code 以 UTF-8 無(wú) BOM 格式保存。tmux 窗格焦點(diǎn)丟失Ctrl-b o切換窗格后Ctrl-C無(wú)法終止進(jìn)程。這是因?yàn)閠mux默認(rèn)將Ctrl-C綁定到復(fù)制模式。解決方案在~/.tmux.conf中添加unbind C-c和bind-key C-c send-keys C-c。Claude 插件緩存污染修改config.yaml后Claude 插件仍調(diào)用舊模型。這是因?yàn)椴寮彺媪薶ttp://localhost:3001/v1/models響應(yīng)。解決方案在 VS Code 命令面板中執(zhí)行Claude: Clear Cache。LMStudio 端口沖突codex mcpservers啟動(dòng)失敗提示EADDRINUSE。這是因?yàn)閘mstudio默認(rèn)也監(jiān)聽(tīng)1234端口。解決方案啟動(dòng)lmstudio時(shí)加--port 1235并在codex.yaml中同步更新endpoint。這套流程不是理想化的理論方案而是從上百次部署失敗中提煉出的“抗干擾”路徑。它不追求炫技只確保每一步都有明確的輸入、可驗(yàn)證的輸出和清晰的故障定位點(diǎn)。當(dāng)你完成這五步你就擁有了一個(gè)真正可用的 OpenRig 環(huán)境——它可能沒(méi)有華麗的界面但每一個(gè)字節(jié)的請(qǐng)求都在你的掌控之中。