关于 claude-code-proxy-patterns
Claude Code Proxy Patterns 是一项介绍本地反向代理模式的 Skill,可按模型将 Claude Code 请求路由到不同提供方。它涵盖模型路由、OAuth 处理、重试、健康检查,以及代理配置和故障排查指引。
主要功能
- 01按模型名称路由请求
- 02支持 Anthropic OAuth 透传
- 03支持兼容 Anthropic 的提供方
- 04介绍令牌缓存与刷新
- 05涵盖重试和并发限制
- 06包含开关与健康检查模式
适用场景
- 01将 Haiku 路由到配置的提供方
- 02排查 OAuth 身份验证失败
- 03接入兼容 Anthropic 的提供方
- 04运维本地 Claude Code 代理
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ terrylica/ cc-skills --skill claude-code-proxy-patterns安装后在 Claude Code 中输入/claude-code-proxy-patterns确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/anti-patterns.mdevolution-log.mdlaunchd-configuration.mdoauth-auto-refresh.mdoauth-internals.mdprovider-compatibility.mdtask-templates.md详细介绍
Claude Code 代理模式
可将 Claude Code 不同模型层级路由到不同后端的多提供商代理。Haiku 路由到成本更低、兼容 Anthropic 的提供商(降低成本、提升速度),Sonnet/Opus 路由到 Anthropic(原生 OAuth 直通)。包含 Go 二进制代理(由 launchd 自动重启)和用于增强可靠性的故障转移包装器。
范围:适用于使用 OAuth 订阅(Max plan)的 Claude Code 本地反向代理。根据请求正文中的模型名称进行路由。
参考实现:
- Go 代理二进制:
/usr/local/bin/claude-proxy(端口 8082)
自进化技能:本技能会在使用过程中不断改进。如果说明有误、参数发生偏移,或需要采用变通方案,请立即修复此文件,不要延后。仅针对真实、可复现的问题进行更新。
何时使用此技能
- 构建或调试 Claude Code 多提供商代理
- 在 OAuth 订阅模式下设置
ANTHROPIC_BASE_URL - 集成兼容 Anthropic 的提供商
- 诊断通过代理时出现的“Oauth not supported”或身份验证失败问题
- 了解 Claude Code 如何存储和传输 OAuth 令牌
请勿用于:仅使用 Claude API 密钥的配置(无需代理)、MCP 服务开发、Claude Code hooks(在工具层而非 API 层运行),或企业 HTTPS 代理转发。
架构
Claude Code (OAuth/Max subscription)
|
| ANTHROPIC_BASE_URL=http://127.0.0.1:8082 (Go proxy)
| (unset ANTHROPIC_API_KEY to avoid auth conflict)
v
+----------------------------------+
| Go proxy (:8082) |
| launchd managed, auto-restart |
+----------------------------------+
|
| model =
| claude-haiku-
| 4-5-20251001
v
+-----------+
| 3rd-party |
| provider |
+-----------+
端口配置:
:8082- Go 代理(入口点,由 launchd 管理,自动重启)
Go 代理使用 cenkalti/backoff/v4 实现内置重试逻辑。
代理会从每个 /v1/messages 请求正文中读取 model 字段。如果该字段与配置的 Haiku 模型 ID 匹配,请求就会发送到配置的提供商。其他所有请求都会转发到真正的 Anthropic,并通过 OAuth 直通。
可行模式
WP-01:读取 Keychain OAuth 令牌
从 macOS Keychain 中读取 Claude Code 存储的 OAuth 令牌。
服务:"Claude Code-credentials"(注意连字符前有一个空格) 账户:通过 getpass.getuser() 获取当前用户名
import subprocess, json, getpass
result = subprocess.run(
["security", "find-generic-password",
"-s", "Claude Code-credentials",
"-a", getpass.getuser(), "-w"],
capture_output=True, text=True, timeout=5, check=False,
)
if result.returncode == 0:
data = json.loads(result.stdout.strip())
oauth = data.get("claudeAiOauth")
完整详解请参阅 references/oauth-internals.md。
WP-02:令牌 JSON 结构
Keychain 会存储一个包含 claudeAiOauth 键的 JSON 信封。
{
"claudeAiOauth": {
"accessToken": "eyJhbG...",
"refreshToken": "rt_...",
"expiresAt": 1740268800000,
"subscriptionType": "claude_pro_2025"
}
}
注意:expiresAt 的单位是毫秒(Unix 时间戳 _ 1000)。请与 time.time() _ 1000 比较,或除以 1000 转换为秒。
WP-03:OAuth Beta 标头
OAuth 令牌身份验证必须使用 anthropic-beta: oauth-2025-04-20 标头。否则,Anthropic 会拒绝 Bearer 令牌。
重要:将此标头追加到现有 beta 标头中,不要替换它们。
# proxy.py:304-308
existing_beta = original_headers.get("anthropic-beta", "")
beta_parts = [b.strip() for b in existing_beta.split(",") if b.strip()] if existing_beta else []
if "oauth-2025-04-20" not in beta_parts:
beta_parts.append("oauth-2025-04-20")
target_headers["anthropic-beta"] = ",".join(beta_parts)
WP-04:ANTHROPIC_API_KEY=proxy-managed
在 OAuth 模式下,仅设置 ANTHROPIC_BASE_URL 并不足够。Claude Code 还必须看到已设置的 ANTHROPIC_API_KEY,才能从仅 OAuth 模式切换到 API 密钥模式,之后才会遵循 ANTHROPIC_BASE_URL。
# In .zshenv (managed by proxy-toggle)
export ANTHROPIC_BASE_URL="http://127.0.0.1:8082"
export ANTHROPIC_API_KEY="proxy-managed"
"proxy-managed" 是一个虚拟标记值。代理会拦截它(第 324 行),绝不会将它转发给提供商。
WP-05:带 TTL 的 OAuth 令牌缓存
将令牌缓存 5 分钟,避免重复调用 Keychain 子进程。
# proxy.py:117-118
_oauth_cache: dict = {"token": None, "expires_at": 0.0, "fetched_at": 0.0}
_OAUTH_CACHE_TTL = 300 # Re-read from Keychain every 5 minutes
以下情况会触发缓存失效:
- TTL 已过期(距上次获取已超过 5 分钟)
- 令牌的
expiresAt已过期 - 代理重启
WP-06:身份验证优先级链
对于发往 Anthropic 的请求,代理会按顺序尝试多个身份验证来源。
1. REAL_ANTHROPIC_API_KEY env var -> x-api-key header (explicit config)
2. Keychain OAuth token -> Authorization: Bearer + anthropic-beta
3. ~/.claude/.credentials.json -> Authorization: Bearer (plaintext fallback)
4. Forward client Authorization -> Pass through whatever Claude Code sent
5. No auth -> Will 401 (expected)
实现请参阅 proxy.py:293-314。
WP-07:count_tokens 端点身份验证
/v1/messages/count_tokens 端点需要与 /v1/messages 相同的身份验证。Claude Code 会调用此端点进行预检令牌计数。此处缺少身份验证会导致静默失败。对于未实现此端点的非 Anthropic 提供商,返回 501。
WP-08:兼容 Anthropic 的提供商 URL
支持 Anthropic /v1/messages API 格式的第三方提供商。
| 提供商 | 基础 URL | 备注 |
|---|---|---|
| (你的提供商) | https://<provider-host>/anthropic | 检查:模型回显、额外内容块、cache_control、count_tokens |
完整列表请参阅 references/provider-compatibility.md。
WP-09:并发信号量
按提供商进行速率限制,防止第三方 API 不堪重负。Anthropic 不使用信号量(他们会自行处理速率限制)。
# proxy.py:207-209
MAX_CONCURRENT_REQUESTS = int(os.getenv("MAX_CONCURRENT_REQUESTS", "5"))
haiku_semaphore = asyncio.Semaphore(MAX_CONCURRENT_REQUESTS)
opus_semaphore = asyncio.Semaphore(MAX_CONCURRENT_REQUESTS)
sonnet_semaphore = asyncio.Semaphore(MAX_CONCURRENT_REQUESTS)
WP-10:proxy-toggle 启用/禁用
proxy-toggle 脚本以原子方式管理 .zshenv 条目和标志文件。
~/.claude/bin/proxy-toggle enable # Adds env vars, creates flag file, checks health
~/.claude/bin/proxy-toggle disable # Removes env vars, removes flag file
~/.claude/bin/proxy-toggle status # Shows routing flag, proxy process, .zshenv state
重要提示:切换后必须重启 Claude Code,因为 ANTHROPIC_BASE_URL 会在启动时读取。
WP-11:健康检查端点
/health 端点会返回提供商配置状态,以便进行监控。
curl -s http://127.0.0.1:8082/health | jq .
WP-12:支持重试的 Go 代理
Go 代理内置重试,使用 cenkalti/backoff/v4(指数退避:500ms -> 1s -> 2s,最长耗时 5s)。
import "github.com/cenkalti/backoff/v4"
backoffConfig := backoff.NewExponentialBackOff(
backoff.WithInitialInterval(500 * time.Millisecond),
backoff.WithMultiplier(2),
backoff.WithMaxInterval(2 * time.Second),
backoff.WithMaxElapsedTime(5 * time.Second),
)
err := backoff.Retry(operation, backoffConfig)
位置:/usr/local/bin/claude-proxy | 环境:.zshenv 中的 ANTHROPIC_BASE_URL=http://127.0.0.1:8082
WP-13:Launchd 服务配置
Go 代理以 macOS launchd 守护进程的形式运行,支持崩溃后自动重启并在系统启动时运行。
Plist:/Library/LaunchDaemons/com.example.claude-proxy.plist
完整的 plist 配置、命令、验证清单和调试说明:references/launchd-configuration.md
WP-14:OAuth 令牌自动刷新
后台 goroutine 每隔 30 分钟刷新一次 OAuth 令牌,在令牌过期前 5 分钟进行刷新。如果 API 刷新失败,则回退到 Keychain。
完整实现和刷新逻辑:references/oauth-auto-refresh.md
反模式摘要
完整详情和代码示例:references/anti-patterns.md
| ID | 严重程度 | 易踩问题 | 修复方案 |
|---|---|---|---|
| CCP-01 | HIGH | 只设置 ANTHROPIC_BASE_URL,未设置 ANTHROPIC_API_KEY | 设置 ANTHROPIC_API_KEY=proxy-managed |
| CCP-02 | HIGH | 缺少 anthropic-beta: oauth-2025-04-20 标头 | 将其追加到现有 beta 标头 |
| CCP-03 | MEDIUM | 使用 /api/oauth/claude_cli/create_api_key 端点 | 该端点需要 org:create_api_key 作用域(用户只有 user:inference) |
| CCP-04 | HIGH | 使用小写密钥链服务名 "claude-code-credentials" | 实际名称中包含空格:"Claude Code-credentials" |
| CCP-05 | MEDIUM | 将 ~/.claude/.credentials.json 作为主要凭据来源读取 | 密钥链是 SSoT;凭据文件是过期的备用来源 |
| CCP-06 | HIGH | 硬编码 OAuth 令牌 | 令牌会过期;应动态读取并缓存 |
| CCP-07 | HIGH | 在代理/钩子中使用 gh auth token | 会引发进程风暴(递归启动) |
| CCP-08 | HIGH | 设置 OAuth 令牌时仍在环境变量中设置 ANTHROPIC_API_KEY | Claude Code 会发出身份验证冲突警告;请取消设置 |
| CCP-09 | MEDIUM | 向不支持 cache_control 参数的提供商发送该参数 | 提供商会拒绝该参数;请从 allowedParams 中移除 |
| CCP-10 | MEDIUM | 代理运行时将 ANTHROPIC_API_KEY 设置为真实密钥 | 代理会将其转发给所有提供商,导致密钥泄露 |
| CCP-11 | MEDIUM | 未处理 /v1/messages/count_tokens | 会导致预检请求身份验证失败 |
| CCP-12 | LOW | 在 0.0.0.0 上运行代理 | 为安全起见,请绑定到 127.0.0.1 |
TodoWrite 任务模板
设置、添加提供商、诊断和禁用模板:references/task-templates.md
参考实现
可正常运行的生产部署(Go 代理为主要实现):
| 文件 | 用途 |
|---|---|
/usr/local/bin/claude-proxy | Go 代理二进制文件(约 960 行) |
~/.claude/tools/claude-code-proxy-go/main.go | Go 代理源码 |
~/.claude/tools/claude-code-proxy-go/oauth_refresh.go | OAuth 自动刷新(80 行) |
~/.claude/tools/claude-code-proxy-go/.env | 提供商配置(chmod 600) |
/Library/LaunchDaemons/com.example.claude-proxy.plist | launchd 配置 |
~/.zshenv | 环境变量(ANTHROPIC_BASE_URL) |
修改后检查清单
修改此技能后:
- 反模式表与 references/anti-patterns.md 一致
- 已根据 proxy.py 源码验证有效模式
- 示例中没有硬编码的 OAuth 令牌
- Beta 标头版本为当前版本(
oauth-2025-04-20) - 所有内部链接均使用相对路径(
./references/...) - 链接验证器通过
- 技能验证器通过
- 将更改追加到 references/evolution-log.md
故障排除
| 问题 | 原因 | 解决方案 |
|---|---|---|
| Claude Code 忽略 ANTHROPIC_BASE_URL | 缺少 ANTHROPIC_API_KEY(CCP-01) | 在 .zshenv 中设置 ANTHROPIC_API_KEY=proxy-managed |
| Anthropic 返回 401 Unauthorized | 缺少 anthropic-beta 标头(CCP-02) | 确保代理添加 oauth-2025-04-20 |
| Keychain 读取结果为空 | 服务名称错误(CCP-04) | 使用 "Claude Code-credentials"(包含空格) |
| 代理转发真实 API 密钥 | ANTHROPIC_API_KEY 设置为真实密钥(CCP-10) | 使用 proxy-managed 哨兵值 |
| count_tokens 身份验证失败 | 缺少端点处理程序(CCP-11) | 代理必须处理 /v1/messages/count_tokens |
| 网络可访问代理 | 绑定到 0.0.0.0(CCP-12) | 仅绑定到 127.0.0.1 |
| 启用时进程风暴 | 钩子中包含 gh auth 令牌(CCP-07) | 切勿从钩子/凭据助手中调用 gh CLI |
| 令牌 5 分钟后过期 | 缓存 TTL(WP-05) | 正常行为;代理会重新从 Keychain 读取 |
| Claude Code 中出现身份验证冲突警告 | 设置了 ANTHROPIC_API_KEY(CCP-08) | 在 .zshenv 中取消设置 ANTHROPIC_API_KEY |
| cache_control.ephemeral.scope 错误 | 提供方不支持 cache_control(CCP-09) | 从 allowedParams 中移除 cache_control |
执行后反思
此技能完成后,请在结束前检查:
- 命令是否成功? — 如果没有,请修复导致失败的指令或错误表。
- 参数或输出是否发生变化? — 如果底层工具的接口发生变化,请相应更新 Usage 示例和 Parameters 表。
- 是否需要变通处理? — 如果你必须临时调整(使用不同的标志、增加额外步骤),请更新此 SKILL.md,避免下次调用时需要采用相同的变通方法。
仅在问题确实存在且可复现时才更新,不要更新推测性问题。