1. 核心背景与架构动因 (Background and Motivation)

在大模型编码智能体(如 Claude Code、InPage Agent、Codex CLI 等)的落地场景中,开发者往往面临跨多云、多供应商切换的复杂现实。各大供应商在 API 协议上呈现明显割裂,主流分为三大协议族:

  1. Anthropic 原生 Messages API 协议 (anthropic):以 /v1/messages 为核心,严格要求角色交替 (user 与 assistant),工具结果以 tool_result 块置于 user 角色中回传,使用 anthropic-version、x-api-key 与 thinking 预算。
  2. OpenAI 传统 Chat Completions 协议 (openai_chat):以 /v1/chat/completions 为核心,具备独立的 role: 'tool' 角色与 tool_calls 结构,依赖 data: [DONE] 流式结尾。
  3. OpenAI 新一代 Responses API 协议 (openai_responses):扁平化 input 序列,将 system 转为顶层 instructions,工具调用提升为平级 function_call 与 function_call_output 项,采用细粒度命名事件生命周期(response.output_item.added、response.function_call_arguments.delta 等)。

CC-Switch 作为目前最完备的桌面端大模型配置管理与中继切换工具,沉淀了一套高可用、泛化性极强的供应商体系与端点探测机制。本文档提炼其设计范式,用于为自主 Agent 提供企业级多协议兼容运行时。


2. 供应商 API Profile 字段规格 (Provider Profile Specification)

一个具备生产可用性的供应商单一 Profile 实体包含如下关键维度:

字段名类型说明与规范
idstring运行时不可变唯一标识符 (UUID 或 nanoId)
namestring界面展示名称(如 "Claude Official"、"火山 Agent Plan")
baseUrlstring目标服务端点 Base URL(支持纯域名、/v1 或兼容子路径)
apiKeystring推理鉴权凭据 (API Key / Token)
apiFormat`'anthropic' \'openai_chat' \'openai_responses'`协议类型,决定请求体序列化与 SSE 流式状态机解码方式
modelstring当前激活/选中的默认模型名
modelsstring[]该供应商预置或动态拉取到的候选模型下拉菜单列表
customModelsstring[]用户手动录入并持久化的自定义扩展模型名
categoryProviderCategory分类:official (国际官方), cn_official (国内大厂), cloud_provider (云服务商), aggregator (聚合商)
websiteUrlstring供应商控制台/官方文档导航链接
apiKeyUrlstring快捷获取 API Key 的直达网页地址
icon / iconColorstring供应商品牌图标名及十六进制主题色
customHeadersRecord<string, string>针对特殊网关额外注入的私有 HTTP 头
reasoningEffort`'none' \'low' \'medium' \'high' \'xhigh'`思考与推理强度档位
maxTokensnumber单次生成最大 token 上限(Anthropic 强制要求必填)

3. 预设供应商筛选逻辑 (Curated Presets Logic)

在桌面与前端 Agent 预设集成中,应遵循“保留第一梯队官方与大厂,剔除低信誉引流中转站”的原则:

保留清单

  • 国际官方与开源旗舰:Anthropic (Claude Official), OpenAI Official, Google Gemini (Gemini Native), DeepSeek (深度求索), xAI (Grok), GitHub Copilot。
  • 国内一线大厂专线:

    • 月之暗面 (Moonshot):Kimi, Kimi For Coding。
    • 字节跳动 (Volcengine):火山 Agent Plan, 火山 Coding Plan, 火山豆包 (DouBaoSeed), BytePlus。
    • 阿里巴巴 (Alibaba Cloud):阿里百炼 (DashScope), 百炼 Coding Plan, 百炼 Token Plan, ModelScope (魔搭)。
    • 智谱清言 (Zhipu BigModel):Zhipu GLM, 智谱 Coding Plan, Zhipu GLM en (Z.AI)。
    • 百度千帆 (Baidu Qianfan):千帆 Coding Plan, 千帆 Token Plan。
    • 腾讯混元 (Tencent Cloud):腾讯 Token Plan (LKEAP)。
    • 其他头部独角兽:MiniMax (稀宇科技), 阶跃星辰 (StepFun), 小米 (Xiaomi MiMo), 美团 (Longcat)。
  • 优质云计算与推理基础设施:硅基流动 (SiliconFlow), 七牛云 (Qiniu), 优云智算 (Compshare), OpenRouter, Nvidia (NIM), Novita AI。

过滤清单

  • 彻底移除带推广标识或非官方中转分销站(如 PackyCode, ZetaAPI, APINebula, AICodeMirror, RunAPI, 胜算云, AIGoCode, AICoding, SubRouter, APIKEY.FUN, 9527CODE, Code0, PPIO, CCSub 等),防止接口生命周期不可靠及安全隐患。

4. 候选模型地址探测与后缀剥离机制 (Candidate URL Derivation)

多数支持 Anthropic 协议的供应商(如 DeepSeek、智谱、Kimi、火山)将 Anthropic 协议挂载在特定的兼容子路径下(例如 /anthropic 或 /api/coding)。但当客户端需要获取该供应商的可用模型列表(GET /models)时,该子路径通常不响应,需要自动剥离并回退到通用根路径:

const KNOWN_COMPAT_SUFFIXES = [
  '/api/claudecode',
  '/api/anthropic',
  '/apps/anthropic',
  '/api/coding',
  '/claudecode',
  '/anthropic',
  '/step_plan',
  '/coding',
  '/claude',
];

export function buildCandidateModelUrls(baseUrl: string): string[] {
  const trimmed = baseUrl.trim().replace(/\/+$/, '');
  const candidates: string[] = [];

  // 1. 若以版本段结尾 (/v1 或 /v4)
  if (/\/(v\d+)$/i.test(trimmed)) {
    candidates.push(`${trimmed}/models`);
  } else {
    candidates.push(`${trimmed}/v1/models`);
    candidates.push(`${trimmed}/models`);
  }

  // 2. 命中兼容后缀时剥离并追加纯净根候选
  for (const suffix of KNOWN_COMPAT_SUFFIXES) {
    if (trimmed.endsWith(suffix)) {
      const stripped = trimmed.slice(0, -suffix.length).replace(/\/+$/, '');
      if (stripped) {
        candidates.push(`${stripped}/v1/models`);
        candidates.push(`${stripped}/models`);
      }
      break;
    }
  }

  return Array.from(new Set(candidates));
}

多格式响应解析

探测接口需同时兼容以下主流数据格式:

  1. OpenAI / Anthropic 标准格式:{ "data": [{ "id": "model-id", "owned_by": "vendor" }] }
  2. 智谱 Responses 格式:{ "models": [{ "slug": "model-slug" }] }
  3. 裸模型数组格式:[ "model-a", "model-b" ]

5. 最短连通性测试设计 (Shortest Connectivity Probe)

传统的全量连通性测试常因生成过长内容而消耗较多 token,或触发过长的等待时间。CC-Switch 演进出的“最短连通性测试”方案具备以下特征:

  • 提示词固定为最短指令:"测试连通,收到回复OK即可"。
  • 强制限制最小输出配额:max_tokens = 16(或 max_output_tokens = 16,Responses API 规定不能低于 16)。
  • 统一非流式短连接模式:直接利用 stream: false 简化回包解析。
  • 核心观测指标:

    • HTTP 状态码 (statusCode)。
    • 首包/往返物理延迟 (latencyMs,使用 performance.now() 高精度测量)。
    • 提取回包纯文本并使用正则 /ok/i 校验语义确认度。

6. 三大协议流式抹平状态机 (Multi-Protocol Streaming Transformation)

在 Agent 运行时底层,必须将来自不同协议的 Server-Sent Events (SSE) 统一适配为 Agent 的内部状态流:

flowchart TD
    Upstream([上游 API 响应流]) --> Detection{协议判定}
    Detection -->|anthropic| AnthropicParser[Anthropic SSE 解码]
    Detection -->|openai_responses| ResponsesParser[Responses SSE 解码]
    Detection -->|openai_chat| ChatParser[Chat SSE 解码]

    AnthropicParser -->|text_delta| OutText[onTextDelta]
    AnthropicParser -->|thinking_delta| OutReasoning[onReasoningDelta]
    AnthropicParser -->|input_json_delta| OutTool[onToolCallDelta]

    ResponsesParser -->|response.text.delta| OutText
    ResponsesParser -->|response.reasoning.delta| OutReasoning
    ResponsesParser -->|response.function_call_arguments.delta| OutTool

    ChatParser -->|delta.content| OutText
    ChatParser -->|delta.reasoning_content| OutReasoning
    ChatParser -->|delta.tool_calls| OutTool

关键细节处理

  1. 浏览器直连 Anthropic CORS 突破:必须注入请求头 anthropic-dangerous-direct-browser-access: true,否则浏览器内 fetch 会被服务端拦截。
  2. Anthropic 连续工具调用回传:多工具并发调用执行完毕后,所有 tool_result 必须包裹在同一个 role: 'user' 消息的 content blocks 中,或严格保证与 assistant 消息交替,切忌出现孤立或非法嵌套。
  3. Responses API 命名事件匹配:必须同时处理 event: 字段或 JSON body 中的 type 字段(如 response.output_item.added)。
  4. 思考流(Reasoning / Thinking)归一化:将 DeepSeek 的 reasoning_content、Anthropic 的 thinking_delta 和 Responses API 的 response.reasoning.delta 统一映射至 Agent 内部的 reasoning_content 字段并在 UI 中实时展开。

7. 架构取舍:关于 Codex OAuth 与网关边界的评估 (Architectural Tradeoffs)

在本次工程演进中,针对 OpenAI Codex Device OAuth 流程进行了完整的浏览器环境适配与跨域评估,并最终确立了清晰的架构边界:

核心结论

  1. 浏览器直接跨域限制 (CORS Barrier):

    • OpenAI Codex 后端(https://chatgpt.com/backend-api/codex)面向终端 CLI 工具设计,并未给第三方 Web 站点开放 CORS 响应头。
    • 纯前端 SPA 环境下直接向该端点发起推理请求必定触发浏览器的同源策略拦截。
  2. Device Auth 协议特性与浏览器控制台冲突:

    • 依据 RFC 8628 规范,客户端在等待授权时轮询 token 端点,OpenAI 官方标准返回 HTTP 403 (deviceauth_authorization_pending)。
    • Chrome DevTools 凡接收到 4xx 状态均强制在 Console 输出红字报错,对前端用户造成严重的心智负担和报错误判。
  3. 架构收敛决策:

    • 若要彻底解决上述问题,必须在本地 Go 网关中构建通用的反向代理与 Session 管理层。
    • 为避免在当前阶段引入过重的代理转发与网关复杂化,系统做出果断收敛:暂缓引入 Codex OAuth 流程,保持 Go 网关专注最纯粹的单流透传,所有 Provider 均统一采用标准的 API Key 模式运作。

8. 前端界面层交互集成与落地 (UI Integration & Provider Management)

在 InPage Agent 的设置面板 (app/src/ui/fileTree.ts) 与弹窗 (app/src/ui/providerModal.ts) 中,已将精简高可用的供应商子系统完整落地到用户界面:

  1. 设置面板 Provider 管理区:

    • 顶部提供两个快捷操作按钮:

      • + 自建 Provider:打开全功能空白供应商新建模态框。
      • + 从预设添加:快速唤起并预选高质量大厂模版。
    • 供应商卡片列表:

      • 展示名称、协议类型徽章 (OpenAI Chat / Responses / Anthropic)、当前生效标记 (当前生效)、接口 Base URL 与当前默认模型。
      • 操作按钮组:启用 (立即切换当前生效源)、测试 (卡片内直接触发最短连通性测试并即时显示延迟与状态)、编辑 (打开配置弹窗修改)、删除 (二次确认后删除自建配置,内置网关受保护)。
  2. 自建与编辑模态弹窗 (showProviderModal):

    • 快捷模版导入:集成 37 个主流大厂预设,选择后自动同步填充 Base URL、协议格式、分类及默认模型。
    • 防误导默认值与严格空 Key 校验:

      • 自建 Provider 默认清空 Base URL 与 Model,避免自动填入 DeepSeek 官方地址导致空 Key 触发 401 Unauthorized。
      • 连通性测试与模型探测前置拦截:外部供应商若未填 Key 明确提示“外部供应商需先输入 API Key 后再进行连通测试”,阻断无效网络消耗。
    • 模型名下拉与扩展机制:

      • 模型下拉选择器 (select):集中渲染已知与自定义候选模型。
      • 动态添加模型名:输入框 + + 添加模型名 按钮,输入即时注入下拉菜单并设为选中。
      • 探测可用模型:一键调用 fetchCandidateModels,自动探测上游 /v1/models 并智能合并。
      • 候选模型 Chip 标签群:支持点击切换当前模型与删除自定义模型项。
    • 最短连通性测试器 (Shortest Connectivity Test):

      • 弹窗内集成连通校验按钮,发送“测试连通,收到回复OK即可”(max_tokens: 16),直接渲染耗时 (ms)、HTTP 状态码及返回内容,确保保存前验证端点可用性。

本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/AI apps