在 Claude Code 中使用 GPT 订阅模型的本地代理实践

October, 24th 2026 11 min read • Markdown •
在 Claude Code 中使用 GPT 订阅模型的本地代理实践

这篇文章记录一种本机接法:保留 Claude Code 的终端、文件工具和子代理,通过本地 CLIProxyAPI 把请求转到 OpenAI 的订阅 OAuth 通道。更新后,同一个 Claude Code 会话里可以选择四个 GPT 模型,保留已有对话和工具历史。

这是一条经过本地验证的第三方集成路径。Claude Code 的原生能力以 Claude 模型为设计目标,代理负责协议转换。本文的账号能力和客户端行为是本次环境的实测,不能直接推广成所有账号、所有版本都支持。

2026 年 11 月 2 日更新:以增强版实践替换旧版正文。验证环境为 Claude Code 2.1.316、CLIProxyAPI 8.0.35。

链路如何分开

text
12345
ccdx shell 函数 → 启动器 → Claude Code
                              ↓ Anthropic 请求格式
                         本机 CLIProxyAPI
                              ↓ 协议转换 + 独立 OAuth
                         OpenAI 订阅模型

如果电脑上已有 Codex 与 DeepSeek 分流桥接,继续保留它自己的程序、端口和系统服务。新入口放在独立目录,使用独立运行状态与 OAuth,不从 Codex 的认证文件复制 Token。两条链路不需要共用一个进程。

程序代码和运行状态也分开。代码可以进入版本控制;本地代理令牌、OAuth、生成配置和完整测试转录只留在私有运行目录。代理默认不记录完整请求内容。

为什么用 shell 函数

我使用 ccdx 作为入口。它启动一个 Python 启动器,再由启动器把认证、模型、上下文窗口等变量仅传给这一次 Claude 子进程。

示意函数如下,项目路径需要替换为自己的代码位置。ccdx 和对应启动器是本次自行封装的入口,并非 Claude Code 或 CLIProxyAPI 自带的命令:

zsh
123
ccdx() {
  /usr/bin/python3 "$HOME/work/gpt-gateway/ccdx/ccdx.py" run "$@"
}

这里不把供应商变量写进 shell 的全局环境,也不直接修改 Claude Code 的用户设置文件。不同入口仍然可以使用各自的供应商。权限模式是另一个独立决策,不应因为换了模型就照抄别人的权限设置。

同一会话切换四个 GPT 模型

当前入口支持:

  • GPT-6.1 Sol
  • GPT-6 Astra
  • GPT-6 Sol
  • GPT-6 Luna

默认启动为 GPT-6.1 Sol / high:

zsh
123
ccdx
ccdx --model gpt-6-astra --effort xhigh
ccdx --model gpt-6-luna --effort low

启动器根据同一份模型策略,生成 Claude Code 原生 modelPicker 设置,通过内联 --settings 传入。菜单显示四个有明确名称的 GPT 项;原生仍会保留一个 Default 项。没有把 GPT 伪装成 Claude,也没有修改客户端二进制。

在会话中输入 /model,上下键选中需要的 GPT 项,按 s 仅用于当前会话。

这里有个容易踩的区别:本次验证的 Claude Code 版本中,Enter 会保存默认模型,直接执行 /model <id> 也会走保存路径。要维持会话之间的隔离,应使用菜单中的 s。旧会话已经启动时,替换启动器不会给它动态增加菜单;新启动的进程才读取更新。

直接打开网关模型发现并不能解决普通 GPT ID 的展示,因为当前客户端发现逻辑会过滤模型名称。显式的原生模型菜单在这个场景更直接。

推理级别如何传递

四个模型当前共同开放 low / medium / high / xhigh / max。推理级别在启动时选择,四个菜单项共同使用该级别。

例如启动器把 gpt-6-astra(xhigh) 交给 CLIProxyAPI,代理再转换为 OpenAI 的 reasoning.effort=xhigh。这样能明确指定上游实际接收到的参数。

Claude 自己的 /effort、菜单左右键和界面指示器不能当作这条链路的真源。代理的模型后缀具有优先级;改变 GPT 推理级别,应使用启动参数。当前代理后缀不支持 ultra,入口会拒绝该值。

为什么统一上下文窗口

会话内换了模型,进程启动时的窗口环境变量并不会自动跟着变化。因此不能把“菜单成功切换”当作窗口也正确更新的证明。

我重新读取了这次账号的订阅模型目录:四个模型声明的最大上下文均为 872,000,默认窗口则分别是 500,000 和 272,000。当前入口以目录声明的最大上下文作为各模型的候选预算,再取四个可选模型预算的最小值,得到共同的 872,000,并按 80% 设置提前压缩窗口,也就是 697,600。这里取的不是默认窗口的最小值。

这是账号目录声明加客户端回读验证,没有做填满 872K 的压力测试。OpenAI API 页面上的模型容量也不能直接套到订阅通道。Claude 本次回读的默认最大输出为 32,000,和模型 API 的最大输出是两个参数。

未来加入能力更小的模型时,启动器应重新取共同预算,避免切换后带着超出目标模型容量的历史继续发送。

子代理如何跟随

普通继承式子代理不再固定为启动时的模型,而是跟随当前主会话模型。自定义代理显式指定模型时,仍保留它自己的选择。

Claude 家族别名通过模型策略集中映射:Fable/Opus 对应 GPT-6 Astra,Sonnet 对应 GPT-6.1 Sol,Haiku 对应 GPT-6 Luna。轻量任务也使用 Luna。这些别名都带上启动时的推理级别,避免误发到代理不支持的 Claude 模型。

本次新版 Claude 的 Agent 是异步任务。验证时要等待任务完成通知,再核对输出文件。主会话先返回一句“仍在执行”并不等于子代理失败,也不能据此宣布任务已经完成。

开机启动和已有会话

代理由 macOS 系统 LaunchDaemon 管理,以普通用户身份运行,开机启动并保持监听。使用本地内置模型目录,避免开机时等待远程目录下载。

登录前可以启动本机监听,不代表此时一定可以调用上游:如果网络依赖一个登录后才启动的本地代理,仍需等待它就绪。

这次菜单更新只涉及启动入口,不需要重新安装服务、重新登录或重启代理。更新前备份启动器,再在隔离副本验证;验收后更新新进程的入口。运行中的 Claude、Codex 和既有桥接继续使用已加载的状态。

验证做到哪一层

验证分成几部分:

  1. 离线边界测试检查子进程环境隔离、菜单生成、共同窗口,以及用户额外设置的保留。
  2. 用真实 Claude 交互终端逐项操作 /model,按 s,比较隔离用户设置文件的字节,确认菜单没有保存全局模型,也没有触发模型生成。
  3. 使用原生 SDK 控制协议,在一个对话中依次经过四个 GPT 模型,再切回首个模型。先记住随机标记,再要求新模型通过 Bash 写文件,按字节比较结果,确认历史和工具结果得以延续。
  4. 检查切换后的默认子代理请求模型,并等待异步完成后核对文件。显式 Haiku 路径另外验证。
  5. 从真实 OpenAI 完成响应读取模型和 reasoning.effort,避免只相信菜单名称或请求参数。

测试脚本的实时验证会消耗订阅额度。报告保存通过和失败的原始记录;偶发 HTTP 500 与后续原生重试成功应同时记录。不能把一次复测通过说成网络已经永远稳定,也不应为偶发故障随意重启正在被其他会话使用的代理。

本次已验证跨模型记忆、工具历史、带 thinking 的历史重放和子代理继承。没有验证实际整机重启或满窗口输入。测试日志与 OAuth 均保留在本地私有目录,本文只描述结构和结果。

参考资料

本文已去除账号、邮箱、真实机器路径、访问令牌、OAuth 内容及个人网络节点。