ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

openrig 实战:用 YAML 和 tmux 统一编排 Claude Code、Codex 与本地模型

openrig 实战:用 YAML 和 tmux 统一编排 Claude Code、Codex 与本地模型 1. openrig 到底在解决什么问题第一次看到 openrig 这个名字很多人会以为是某个硬件项目或者机械臂框架但如果你最近在折腾 Claude Code、Codex 这类终端里的 AI 编程助手大概率已经隐约感觉到它要解决的是什么了——多工具、多模型、多会话之间的编排与切换问题。我自己的日常是这样的主力用 Claude Code 写业务代码遇到需要长上下文推理或者特定模型能力的场景会切到 Codex本地还跑着 LM Studio 提供的一些开源模型做补充。问题在于这三套东西各有各的配置、各有各的会话状态、各有各的启动方式。每次切换要么手动改配置文件要么开一堆 tmux 窗口来回跳时间久了非常割裂。openrig 这个项目标题背后指向的核心需求就是把这些散落的 AI 编程工具用一个统一的配置层和会话管理层串起来。它适合谁我认为有三类人值得关注。第一类是已经在用 Claude Code 或 Codex但觉得单工具不够用、想组合起来的人第二类是想接入本地模型比如通过 LM Studio 或 DeepSeek来降低成本或做离线开发的人第三类是习惯 tmux 工作流、希望把 AI 助手真正嵌进终端环境而不是当个网页玩具的人。如果你属于这三类中的任何一类下面这些内容应该能帮你少走不少弯路。需要提前说明的是openrig 目前并不是一个官方大厂产品它更像是一个围绕 Claude Code、Codex 生态自发形成的配置编排思路或轻量工具集合。所以我会把重点放在它背后的编排逻辑、YAML 配置方法、tmux 会话管理、以及多模型接入的实操细节上而不是假设它有一个完美的官方文档。这些内容基于我实际折腾 Claude Code、Codex、tmux 和 YAML 配置的经验整理你可以直接抄作业。2. 核心设计思路为什么是 YAML tmux 多模型2.1 为什么配置层选 YAML 而不是 JSON 或 TOMLClaude Code 和 Codex 的配置文件格式各有不同但社区里越来越多的编排方案倾向于用 YAML 做统一配置层原因很实际。JSON 不支持注释你没法在配置里写“这行是给 DeepSeek 用的那行是给本地 LM Studio 用的”TOML 虽然支持注释但嵌套结构一深就变得很难读。YAML 在可读性和表达力之间取得了比较好的平衡尤其是当你需要描述多个模型端点、多个会话模板、多个工具别名的时候。举个实际场景。假设你要配置三个模型来源Anthropic 官方的 Claude、本地 LM Studio 的模型、以及 DeepSeek 的 API。用 YAML 写出来大概是这样models: claude-main: provider: anthropic model: claude-sonnet-4-20250514 api_key_env: ANTHROPIC_API_KEY max_tokens: 8192 local-lmstudio: provider: openai-compatible base_url: http://localhost:1234/v1 model: qwen2.5-coder-32b api_key: lm-studio deepseek-backup: provider: openai-compatible base_url: https://api.deepseek.com/v1 model: deepseek-chat api_key_env: DEEPSEEK_API_KEY这种结构一眼就能看出每个模型的用途。如果你用 JSON 写同样的内容光是引号和括号就够你受的更别说没法加注释说明每个字段的意图。YAML 的另一个好处是它和 Claude Code、Codex 的很多配置格式天然兼容你不需要做额外的格式转换。注意YAML 对缩进极其敏感Tab 和空格混用会直接报错。我建议统一用两个空格缩进并且在编辑器里开启“显示空白字符”这样能避免 90% 的解析错误。2.2 tmux 为什么是会话编排的最佳载体很多人第一次接触 tmux 是因为“服务器断开后任务还能继续跑”但它在 AI 编程助手场景下的价值远不止于此。Claude Code 和 Codex 都是长时间运行的交互式进程你不可能每次切换工具都重新启动一遍、重新加载上下文。tmux 的 session 和 window 机制恰好能解决这个问题。我的做法是给每个工具分配一个固定的 tmux windowwindow 0 跑 Claude Codewindow 1 跑 Codexwindow 2 跑本地模型的服务端或者日志监控。这样我只需要Ctrlb加数字就能瞬间切换而且每个工具的会话状态都保留着。更进一步你可以用 tmux 的send-keys功能做自动化比如把一段代码同时发给 Claude Code 和 Codex对比两个模型的输出。# 创建一个名为 airig 的会话专门跑 AI 编程工具 tmux new-session -d -s airig -n claude tmux new-window -t airig -n codex tmux new-window -t airig -n local # 在 claude window 里启动 Claude Code tmux send-keys -t airig:claude claude C-m # 在 codex window 里启动 Codex tmux send-keys -t airig:codex codex C-m这段脚本跑完之后你tmux attach -t airig就能看到一个已经准备好的三窗口工作区。这比每次手动开三个终端、分别 cd 到项目目录、再分别启动工具要高效得多。2.3 多模型接入的核心考量为什么要在 openrig 的思路里强调多模型因为单一模型很难覆盖所有场景。Claude 在代码理解和长上下文方面表现稳定但成本不低Codex 在某些代码生成任务上有自己的优势本地 LM Studio 跑的模型虽然能力有差距但胜在免费、离线、数据不出本机DeepSeek 则在中文理解和特定推理任务上有不错的性价比。关键问题是怎么让这些模型在同一个工作流里无缝切换而不是每次都要改环境变量、改配置文件、重启工具我的经验是把模型配置抽象成“端点 密钥 参数”三要素然后用一个统一的代理层或者配置生成脚本来管理。Claude Code 支持通过环境变量指定 API 端点Codex 也有类似的机制你完全可以在启动脚本里根据当前场景动态注入不同的配置。这里有个坑需要提前说不同工具对“OpenAI 兼容接口”的支持程度不一样。LM Studio 提供的/v1/chat/completions接口大部分情况下能用但某些工具会调用/v1/responses这类非标准端点导致cc switch local proxy failed while handling codex endpoint /responses这种报错。遇到这种情况要么在代理层做路径重写要么确认工具是否支持自定义端点路径。3. 从零搭建 openrig 风格的工作环境3.1 基础依赖安装与版本确认在开始配置之前先把基础环境理清楚。你需要的东西不多但版本要对。组件推荐版本检查命令备注Node.js20 LTS 或更高node -vClaude Code 和 Codex 都依赖npm10 以上npm -v用于全局安装 CLI 工具tmux3.2 以上tmux -V会话管理核心YAML 解析器任意python -c import yaml用于校验配置文件Claude Code最新版claude --version主力编程助手Codex CLI最新版codex --version辅助编程助手安装 Claude Code 的方式取决于你的系统。macOS 和 Linux 下通常用 npm 全局安装npm install -g anthropic-ai/claude-codeWindows 下如果遇到权限问题建议用管理员权限打开 PowerShell或者考虑在 WSL2 里操作。我实测下来WSL2 里的体验比原生 Windows 更稳定尤其是涉及到 tmux 和文件路径的时候。Codex 的安装类似但要注意它的包名和版本更新比较频繁建议直接看官方仓库的最新说明。安装完成后先跑一次claude --version和codex --version确认可执行文件在 PATH 里。提示如果你在国内网络环境下遇到安装缓慢的问题可以配置 npm 镜像源。但注意不要使用任何来路不明的第三方脚本优先用官方支持的镜像配置方式。3.2 YAML 配置文件的完整结构与字段说明openrig 风格的核心配置文件我一般命名为openrig.yaml放在项目根目录或者~/.config/openrig/下。下面是一个相对完整的示例你可以根据自己的情况删减version: 1 workspace: root: ~/projects/current tmux_session: airig default_window: claude models: claude-main: provider: anthropic model: claude-sonnet-4-20250514 api_key_env: ANTHROPIC_API_KEY max_tokens: 8192 temperature: 0.3 local-lmstudio: provider: openai-compatible base_url: http://127.0.0.1:1234/v1 model: qwen2.5-coder-32b api_key: not-needed max_tokens: 4096 temperature: 0.2 deepseek-chat: provider: openai-compatible base_url: https://api.deepseek.com/v1 model: deepseek-chat api_key_env: DEEPSEEK_API_KEY max_tokens: 4096 temperature: 0.4 tools: claude: command: claude model_ref: claude-main env: ANTHROPIC_BASE_URL: ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY} codex: command: codex model_ref: deepseek-chat env: OPENAI_BASE_URL: ${DEEPSEEK_BASE_URL} OPENAI_API_KEY: ${DEEPSEEK_API_KEY} windows: - name: claude tool: claude cwd: ${workspace.root} - name: codex tool: codex cwd: ${workspace.root} - name: local command: tail -f ~/.lmstudio/server.log cwd: ${workspace.root}这个配置里几个关键点值得展开说。models段定义了所有可用的模型端点每个端点有唯一的 key后面在tools里通过model_ref引用。tools段定义了每个工具怎么启动、用哪个模型、需要注入哪些环境变量。windows段定义了 tmux 会话里每个窗口跑什么。环境变量用${VAR}语法引用这样你可以把密钥放在.env文件或者系统的环境变量里而不是硬编码在 YAML 中。这一点很重要因为配置文件很可能被提交到 Git 仓库密钥泄露的后果不用我多说。3.3 启动脚本与 tmux 会话自动化有了配置文件之后你需要一个启动脚本来解析 YAML 并创建 tmux 会话。我用 Python 写了一个简单的版本依赖pyyaml#!/usr/bin/env python3 import os import subprocess import yaml import sys def load_config(path): with open(path, r) as f: return yaml.safe_load(f) def expand_env(value): if isinstance(value, str): return os.path.expandvars(value) return value def build_env(env_dict): result {} for k, v in (env_dict or {}).items(): result[k] expand_env(v) return result def main(): config_path sys.argv[1] if len(sys.argv) 1 else openrig.yaml cfg load_config(config_path) session cfg[workspace][tmux_session] # 如果会话已存在先杀掉重建 subprocess.run([tmux, kill-session, -t, session], stderrsubprocess.DEVNULL) windows cfg[windows] for idx, win in enumerate(windows): name win[name] cwd expand_env(win.get(cwd, .)) if idx 0: subprocess.run([tmux, new-session, -d, -s, session, -n, name, -c, cwd]) else: subprocess.run([tmux, new-window, -t, session, -n, name, -c, cwd]) # 构建启动命令 if tool in win: tool_name win[tool] tool_cfg cfg[tools][tool_name] cmd tool_cfg[command] env build_env(tool_cfg.get(env, {})) env_prefix .join(f{k}{v} for k, v in env.items()) full_cmd f{env_prefix} {cmd}.strip() else: full_cmd win.get(command, ) if full_cmd: subprocess.run([tmux, send-keys, -t, f{session}:{name}, full_cmd, C-m]) print(fSession {session} created with {len(windows)} windows.) if __name__ __main__: main()这个脚本做的事情很直接读 YAML、杀旧会话、按顺序创建窗口、在每个窗口里发送启动命令。你可以把它保存为openrig.py然后python openrig.py openrig.yaml就能一键拉起整个工作环境。注意tmux send-keys发送命令后需要加C-m模拟回车否则命令只是输入到终端里但不会执行。这个坑我踩过不止一次尤其是命令比较长的时候很容易忘记加回车。4. 多模型接入的实操细节与踩坑记录4.1 Claude Code 接入本地 LM Studio 的完整流程Claude Code 默认走 Anthropic 官方 API但通过设置ANTHROPIC_BASE_URL环境变量你可以把它指向任何兼容 Anthropic 接口的端点。LM Studio 从某个版本开始支持 Anthropic 兼容模式但需要手动开启。第一步在 LM Studio 里加载一个模型比如qwen2.5-coder-32b-instruct然后在 Server 设置里确认端口是 1234并且开启了“Anthropic-compatible API”选项。如果没有这个选项说明你的 LM Studio 版本太旧需要升级。第二步设置环境变量并启动 Claude Codeexport ANTHROPIC_BASE_URLhttp://127.0.0.1:1234 export ANTHROPIC_API_KEYlm-studio claude如果一切正常Claude Code 会认为自己在和官方 API 通信但实际上请求都发给了本地模型。实测下来Qwen2.5-Coder 在代码补全和简单重构任务上表现尚可但复杂推理和长上下文任务还是和官方 Claude 有差距。所以我的建议是本地模型用来做快速补全、格式化、简单重构复杂任务还是切回官方模型。提示LM Studio 的 Anthropic 兼容模式并不是 100% 覆盖官方接口。如果你遇到cc switch local proxy failed这类错误先检查 LM Studio 的日志看是哪个端点返回了 404 或 400。常见原因是 Claude Code 调用了/v1/messages之外的端点而 LM Studio 没有实现。4.2 Codex 接入 DeepSeek 的配置方法Codex 的配置方式和 Claude Code 略有不同。它通常读取OPENAI_BASE_URL和OPENAI_API_KEY环境变量所以接入 DeepSeek 的思路是类似的export OPENAI_BASE_URLhttps://api.deepseek.com/v1 export OPENAI_API_KEYsk-your-deepseek-key codex但这里有个细节Codex 某些版本会调用/v1/responses端点而 DeepSeek 的兼容接口可能只实现了/v1/chat/completions。如果你遇到codex endpoint /responses相关的报错说明端点不匹配。解决办法有两个一是找一个支持/v1/responses的代理层做转换二是确认你使用的 Codex 版本是否支持自定义端点路径。我在实际使用中的体会是Codex 接 DeepSeek 的稳定性不如 Claude Code 接 LM Studio主要是因为 Codex 的接口调用模式更复杂对兼容层的要求更高。如果你主要用 DeepSeek建议优先考虑通过 Claude Code 接入或者等 Codex 官方对 OpenAI 兼容接口的支持更完善之后再折腾。4.3 模型切换的自动化脚本手动改环境变量再重启工具太麻烦我写了一个简单的切换脚本放在~/bin/switch-model.sh#!/bin/bash # 用法: switch-model.sh claude-main | local-lmstudio | deepseek-chat MODEL_KEY$1 CONFIG~/projects/current/openrig.yaml # 用 Python 解析 YAML 并输出环境变量 eval $(python3 -c import yaml, os with open($CONFIG) as f: cfg yaml.safe_load(f) m cfg[models][$MODEL_KEY] provider m[provider] if provider anthropic: print(fexport ANTHROPIC_BASE_URL{m.get(\base_url\, \\)}) print(fexport ANTHROPIC_API_KEY\${m[\api_key_env\]}) elif provider openai-compatible: print(fexport OPENAI_BASE_URL{m[\base_url\]}) key m.get(api_key) or os.environ.get(m.get(api_key_env,), ) print(fexport OPENAI_API_KEY{key}) ) echo Switched to model: $MODEL_KEY这个脚本的核心思路是把 YAML 里的模型配置转换成环境变量。你可以在 tmux 的某个窗口里 source 这个脚本然后重启对应的工具。更激进的做法是结合 tmux 的respawn-window功能直接重启窗口里的进程而不影响其他窗口。5. 常见问题排查与避坑指南5.1 配置类问题速查表问题现象可能原因排查方法解决方案YAML 解析报错缩进用了 Tabpython -c import yaml; yaml.safe_load(open(openrig.yaml))统一用两个空格缩进环境变量未生效${VAR}引用的变量未导出echo $ANTHROPIC_API_KEY在.bashrc或.env中导出tmux 窗口命令未执行忘记加C-m检查send-keys调用命令末尾加C-mClaude Code 连不上本地模型LM Studio 未开启兼容模式查看 LM Studio Server 日志升级 LM Studio 并开启 Anthropic 兼容Codex 报/responses端点错误兼容层未实现该端点抓包或看代理日志换用支持该端点的代理或降级 Codex模型切换后仍走旧配置环境变量被缓存envgrep -E ANTHROPIC5.2 那些文档里不会写的实操心得第一个心得不要把密钥写在 YAML 里。我见过太多人图省事直接把 API Key 写在配置文件里然后不小心提交到了公开仓库。正确的做法是用${VAR}引用环境变量并且把.env文件加入.gitignore。如果你用的是团队协作环境建议用密钥管理工具或者 CI/CD 的 secret 机制。第二个心得tmux 会话命名要有规律。我一开始用随机名字结果tmux ls出来一堆 session根本分不清哪个是哪个。后来统一用airig-项目名的格式比如airig-webapp、airig-datapipe一眼就能看出这个会话是给哪个项目用的。第三个心得本地模型的上下文窗口要留足余量。LM Studio 里加载模型时可以设置 context length但设置得太大会吃满显存太小又会导致长文件处理时截断。我的经验是对于 32B 级别的代码模型context length 设置在 8192 到 16384 之间比较平衡。如果你主要处理小文件4096 也够用。第四个心得Claude Code 和 Codex 的会话不要混在同一个 tmux window 里。我试过在一个窗口里先跑 Claude Code 再跑 Codex结果两个工具的终端状态互相干扰输出混在一起根本没法看。后来改成每个工具独立 window世界就清净了。5.3 性能与成本优化的几个实操技巧成本这块如果你主要用官方 Claude APItoken 消耗是实打实的钱。我的做法是日常补全和简单问答走本地 LM Studio只有复杂重构、架构设计、长文档分析才切到官方模型。这样一个月下来能省不少。性能方面tmux 本身开销很小但如果你同时跑多个模型服务端比如 LM Studio 加载了两个模型内存和显存压力会比较大。建议一次只加载一个本地模型需要切换时再换。LM Studio 支持模型热切换但切换过程中会有几秒到几十秒的加载时间这个要有心理预期。还有一个容易被忽略的点日志和输出重定向。Claude Code 和 Codex 在长时间运行后会产生大量输出如果全部留在 tmux 的 scrollback buffer 里内存占用会越来越高。我一般会定期clear或者配置 tmux 的history-limit为一个合理值比如 5000 行。6. 进阶玩法把 openrig 思路扩展到更多场景6.1 多项目并行时的会话隔离当你同时维护多个项目时每个项目一套 tmux 会话是最清晰的做法。我通常用项目名作为 session 后缀然后在每个 session 里保持相同的窗口布局claude、codex、local、logs。这样无论切到哪个项目操作习惯都是一致的。更进一步你可以写一个openrig-init.sh脚本接收项目路径作为参数自动创建对应的 tmux 会话并 cd 到项目目录。这样新项目上手只需要一条命令。6.2 结合 VS Code 的混合工作流虽然 tmux 终端很强大但有些场景下 VS Code 的图形界面更顺手比如看 diff、管理 Git、调试代码。我的做法是VS Code 里开一个终端面板连到 tmux 会话这样既能在图形界面里编辑文件又能随时切到终端和 AI 助手交互。VS Code 的 Claude Code 插件也可以配置自定义端点和终端里的配置保持一致即可。6.3 配置版本管理与团队共享openrig.yaml 本身应该纳入版本管理但密钥和本地路径相关的配置应该抽离成单独的openrig.local.yaml然后通过include或者环境变量覆盖的方式合并。这样团队共享时每个人只需要维护自己的 local 配置核心的模型定义和窗口布局可以统一管理。我目前用的合并逻辑是先加载openrig.yaml再用openrig.local.yaml做深度合并。Python 的dict.update是浅合并嵌套字典需要自己写递归合并函数。这个逻辑不复杂但能省去很多手动同步的麻烦。6.4 后续可以继续折腾的方向如果你已经把基础环境跑通了接下来可以尝试几个方向。一是给 tmux 会话加状态栏显示当前使用的模型和 token 消耗二是写一个简单的 Web 面板远程查看各个会话的运行状态三是把常用的 prompt 模板化通过脚本快速注入到 Claude Code 或 Codex 的输入框里。我个人最想做的其实是第三点。现在每次让 AI 助手做代码审查都要手动敲一遍类似的指令如果能把这些 prompt 存在 YAML 里用快捷键或者命令快速调用效率还能再提升一截。这个思路应该不难实现核心就是 tmux 的send-keys加上一个 prompt 模板库。踩过几次坑之后我越来越觉得 openrig 这类编排方案的价值不在于工具本身有多复杂而在于它把散落的工作流收拢到了一个可配置、可复现、可版本管理的框架里。你不需要一次做到完美先把最常用的两三个工具串起来后面再慢慢加东西这样上手压力最小也最容易坚持下来。
返回列表