本地网关:解锁 Codex 与 Claude Code 的多模型自由路由

本地网关:解锁 Codex 与 Claude Code 的多模型自由路由 如果你最近在同时使用 Codex 和 Claude Code应该很快会遇到一个问题工具本身是分开的模型提供方也是分开的。Codex 默认面向 OpenAI 模型Claude Code 默认面向 Anthropic 模型如果你想在其中一个标签页里换成 DeepSeek、Kimi或者本地跑的 Qwen官方设置里通常没有直接入口。更常见的场景是团队内部每个人各自充值 API Key月底对账困难或者公司希望统一管控模型权限又不想限制开发者选择客户端。此时最自然的做法不是在应用层写死某一个厂商而是在中间加一层“本地网关”。t3 这类支持 Codex 与 Claude 标签页的 AI 终端工具出现之后这个需求变得尤其明显你希望一个客户端入口能够路由到多个模型提供商。这篇文章会以 t3 的 Codex 和 Claude 两个标签页为落点讲清楚为什么要用本地网关、网关需要具备哪些能力、如何用现成方案或自写方式搭起来以及在配置过程中最常见的报错和排查思路。我的判断是本地网关不是绕路而是 AI 编程工具走向“可组合”之后必然出现的中间层。它解决的不是破解或越权而是密钥管理、协议适配、请求日志和模型路由这些真实工程问题。1. 为什么要用本地网关而不是直接改客户端配置很多 AI 编程客户端都提供了“自定义 Base URL”或“API 地址”配置项。听起来很简单我把 Codex 标签页的 Base URL 改成某个模型厂商的 OpenAI 兼容地址把 Claude 标签页的 Base URL 改成另一个厂商的 Anthropic 兼容地址不就行了现实没有这么理想。你面对的是三类问题。第一模型协议不统一。OpenAI 系客户端走的是/v1/chat/completions新版 Codex 甚至可能走/v1/responses这一套语义Claude Code 走的是 Anthropic Messages API。绝大多数模型厂商只实现了其中一种最多兼容 OpenAI 格式同时兼容 Anthropic 格式的厂商非常少。于是你会发现目标是任意 LLM但客户端要求的是某种固定协议。第二密钥分散在各个终端里。开发者机器上可能有一份OPENAI_API_KEY一份ANTHROPIC_API_KEY还有一份 DeepSeek 的 Key。每个 Key 都要单独管理泄漏了很难追踪。如果有一个统一网关客户端只需要拿着一个本地 Key 请求127.0.0.1:4000网关再把真实 Key 注入到上游请求里安全和审计都会好很多。第三切换成本太高。今天想用 A 模型写前端明天想用 B 模型做架构分析如果每个标签页的 Base URL 都要打开配置文件改一遍体验非常糟糕。网关可以按照模型名或路由规则把请求分发到不同上游客户端完全无感。所以本地网关承担的核心职责是统一入口、协议适配、密钥管理、请求路由。它不一定需要多复杂但必须能稳定处理长连接和流式响应否则在 Codex 这样的编程场景里会频繁断流。2. 核心概念t3、Codex、Claude 与本地网关2.1 t3 是什么这里说的 t3指的是支持 Codex 和 Claude 两个工作区标签的 AI 终端客户端不是财务软件里的 T3。它把两个编程助手放到同一个界面里好处是开发者不需要在多个终端窗口之间来回切换Codex 的会话和 Claude 的会话可以并排查看。这类客户端的底层往往仍然是调用系统里的 Codex CLI 或 Claude Code。区别只在于 UI 层帮你统一了入口。也正因为如此它能不能接入任意 LLM取决于 CLI 给你留了哪些配置口子。2.2 Codex 与 Claude CodeCodex 是 OpenAI 推出的命令行编程助手。它可以根据代码仓库上下文生成修改方案并执行命令。新版 Codex 对模型和 API 的配置越来越开放支持通过config.toml自定义 model provider支持指向任意 OpenAI 兼容地址。Claude Code 是 Anthropic 推出的终端编程助手。它默认使用 Claude 模型但可以通过环境变量覆盖 API 地址。很多第三方模型服务为了兼容 Claude Code会提供 Anthropic Messages API 兼容端点。它们本质上都是“终端里的 Agent 客户端”。客户端负责收集上下文、调用工具、执行命令、展示结果模型负责理解和生成。只要客户端和模型之间走的是标准 HTTP 协议中间就存在被网关接管的空间。2.3 本地网关本地网关是一个运行在你本机或内网服务器上的服务通常监听127.0.0.1或内网地址。它接收来自 Codex、Claude Code 或其他工具的请求然后转发给真正的模型服务商。为什么不直接让客户端连接模型服务商因为网关可以在中间做这些事能力说明统一 Base URL所有客户端只配置一个地址密钥注入真实密钥保存在服务端或环境变量不暴露给客户端协议转换把 OpenAI 格式转成上游需要的格式或反向转换模型路由根据模型名、标签、用户把请求分发给不同模型日志审计记录请求来源、模型、Token 消耗、耗时限流与熔断控制调用频率上游异常时快速失败对个人开发者来说本地网关最大的价值是统一入口。对公司团队来说最大价值是审计和成本控制。3. 环境准备与前置条件在开始配置之前先确认以下环境。具体版本号以你实际安装的为准这篇文章更多是通用思路但版本差异可能导致字段名变化。3.1 基础环境操作系统macOS / Linux / WindowsWSL2均可。本文示例基于类 Unix 环境。Node.js 18 或 Python 3.10取决于你选择哪套网关方案。Git用于拉取代码或检查 CLI 版本。终端工具需要能运行 Codex CLI 和 Claude Code。3.2 模型上游你需要至少一个模型来源。常见选择OpenAI 官方 API。DeepSeek、Kimi、智谱等国内平台提供的 OpenAI 兼容 API。本地模型服务例如 Ollama、vLLM、LM Studio 提供的 OpenAI 兼容端点。某些平台同时提供 Anthropic 兼容端点可以直接给 Claude Code 使用。如果没有现成 API Key也可以先用 Ollama 跑一个小参数代码模型走通全流程之后再替换成商业模型。3.3 安装客户端Codex CLI 和 Claude Code 的安装方式会不断更新请以官方文档为准。常见方式是# 安装 Codex CLInpm 方式示例 npm install -g openai/codex # 安装 Claude Codenpm 方式示例 npm install -g anthropic-ai/claude-code安装后先确认命令存在codex --version claude --version如果你使用的是 t3 这类带标签页的客户端它内部可能会自动调用这两个 CLI。你需要确保 CLI 已经能在终端里正常启动再进入图形界面配置。4. 搭建本地网关三种方案网关方案很多我这里给出三种从最轻量到可扩展按需选择。4.1 方案一使用 Ollama 作为 OpenAI 兼容网关如果你只想先跑通“任意 LLM”这个概念Ollama 是最快的方式。它启动后会在11434端口暴露一个 OpenAI 兼容接口。# 安装并启动 Ollama ollama serve # 拉取一个适合代码场景的模型 ollama pull qwen2.5-coder:7b # 验证本地 OpenAI 兼容端点 curl http://127.0.0.1:11434/v1/models这个方案适合本地模型不需要真实 API Key。缺点是 Ollama 本身主要提供 OpenAI 兼容协议不提供 Anthropic Messages API。如果你要在 Claude 标签页里面接 Ollama需要再套一层协议转换网关或者选择一个本身支持 Anthropic 兼容格式的上游服务。4.2 方案二使用 LiteLLM Proxy 做统一网关LiteLLM 是 Python 生态里比较常用的模型网关。它可以一个服务同时暴露 OpenAI 兼容接口和 Anthropic 兼容接口并路由到几十种模型厂商。适合需要统一管理和后续扩展的场景。安装pip install litellm[proxy]创建一个配置文件config.yamlmodel_list: - model_name: codex-model litellm_params: model: openai/deepseek-chat api_key: os.environ/DEEPSEEK_API_KEY api_base: https://api.deepseek.com - model_name: claude-model litellm_params: model: anthropic/claude-sonnet-4-20250514 api_key: os.environ/ANTHROPIC_API_KEY启动网关export DEEPSEEK_API_KEYyour_deepseek_key export ANTHROPIC_API_KEYyour_anthropic_key litellm --config config.yaml --port 4000启动后http://127.0.0.1:4000就是你的统一入口。LiteLLM 会打印日志告诉你哪些路径是可用的。通常它同时支持 OpenAI 风格的/v1/chat/completions也会提供 Anthropic 兼容的路径用于接入 Claude Code。这个方案的好处是模型名、API Key、上游地址全部集中在 YAML 配置里之后切换模型只需要改配置重启。4.3 方案三手写一个极简本地网关如果你想完全掌控转发逻辑或者需要加一层日志手写一个 Node.js 网关是比较直接的做法。下面这个示例使用express和http-proxy-middleware只做请求转发不修改请求体。先初始化项目mkdir local-llm-gateway cd local-llm-gateway npm init -y npm install express http-proxy-middleware创建server.js// server.js const express require(express); const { createProxyMiddleware } require(http-proxy-middleware); const app express(); // 上游 OpenAI 兼容服务 const OPENAI_UPSTREAM process.env.OPENAI_UPSTREAM || https://api.deepseek.com; // 上游 Anthropic 兼容服务 const ANTHROPIC_UPSTREAM process.env.ANTHROPIC_UPSTREAM || http://127.0.0.1:11434; const openaiProxy createProxyMiddleware({ target: OPENAI_UPSTREAM, changeOrigin: true, on: { proxyReq: (proxyReq, req, res) { // 在这里可以注入真实 API Key // proxyReq.setHeader(Authorization, Bearer ${process.env.UPSTREAM_API_KEY}); console.log([OpenAI] ${req.method} ${req.originalUrl}); }, error: (err, req, res) { console.error([OpenAI Proxy Error], err.message); if (!res.headersSent) { res.status(502).json({ error: { message: Bad Gateway: upstream request failed, type: err.message } }); } } } }); const anthropicProxy createProxyMiddleware({ target: ANTHROPIC_UPSTREAM, changeOrigin: true, on: { proxyReq: (proxyReq, req, res) { console.log([Anthropic] ${req.method} ${req.originalUrl}); }, error: (err, req, res) { console.error([Anthropic Proxy Error], err.message); if (!res.headersSent) { res.status(502).json({ error: { message: Bad Gateway: upstream request failed, type: err.message } }); } } } }); // OpenAI 兼容路径 app.use(/v1, openaiProxy); // Anthropic 兼容路径 app.use(/anthropic, anthropicProxy); app.listen(4000, 127.0.0.1, () { console.log(Local LLM Gateway listening on http://127.0.0.1:4000); });启动node server.js这个示例没有做协议转换它假设上游本身就提供对应的协议。如果上游只提供 OpenAI 兼容接口而你想把 Anthropic Messages API 的请求转换成 OpenAI 格式需要自己解析 body这种复杂场景更推荐直接使用 LiteLLM 这类成熟项目。手写网关适合做教学演示和简单转发生产环境建议用现成网关因为你还需要处理超时、流式响应、错误兜底、限流等细节。5. 在 t3 中配置 Codex 与 Claude 标签页网关启动后接下来就是把 Codex 和 Claude 标签页指向它。由于 t3 只是一个外壳真正的配置还是在 CLI 层。5.1 配置 Codex 使用本地网关Codex 支持通过config.toml配置模型提供方。通常路径是~/.codex/config.toml。示例配置# ~/.codex/config.toml model codex-model [model_providers.local_gateway] name Local Gateway base_url http://127.0.0.1:4000/v1 env_key LOCAL_GATEWAY_KEY然后设置环境变量export LOCAL_GATEWAY_KEYsk-local-gateway codex这里的关键是base_url指向本地网关的 OpenAI 兼容路径。如果你使用 LiteLLM那么http://127.0.0.1:4000/v1就是合法的。如果你使用自写网关/v1也会被转发到上游。另一种方式是通过环境变量覆盖export OPENAI_BASE_URLhttp://127.0.0.1:4000/v1 export OPENAI_API_KEYsk-local-gateway codex注意新版 Codex 可能对模型名有校验如果提示模型不存在可以在网关层把任意模型名映射到你想要的上游模型而不是在 Codex 配置里硬改模型名。5.2 配置 Claude 使用本地网关Claude Code 支持通过环境变量指定 API 地址。不同版本的变量名可能不同常见的是ANTHROPIC_BASE_URL和ANTHROPIC_AUTH_TOKEN。export ANTHROPIC_BASE_URLhttp://127.0.0.1:4000 export ANTHROPIC_AUTH_TOKENsk-local-gateway export ANTHROPIC_MODELclaude-model claude这里把ANTHROPIC_BASE_URL指向网关根地址而不是带/v1的地址。具体路径要看网关暴露的 Anthropic 兼容端点。LiteLLM 类的网关通常会在日志里打印出可用的 Anthropic 端点例如http://127.0.0.1:4000/anthropic这时你应该把ANTHROPIC_BASE_URL配成对应的完整地址。5.3 t3 标签页的配置入口如果你用的是 t3 这类带图形界面的工具通常它会导出一份环境变量或配置文件。你只需要在启动 t3 之前把上面两组环境变量 export 好或者在 t3 的配置界面里填写网关地址。一个通用做法是在 shell 配置文件中加入# ~/.bashrc 或 ~/.zshrc export OPENAI_BASE_URLhttp://127.0.0.1:4000/v1 export OPENAI_API_KEYsk-local-gateway export ANTHROPIC_BASE_URLhttp://127.0.0.1:4000 export ANTHROPIC_AUTH_TOKENsk-local-gateway然后重启终端再启动 t3。这样 Codex 标签页和 Claude 标签页默认都会走本地网关。6. 运行结果与效果验证配置完成之后先不要急着进入复杂任务先用最小请求验证网关和客户端链路。6.1 验证网关本身用 curl 直接请求网关确认它能正常返回curl http://127.0.0.1:4000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: codex-model, messages: [{role: user, content: 请回答网关是否连通}] }如果返回包含choices字段的内容说明网关到上游是通的。如果这里就失败不要先去检查 t3先确认上游 API Key 和 Base URL 是否正确。对于 Claude 兼容端点也可以用类似方式验证只是请求格式是 Anthropic Messages 格式。具体字段取决于网关版本和上游服务。6.2 在 Codex 标签页验证启动 t3进入 Codex 标签页输入一个简单问题请读取当前目录结构并告诉我这个项目用的是什么语言。如果 Codex 能正常读取目录并返回结果说明本地网关的 OpenAI 兼容链路已经通了。如果返回报错优先看网关进程的日志。6.3 在 Claude 标签页验证切到 Claude 标签页输入同样类型的问题。如果 Claude Code 能正常回复说明 Anthropic 兼容链路也通了。这里最容易出现的现象是Codex 可以用但 Claude 标签页报错。原因通常是ANTHROPIC_BASE_URL指向的端点不是标准的 Anthropic Messages API而是 OpenAI 格式导致 Claude Code 无法解析。6.4 判断成功的标准客户端界面不报 401、403、404。网关日志里能看到来自本机的请求。模型返回内容符合预期。工具调用类请求读取文件、执行命令能正常执行。如果只是简单对话正常但工具调用失败说明模型本身不具备工具调用能力或者协议转换层没有正确处理tools字段。这需要单独排查。7. 常见问题与排查思路下面这些问题是从实际配置过程中最容易遇到的尤其是当你用本地网关同时接 Codex 和 Claude 时。问题现象可能原因排查方式解决方案网关返回 502 Bad Gateway日志显示cc switch local gateway failed while handling codex endpoint /responses上游地址不可达或上游服务 5xx查看网关错误日志用 curl 直接请求上游接口检查 API Key 和api_base配置确认上游服务是否限流LLM request failed: provider rejected the request schema or tool payload模型不支持当前请求中的 tools 格式或网关没有正确移除不支持字段比较业务模型支持的 tools 参数在网关层对 tools 字段做清理更换支持工具调用的模型ECONNREFUSED 连接被拒绝网关没有启动或端口不对curl http://127.0.0.1:4000/v1/models查看是否响应启动网关确认端口绑定在 4000Codex 能用Claude 标签页 404Anthropic 兼容路径配置错误查看网关日志确认请求到达的路径把ANTHROPIC_BASE_URL调整成网关实际的 Anthropic 端点对话正常但工具调用不执行选择的模型没有工具调用能力查看模型文档用官方客户端试同样的请求更换为代码能力更强的模型在网关配置中禁用不支持的参数流式输出断断续续客户端和网关之间的 SSE 连接被中断检查终端代理设置、防火墙确保网关监听127.0.0.1不要经过不必要的中间层提示模型不存在Codex 或 Claude 的模型名没有映射到网关配置查看网关日志中实际收到的 model 字段在网关中配置model_name映射7.1 502 的深层排查502 是最常见的错误。它代表网关已经接收到了客户端的请求但把请求转发到上游时失败了。此时先看一层层链路# 1. 网关本身是否存活 curl http://127.0.0.1:4000/v1/models # 2. 上游是否可达 curl https://api.deepseek.com/v1/models \ -H Authorization: Bearer $DEEPSEEK_API_KEY # 3. 客户端环境变量是否正确 env | grep -E OPENAI|ANTHROPIC如果第 1 步失败说明网关没起来。如果第 2 步失败说明上游密钥或网络有问题。如果第 3 步看起来没问题那问题一定在请求路径或模型名上。7.2 协议不一致的排查有的模型厂商说“支持 OpenAI 兼容”但只实现了一部分字段。比如在/v1/chat/completions里遇到tools参数时直接报 400而不是忽略它。这种问题很难从客户端侧解决只能在网关里做字段过滤。如果你用的是 LiteLLM可以尝试在模型配置中增加参数兼容性选项。如果用的是自写网关建议在请求转发前打印 body确定哪些字段引起上游拒绝。// 在网关中增加一段日志中间件 app.use((req, res, next) { let body ; req.on(data, chunk body chunk); req.on(end, () { if (body) { try { const parsed JSON.parse(body); console.log([Request Body] model , parsed.model, tools , parsed.tools ? enabled : disabled); } catch (e) { console.log([Request Body] raw , body.substring(0, 200)); } } }); next(); });日志会告诉你客户端实际发送的请求体是最直接的排查手段。8. 最佳实践与工程建议本地网关看起来简单但真正用到生产或团队协作中有几个容易忽略的地方。8.1 网关只监听本机地址默认应该使用127.0.0.1不要使用0.0.0.0。监听0.0.0.0意味着局域网内任何设备都能访问你的网关如果网关还保存了真实 API Key这等于把密钥暴露给内网。如果你确实需要多台机器共享网关应该部署在内网服务器上并通过防火墙限制来源 IP同时在网关前面加一层身份认证。至少需要一个自定义 Token 校验不要裸奔。8.2 密钥放在服务端不要放在客户端客户端只需要知道本地网关的 Key 或干脆不填真实 Key 应该放在网关环境变量或配置中心。这样即使开发者的终端被截图、环境变量被 dump也不会直接泄漏上游厂商的密钥。在自写网关中可以通过环境变量注入密钥而不是硬编码在代码里。8.3 记录 Token 消耗和请求日志如果你负责团队的 AI 成本一定要记录每次请求的模型、Token 数、耗时和来源会话。大部分现成网关自带日志自写网关需要手动加。一个轻量做法是每次转发完成后把请求信息写到本地 JSON 文件或标准日志里app.use(/v1, (req, res, next) { const start Date.now(); res.on(finish, () { console.log(JSON.stringify({ ts: new Date().toISOString(), path: req.originalUrl, status: res.statusCode, durationMs: Date.now() - start, model: req.body req.body.model })); }); next(); });这些数据对成本优化非常有用。你会发现某些模型在代码任务上 token 消耗特别高换一个模型可能更划算。8.4 预留模型路由而不是写死一个上游即使你现在只有一个模型供应商也建议把网关配置设计成“模型名 - 上游”的映射结构而不是写死一个 base URL。这样以后新增模型时不需要改客户端只需要在网关里加一行配置。8.5 注意上游模型的工具调用能力Codex 和 Claude Code 不只是聊天工具它们会调用文件读写、命令执行等工具。如果你把模型切换成一个不擅长工具调用的模型即使语法支持实际使用体验也会很差。在接入新模型前最好先用一个需要工具调用的任务测试例如请列出当前目录下所有文件名并写入 result.txt 中。如果模型不能正确调用工具说明它不适合接入 Codex 或 Claude Code 这类 Agent 环境。8.6 版本兼容性管理Codex CLI、Claude Code、t3 这类工具更新速度非常快。网关配置可能在一次升级后就失效常见原因是某个 CLI 开始强制使用新接口比如 Codex 开始默认请求/v1/responses而你的网关只实现了/v1/chat/completions。建议固定工具版本或者至少保持关注更新日志。升级前先阅读变更说明不要盲目更新到最新版本。9. 总结与后续建议本地网关解决的是一个很现实的工程问题当客户端和模型提供方分离之后如何在中间加一个统一控制层。你可以用很简单的方式跑通它比如 Ollama也可以引入更完善的 LiteLLM 管理多模型路由还可以手写一个最小转发器理解请求链路是怎么走的。对于个人开发者我建议先用 LiteLLM 或 Ollama 跑通全流程不要一开始就陷入协议转换的细节。先让 Codex 标签页能调用 DeepSeek让 Claude 标签页能调用本地模型再逐步扩展。对于团队把网关部署在内网服务器配套日志、限额和密钥管理比让每个开发各自配置 API Key 要安全得多。但前提是做好权限控制网关是敏感节点权限设计不能省。接下来值得深入的方向是深入理解/v1/responses和/v1/chat/completions的差异这对配置新版 Codex 非常重要。研究 Anthropic Messages API 的工具调用格式以及它和 OpenAI tools 格式的映射关系。尝试用网关做请求缓存减少重复代码生成任务的成本。了解模型路由策略比如根据请求类型自动选择不同模型。本地网关不会取代客户端也不会取代模型厂商它更像是客户端和模型之间的“路由器”。只要你想自由组合 AI 编程工具最终都会走到这一层。希望这篇文章能帮你少走弯路。