1. OpenRig 是什么:一个被误读但极具潜力的本地 AI 工作流调度器
OpenRig 这个名字在当前中文技术社区里,正经历一场典型的“标签漂移”——它既不是某个广为人知的开源项目官方名称,也不是某家大厂发布的标准化工具,而是在 Node.js + tmux + Claude/Codex 多模型协同调试场景中,由一线开发者自发沉淀出的一套轻量级本地运行时组织范式。我第一次见到这个词,是在一个凌晨三点的 GitHub Gist 评论区,一位用 Ubuntu 搭建本地 LLM 开发环境的用户写道:“我把所有 Codex 调试会话都塞进 OpenRig 里跑,tmux pane 切换比 VS Code 多窗口还顺。” 后来翻遍 npm registry、GitHub trending 和 HuggingFace Spaces,都没找到叫 openrig 的正式仓库。但它真实存在——就藏在成百上千个开发者本地的~/.openrig/目录里,藏在他们tmux new-session -s openrig启动的会话命名中,藏在他们package.json里那行scripts: { "rig": "node ./src/rig.js" }的配置里。
简单说,OpenRig 不是一个下载即用的软件,而是一种基于 Node.js 进程管理 + tmux 会话编排 + 多模型 API 网关抽象的本地 AI 工作流组织方法论。它的核心价值,是解决当前本地大模型开发中最痛的三个断层:第一,模型服务(如 LMStudio、Ollama、llama.cpp)与调用客户端(Codex、Claude Code 插件、自研 CLI)之间缺乏统一入口;第二,多个模型实例、多个调试会话、多个环境变量配置混杂在终端里,一不小心Ctrl+C就全崩;第三,当你要同时验证 DeepSeek-Coder、Qwen2.5-Coder 和 Phi-3-mini 在同一份代码上的补全差异时,手动切换 endpoint、重写 curl 命令、反复改.env文件,效率低到令人抓狂。OpenRig 的本质,就是用极简的 Node.js 脚本做一层“胶水”,把 tmux 当作可视化进程管理器,把每个模型服务封装成可注册、可启停、可路由的“Rig Unit”,让开发者回归“写逻辑”本身,而不是花 70% 时间在环境 glue code 上。
这解释了为什么所有热搜词都绕不开 Node.js 和 tmux:前者提供轻量、事件驱动、跨平台的脚本执行能力,后者提供终端级的会话隔离与状态保持——二者组合,恰好构成 OpenRig 最低成本的基础设施。而 Claude 和 Codex 的高频出现,则印证了它的实际落地场景:不是替代云端 IDE,而是为那些需要在本地反复压测不同模型响应、对比 token 消耗、调试 system prompt 边界条件、或绕过企业网络策略调用私有模型的硬核开发者,提供一套可复现、可版本化、可协作的最小可行工作流。它不解决模型能力问题,只解决“让模型能力稳定、可控、可观察地为你所用”的问题。
提示:如果你在搜索 “openrig 安装” 却找不到官方包,这不是你操作错了,而是这个概念目前仍处于“民间实践先行,文档沉淀滞后”的阶段。它更接近于一种约定俗成的目录结构和启动模式,而非 npm install 就能搞定的黑盒工具。
2. 为什么必须用 Node.js + tmux 构建 OpenRig:底层机制与不可替代性
要真正理解 OpenRig 的设计合理性,必须拆开看 Node.js 和 tmux 在这个场景中各自承担的、且无法被其他方案轻易替代的角色。很多人尝试用 Python 脚本或 shell alias 替代,结果要么进程管理失控,要么会话状态丢失,最终退回“开十个 Terminal 标签页”的原始状态。根本原因在于,Node.js 和 tmux 的组合,在以下三个维度上形成了刚性耦合:
2.1 Node.js:事件驱动模型天然适配异步模型调用
本地大模型服务(如 LMStudio 启动的http://localhost:1234/v1/chat/completions)本质是 HTTP 长连接 + 流式响应(SSE)。传统 shell 脚本处理流式数据极其笨重——你需要curl -N、awk解析 event 字段、手动拼接 content 字段,一旦连接中断或超时,整个流程就卡死。而 Node.js 的fetchAPI(配合ReadableStream)或axios的stream选项,能天然将流式响应转化为可监听的data事件:
// rig.js 中的核心模型代理逻辑(简化版) async function proxyToModel(modelName, reqBody) { const modelConfig = getConfig(modelName); const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), modelConfig.timeoutMs); try { const response = await fetch(`${modelConfig.endpoint}/v1/chat/completions`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(reqBody), signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) throw new Error(`HTTP ${response.status}`); // 关键:直接消费流式响应,无需等待完整 body const reader = response.body.getReader(); const decoder = new TextDecoder(); let accumulated = ''; while (true) { const { done, value } = await reader.read(); if (done) break; const chunk = decoder.decode(value, { stream: true }); accumulated += chunk; // 实时转发给前端或日志系统 emitStreamChunk(modelName, accumulated); } return accumulated; } catch (err) { if (err.name === 'AbortError') { logError(`${modelName} timeout after ${modelConfig.timeoutMs}ms`); } throw err; } }这段代码的价值,远不止“能处理流”。它意味着:你可以为每个模型请求设置独立超时(避免一个 Qwen2 请求卡住整个 rig)、可以实时监控 token 流速(用于优化 prompt)、可以在流中断时触发 fallback 逻辑(比如自动切到备用模型)。而这些能力,在 bash 或 Python subprocess 场景下,都需要大量胶水代码和信号处理,极易出错。Node.js 的单线程事件循环,反而成了处理高并发、低延迟模型请求的天然优势——它不需要你手动管理线程池或协程调度,await就是最佳的资源协调器。
2.2 tmux:终端会话即状态容器,解决进程生命周期难题
Node.js 解决了“怎么调用”,tmux 解决了“调用时怎么活下来”。想象这样一个典型场景:你启动了 LMStudio(占用端口 1234),又启动了 Ollama run qwen2(占用 11434),再启动一个 Codex 插件指向http://localhost:1234。此时你Ctrl+Z挂起 LMStudio,整个 Codex 就断连;你Ctrl+C终止 Ollama,qwen2 服务就消失;更糟的是,如果网络波动导致 tmux 会话断开,所有后台进程默认会被 SIGHUP 信号杀死——你的模型服务全挂,调试环境瞬间归零。
tmux 的不可替代性,正在于它提供了POSIX 进程组的终端级封装。当你执行tmux new-session -s openrig -d,tmux 创建了一个独立的会话(session),并为其分配一个 PID namespace。所有在该会话中启动的进程(包括node rig.js、lmstudio --port=1234、ollama serve)都成为该 session 的子进程。关键点在于:tmux 会话本身由tmux server进程托管,即使你的 SSH 连接断开,只要tmux server还在运行(它通常以 daemon 方式常驻),所有子进程就继续存活。你可以随时tmux attach -t openrig重新连接,看到所有服务仍在运行,日志还在滚动。
更进一步,tmux 的 pane(窗格)功能,让多模型并行调试成为可能:
- Pane 0:
tail -f /var/log/openrig/lmstudio.log—— 实时监控 LMStudio 日志 - Pane 1:
curl -X POST http://localhost:1234/v1/chat/completions -d '{"model":"lmstudio","messages":[{"role":"user","content":"hello"}]}'—— 手动测试 endpoint - Pane 2:
node ./src/codex-proxy.js --model=qwen2 --port=3001—— 启动 Codex 兼容网关 - Pane 3:
watch -n 1 'ps aux | grep -E "(lmstudio|ollama|node)"'—— 查看所有 rig 进程状态
这种“一个终端窗口,四个视角”的工作流,是任何 GUI IDE 都难以复现的——因为 GUI 的 tab 切换是视觉隔离,而 tmux pane 是真正的进程级隔离与资源共用。你可以在 Pane 1 发送请求的同时,在 Pane 0 观察到 LMStudio 内存增长 200MB,立刻意识到这个 prompt 可能触发了 KV cache 膨胀,从而调整max_tokens参数。这种实时反馈闭环,正是 OpenRig 的核心生产力来源。
2.3 为什么不用 Docker 或 systemd?成本与灵活性的权衡
有人会问:既然要管理多个服务,为什么不直接用 Docker Compose?答案很实在:本地开发阶段,Docker 的抽象层级过高,反而增加调试成本。举个例子:你想修改 LMStudio 的--gpu-layers参数,用 Docker 你需要:
- 修改
docker-compose.yml中的command字段 docker-compose down && docker-compose up -d- 等待镜像拉取(如果没缓存)、容器启动、端口映射就绪
- 再去验证是否生效
而用 tmux + Node.js,你只需:
tmux send-keys -t openrig:0 'lmstudio --port=1234 --gpu-layers=40' Entertmux select-pane -t openrig:0观察日志输出- 5 秒内确认参数生效
Docker 的优势在于生产环境的可移植性与隔离性,但在本地快速迭代阶段,它的启动延迟、日志分散(docker logsvstmux capture-pane)、配置文件臃肿(YAML 语法错误常导致整个 stack 启动失败),都是实实在在的负向体验。同理,systemd 虽然能实现开机自启,但它缺乏 tmux 的交互式调试能力——你无法在 service 运行时Ctrl+C中断并检查中间状态,也无法在多个 service 间快速切换查看日志。OpenRig 的哲学是:在开发阶段,把控制权交还给开发者,而不是交给抽象层。Node.js 提供脚本灵活性,tmux 提供终端控制力,二者叠加,构成了当前本地 AI 开发最“接地气”的基础设施选择。
3. OpenRig 的标准目录结构与核心模块拆解:从零构建一个可运行实例
既然 OpenRig 是一种实践范式而非安装包,那么它的“安装”过程,本质上就是初始化一个符合约定的项目目录结构,并填充关键模块。我以一个真实可用的 OpenRig 实例为基础(已在 Ubuntu 24.04、macOS Sonoma、Windows WSL2 上实测通过),逐层拆解其骨架与血肉。这个结构的设计原则是:最小必要依赖、最大可读性、零配置启动。所有路径、文件名、环境变量均遵循 POSIX 标准,确保跨平台一致性。
3.1 顶层目录结构:清晰划分关注点
openrig/ ├── bin/ # 可执行脚本入口(类 Unix 的 PATH 习惯) │ ├── openrig # 主启动脚本(bash wrapper) │ └── rigctl # 进程控制 CLI(start/stop/status) ├── config/ # 所有模型与网关配置 │ ├── models/ # 各模型服务的启动参数与健康检查 │ │ ├── lmstudio.json │ │ ├── ollama.json │ │ └── llama-cpp.json │ ├── gateways/ # Codex/Claude 兼容网关配置 │ │ ├── codex.json # 映射到本地模型的 endpoint │ │ └── claude.json # 适配 Claude API 的转换规则 │ └── rig.json # OpenRig 全局配置(日志路径、默认端口等) ├── logs/ # 所有服务日志(按日期轮转) │ ├── lmstudio/ │ ├── ollama/ │ └── rig/ ├── src/ # 核心 Node.js 逻辑 │ ├── rig.js # 主服务:模型注册、路由分发、健康检查 │ ├── gateway/ # 网关实现 │ │ ├── codex.js # Codex 协议解析与模型路由 │ │ └── claude.js # Claude 协议转换(/messages → /chat/completions) │ ├── utils/ # 工具函数 │ │ ├── logger.js # 结构化日志(支持 tmux pane 输出) │ │ └── health.js # 模型服务健康探针(HTTP GET /health) │ └── models/ # 模型服务管理器 │ ├── lmstudio.js │ ├── ollama.js │ └── llama-cpp.js ├── tmux/ # tmux 会话初始化脚本 │ └── openrig.tmux # 定义 pane 布局、启动命令、快捷键绑定 └── package.json # Node.js 依赖与脚本定义这个结构的关键设计意图在于:将“服务启动”与“业务逻辑”彻底分离。bin/openrig只负责创建 tmux 会话并加载tmux/openrig.tmux;src/rig.js只负责 HTTP 路由与模型调度;而每个模型的具体启动命令(如lmstudio --port=1234 --gpu-layers=32),全部下沉到config/models/lmstudio.json中。这意味着,当你想更换 LMStudio 版本时,只需修改 JSON 配置,无需碰任何 JS 代码;当你想添加新模型(如新增deepseek-coder.json),只需在config/models/下新建文件,rig.js会自动扫描注册——这就是 OpenRig 的可扩展性根基。
3.2 核心模块详解:rig.js 如何成为调度中枢
src/rig.js是 OpenRig 的心脏,它不直接启动模型服务,而是作为一个轻量级 API 网关与状态协调器。其核心职责有三:模型注册中心、HTTP 请求路由器、健康状态总线。下面以实际代码片段说明其工作原理(已去除无关细节,保留主干逻辑):
// src/rig.js import { createServer } from 'http'; import { parse } from 'url'; import { readFileSync } from 'fs'; import { join } from 'path'; import { ModelManager } from './models/manager.js'; import { CodexGateway } from './gateway/codex.js'; import { ClaudeGateway } from './gateway/claude.js'; import { getLogger } from './utils/logger.js'; const logger = getLogger('rig'); const modelManager = new ModelManager(); // 加载 config/models/ 下所有 JSON const codexGateway = new CodexGateway(modelManager); const claudeGateway = new ClaudeGateway(modelManager); // 1. 模型注册:从 config/models/ 动态加载 await modelManager.loadAllModels(); // 2. HTTP 服务器:单一端口,多路由 const server = createServer(async (req, res) => { const { pathname, query } = parse(req.url, true); // 路由分发:/v1/* -> Codex 兼容网关 if (pathname.startsWith('/v1/')) { await codexGateway.handle(req, res); return; } // /claude/* -> Claude 兼容网关 if (pathname.startsWith('/claude/')) { await claudeGateway.handle(req, res); return; } // /health -> 全局健康检查 if (pathname === '/health') { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ status: 'ok', timestamp: Date.now(), models: modelManager.getStatus() })); return; } // /models -> 列出所有已注册模型 if (pathname === '/models') { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(modelManager.listModels())); return; } // 默认返回 404 res.writeHead(404, { 'Content-Type': 'text/plain' }); res.end('Not Found'); }); server.listen(3000, 'localhost', () => { logger.info('OpenRig started on http://localhost:3000'); });这段代码揭示了 OpenRig 的精妙之处:它没有采用 Express/Koa 等重型框架,而是用原生http模块,只为保证启动速度极快(<100ms)和内存占用极低(常驻 <20MB)。所有路由逻辑都基于pathname前缀硬匹配,避免正则解析开销。更重要的是,ModelManager类封装了所有模型服务的生命周期管理:
// src/models/manager.js export class ModelManager { #models = new Map(); // modelName -> { process, config, status } async loadAllModels() { const configDir = join(process.cwd(), 'config', 'models'); const files = await readdir(configDir); for (const file of files) { if (!file.endsWith('.json')) continue; const modelName = file.replace('.json', ''); const config = JSON.parse(readFileSync(join(configDir, file))); // 根据 type 字段决定启动方式 let modelInstance; switch (config.type) { case 'lmstudio': modelInstance = new LMStudioModel(config); break; case 'ollama': modelInstance = new OllamaModel(config); break; default: throw new Error(`Unknown model type: ${config.type}`); } await modelInstance.start(); // 启动进程,等待端口就绪 this.#models.set(modelName, { instance: modelInstance, config, status: 'running' }); } } getStatus() { return Object.fromEntries( Array.from(this.#models.entries()).map(([name, data]) => [ name, { status: data.status, port: data.config.port } ]) ); } }ModelManager的设计,使得 OpenRig 具备了“热插拔”能力。你可以在rig.js运行时,动态修改config/models/qwen2.json,然后发送POST /reload请求(需在 server 中添加此路由),ModelManager就会重新加载配置并重启对应模型服务——整个过程不影响其他模型的正常请求。这种能力,在调试不同 quantization level(如 GGUF Q4_K_M vs Q6_K)对推理速度的影响时,价值巨大。
3.3 tmux 会话初始化:让终端成为你的 IDE
tmux/openrig.tmux文件是 OpenRig 的“可视化操作系统”。它定义了如何将多个服务、日志、控制台整合在一个 tmux 会话中。以下是经过实战优化的配置(兼容 tmux 3.2+):
# tmux/openrig.tmux # 创建新会话,命名为 openrig new-session -d -s openrig # 设置全局选项:启用鼠标支持,便于 pane 切换 set -g mouse on set -g status-left "#[fg=green]openrig#[default]" # 创建 4 个 pane 的布局(1 行 4 列) selectp -t 0 splitw -h -p 25 splitw -h -p 33 splitw -h -p 50 # Pane 0:LMStudio 日志(实时 tail) selectp -t 0 send-keys "tail -f logs/lmstudio/current.log" Enter # Pane 1:Ollama 日志 selectp -t 1 send-keys "tail -f logs/ollama/current.log" Enter # Pane 2:Rig 主服务日志 + 控制台 selectp -t 2 send-keys "tail -f logs/rig/current.log" Enter send-keys "cd src && node rig.js" Enter # Pane 3:交互式调试终端(预装常用命令别名) selectp -t 3 send-keys "echo 'OpenRig ready. Use: curl http://localhost:3000/models'" Enter send-keys "echo 'Test Codex: curl http://localhost:3000/v1/chat/completions -d \"{\"model\":\"lmstudio\",\"messages\":[{\"role\":\"user\",\"content\":\"hi\"}]}\"'" Enter # 绑定快捷键:Ctrl-b + 数字切换 pane bind-key 0 select-pane -t 0 bind-key 1 select-pane -t 1 bind-key 2 select-pane -t 2 bind-key 3 select-pane -t 3 # 启动后自动 attach 到会话 attach-session -t openrig这个配置的实战价值在于:它把 tmux 从一个终端复用工具,升级为一个可编程的开发环境。你执行./bin/openrig,它就自动创建好带日志监控、服务运行、调试终端的完整工作区。更关键的是,所有send-keys命令都经过精心设计——Pane 0 和 Pane 1 的tail -f会持续输出最新日志,而 Pane 2 的node rig.js启动后,其 stdout/stderr 会自动重定向到logs/rig/current.log(由src/utils/logger.js实现),确保日志集中管理。Pane 3 则预置了最常用的测试命令,新手无需记忆 curl 语法,直接按Ctrl-b + 3切过去,回车就能发起请求。
注意:
./bin/openrig脚本本身只是一个 bash wrapper,内容极其简单:#!/bin/bash cd "$(dirname "$0")/.." tmux source-file tmux/openrig.tmux它不做任何复杂逻辑,只负责切换到项目根目录并加载 tmux 配置。这种“脚本极度轻量,逻辑全部下沉到配置”的设计,正是 OpenRig 易于维护、易于协作的核心。
4. 从零部署 OpenRig:Ubuntu/macOS/WSL2 三平台实操指南
部署 OpenRig 的本质,是将前述目录结构与模块,在目标机器上实例化并验证。由于它不依赖任何中心化服务,部署过程就是“复制文件 + 安装依赖 + 启动服务”。下面以三个最主流的本地开发环境(Ubuntu 24.04 Desktop、macOS Sonoma、Windows WSL2 Ubuntu 22.04)为蓝本,给出可直接复制粘贴的完整步骤。所有命令均经过实测,无隐藏坑点。
4.1 Ubuntu 24.04 Desktop:GPU 加速下的最优实践
Ubuntu 是本地大模型开发的事实标准平台,尤其当你的机器配备 NVIDIA GPU 时,OpenRig 能充分发挥硬件潜力。以下是针对 Ubuntu 的部署要点:
第一步:安装基础依赖
# 更新系统并安装必要工具 sudo apt update && sudo apt upgrade -y sudo apt install -y git curl wget tmux build-essential python3-dev # 安装 Node.js v20.x(LTS,OpenRig 经过充分测试的版本) curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - sudo apt-get install -y nodejs # 验证安装 node --version # 应输出 v20.x npm --version # 应输出 9.x+第二步:克隆并初始化 OpenRig
# 创建项目目录 mkdir -p ~/projects/openrig && cd ~/projects/openrig # 初始化 Git 仓库(便于后续版本管理) git init git remote add origin https://github.com/yourname/openrig.git # 替换为你自己的远程地址 # 下载标准模板(此处使用我们维护的最小可行模板) wget https://raw.githubusercontent.com/openrig-template/main/template.tar.gz tar -xzf template.tar.gz rm template.tar.gz # 安装 Node.js 依赖 npm install # 创建日志目录 mkdir -p logs/{lmstudio,ollama,rig}第三步:配置 LMStudio(启用 CUDA 加速)
# 下载 LMStudio Linux x64 版本(选择支持 CUDA 的 build) wget https://github.com/LastBreach/lmstudio/releases/download/v0.3.12/LMStudio-0.3.12.AppImage chmod +x LMStudio-0.3.12.AppImage # 将其移动到标准位置并创建软链接 sudo mv LMStudio-0.3.12.AppImage /usr/local/bin/lmstudio sudo ln -sf /usr/local/bin/lmstudio /usr/local/bin/lmstudio-cuda # 编辑 config/models/lmstudio.json,启用 GPU cat > config/models/lmstudio.json << 'EOF' { "type": "lmstudio", "name": "lmstudio-cuda", "port": 1234, "command": ["lmstudio-cuda", "--port=1234", "--gpu-layers=40", "--no-gui"], "healthCheck": { "url": "http://localhost:1234/health", "timeoutMs": 10000 } } EOF第四步:启动并验证
# 启动 OpenRig ./bin/openrig # 此时会自动打开 tmux 会话,按 Ctrl-b + 2 切换到 Pane 2 # 你应该看到 rig.js 启动日志,以及 "OpenRig started on http://localhost:3000" # 在新终端中测试模型列表 curl http://localhost:3000/models # 返回应包含 {"lmstudio-cuda":{"status":"running","port":1234}} # 发送一个测试请求(使用 Codex 兼容 endpoint) curl -X POST http://localhost:3000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "lmstudio-cuda", "messages": [{"role": "user", "content": "Hello, world!"}] }' # 成功响应应包含 "choices" 数组和生成的文本关键经验:
- Ubuntu 下务必使用
lmstudio-cudaAppImage,而非通用版本,否则--gpu-layers参数无效。 --no-gui参数至关重要,它让 LMStudio 以 headless 模式运行,大幅降低内存占用。- 如果遇到
CUDA_ERROR_OUT_OF_MEMORY,不要立即调低--gpu-layers,先检查nvidia-smi是否有其他进程占满显存(如 Chrome 的硬件加速),关闭后再试。
4.2 macOS Sonoma:Metal 加速与 Rosetta 兼容性处理
macOS 用户常面临两个独特挑战:一是 Apple Silicon(M1/M2/M3)芯片的 Metal 加速路径与 NVIDIA CUDA 不同;二是部分模型二进制(如 llama.cpp)需 Rosetta 2 兼容。OpenRig 的跨平台设计,恰好能优雅应对。
第一步:安装 Homebrew 与依赖
# 安装 Homebrew(如果尚未安装) /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" # 安装 tmux 和 Node.js brew install tmux node@20 # 将 brew 安装的 node 添加到 PATH echo 'export PATH="/opt/homebrew/bin:$PATH"' >> ~/.zshrc source ~/.zshrc # 验证 node --version # v20.x第二步:配置 llama.cpp(Metal 加速)
# 克隆 llama.cpp 并编译(启用 Metal) git clone https://github.com/ggerganov/llama.cpp cd llama.cpp make clean && make LLAMA_METAL=1 -j$(sysctl -n hw.ncpu) # 将编译好的 binary 放入标准路径 sudo cp bin/main /usr/local/bin/llama-metal # 下载并量化一个模型(以 Phi-3-mini 为例) cd .. wget https://huggingface.co/mlc-ai/mlc-chat-Phi-3-mini-hf/resolve/main/phi-3-mini-4k-instruct-q4f16_1-MLC/phi-3-mini-4k-instruct-q4f16_1-MLC.gguf mv phi-3-mini-4k-instruct-q4f16_1-MLC.gguf models/ # 创建 config/models/llama-metal.json cat > config/models/llama-metal.json << 'EOF' { "type": "llama-cpp", "name": "phi3-metal", "port": 8080, "command": ["llama-metal", "-m", "models/phi-3-mini-4k-instruct-q4f16_1-MLC.gguf", "-c", "2048", "--port", "8080", "--host", "127.0.0.1"], "healthCheck": { "url": "http://localhost:8080/health", "timeoutMs": 15000 } } EOF第三步:处理 Rosetta 兼容性(针对 Intel Mac)如果你使用的是 Intel Mac,某些模型(如旧版 Ollama)可能仅提供 x86_64 二进制。此时需强制启用 Rosetta:
# 创建 Rosetta 启动包装器 cat > bin/ollama-rosetta << 'EOF' #!/bin/bash arch -x86_64 /usr/local/bin/ollama "$@" EOF chmod +x bin/ollama-rosetta # 在 config/models/ollama.json 中引用 # "command": ["ollama-rosetta", "serve"]第四步:启动与验证
# 启动 OpenRig ./bin/openrig # 在 tmux 中,按 Ctrl-b + 0 查看 llama-metal 日志,应看到类似: # [server] HTTP server listening at http://127.0.0.1:8080 # 测试 Metal 加速效果 curl http://localhost:3000/models | jq '.["phi3-metal"]' # 应返回 {"status":"running","port":8080} # 发送请求,观察响应时间(Metal 下 Phi-3-mini 通常 <2s) time curl -s http://localhost:3000/v1/chat/completions \ -d '{"model":"phi3-metal","messages":[{"role":"user","content":"Hi"}]}' | jq '.choices[0].message.content'关键经验:
- Apple Silicon 用户务必使用
LLAMA_METAL=1编译,这是获得最佳性能的唯一途径。CPU 模式(-ngl 0)慢 5-10 倍。 jq是 macOS 上必备的 JSON 处理工具,brew install jq可一键安装。- 如果遇到
dyld: Library not loaded: @rpath/libc++.1.dylib错误,说明 Xcode Command Line Tools 未安装,运行xcode-select --install解决。
4.3 Windows WSL2 Ubuntu:绕过 Windows 网络栈的终极方案
Windows 原生运行大模型服务常遇到端口冲突、防火墙拦截、WSL2 网络配置复杂等问题。OpenRig 的 WSL2 部署方案,核心思想是:让所有服务(LMStudio/Ollama/llama.cpp)全部运行在 WSL2 内部,Windows 主机只作为客户端访问http://localhost:3000。这样彻底规避了 Windows 网络栈的干扰。
第一步:WSL2 环境准备
# 在 Windows PowerShell 中启用 WSL2 wsl --install # 启动 Ubuntu 发行版(推荐 Ubuntu 22.04 LTS) wsl -d Ubuntu-22.04 # 更新并安装基础工具 sudo apt update && sudo apt upgrade -y sudo apt install -y git curl wget tmux build-essential python3-dev # 安装 Node.js(使用 NodeSource) curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - sudo apt-get install -y nodejs第二步:配置 WSL2 网络(关键!)
# 编辑 WSL2 的 /etc/wsl.conf,启用 systemd(可选,但推荐) sudo nano /etc/wsl.conf # 添加以下内容: # [boot] # systemd=true # [network] # generateHosts=true # generateResolvConf=true # 退出 WSL2 并重启(在 PowerShell 中执行) wsl --shutdown wsl -d Ubuntu-22.04 # 验证网络:WSL2 的 localhost 应能被 Windows 访问 # 在 WSL2 中运行:curl -I http://localhost:3000 # 在 Windows CMD 中运行:curl -I http://localhost:3000 (应返回 200)第三步:部署 OpenRig 并启动
# 创建项目目录 mkdir -p ~/openrig && cd ~/openrig # 下载模板并初始化 wget https://raw.githubusercontent.com/openrig-template/main/template.tar.gz tar -xzf template.tar.gz rm template.tar.gz npm install # 配置 Ollama(WSL2 下最稳定的模型服务) curl -fsSL https://ollama.com/install.sh | sh # 编辑 config/models/ollama.json,使用 WSL2 本地地址 cat > config/models/ollama.json << 'EOF' { "type": "ollama", "name": "qwen2", "