ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

用本地网关统一Codex与Claude接入:协议转换实践

用本地网关统一Codex与Claude接入:协议转换实践 记得有一次团队里一位同事在本地跑 Codex CLI想把它接到自建的模型服务上。配置了半天模型名字、base URL、API key 都填了结果一调用就报错日志里反复出现 “failed while handling codex endpoint /responses” 这样的字样。他当时的第一反应是“是不是我的 base URL 写错了”但反复检查之后发现问题根本不是地址而是本地代理服务对 OpenAI Responses API 和 Claude 消息格式之间的转换没有处理好。这件事让我意识到很多人折腾 CLI 接本地模型时真正卡住的往往不是模型本身而是中间那一层 gateway。这个标题看起来是在讲“在 t3 的 Codex 和 Claude 标签页里运行任意 LLM”但拆开看它要解决的是本地网关如何统一不同模型服务的接入协议。如果能把这个链路理清楚你会发现不止 Codex其它 CLI 工具接本地模型也会顺畅很多。1. 先搞清楚这个工具真正解决的是哪类重复劳动先说结论这个项目解决的不是“多一个模型入口”的问题而是把“不同 CLI 工具各自对接不同模型服务”的重复适配工作收敛到一层本地网关里。1.1 为什么 CLI 工具接模型最麻烦的不是 API key很多人以为接模型难在配置其实配置只是第一道门槛。真正麻烦的是每个 CLI 工具对后端模型服务的协议假设不一样。比如 OpenAI 系的工具默认你会提供一个兼容 OpenAI 的 base URL它内部会调用/responses或者/chat/completions。而 Claude Code 这类工具它更习惯于 Anthropic Messages API 的格式。当你只有一个本地模型服务时你不可能让每个工具都直接适配这个服务的私有格式。更常见的做法是给每个工具分别配一个 base URL在本地找一个支持多协议转换的 gateway把 gateway 地址填进每个 CLI 的配置里由 gateway 完成协议转换和请求转发。这里最容易踩的坑是你本地起了两个服务一个走 OpenAI 兼容端口一个走 Anthropic 兼容端口但两个工具相互之间不知道对方的存在。结果就是 Codex 配了一个 8080 端口Claude Code 配了另一个 9090 端口两边各跑各的根本谈不上“统一接入”。1.2 这个项目的关键变化把协议转换放到本地它真正的思路不是让每个 CLI 都去兼容所有模型而是通过一个本地 gateway把 Codex 标签页和 Claude 标签页的请求统一接收下来再转给后端真正的模型服务。这和你直接在命令行里写export OPENAI_BASE_URLhttp://localhost:1234/v1是两回事。后者只是改变了客户端请求的目标地址而协议格式仍然是 OpenAI 风格。一旦工具切换成 Anthropic 风格你又要重新配一遍。而本地 gateway 会做三件事接收不同 CLI 发来的请求识别请求协议和工具来源转换成目标模型服务真正需要的格式再转发出去。这才是从“每个工具各接各的”变成“所有工具都接同一个网关”的关键变化。2. 为什么单次跑通不等于能稳定批量使用我第一次看到这个标题时想到另一个常见操作把 OpenAI 的 base URL 改成本地代理然后就能在 Codex 里调本地模型了。这种用法听起来很简单实际跑通一次也不难但真正用起来会发现问题很多。2.1 先跑一个最小链路确认协议转换没有断不管你的后端模型是 LLM、本地推理服务还是远程兼容接口第一步都应该先跑一个最小链路。我建议按这个顺序验证先启动本地 gateway 服务确认 gateway 能访问后端模型服务在 Codex 标签页填入 gateway 地址发送一条最简单的请求比如“你好”观察 gateway 日志中是否出现/responses或/v1/messages的转发记录。如果这一步能正常返回说明基础链路是通的。如果这里就报错先不要查模型参数而是看协议是否匹配。2.2 真正麻烦的是批量任务、异常重试和长期维护当你只是测试一条消息时请求量小参数简单很多边界问题不会暴露。但一旦开始用 Codex 处理多文件项目或者让 Claude 标签页连续跑多个任务就会出现几类常见问题请求超时设置不当长任务在 gateway 侧被中断并发请求时本地 gateway 没有做排队或限流模型返回格式不标准导致 CLI 端解析失败日志不够详细出问题时无法判断是客户端、网关还是后端模型的问题本地服务重启后端口占用或配置文件丢失。所以我在实际落地时最看重的不只是能不能跑通而是网关能不能在持续使用中保持稳定。单次跑通只能说明流程没有断不代表能够稳定批量使用。3. 新手最容易忽略的不是参数而是输入和输出边界很多人配置这类本地网关时把注意力放在模型名称和端口上却忽略了输入输出边界。这里说的边界不只是字符长度还包括请求上下文、工具调用、流式输出和错误处理。3.1 请求路径和工具来源决定了网关如何路由在这个项目中Codex 和 Claude 标签页最终都会指向同一个 gateway但它们的请求路径可能不同。Codex 可能请求/responsesClaude 标签页可能请求/v1/messages。网关要根据路径来判断它正在和哪个 CLI 通信再决定把请求转换成什么格式。如果你让 Claude 标签页去请求一个 OpenAI 风格的路径网关就很难正确路由。所以我建议先把这些信息列出来工具名称请求路径请求头中的认证方式模型参数字段是否支持流式输出。这样你的 gateway 配置就不是一坨“魔法变量”而是一张清晰的路由表。3.2 上下文长度不是越大越好但也不是越小越安全另一个容易被忽略的地方是上下文长度。本地模型服务如果上下文窗口有限而 Codex 标签页里的任务携带了大量历史信息请求很可能超限。这时你需要判断是后端模型支持长上下文还是需要在 gateway 层做 token 截断。如果 gateway 只是原样转发不做任何处理CLI 端可能会收到一个无法处理的错误。从工程经验看建议分两步处理先确认后端模型服务的最大上下文再在 gateway 配置中设置一个略小于该值的限制超过限制时明确返回错误而不是静默截断。这样至少出问题时你能知道是哪个环节导致的。4. 把一次经验沉淀成可复用流程才是这类方案的长期价值如果只是自己本地调试一次用不用 gateway 其实差别不大。但如果你想在团队内统一接入方式或者在不同项目里反复使用那就需要把经验固化成一套流程。4.1 从单次使用到批量化再到工程化这里有一个实用的递进路径单次使用手动启动 gateway手动配 base URL确认能跑通批量化固定端口和配置模板启动脚本自动拉起 gateway工程化加入日志、健康检查、失败重试、权限控制和版本管理。对于大多数个人开发者来说做到批量化已经能覆盖绝大部分需求。工程化则需要考虑更多比如网关挂了怎么恢复日志怎么轮转配置变更怎么追踪。最怕的是你只停留在“能跑”这个层面然后把同一套手动操作重复几十次每次都要重新排查一遍端口、路径和依赖版本。4.2 设计一个“先用起来、再逐步加固”的落地清单如果你的目标是在 t3 的 Codex 和 Claude 标签页里接入任意 LLM我会建议你按这个顺序走先把 gateway 跑起来确认端口监听正常分别用 Codex 和 Claude 标签页发一条测试消息查看 gateway 日志确认协议转换成功把模型名称、路径、超时时间等关键参数记录成配置文件写一个启动脚本固定环境变量和启动命令测试失败场景比如后端模型服务关闭、请求超限、认证失败再加入日志和告警方便长期观察。这个清单不复杂但每一步都有明确目的前两步验证可连通第三步验证可转换第四到第五步把临时经验固化第六步确认边界第七步才进入长期维护。5. 常见报错与排查链路不管配置多仔细总会有出错的时候。这里整理几条常见排查链路。5.1 首先看现象再看输入和环境当你遇到类似failed while handling codex endpoint /responses. provider rejected the request schema or tool payload这样的报错时很容易被长串英文误导觉得是模型服务拒绝请求。但先别急着改模型端。按照这个顺序排查看现象到底是连接失败、超时、还是返回了错误码。看输入请求体里的 model 字段是否合法messages 格式是否符合预期。看环境gateway 版本、后端服务版本、端口是否被占用。看参数超时时间、并发数、上下文限制是否设置过小。看工具边界这个 CLI 是否只支持某种特定协议gateway 是否真的实现了对应转换。很多时候错误信息里包含endpoint这个词它其实是在提示你请求路径可能不对。如果 gateway 把请求转到了一个并不存在的路径后端自然会拒绝。5.2 502 Bad Gateway 是 gateway 层最常见的报错之一如果你看到unexpected status 502 bad gateway那基本可以确定问题出在 gateway 和后端服务之间的连接上。可能的原因有后端模型服务没有启动gateway 配置的转发地址写错后端服务响应过慢触发了 gateway 超时请求体过大后端拒绝接收。这时打开 gateway 的日志看它实际请求了哪个地址、耗时多久、返回了什么错误。只要日志完整这类问题通常很快能定位。5.3 不要忽视认证和版本兼容很多本地服务不需要认证但如果你接的是一个远程兼容端点认证信息就会变成一个变量。API key 写在配置文件里环境变量覆盖时可能会出现“本地能跑但脚本里跑不通”的诡异问题。版本兼容也是隐藏坑位。OpenAI 的 SDK 版本和 Anthropic 的 SDK 版本都会影响请求格式。如果 gateway 实现时参考的是旧版 API而 CLI 端已经升级到新版就可能出现字段不匹配。我的建议是尽量锁定关键依赖版本把版本号写入文档或配置注释里避免隔了几个月再回来使用时完全不知道当初用的是哪个版本。6. 适合谁用不适合谁用一个方案不能写成万能。这个项目的定位更适合以下场景你同时使用 Codex 和 Claude Code希望统一接入本地模型你在做多模型测试需要快速切换不同后端你想把本地推理服务接入命令行工具而不是通过网页界面使用你愿意花一点时间配置配置文件并接受自己维护一个本地网关。不适合的场景也很清楚如果你只用官方云端服务完全不需要本地 gateway如果你只想运行一个模型且该模型已经提供官方 CLI那也不需要额外加层如果你没有日志排查习惯gateway 反而会变成一个黑盒增加排查难度。还有一个容易被忽视的点本地 gateway 本身会占用端口和内存。如果你在一个资源紧张的机器上跑大型本地模型再叠加 gateway 进程可能会导致模型推理变慢。这种情况下建议把 gateway 和推理服务分离到不同机器或者接受一定的性能损失。7. 我的最终建议回到最初那个同事的问题。他后来换了一种方式先启动一个统一网关再把 Codex 和 Claude Code 的 base URL 指向它。原本反复配置、反复报错的问题很快就稳定下来。这个项目给我的启发是工具链的价值不是绑定某个特定模型而是让你拥有一个稳定的接入层。模型可以换后端可以换但 gateway 的职责始终是连接客户端和模型服务。谁能把这一层维护好谁就能灵活使用不同体系的 LLM。如果你正打算在 Codex 和 Claude 标签页里接入本地模型我的建议是不要一上来就追求复杂的参数调优先让最小链路跑通再逐步固化配置最后才去考虑工程化。先跑通再优化最后长期维护。这个顺序值得记下来。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进