1
0
Files
nex/docs/analysis_reference/analysis_cc-switch.md

42 KiB
Raw Permalink Blame History

CC-Switch API 转换层详细分析报告

1. 项目概述

CC-Switch 是一个基于 Tauri (Rust 后端 + Web 前端) 的桌面应用用于管理多个大模型编程工具Claude Code、Codex CLI、Gemini CLI 等)的配置切换。其核心功能之一是本地 HTTP 代理服务器,在客户端与上游 LLM API 之间充当协议翻译层,使仅支持特定 API 格式的客户端(如 Claude Code 只支持 Anthropic Messages API能通过代理访问不同协议的后端服务。

核心能力

  • Anthropic Messages API 请求/响应转换为 OpenAI Chat CompletionsOpenAI Responses APIGoogle Gemini Native 等格式
  • 支持流式 (SSE)非流式两种模式的实时协议翻译
  • 内置故障转移、熔断器、Thinking 自修复、Copilot 请求优化等企业级特性
  • 支持 GitHub Copilot、ChatGPT Plus/Pro (Codex OAuth) 等动态 Token 认证的供应商

与同类项目的核心差异

CC-Switch 是唯一的桌面端代理工具(非服务端部署),面向个人开发者场景。其协议转换是单方向锚定的——以 Anthropic Messages API 为唯一"客户端协议",向多种上游协议转换。相比 One-API / New-API 的多协议互转、LiteLLM 的 OpenAI-centric 统一格式CC-Switch 的转换矩阵更聚焦但深度更大(如 Gemini Shadow Store、Copilot Optimizer 等属于独有的复杂机制)。


2. 技术架构总览

┌─────────────────────────────────────────────────────────────────┐
│                    CC-Switch Tauri 桌面应用                       │
├─────────────────────────────────────────────────────────────────┤
│  Web 前端 (React)  │          Rust 后端 (Tauri)                  │
│                    │  ┌──────────────────────────────────────┐   │
│  - 供应商管理      │  │       proxy/ 模块 (Axum HTTP Server)  │   │
│  - 配置切换        │  │                                      │   │
│  - 用量展示        │  │  ┌──────────┐   ┌────────────────┐   │   │
│                    │  │  │ server.rs│──▶│  handlers.rs   │   │   │
│                    │  │  │ (路由层)  │   │  (请求分发器)   │   │   │
│                    │  │  └──────────┘   └───────┬────────┘   │   │
│                    │  │                         │             │   │
│                    │  │  ┌──────────────────────▼─────────┐   │   │
│                    │  │  │       forwarder.rs (转发器)      │   │   │
│                    │  │  │  - 供应商选择 / 故障转移         │   │   │
│                    │  │  │  - 请求体预处理 / 参数过滤       │   │   │
│                    │  │  │  - Thinking 自修复 / Copilot优化  │   │   │
│                    │  │  └──────────────┬─────────────────┘   │   │
│                    │  │                 │                     │   │
│                    │  │  ┌──────────────▼─────────────────┐   │   │
│                    │  │  │     providers/ (适配器层)        │   │   │
│                    │  │  │                                 │   │   │
│                    │  │  │  ┌─────────┐  ┌──────────────┐  │   │   │
│                    │  │  │  │adapter.rs│  │   claude.rs  │  │   │   │
│                    │  │  │  │(Trait定义)│  │ (Claude适配器)│  │   │   │
│                    │  │  │  └─────────┘  ├──────────────┤  │   │   │
│                    │  │  │               │   codex.rs    │  │   │   │
│                    │  │  │               ├──────────────┤  │   │   │
│                    │  │  │               │   gemini.rs   │  │   │   │
│                    │  │  │               └──────────────┘  │   │   │
│                    │  │  └─────────────────────────────────┘   │   │
│                    │  │                                        │   │
│                    │  │  ┌─────────────────────────────────┐   │   │
│                    │  │  │   转换层 (transform/ 模块)        │   │   │
│                    │  │  │                                 │   │   │
│                    │  │  │  transform.rs         (→Chat)   │   │   │
│                    │  │  │  transform_responses.rs (→Resp)  │   │   │
│                    │  │  │  transform_gemini.rs    (→Gemini)│   │   │
│                    │  │  └─────────────────────────────────┘   │   │
│                    │  │                                        │   │
│                    │  │  ┌─────────────────────────────────┐   │   │
│                    │  │  │   流式转换层 (streaming/ 模块)     │   │   │
│                    │  │  │                                 │   │   │
│                    │  │  │  streaming.rs          (Chat)   │   │   │
│                    │  │  │  streaming_responses.rs (Resp)   │   │   │
│                    │  │  │  streaming_gemini.rs    (Gemini) │   │   │
│                    │  │  └─────────────────────────────────┘   │   │
│                    │  │                                        │   │
│                    │  │  ┌─────────────────────────────────┐   │   │
│                    │  │  │   辅助模块                        │   │   │
│                    │  │  │  gemini_shadow.rs  (状态回放)     │   │   │
│                    │  │  │  gemini_schema.rs  (Schema转换)   │   │   │
│                    │  │  │  copilot_optimizer.rs (Copilot优化)│   │   │
│                    │  │  │  thinking_rectifier.rs (Thinking修复)│   │
│                    │  │  │  thinking_budget_rectifier.rs     │   │   │
│                    │  │  │  cache_injector.rs (缓存注入)     │   │   │
│                    │  │  │  body_filter.rs   (私有参数过滤)   │   │   │
│                    │  │  │  model_mapper.rs  (模型名映射)     │   │   │
│                    │  │  │  gemini_url.rs    (Gemini URL构建)│   │   │
│                    │  │  └─────────────────────────────────┘   │   │
│                    │  └──────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘

源文件规模proxy/ 目录共 53 个源文件,其中核心转换层 6 个文件合计约 7,700 行,辅助模块 7 个文件合计约 4,000 行,转发器和处理器合计约 3,700 行。


3. 路由层 (server.rs)

文件: src-tauri/src/proxy/server.rs (354 行)

代理服务器基于 Axum 框架构建,使用手动 hyper HTTP/1.1 accept loop通过 TCP peek() 捕获原始请求头大小写,存入 OriginalHeaderCases 扩展供转发器使用)。

路由表

路由路径 处理器 协议
/v1/messages, /claude/v1/messages handle_messages Claude (Anthropic Messages API)
/chat/completions, /v1/chat/completions, /v1/v1/chat/completions, /codex/v1/chat/completions handle_chat_completions OpenAI Chat Completions
/responses, /v1/responses, /v1/v1/responses, /codex/v1/responses handle_responses OpenAI Responses API
/responses/compact, /v1/responses/compact, /v1/v1/responses/compact, /codex/v1/responses/compact handle_responses_compact Responses Compact (Codex CLI 远程压缩透传)
/v1beta/*path, /gemini/v1beta/*path handle_gemini Gemini (Google AI API)
/health health_check 健康检查
/status get_status 状态查询

关键设计细节:

  • 多前缀兼容: 裸路径 (/v1/...) 和带供应商前缀 (/claude/, /codex/, /gemini/) 均支持,兼容不同客户端的 base_url 配置
  • 双前缀容错: /v1/v1/... 路由处理客户端双重前缀的配置错误
  • 无前缀路由: /chat/completions/responses 不带 /v1/,适配 Codex CLI 的特定 base_url 配置
  • 请求体限制: DefaultBodyLimit::max(200MB),支撑大体积上下文和图片请求

4. 适配器层 (Adapter Pattern)

4.1 ProviderAdapter Trait

文件: src-tauri/src/proxy/providers/adapter.rs (50 行)

所有供应商适配器都实现统一的 ProviderAdapter trait

pub trait ProviderAdapter: Send + Sync {
    fn name(&self) -> &'static str;
    fn extract_base_url(&self, provider: &Provider) -> Result<String, ProxyError>;
    fn extract_auth(&self, provider: &Provider) -> Option<AuthInfo>;
    fn build_url(&self, base_url: &str, endpoint: &str) -> String;
    fn get_auth_headers(&self, auth: &AuthInfo) -> Vec<(HeaderName, HeaderValue)>;
    fn needs_transform(&self, _provider: &Provider) -> bool;         // 默认 false
    fn transform_request(&self, body: Value, provider: &Provider) -> Result<Value, ProxyError>;  // 默认透传
    fn transform_response(&self, body: Value) -> Result<Value, ProxyError>;  // 默认透传
}

其中 needs_transform()transform_request()transform_response() 提供默认实现(透传),供应商适配器仅需覆写需要的方法。

4.2 供应商类型枚举 (ProviderType)

文件: src-tauri/src/proxy/providers/mod.rs (515 行)

系统定义 8 种供应商类型,决定认证和请求处理逻辑:

ProviderType 说明 认证策略 是否需要转换
Claude Anthropic 官方 API Anthropic (x-api-key) 视 api_format 决定
ClaudeAuth Claude 中转服务 (仅 Bearer) ClaudeAuth 视 api_format 决定
Codex OpenAI Codex Bearer
Gemini Google Gemini API (API Key) Google (x-goog-api-key)
GeminiCli Gemini CLI (OAuth) GoogleOAuth
OpenRouter OpenRouter 中转 Bearer 否 (已支持原生)
GitHubCopilot GitHub Copilot GitHubCopilot (动态 Token) → OpenAI Chat/Responses
CodexOAuth ChatGPT Plus/Pro 反代 CodexOAuth (动态 Token) → OpenAI Responses

适配器工厂 get_adapter_for_provider_type() 的映射逻辑:

  • Claude, ClaudeAuth, OpenRouter, GitHubCopilot, CodexOAuthClaudeAdapter
  • CodexCodexAdapter
  • Gemini, GeminiCliGeminiAdapter

4.3 API 格式识别

文件: src-tauri/src/proxy/providers/claude.rs (1313 行)

Claude 适配器通过 get_claude_api_format() 函数识别需要使用的 API 格式,优先级为:

  1. Codex OAuth 强制: meta.provider_type == "codex_oauth"openai_responses
  2. meta.apiFormat (SSOT): meta.api_format 字段 → openai_chat / openai_responses / gemini_native
  3. settings_config.api_format: 旧版兼容
  4. openrouter_compat_mode: 旧版 OpenRouter 兼容开关 → openai_chat
  5. 默认: anthropic (直接透传)

4.4 认证策略

文件: src-tauri/src/proxy/providers/auth.rs (259 行)

7 种认证策略覆盖所有上游服务:

策略 Header 注入
Anthropic x-api-key: <key> + anthropic-version: 2023-06-01 (版本由转发器注入)
ClaudeAuth Authorization: Bearer <key> (无 x-api-key)
Bearer Authorization: Bearer <key>
Google x-goog-api-key: <key>
GoogleOAuth Authorization: Bearer <token> + x-goog-client: GeminiCLI/1.0
GitHubCopilot Authorization: Bearer <token> + 多个 Copilot 专有 Header (openai-intent, x-initiator, x-interaction-type, x-request-id, x-agent-task-id 等约 10 个)
CodexOAuth Authorization: Bearer <token> + originator: cc-switch + chatgpt-account-id

动态认证机制: GitHub Copilot 和 Codex OAuth 的 Token 是动态获取的,通过 CopilotAuthManagerCodexOAuthAuth 分别管理 Token 的刷新和多账户绑定(通过 meta.authBinding 实现供应商到账户的映射)。


5. 转换层详解 — 核心协议转换

5.1 Anthropic ↔ OpenAI Chat Completions

文件: src-tauri/src/proxy/providers/transform.rs (1193 行)

请求转换: anthropic_to_openai(body) → Value

将 Anthropic Messages API 请求转换为 OpenAI Chat Completions 请求。

字段映射:

Anthropic 字段 OpenAI 字段 说明
system (string) messages[0].role = "system" System prompt 提升为 system role message
system (array) messages[0].role = "system" (合并) 多个 system message 合并,冲突的 cache_control 被丢弃
messages messages 按角色转换内容格式
max_tokens max_tokens / max_completion_tokens o-series 模型使用 max_completion_tokens
temperature temperature 直接透传
top_p top_p 直接透传
stop_sequences stop 直接透传
tools[].input_schema tools[].function.parameters Schema 格式转换,过滤 BatchTool,移除 format: "uri"
tool_choice tool_choice 直接透传
thinking + output_config.effort reasoning_effort 仅对支持推理的模型注入 (o-series, GPT-5+)

消息内容转换:

  • text{type: "text", text: "..."}
  • image{type: "image_url", image_url: {url: "data:...;base64,..."}} (data URI)
  • tool_usetool_calls[{id, type: "function", function: {name, arguments}}]
  • tool_result{role: "tool", tool_call_id: "...", content: "..."} (独立 tool role 消息)
  • thinking → 丢弃

推理强度 (reasoning_effort) 映射规则:

Anthropic thinking 配置 OpenAI reasoning_effort
type: "adaptive" "xhigh"
type: "enabled" + budget < 4000 "low"
type: "enabled" + budget 4000-15999 "medium"
type: "enabled" + budget >= 16000 "high"
type: "enabled" + 无 budget "high"
output_config.effort: "max" "xhigh"

特殊处理:

  • 多个 system message 自动合并,冲突的 cache_control 被丢弃
  • 支持 cache_control 在 system message、text block、tool 上的透传
  • clean_schema() 清理 JSON Schema 中 OpenAI 不支持的 format: "uri" 等字段

响应转换: openai_to_anthropic(body) → Value

OpenAI 字段 Anthropic 字段
choices[0].message.content content[{type: "text"}]
choices[0].message.tool_calls content[{type: "tool_use", id, name, input}]
choices[0].message.function_call content[{type: "tool_use"}] (旧格式兼容)
choices[0].message.refusal content[{type: "text", text: refusal}]
choices[0].finish_reason stop_reason (stop→end_turn, length→max_tokens, tool_calls→tool_use)
usage.prompt_tokens usage.input_tokens
usage.completion_tokens usage.output_tokens
usage.prompt_tokens_details.cached_tokens usage.cache_read_input_tokens

5.2 Anthropic ↔ OpenAI Responses API

文件: src-tauri/src/proxy/providers/transform_responses.rs (1329 行)

Responses API 是 OpenAI 2025 年推出的新一代 API采用扁平化的 input/output 结构。

请求转换: anthropic_to_responses(body, cache_key, is_codex_oauth) → Value

Anthropic 字段 Responses API 字段 说明
system instructions System prompt 转为 instructions 字段
messages input 消息数组转为扁平化的 input items
max_tokens max_output_tokens 统一使用 max_output_tokens
tools[].input_schema tools[].parameters Schema 格式转换,移除 cache_control
tool_choice.type = "any" tool_choice = "required" 映射工具选择策略
tool_choice.type = "tool" tool_choice = {type: "function", name} 强制指定工具
thinking reasoning.effort 推理强度映射

消息结构转换核心差异 — 消息从"嵌套在 role message 中"变为"独立 top-level item"

  • tool_use 从 assistant message 中提升为独立的 function_call item:
    // Anthropic
    {"role": "assistant", "content": [{"type": "tool_use", "id": "call_1", ...}]}
    // Responses API
    {"type": "function_call", "call_id": "call_1", ...}
    
  • tool_result 从 user message 中提升为独立的 function_call_output item:
    // Anthropic
    {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "call_1", ...}]}
    // Responses API
    {"type": "function_call_output", "call_id": "call_1", ...}
    
  • 文本类型区分: user 的 text → input_text, assistant 的 text → output_text

Codex OAuth (ChatGPT Plus/Pro 反代) 特殊协议约束:

is_codex_oauth = true 时,需满足 ChatGPT 后端的协议限制:

  • store: false — 不允许服务端持久化
  • include: ["reasoning.encrypted_content"] — 保持多轮 reasoning 上下文ChatGPT 后端通过加密 reasoning blob 维持推理状态)
  • 删除 max_output_tokenstemperaturetop_p (ChatGPT 后端不支持这些参数)
  • 兜底注入 instructions("")、tools([])、parallel_tool_calls(false) 默认值
  • 强制 stream: true (CC-Switch SSE 解析层只支持流式)

响应转换: responses_to_anthropic(body) → Value

Responses API 字段 Anthropic 字段
output[type="message"].content[type="output_text"] content[{type: "text"}]
output[type="function_call"] content[{type: "tool_use", id: call_id, name, input}]
output[type="reasoning"].summary content[{type: "thinking", thinking: ...}]
output[type="message"].content[type="refusal"] content[{type: "text"}]
status = "completed" (无 tool_use) stop_reason: "end_turn"
status = "completed" (有 function_call) stop_reason: "tool_use"
status = "incomplete" (reason: max_output_tokens) stop_reason: "max_tokens"
usage.input_tokens usage.input_tokens
usage.input_tokens_details.cached_tokens usage.cache_read_input_tokens

5.3 Anthropic ↔ Google Gemini Native

文件: src-tauri/src/proxy/providers/transform_gemini.rs (2152 行)

将 Anthropic Messages 请求转换为 Gemini generateContent 格式。这是三个转换中最复杂的,涉及有状态管理。

请求转换: anthropic_to_gemini_with_shadow(body, shadow_store, provider_id, session_id) → Value

Anthropic 字段 Gemini 字段 说明
system systemInstruction.parts[{text}] System prompt 转为 systemInstruction
messages contents[{role, parts}] role: assistant→model, 其他→user
max_tokens generationConfig.maxOutputTokens
temperature generationConfig.temperature
top_p generationConfig.topP
stop_sequences generationConfig.stopSequences
tools[].input_schema tools[].functionDeclarations[] 转为 Gemini FunctionDeclaration
tool_choice toolConfig.functionCallingConfig auto→AUTO, none→NONE, any→ANY, tool→ANY+allowedFunctionNames

消息内容转换:

  • text{text: "..."}
  • image (base64) → {inlineData: {mimeType, data}}
  • document (base64) → {inlineData: {mimeType, data}}
  • tool_use{functionCall: {name, args, id}} (仅 assistant)
  • tool_result{functionResponse: {name, response, id}} (通过 id→name 映射解析)
  • thinking / redacted_thinking → 丢弃

Shadow Store (状态回放机制)

文件: src-tauri/src/proxy/providers/gemini_shadow.rs (389 行)

Gemini 的 thoughtSignaturefunctionCall.id 是有状态的需要跨轮次保留。CC-Switch 实现了 GeminiShadowStore 来解决此问题:

  • 存储结构: 以 (provider_id, session_id) 为键,存储 GeminiAssistantTurn(包含 assistant_content + tool_calls 及 thoughtSignature
  • 容量限制: 默认 200 个 session每 session 64 轮对话,超出后 LRU 淘汰最旧 session
  • 回放机制: 在后续请求中,将存储的 shadow turn包含 thoughtSignature 和原始 Gemini 格式内容)替换到对应 assistant 消息的位置,确保多轮对话的 functionResponsethoughtSignature 能正确传递
  • 线程安全: 使用 std::sync::RwLock(非 tokio async lock因为 shadow store 操作很快

工具参数修正 (Tool Call Rectification)

Gemini 模型有时会将工具调用的参数结构"展平"或混淆(如将 {skill: "git-commit"} 发为 {name: "git-commit"})。系统通过 AnthropicToolSchemaHints 机制:

  1. 从请求中的 tools[].input_schema 提取预期参数结构
  2. 在响应中检测并修正参数名映射 (如 nameskill)
  3. 处理 parameters 嵌套展平问题
  4. 通过 rectify_tool_call_parts() 实现类型强制转换(如 string "123" → integer 123

合成 ID 机制

Gemini 2.x 并行调用常省略 functionCall.id。系统处理:

  • synthesize_tool_call_id() 生成 gemini_synth_<uuid> 格式的合成 ID在 Anthropic 侧使用
  • 不会转发回 Gemini在构建 Gemini 请求时被过滤)
  • 流式场景支持 "synth → real id upgrade":当后续 chunk 携带真实 ID 时替换合成 ID

Gemini Schema 构建

文件: src-tauri/src/proxy/providers/gemini_schema.rs (338 行)

工具定义的 Schema 转换使用双通道策略:

  • parameters 通道: 使用受限的 Gemini Schema 格式(去掉 $ref, $defs, additionalProperties, oneOf, allOf, const, not, if/then/else 等不支持的关键字)
  • parametersJsonSchema 通道: 使用完整 JSON Schema 格式(当 Schema 包含 Gemini 不支持的关键字时自动升级)
  • build_gemini_function_parameters() 自动根据 Schema 复杂度选择通道

响应转换: gemini_to_anthropic_with_shadow_and_hints(body, ...) → Value

Gemini 字段 Anthropic 字段
candidates[0].content.parts[{text}] content[{type: "text"}]
candidates[0].content.parts[{functionCall}] content[{type: "tool_use", id, name, input}]
candidates[0].content.parts[{thought: true}] 丢弃 (Gemini thinking)
candidates[0].finishReason = "STOP" stop_reason: "end_turn" / "tool_use"
candidates[0].finishReason = "MAX_TOKENS" stop_reason: "max_tokens"
candidates[0].finishReason = "SAFETY" stop_reason: "refusal"
promptFeedback.blockReason stop_reason: "refusal" + 错误文本
usageMetadata.promptTokenCount usage.input_tokens
usageMetadata.cachedContentTokenCount usage.cache_read_input_tokens

6. 流式转换层

6.1 OpenAI Chat Completions SSE → Anthropic SSE

文件: src-tauri/src/proxy/providers/streaming.rs (821 行)

转换状态机:

OpenAI SSE chunk ──▶ 状态解析 ──▶ Anthropic SSE event
                                    │
    choices[0].delta.content ──────▶ content_block_start (type: "text")
                                    content_block_delta (type: "text_delta")
                                    content_block_stop
                                    
    choices[0].delta.reasoning ────▶ content_block_start (type: "thinking")
                                    content_block_delta (type: "thinking_delta")
                                    content_block_stop
                                    
    choices[0].delta.tool_calls ───▶ content_block_start (type: "tool_use")
                                    content_block_delta (type: "input_json_delta")
                                    content_block_stop
                                    
    choices[0].finish_reason ──────▶ message_delta (stop_reason)
    [DONE] ───────────────────────▶ message_stop

特殊处理:

  • UTF-8 安全: 处理 TCP 分包导致的 UTF-8 多字节字符截断,使用 utf8_remainder 缓冲区确保不会产生 U+FFFD 替换字符
  • Copilot 无限空白 Bug 检测: 跟踪连续空白字符数,超过 20 个时强制中止 tool call 流Copilot 有时会无限输出空白字符的已知 Bug
  • 延迟工具调用: 处理 id/namearguments 之后到达的乱序情况

6.2 OpenAI Responses API SSE → Anthropic SSE

文件: src-tauri/src/proxy/providers/streaming_responses.rs (1070 行)

Responses API 使用命名事件 (named events) 的生命周期模型,与 Chat Completions 的 delta chunk 模型完全不同。

事件映射:

Responses API SSE Event Anthropic SSE Event
response.created message_start
response.content_part.added (output_text) content_block_start(type:text)
response.output_text.delta content_block_delta(text_delta)
response.refusal.delta content_block_delta(text_delta)
response.output_text.done content_block_stop
response.output_item.added (function_call) content_block_start(type:tool_use)
response.function_call_arguments.delta content_block_delta(input_json_delta)
response.function_call_arguments.done content_block_stop
response.reasoning.delta content_block_start(type:thinking) + content_block_delta(thinking_delta)
response.reasoning.done content_block_stop
response.completed message_delta (stop_reason + usage) + message_stop

状态管理: 维护 content_part_key (item_id + content_index 复合键)、index_by_key (content part → Anthropic index 映射)、tool_index_by_item_id (item_id → index 映射)、open_indices (未关闭的 block 索引集合)。

6.3 Gemini SSE → Anthropic SSE

文件: src-tauri/src/proxy/providers/streaming_gemini.rs (1054 行)

Gemini 的 streamGenerateContent?alt=sse 每个 chunk 都是完整的 GenerateContentResponse,需要增量合并。

核心机制:

  • 累积快照模型: 每个 SSE chunk 包含完整的 candidates系统通过比较 functionCall.name 和位置匹配来去重和合并跨 chunk 的工具调用
  • 工具调用 ID 去重合并: merge_tool_call_snapshots() 处理跨 chunk 的工具调用累积(支持合成 ID → 真实 ID 升级)
  • Shadow Store 记录: 在流结束时记录 assistant turn 到 shadow store包括 thoughtSignature
  • Tool Call Rectification: 流式场景下同样应用工具参数修正
  • thoughtSignature 提取: 从 text parts 中提取 thoughtSignature 用于后续回放

7. 请求处理流程

7.1 主处理链

以 Claude Code → CC-Switch → 上游 API 为例的完整流程:

Claude Code 发送 Anthropic Messages API 请求
         │
         ▼
[server.rs] 路由匹配 → /v1/messages → handle_messages()
         │
         ▼
[handlers.rs] handle_messages():
  1. 解析请求体
  2. 创建 RequestContext (识别 AppType::Claude, 提取 session_id)
  3. 调用 forwarder.forward_with_retry()
         │
         ▼
[forwarder.rs] RequestForwarder.forward_with_retry():
  遍历供应商列表(故障转移队列):
  1. 检查熔断器状态
  2. forward() 内部处理:
     a. get_adapter(AppType::Claude) → ClaudeAdapter
     b. 提取 base_url应用 model_mapper 映射模型名
     c. 规范化 thinking 类型
     d. 确定端点路径Copilot 动态端点 / 格式化重写)
     e. Copilot Optimizer: 分类请求、清理孤立 tool_result、合并 tool_result、热身降级、确定性 ID
     f. 解析 API 格式: get_claude_api_format()
     g. 如需转换: transform_claude_request_for_api_format()
        - openai_chat → anthropic_to_openai()
        - openai_responses → anthropic_to_responses()
        - gemini_native → anthropic_to_gemini_with_shadow()
     h. body_filter: 过滤 `_` 前缀的私有参数
     i. 获取动态认证 Token (Copilot/CodexOAuth)
     j. 构建有序 HeaderMap
     k. 发送请求 (hyper for HTTP/CONNECT proxy, reqwest for SOCKS5 proxy)
  3. 成功: 记录结果、更新状态、触发 UI 切换
  4. 失败: 检查 thinking_rectifier / thinking_budget_rectifier各自最多触发一次修复后重试
         │
         ▼
[handlers.rs] 响应处理:
  if needs_transform:
    流式: 根据格式选择:
      - openai_responses → create_anthropic_sse_stream_from_responses()
      - gemini_native → create_anthropic_sse_stream_from_gemini()
      - 其他 → create_anthropic_sse_stream()
    非流式: 读取完整响应,应用:
      - responses_to_anthropic()
      - gemini_to_anthropic_with_shadow_and_hints()
      - openai_to_anthropic()
  else:
    透传响应

7.2 Copilot Optimizer

文件: src-tauri/src/proxy/copilot_optimizer.rs (1251 行)

专用于 GitHub Copilot 的请求优化系统,在转发器内部对请求进行预处理:

优化策略 说明
请求分类 识别 initiator (user/agent)、热身请求、压缩请求、子代理请求
孤立 tool_result 清理 清理无对应 tool_use 的 tool_resultClaude Code 偶尔产生)
tool_result 合并 将多个 tool_result 合并为一个,减少 Copilot 高级计费
热身降级 检测到热身请求时降级为小模型,节省成本
确定性请求 ID 基于 session 生成确定性 x-request-idx-interaction-id,提高 Copilot 稳定性
子代理头修改 子代理请求时修改 x-initiatorx-interaction-type 为 agent

7.3 Thinking 自修复机制

文件: src-tauri/src/proxy/thinking_rectifier.rs (609 行), thinking_budget_rectifier.rs (307 行)

两个独立的自修复 rectifier在 Anthropic API 返回特定错误时自动修复并重试:

Rectifier 触发条件 修复动作 触发次数限制
Signature Rectifier Anthropic API 报告 thinking signature 无效 移除 thinking/redacted_thinking blocks 和 signature 字段 每请求 1 次
Budget Rectifier Anthropic API 报告 thinking budget 错误 调整 thinking.budget_tokens 每请求 1 次

修复后通过 release_permit_neutral() 释放熔断器的 HalfOpen 探测槽位,不影响健康统计。

7.4 其他辅助机制

模块 文件 行数 说明
私有参数过滤 body_filter.rs 261 过滤 _ 前缀的参数,允许客户端传递控制参数而不发送到上游
缓存注入 cache_injector.rs 329 为 Bedrock 等支持 prompt 缓存的供应商注入缓存控制标记
Thinking 优化 thinking_optimizer.rs 230 Bedrock 场景下的 thinking 参数优化
模型名映射 model_mapper.rs 312 将客户端请求的模型名映射为上游实际模型名
Gemini URL gemini_url.rs 583 处理 Gemini API 的复杂 URL 构建逻辑
SSE 基础 sse.rs 294 SSE 事件解析和生成的基础工具

8. 熔断器与故障转移

8.1 熔断器

文件: src-tauri/src/proxy/circuit_breaker.rs (482 行)

三态熔断器保护上游服务:

参数 默认值
failure_threshold 4 (连续失败次数)
success_threshold 2 (连续成功次数)
timeout_seconds 60 (Open 状态持续时间)
error_rate_threshold 0.6 (错误率阈值)
min_requests 10 (最小请求数)

状态转换: Closed (正常) → Open (熔断) → HalfOpen (探测,最多 1 个并发探测请求) → Closed/Open

8.2 供应商路由

文件: src-tauri/src/proxy/provider_router.rs (512 行)

  • 故障转移关闭时:仅使用当前供应商
  • 故障转移开启时:返回按优先级排列的故障转移队列,跳过熔断中的供应商

9. 支持的协议转换矩阵

                    ┌──────────────────────────────────────────────┐
                    │              CC-Switch 代理                    │
                    │                                              │
                    │  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
 Claude Code ──────▶│  │ Claude   │  │ Codex    │  │ Gemini   │   │
 (Anthropic        │  │ Handler  │  │ Handler  │  │ Handler  │   │
  Messages API)    │  └────┬─────┘  └────┬─────┘  └────┬─────┘   │
                    │       │             │              │         │
                    │  ┌────▼─────────────▼──────────────▼─────┐  │
                    │  │          Forwarder (转发器)              │  │
                    │  │  - 供应商选择 / 故障转移 / Copilot优化   │  │
                    │  │  - Thinking自修复 / 参数过滤             │  │
                    │  └────────────────┬───────────────────────┘  │
                    │                   │                          │
                    │       ┌───────────┼───────────┐              │
                    │       ▼           ▼           ▼              │
                    │  ┌─────────┐ ┌─────────┐ ┌──────────┐      │
                    │  │OpenAI   │ │OpenAI   │ │  Gemini  │      │
                    │  │Chat     │ │Responses│ │  Native  │      │
                    │  │Complet. │ │API      │ │          │      │
                    │  └────┬────┘ └────┬────┘ └────┬─────┘      │
                    │       │           │           │             │
                    └───────┼───────────┼───────────┼─────────────┘
                            ▼           ▼           ▼
                    ┌───────────┐ ┌──────────┐ ┌──────────────┐
                    │OpenAI/    │ │ChatGPT/  │ │ Google AI    │
                    │OpenRouter/│ │OpenAI/   │ │ Gemini API   │
                    │Copilot    │ │Codex OAuth│ │              │
                    └───────────┘ └──────────┘ └──────────────┘

转换路径汇总

转换路径 请求转换 响应转换 流式转换 使用场景
Anthropic → OpenAI Chat anthropic_to_openai() openai_to_anthropic() streaming.rs GitHub Copilot, OpenRouter (旧版)
Anthropic → OpenAI Responses anthropic_to_responses() responses_to_anthropic() streaming_responses.rs Codex OAuth (ChatGPT Plus/Pro)
Anthropic → Gemini anthropic_to_gemini_with_shadow() gemini_to_anthropic_with_shadow_and_hints() streaming_gemini.rs Gemini 模型直连
Anthropic → Anthropic (透传) 直接转发 直接转发 直接转发 Anthropic 官方, OpenRouter (新版)

10. 文件索引

核心转换文件

文件路径 功能 代码行数
src-tauri/src/proxy/providers/transform.rs Anthropic ↔ OpenAI Chat Completions 转换 1193
src-tauri/src/proxy/providers/transform_responses.rs Anthropic ↔ OpenAI Responses API 转换 1329
src-tauri/src/proxy/providers/transform_gemini.rs Anthropic ↔ Gemini Native 转换 2152
src-tauri/src/proxy/providers/streaming.rs OpenAI Chat SSE → Anthropic SSE 流式转换 821
src-tauri/src/proxy/providers/streaming_responses.rs Responses SSE → Anthropic SSE 流式转换 1070
src-tauri/src/proxy/providers/streaming_gemini.rs Gemini SSE → Anthropic SSE 流式转换 1054

适配器与认证

文件路径 功能 代码行数
src-tauri/src/proxy/providers/adapter.rs ProviderAdapter trait 定义 50
src-tauri/src/proxy/providers/auth.rs AuthInfo / AuthStrategy 认证类型定义 259
src-tauri/src/proxy/providers/claude.rs Claude 适配器 (API 格式检测, URL 构建, 认证) 1313
src-tauri/src/proxy/providers/codex.rs Codex 适配器 305
src-tauri/src/proxy/providers/gemini.rs Gemini 适配器 442
src-tauri/src/proxy/providers/mod.rs ProviderType 枚举, get_adapter() 工厂函数 515
src-tauri/src/proxy/providers/copilot_auth.rs Copilot 动态 Token 管理 1820
src-tauri/src/proxy/providers/codex_oauth_auth.rs Codex OAuth 动态 Token 管理 1132
src-tauri/src/proxy/providers/gemini_shadow.rs Gemini Shadow Store (状态回放) 389
src-tauri/src/proxy/providers/gemini_schema.rs Gemini Schema 构建 (双通道策略) 338

请求处理链

文件路径 功能 代码行数
src-tauri/src/proxy/server.rs Axum HTTP 服务器, 路由注册 354
src-tauri/src/proxy/handlers.rs 请求处理器 (分发 + Claude 格式转换入口) 643
src-tauri/src/proxy/forwarder.rs 请求转发器 (供应商选择, 故障转移, 请求预处理) 2169
src-tauri/src/proxy/copilot_optimizer.rs Copilot 请求优化 1251
src-tauri/src/proxy/thinking_rectifier.rs Thinking Signature 自修复 609
src-tauri/src/proxy/thinking_budget_rectifier.rs Thinking Budget 自修复 307
src-tauri/src/proxy/thinking_optimizer.rs Bedrock Thinking 优化 230
src-tauri/src/proxy/cache_injector.rs Prompt 缓存注入 329
src-tauri/src/proxy/body_filter.rs 私有参数过滤 (_ 前缀) 261
src-tauri/src/proxy/model_mapper.rs 模型名映射 312
src-tauri/src/proxy/gemini_url.rs Gemini URL 构建 583
src-tauri/src/proxy/sse.rs SSE 基础工具 294
src-tauri/src/proxy/provider_router.rs 供应商路由 (故障转移队列) 512
src-tauri/src/proxy/circuit_breaker.rs 熔断器实现 482
src-tauri/src/proxy/handler_context.rs RequestContext 构建 246
src-tauri/src/proxy/response_processor.rs 响应处理 (透传/日志/usage) 915
src-tauri/src/proxy/session.rs 会话管理 565
src-tauri/src/proxy/hyper_client.rs Hyper HTTP 客户端 626
src-tauri/src/proxy/http_client.rs Reqwest HTTP 客户端 (SOCKS5) 392
src-tauri/src/proxy/error.rs 错误类型定义 177
src-tauri/src/proxy/error_mapper.rs 错误映射 99

11. 关键设计特点

11.1 单方向锚定转换

所有转换以 Anthropic Messages API 为锚点,仅实现 Anthropic ↔ X 的双向转换。客户端协议只有一种Anthropic Messages API上游协议有三种OpenAI Chat、OpenAI Responses、Gemini Native加一种透传Anthropic 直连)。

11.2 流式 + 非流式双轨支持

每种协议转换都同时实现了非流式 (JSON-to-JSON) 和流式 (SSE 事件逐事件翻译,基于 async_stream 异步流)。

11.3 有状态转换 (Gemini Shadow Store)

Gemini 的 thoughtSignature 是有状态的,系统通过 Shadow Store 在内存中记录每轮 assistant 的原始 Gemini 响应,在后续请求中回放。这是 CC-Switch 独有的复杂机制。

11.4 自修复能力 (Thinking Rectifiers)

两个独立 rectifier 在 API 错误时自动修复请求并重试,大幅提高了对 Anthropic API thinking 功能变更的容错能力。

11.5 Copilot 深度适配

Copilot Optimizer 针对性地解决了 Copilot 的多个实际问题(无限空白 Bug、请求不稳定、高级计费优化等是与供应商深度绑定的典型案例。

11.6 请求头大小写保留

通过手动 hyper accept loop + TCP peek() 捕获原始请求头大小写,转发给上游时保持一致(部分上游 API 对 header 大小写敏感)。

11.7 代理协议支持

支持 HTTP/CONNECT 和 SOCKS5 两种代理协议,分别使用 hyper 和 reqwest 客户端。

11.8 UTF-8 安全

流式转换中处理 TCP 分包导致的 UTF-8 多字节字符截断,使用 utf8_remainder 缓冲区确保不会产生 U+FFFD 替换字符。