前言

提示:本文用于记录本人自己使用CC switch时遇到的问题:

随着人工智能的不断发展,AI不可或缺,之前在公司用Claude体验非常好,但是奈何实在太穷,Claude官方的token也就上班能用用,私人没钱用高级货,想着用codex试试,直接使用ccswitch代理转发,没想到全是坑


一、先说说大家最容易踩坑的地方

大家正常情况下是不是以为打开ccswitch的Claude界面开启代理,正常添加自定义配置,选择openAI接口就完事了是吧
在这里插入图片描述
后面再去自己的api接口找找模型列表填完,万事大吉是吧。结果捣鼓了3小时,不是503就是401报错

二、原因分析

1.上面几处配置是“Claude 自定义供应商”和“OpenAI 兼容上游”混在了一起。ccswitch 的 Claude 入口默认按 Anthropic 语义处理,不是把任意 https://…/v1 填进去就能用。它必须额外指定协议转译类型,这次真正能工作的关键字段是 apiFormat = openai_responses。日志里的 503 No available providers,本质上就是它没正确走到可用的上游协议链路。
2. 你手上的 ASXS 页面确实给了对的 key,但 ccswitch 在 Claude 接管时会把“当前 Claude live 配置里的 token”再同步回数据库。你本机之前的 Claude live 配置里还是旧的 shir token,所以我第一次虽然把 endpoint 改到了https://api.asxs.top/v1,请求也确实打到了 ASXS,但上游收到的却是旧token,于是回了 401 invalid_api_key。这也是为什么表面看起来“地址对了、模型也对了”,还是不通。

2.1如何标题排查

  1. 先确认 ccswitch 本地到底支持什么。我从程序和数据库里确认了 Claude provider 不只支持 anthropic,还支持openai_responses / openai_chat。
  2. 再确认你给的页面到底提供了什么。我直接读了页面后端接口,拿到这张 CDK 的真实 remote_api_key 和 remote_web_url
  3. 最后才修 ccswitch。我把当前 Claude provider 改成正确的 openai_responses 格式,同时把数据库里的当前 provider 和接管
  4. 备份里的旧 token 一起修掉,再用本地代理地址 http://127.0.0.1:15721/v1/messages 做真实 Claude 路径测试,并且在重启 ccswitch后又验证了一次。

三 操作指南

前面都是废话,大家要是能解决就不用来看我这个博客了,总结一下:
真正要改的,只有这 2 个地方是“主改动”,第 3 个是“检查项”。

.cc-switch/cc-switch.db
这是最核心的。要改 3 张表:

  • providers
    • 找 app_type=‘claude’
    • 新增或更新一条 Claude provider
    • 关键字段:
      • settings_config.env.ANTHROPIC_AUTH_TOKEN = 你的 remote_api_key
      • settings_config.env.ANTHROPIC_BASE_URL = https://api.abcdefg.top/v1
      • meta.apiFormat = openai_responses
      • is_current = 1
    • 其他 Claude provider 的 is_current 设为 0
  • proxy_config
    • 找 app_type=‘claude’
    • 设成:
      • proxy_enabled = 1
      • enabled = 1
      • live_takeover_active = 1
  • proxy_live_backup
    • 如果这张表里有 app_type=‘claude’ 的记录,也要改
    • 这里最容易坑你
    • 把 original_config.env.ANTHROPIC_AUTH_TOKEN 也改成新的 remote_api_key
    • 把 original_config.env.ANTHROPIC_BASE_URL 改成 https://api.asxs.top
    • 不然重启 ccswitch 时,它会把旧 token 又同步回来

.cc-switch/settings.json
只改一个字段:

  • currentProviderClaude = 你刚才那条 Claude provider 的 id
    这个通常不要手改,它是 ccswitch 接管后自动重写的。
    正确结果应该是:

  • ANTHROPIC_BASE_URL = http://127.0.0.1:15721

  • ANTHROPIC_AUTH_TOKEN = PROXY_MANAGED

也就是说:
这个文件是“结果”,不是“源配置”。

你不用改的文件:

  • D:/program/CCswitch/cc-switch.exe
  • .claude.json

最关键的一句话:

  • 真正决定能不能用的是 .cc-switch/cc-switch.db
  • 真正决定当前选中哪条 Claude provider 的是 .cc-switch/settings.json
  • .claude/settings.json 只是接管后的落地结果
    下面附一段我的 .cc-switch/settings.json
{
  "showInTray": true,
  "minimizeToTrayOnClose": true,
  "enableClaudePluginIntegration": true,
  "skipClaudeOnboarding": false,
  "launchOnStartup": false,
  "silentStartup": false,
  "enableLocalProxy": true,
  "proxyConfirmed": true,
  "streamCheckConfirmed": true,
  "enableFailoverToggle": false,
  "language": "zh",
  "currentProviderClaude": "asxs-claude-1775320526032",
  "currentProviderCodex": "asxscodexapi-1775304677264",
  "skillSyncMethod": "auto"
}

忘了说一句大概率你直接打开.cc-switch/cc-switch.db也找不到我说的“currentProviderClaude = 你刚才那条 Claude provider 的 id”
cc-switch.db(C:/Users/QQ298/.cc-switch/cc-switch.db) 是 SQLite 数据库,不是文本文件,直接双击看一定像乱码。

你有 3 种可行办法:

  1. 用 SQLite 可视化工具打开
  • 推荐 DB Browser for SQLite
  • 打开 cc-switch.db
  • 看表:
    • providers
    • proxy_config
    • proxy_live_backup
  1. 用 Python 直接查
    在 PowerShell 里跑:

四 懒人一步到位

$ErrorActionPreference = "Stop"

# Edit only these values before running.
$ApiKey = "sk-REPLACE_ME"
$Endpoint = "https://api.asxs.top/v1"
$Model = "gpt-5.4"

if (-not $ApiKey.StartsWith("sk-")) {
    throw "Set `$ApiKey at the top of the script first."
}

if (-not $Endpoint.StartsWith("http")) {
    throw "Set `$Endpoint to a full URL, for example https://api.asxs.top/v1"
}

$EndpointV1 = $Endpoint.Trim().TrimEnd("/")
if ($EndpointV1 -notmatch "/v1$") {
    $EndpointV1 = $EndpointV1 + "/v1"
}
$EndpointRoot = $EndpointV1 -replace "/v1$", ""

$HomeDir = [Environment]::GetFolderPath("UserProfile")
$CcSwitchDir = Join-Path $HomeDir ".cc-switch"
$ClaudeDir = Join-Path $HomeDir ".claude"
$DbPath = Join-Path $CcSwitchDir "cc-switch.db"
$SettingsPath = Join-Path $CcSwitchDir "settings.json"
$BackupsDir = Join-Path $CcSwitchDir "backups"
$CcSwitchExe = "D:\program\CCswitch\cc-switch.exe"
$ProviderId = "asxs-claude-fixed"
$ProviderName = "ASXS Claude Proxy"

if (-not (Test-Path -LiteralPath $DbPath)) {
    throw "Missing file: $DbPath"
}

if (-not (Test-Path -LiteralPath $SettingsPath)) {
    throw "Missing file: $SettingsPath"
}

if (-not (Get-Command python -ErrorAction SilentlyContinue)) {
    throw "Python is required for this script."
}

if (-not (Test-Path -LiteralPath $BackupsDir)) {
    New-Item -ItemType Directory -Path $BackupsDir | Out-Null
}

$Timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$DbBackup = Join-Path $BackupsDir ("cc-switch_" + $Timestamp + ".db")
$SettingsBackup = Join-Path $BackupsDir ("settings_" + $Timestamp + ".json")
Copy-Item -LiteralPath $DbPath -Destination $DbBackup -Force
Copy-Item -LiteralPath $SettingsPath -Destination $SettingsBackup -Force

$Proc = Get-Process "cc-switch" -ErrorAction SilentlyContinue
if ($null -ne $Proc) {
    Stop-Process -Id $Proc.Id -Force
    Start-Sleep -Seconds 2
}

$PyCode = @"
import json
import sqlite3
from pathlib import Path

db_path = Path(r"$DbPath")
settings_path = Path(r"$SettingsPath")
provider_id = "$ProviderId"
provider_name = "$ProviderName"
api_key = "$ApiKey"
endpoint_v1 = "$EndpointV1"
endpoint_root = "$EndpointRoot"
model = "$Model"

conn = sqlite3.connect(db_path)
cur = conn.cursor()

settings_config = {
    "effortLevel": "high",
    "env": {
        "ANTHROPIC_AUTH_TOKEN": api_key,
        "ANTHROPIC_BASE_URL": endpoint_v1,
        "ANTHROPIC_DEFAULT_HAIKU_MODEL": "gpt-5.2-codex",
        "ANTHROPIC_DEFAULT_OPUS_MODEL": "gpt-5.4",
        "ANTHROPIC_DEFAULT_SONNET_MODEL": "gpt-5.3-codex",
        "ANTHROPIC_MODEL": model,
    },
}

meta = {
    "commonConfigEnabled": False,
    "endpointAutoSelect": True,
    "apiFormat": "openai_responses",
}

cur.execute("UPDATE providers SET is_current = 0 WHERE app_type = 'claude'")

exists = cur.execute(
    "SELECT 1 FROM providers WHERE id = ? AND app_type = 'claude'",
    (provider_id,),
).fetchone()

if exists:
    cur.execute(
        '''
        UPDATE providers
        SET name = ?,
            settings_config = ?,
            website_url = ?,
            meta = ?,
            is_current = 1,
            in_failover_queue = 0,
            cost_multiplier = '1.0'
        WHERE id = ? AND app_type = 'claude'
        ''',
        (
            provider_name,
            json.dumps(settings_config, ensure_ascii=False, separators=(",", ":")),
            endpoint_v1,
            json.dumps(meta, ensure_ascii=False, separators=(",", ":")),
            provider_id,
        ),
    )
else:
    cur.execute(
        '''
        INSERT INTO providers (
            id, app_type, name, settings_config, website_url, category, created_at, sort_index,
            notes, icon, icon_color, meta, is_current, in_failover_queue, cost_multiplier,
            limit_daily_usd, limit_monthly_usd, provider_type
        ) VALUES (?, 'claude', ?, ?, ?, NULL, NULL, NULL, NULL, NULL, NULL, ?, 1, 0, '1.0', NULL, NULL, NULL)
        ''',
        (
            provider_id,
            provider_name,
            json.dumps(settings_config, ensure_ascii=False, separators=(",", ":")),
            endpoint_v1,
            json.dumps(meta, ensure_ascii=False, separators=(",", ":")),
        ),
    )

cur.execute(
    '''
    UPDATE proxy_config
    SET proxy_enabled = 1,
        enabled = 1,
        live_takeover_active = 1,
        updated_at = datetime('now')
    WHERE app_type = 'claude'
    '''
)

backup_row = cur.execute(
    "SELECT original_config FROM proxy_live_backup WHERE app_type = 'claude'"
).fetchone()
if backup_row:
    original = json.loads(backup_row[0])
    original.setdefault("env", {})
    original["env"]["ANTHROPIC_AUTH_TOKEN"] = api_key
    original["env"]["ANTHROPIC_BASE_URL"] = endpoint_root
    cur.execute(
        "UPDATE proxy_live_backup SET original_config = ? WHERE app_type = 'claude'",
        (json.dumps(original, ensure_ascii=False, separators=(",", ":")),),
    )

settings = json.loads(settings_path.read_text(encoding="utf-8"))
settings["currentProviderClaude"] = provider_id
settings_path.write_text(
    json.dumps(settings, ensure_ascii=False, indent=2) + "\n",
    encoding="utf-8",
)

conn.commit()
conn.close()
"@

$TmpPy = [System.IO.Path]::GetTempFileName() + ".py"
Set-Content -LiteralPath $TmpPy -Value $PyCode -Encoding UTF8

try {
    python $TmpPy
    if ($LASTEXITCODE -ne 0) {
        throw "Python update failed."
    }
} finally {
    Remove-Item -LiteralPath $TmpPy -Force -ErrorAction SilentlyContinue
}

if (Test-Path -LiteralPath $CcSwitchExe) {
    Start-Process -FilePath $CcSwitchExe | Out-Null
    Start-Sleep -Seconds 4
}

try {
    $Headers = @{
        "x-api-key" = "PROXY_MANAGED"
        "anthropic-version" = "2023-06-01"
        "content-type" = "application/json"
    }
    $Body = @{
        model = $Model
        max_tokens = 64
        messages = @(
            @{
                role = "user"
                content = "Reply with exactly OK."
            }
        )
    } | ConvertTo-Json -Depth 10

    $Result = Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:15721/v1/messages" -Headers $Headers -Body $Body -TimeoutSec 90
    $Reply = $null
    if ($Result.content -and $Result.content.Count -gt 0) {
        $Reply = $Result.content[0].text
    }

    Write-Host ""
    Write-Host "Success."
    Write-Host "Provider: $ProviderName"
    Write-Host "Model: $Model"
    Write-Host "Endpoint: $EndpointV1"
    Write-Host "Proxy reply: $Reply"
    Write-Host "DB backup: $DbBackup"
    Write-Host "Settings backup: $SettingsBackup"
} catch {
    Write-Warning "Local update finished, but proxy verification failed."
    Write-Warning $_.Exception.Message
    Write-Host "DB backup: $DbBackup"
    Write-Host "Settings backup: $SettingsBackup"
    exit 1
}

用法很简单:
给文件命名,就命下面这个也行,位置是自己的

  1. 打开 setup-ccswitch-asxs-claude-local.ps1
  2. 只改顶部 3 行

$ApiKey = “sk-REPLACE_ME”
$Endpoint = “https://api.asxs.top/v1”
$Model = “gpt-5.4”

  1. 保存
  2. 在 PowerShell 运行

powershell -ExecutionPolicy Bypass -File C:\Users\QQ298\setup-ccswitch-asxs-claude-local.ps1

它会做这些事:

  • 备份 cc-switch.db
  • 备份 settings.json
  • 把 Claude 当前 provider 改成 ASXS Claude Proxy
  • 把协议设成 openai_responses
  • 打开 Claude 接管
  • 重启 ccswitch
  • 最后用本地 127.0.0.1:15721 做一次 OK 测试
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐