---
title: 在 Claude Code 中使用 GPT 订阅模型的本地代理实践
slug: claude-code-gpt-subscription-local-proxy
date: 2026-10-24
author: Frankie 徐
category: ai
tags: ['claude-code', 'codex', 'gpt', 'oauth', 'local-proxy', 'cliproxyapi']
description: 用本机 CLIProxyAPI 为 Claude Code 转换协议并独立管理 GPT 订阅授权，梳理模型、推理档位、上下文预算、macOS 服务与真实工具调用的验证边界。
permalink: https://www.210k.cc/claude-code-gpt-subscription-local-proxy
---

*保留 Claude Code 的工具链，用本机代理转换协议、独立管理订阅授权，并验证模型、推理档位和上下文配置。*

我平时同时使用 Codex 和 Claude Code。Codex 通过 ChatGPT 账号登录，使用订阅提供的模型额度；Claude Code 则有另一套习惯用的工具、命令和工作流。

这次想解决的问题很具体：保留 Claude Code 的交互和工具执行方式，把模型请求交给 OpenAI 官方 GPT，并使用自己的订阅授权。

实际接通之后，最值得分享的并不是某个环境变量，而是几个容易混淆的边界：客户端与模型、订阅 OAuth 与 API Key、Claude 的 effort 与 GPT 的推理级别，以及开机启动与网络就绪。

> 本次实测环境为 macOS、Claude Code 2.1.310、CLIProxyAPI 8.0.35。验证时间为 2026 年 10 月，后续版本需要重新核对配置与模型能力。

## 先分清 Claude Code 和模型的职责

Claude Code 不只是一个聊天窗口。它负责读取项目、调用工具、执行命令、管理子代理和组织上下文。模型负责根据这些上下文决定接下来做什么、生成什么内容。

因此，换成 GPT 之后，运行的仍是 Claude Code 的工作流。它不会自动变成 Codex CLI，同一模型在两个客户端中的行为也不必完全相同。

这次采用的链路是：

```text
Claude Code
    │ Anthropic Messages 格式
    ▼
本机 CLIProxyAPI
    │ 协议转换与独立 OAuth 认证
    ▼
OpenAI 官方 GPT 模型
```

CLIProxyAPI 在本机提供 Anthropic 兼容接口，负责将请求、工具调用和流式响应转换成上游需要的形式。模型请求随后使用代理自己取得的 OpenAI OAuth 凭据发送。

需要区分技术可行性与厂商支持范围。Anthropic 的网关文档明确说明，不支持通过网关将 Claude Code 路由到非 Claude 模型。这个组合的兼容性，要靠所用代理版本和实际验证来确认。[官方说明](https://code.claude.com/docs/en/llm-gateway)

## 已有 Codex 桥接为什么不能直接接上 Claude Code

这台机器原本已经有一个本地桥接，让 Codex 在 GPT 订阅和 DeepSeek 官方 API 之间分流。

乍看之下，似乎可以把 Claude Code 的地址改到同一个桥接上。但阅读代码之后发现，原桥接只处理 Responses 请求，GPT 登录态由 Codex 客户端随请求传入。桥接本身既不执行 GPT 登录，也不负责刷新 OAuth。

Claude Code 发出的协议不同，手里也没有 Codex 的登录凭据。只改地址，缺少的两项能力仍然缺少。

最后没有在原链路上继续叠代理，而是让两个入口独立运行：

```text
Codex → 原有桥接 → GPT 订阅或 DeepSeek API

Claude Code → 新的本地代理 → GPT 订阅

Claude Code 的 DeepSeek 入口 → DeepSeek 官方兼容接口
```

原来的 Codex 工作方式继续使用。新代理只处理新增的 Claude Code GPT 入口，排查问题时也能明确知道请求经过哪一层。

## 代理有自己的凭据，不复制 Codex 的 Token

订阅 OAuth 与 OpenAI Platform API Key 是两种认证和计费路径。Codex 能使用 ChatGPT 订阅，不意味着把它的 Token 填进任意 API Key 字段，就能获得同样的能力。[Codex 认证文档](https://learn.chatgpt.com/docs/auth)

本次使用 CLIProxyAPI 的 Codex OAuth 登录流程，让它单独完成浏览器授权，使用同一个 ChatGPT 订阅账号。没有复制现有 Codex 的 `auth.json`，也没有让两个程序共同管理同一份 refresh token。

Claude Code 访问本机代理时，使用的是另一把本地访问密钥。这把密钥只负责保护本机接口，不是 OpenAI API Key，也不是订阅的 OAuth Token。

### 安装与版本配置

先安装依赖：

```bash
brew install cliproxyapi
```

代理配置使用 v8 格式，核心结构如下。示例中的占位符需要自行替换，不能直接作为生产配置使用。

```yaml
config-version: 8

server:
  host: "127.0.0.1"
  port: 18317

access:
  api-keys:
    - "<随机生成的本地访问密钥>"

oauth:
  auth-dir: "~/.local/share/ccdx/auth"

management:
  allow-remote: false
  secret-key: ""
  disable-control-panel: true

observability:
  logs:
    debug: false
    request-log: false
```

这里有一个版本坑：旧教程中的顶层 `api-keys` 列表，在 v8 中对应 `access.api-keys`。把不同版本的片段拼到一起，可能得到一份看似合理、实际含义已经变化的配置。

### 独立登录与凭据保存

准备好配置后，执行独立登录：

```bash
cliproxyapi -config /path/to/private/proxy.yaml -codex-login
```

浏览器使用已经登录的订阅账号完成授权即可。配置和 OAuth 文件放在私有目录，运行目录权限设为 `700`，私有配置文件设为 `600`。

我的封装另外保留了一份私有 JSON 作为配置真源，再生成代理配置，避免修改密钥时还要到多个脚本里找副本。

OpenAI 也有面向第三方应用的 Sign in with ChatGPT 订阅授权机制。它有自己的注册、授权和接口要求，不能把任意代理的 Codex 登录都笼统视为采用了这一流程。[正式接入文档](https://developers.openai.com/siwc/token-sharing-open-source)

## 用独立命令启动，保留原来的 Claude Code 配置

我没有把 GPT 代理地址写进 Claude Code 的全局配置，而是封装了一个叫 `ccdx` 的 shell 函数。

`ccdx` 是这次自己定义的入口，不是 Claude Code 或 CLIProxyAPI 自带的命令。shell 函数只调用启动脚本，启动脚本读取私有配置，构造本次 Claude 子进程的环境：

```python
route_model = f"{model}({effort})"
child_env = os.environ.copy()
child_env.pop("ANTHROPIC_API_KEY", None)

child_env.update({
    "ANTHROPIC_BASE_URL": local_gateway_url,
    "ANTHROPIC_AUTH_TOKEN": local_gateway_key,
    "ANTHROPIC_MODEL": route_model,
    "CLAUDE_CODE_SUBAGENT_MODEL": route_model,
})

os.execvpe("claude", ["claude", *claude_args], child_env)
```

这段展示的是封装的核心逻辑。实际入口还统一设置了模型家族别名、轻量模型入口和上下文预算，避免主会话切到了 GPT，子代理却仍请求另一个模型。

这样，新命令的变量只随这次 Claude 进程生效，普通 `claude` 和其他模型入口继续使用各自的设置。密钥也不需要直接写在 shell 函数里。

还有一个值得提前检查的细节：Claude Code 的 settings 文件可以覆盖 shell 中的环境变量。安装前应检查已有的模型地址与认证配置，启动后再用 `/status` 确认实际生效的地址和模型，而不是只看函数里写了什么。[网关配置文档](https://code.claude.com/docs/en/llm-gateway-connect)

权限参数应单独决定。使用 GPT 不要求开启 `--dangerously-skip-permissions`；它控制的是本地执行权限，与模型和订阅认证无关。

## GPT 推理级别要检查上游收到的值

这次没有照搬另一个模型入口的 `max`、`[1m]` 和压缩参数，而是分别验证 GPT 的推理级别与窗口。

本次入口开放五档：

```text
low / medium / high / xhigh / max
```

Claude Code 的 effort 设置与 GPT 的 `reasoning.effort` 不完全对应。尤其是 `xhigh`，不能因为某个客户端只显示 `high`，就假定两者相同。

### 用模型后缀传递推理档位

所用 CLIProxyAPI 版本支持模型后缀，将明确选择的推理档位转换到上游。例如：

```text
代理收到：gpt-6-astra(xhigh)

上游请求：
model = gpt-6-astra
reasoning.effort = xhigh
```

括号后缀是代理约定，不是 OpenAI 官方模型 ID 的一部分。启动器负责验证参数，再统一生成它。

### 在启动时选择，在完成响应中验收

封装后的使用方式是：

```bash
ccdx
ccdx --model gpt-6-astra --effort xhigh
ccdx --model gpt-6-luna --effort low
ccdx --model gpt-6-sol --effort max
```

默认使用 GPT-6.1 Sol、high。主会话和子代理使用同一次启动选定的模型与推理级别。

这个实现将推理级别固定在启动参数中，因此会话内的 `/effort` 不会覆盖模型后缀。需要调整时，重新运行对应的命令。Codex 客户端里出现的 `ultra`，本次代理后缀没有支持，所以入口没有开放这一档。

验证时检查的是上游完成响应中的模型和 `reasoning.effort`，而不是让模型口头回答“你现在用了什么档位”。官方支持范围还要结合模型、接口与账号权限核对。[OpenAI 推理设置](https://developers.openai.com/api/docs/guides/deployment-checklist#set-up-reasoningeffort)

## 上下文预算不能直接复制另一个入口

另一个模型支持大窗口，不代表把同样的 `[1m]` 后缀加到 GPT 入口就合理。Claude Code 对无法识别的模型 ID 还可能默认按 200K 窗口处理。

本次采用明确的客户端预算，并让提前压缩窗口统一取预算的 80%：

| 模型 | 客户端上下文预算 | 提前压缩窗口 |
| --- | ---: | ---: |
| GPT-6.1 Sol | 500,000 | 400,000 |
| GPT-6 Astra | 272,000 | 217,600 |
| GPT-6 Sol | 272,000 | 217,600 |
| GPT-6 Luna | 272,000 | 217,600 |

这些预算参考了本机 Codex 模型目录的默认窗口，不是对各模型最大容量的声明。Claude Code 执行后的 `modelUsage.contextWindow` 回读与这些值一致；这验证了客户端配置生效，没有证明填满整个窗口时的表现。

模型预算集中保存在一处，压缩窗口通过计算生成。切换模型时一起更新窗口，避免仅改变模型名称，仍沿用上一个模型的参数。[Claude Code 自定义窗口说明](https://code.claude.com/docs/en/model-config#correct-the-window-for-a-gateway-or-custom-model-id)

## 开机启动与上游可用是两个条件

### 本地服务启动

后台运行不等于登录前启动。macOS 的 LaunchAgent 通常依赖用户登录；需要让本地代理在会话之前启动，应使用系统 LaunchDaemon，再指定普通用户身份运行程序。

本次服务使用 `RunAtLoad` 和 `KeepAlive`，独立监听回环地址。它与原有桥接采用不同的服务标识和端口，安装、重启和停用都只针对自己。

启动时使用内置模型目录，避免先下载远程目录才开始监听。隔离测试中，即使没有账号凭据、上游代理不可用，本地接口仍能启动并响应。

### 网络出口就绪

不过，如果上游流量需要经过一个登录后才启动的本机网络代理，真正的模型请求仍要等网络代理就绪。LaunchDaemon 可以解决本地服务启动时机，不能让另一个依赖提前可用。

使用 Surge 一类工具时，还要确认回环地址不会被进程规则送到远端代理。相关规则应排在需要它们兜底的进程规则之前：

```text
IP-CIDR,127.0.0.0/8,DIRECT,no-resolve
DOMAIN,localhost,DIRECT
```

这次现有规则已经满足要求，所以没有修改网络配置。确需修改时，先备份，再验证实际命中的路由。

系统级服务已经安装并运行，登录前启动所需的配置也已核对；本次没有通过实际重启电脑完成一次完整开机验收。

## 用真实工具调用验证接入结果

能返回一句话，只能证明链路的一小部分。编程场景还需要工具调用、子代理以及连续多轮交互正常。

### 测试范围与验收条件

本次对四个常用 GPT 模型分别进行了验证：

| 模型 | 五档推理 | Anthropic 流式响应 | Claude 文件操作与子代理 |
| --- | --- | --- | --- |
| GPT-6.1 Sol | 通过 | 通过 | 通过 |
| GPT-6 Astra | 通过，含一次复测 | 通过 | 通过 |
| GPT-6 Sol | 通过，含一次复测 | 通过 | 通过 |
| GPT-6 Luna | 通过 | 通过 | 通过 |

推理测试要求收到 `response.completed`，返回模型与请求一致，返回的 `reasoning.effort` 与选定档位一致，并得到固定文本。Anthropic 格式测试则检查固定文本及 `message_stop`，避免把流中途断开当成成功。

Claude Code 测试使用临时目录：主会话读取文件，调用一个子代理复制内容，随后执行 Bash 比较文件并生成结果。验证脚本检查实际文件、工具调用记录和执行结果，不依赖模型一句“已经完成”。

### 首次失败与复测

首次共执行 28 项检查，其中 26 项通过，两项返回 HTTP 500。日志中的错误是 TLS 握手 EOF；原失败项单独复测后，均返回正确模型、正确推理级别和完整结束事件。

这两次错误没有被当成参数不兼容，也没有通过静默换模型掩盖。首次失败与复测结果分别保留。偶发网络断流可以重试，但一次复测成功不代表出口从此不会中断。

此外，新开终端能够自动加载 `ccdx`，默认模型真实调用成功。原有 Codex 配置和登录文件的内容哈希保持一致，现有桥接也继续通过健康检查。

这次实践最终形成了一个独立入口：模型、推理级别和窗口由启动器统一选择，认证由本地代理管理，工具执行继续交给 Claude Code。后续升级客户端或代理时，可以重复同一套可执行验证，判断变化到底发生在模型、协议转换、工具调用还是网络边界。

## 参考资料

- [CLIProxyAPI 项目](https://github.com/router-for-me/CLIProxyAPI)
- [CLIProxyAPI v8.0.35 源码](https://github.com/router-for-me/CLIProxyAPI/tree/v8.0.35)
- [Claude Code 网关说明](https://code.claude.com/docs/en/llm-gateway)
- [Claude Code 模型与上下文设置](https://code.claude.com/docs/en/model-config)
- [Codex 认证说明](https://learn.chatgpt.com/docs/auth)
- [OpenAI 推理级别设置](https://developers.openai.com/api/docs/guides/deployment-checklist#set-up-reasoningeffort)