# One-API 项目转换层深度分析报告 ## 一、项目概览 One-API 是一个基于 Go 语言(Gin 框架)开发的大模型 API 网关代理项目。其核心功能是:**将用户发来的统一 OpenAI 格式请求,转换为各家大模型厂商的原生 API 格式,转发请求后,再将厂商的响应统一转换回 OpenAI 格式返回给用户**。 对外暴露的接口完全兼容 OpenAI API 规范,用户只需更改 `base_url` 和 `api_key` 即可使用。 ### 与同类项目的核心差异 One-API 是此类项目的**鼻祖和基线**,采用最简单的架构模式——仅支持 OpenAI 格式作为唯一输入/输出协议,所有转换都是 **OpenAI ↔ 厂商原生格式** 的双向转换。New-API 在其基础上增加了 Claude/Gemini 输入支持和 Hub-and-Spoke 架构。One-API 的设计追求简洁实用:56 种渠道类型通过三层映射归并为 19 种 API 类型,其中 18 种 OpenAI 兼容渠道直接复用同一适配器,实现零开销透传。 --- ## 二、项目目录结构 ``` one-api/ ├── main.go # 程序入口 ├── router/ │ └── relay.go # 路由定义(/v1/chat/completions 等) ├── middleware/ │ ├── auth.go # Token 认证 │ ├── distributor.go # 渠道分发(负载均衡) │ └── rate-limit.go # 限流 ├── controller/ │ └── relay.go # 入口控制器(含重试逻辑) ├── relay/ # ★ 转换层核心目录 │ ├── adaptor.go # Adaptor 工厂函数 (69行) │ ├── adaptor/ # 各厂商 Adaptor 实现 │ │ ├── interface.go # Adaptor 接口定义 (9方法) │ │ ├── common.go # 公共辅助函数 │ │ ├── openai/ # OpenAI 适配器(基座) │ │ ├── anthropic/ # Anthropic Claude 适配器 │ │ ├── gemini/ # Google Gemini 适配器 │ │ ├── geminiv2/ # Gemini V2 模型适配器 │ │ ├── ali/ # 阿里通义千问适配器 │ │ ├── baidu/ # 百度文心适配器 │ │ ├── zhipu/ # 智谱 ChatGLM 适配器 │ │ ├── tencent/ # 腾讯混元适配器 │ │ ├── xunfei/ # 讯飞星火适配器 │ │ ├── aws/ # AWS Bedrock Claude 适配器 (含子适配器) │ │ │ ├── claude/ # Claude on Bedrock │ │ │ └── llama3/ # Llama3 on Bedrock │ │ ├── vertexai/ # Google Vertex AI (含子适配器) │ │ │ ├── claude/ # Claude on Vertex AI │ │ │ └── gemini/ # Gemini on Vertex AI │ │ ├── ollama/ # Ollama 适配器 │ │ ├── coze/ # Coze 适配器 │ │ ├── cohere/ # Cohere 适配器 │ │ ├── cloudflare/ # Cloudflare Workers AI 适配器 │ │ ├── deepl/ # DeepL 翻译适配器 │ │ ├── replicate/ # Replicate 适配器 │ │ ├── palm/ # Google PaLM 适配器 │ │ ├── proxy/ # 通用代理适配器 │ │ ├── aiproxy/ # AIProxy 适配器 │ │ └── ... (38个子目录) │ ├── controller/ # 中转控制器(按功能分类) │ │ ├── text.go # 文本类请求处理 (115行) │ │ ├── image.go # 图片生成请求处理 (238行) │ │ ├── audio.go # 音频请求处理 (281行) │ │ ├── proxy.go # 通用代理请求处理 │ │ ├── helper.go # 辅助函数(配额、计费等) │ │ └── error.go # 统一错误处理 │ ├── meta/ │ │ └── relay_meta.go # 请求元数据结构 (66行) │ ├── model/ # 内部数据模型 │ │ ├── general.go # 统一 OpenAI 请求结构 (88行) │ │ ├── message.go # 消息结构(支持多模态) (91行) │ │ ├── misc.go # Usage、Error 等通用结构 (27行) │ │ ├── tool.go # Tool/Function Calling 结构 │ │ └── image.go # 图片请求结构 │ ├── apitype/ │ │ └── define.go # API 类型枚举 (19种) │ ├── channeltype/ │ │ ├── define.go # 渠道类型枚举 (56种) │ │ ├── helper.go # ChannelType → APIType 映射 │ │ └── url.go # 各渠道默认 BaseURL (52条) │ ├── relaymode/ │ │ ├── define.go # 中转模式枚举 (11种) │ │ └── helper.go # URL 路径 → 中转模式映射 │ └── billing/ # 计费相关 └── model/ # 数据库模型 ├── channel.go # 渠道配置 └── ... ``` --- ## 三、转换层技术架构 ### 3.1 整体架构图 ``` ┌─────────────────────────────────────────┐ │ 用户请求 (OpenAI 格式) │ │ POST /v1/chat/completions │ └──────────────────┬──────────────────────┘ │ ┌──────────────────▼──────────────────────┐ │ router/relay.go │ │ 路由: /v1/* → controller.Relay │ └──────────────────┬──────────────────────┘ │ ┌──────────────────▼──────────────────────┐ │ middleware (中间件链) │ │ CORS → GzipDecode → PanicRecover │ │ → TokenAuth → Distribute │ │ 1. 解析 Token, 验证身份 │ │ 2. 根据模型名选择渠道(随机负载均衡) │ │ 3. 将渠道信息注入 gin.Context │ └──────────────────┬──────────────────────┘ │ ┌──────────────────▼──────────────────────┐ │ controller/relay.go │ │ 1. 根据 URL 判断 relayMode │ │ 2. 调用 relayHelper 分发 │ │ 3. 失败时自动重试(切换渠道) │ └──────────────────┬──────────────────────┘ │ ┌────────────────────────┼────────────────────────┐ │ │ │ ┌─────────▼──────────┐ ┌─────────▼──────────┐ ┌─────────▼──────────┐ │ RelayTextHelper │ │ RelayImageHelper │ │ RelayAudioHelper │ │ text.go (115行) │ │ image.go (238行) │ │ audio.go (281行) │ └─────────┬──────────┘ └─────────┬──────────┘ └─────────┬──────────┘ │ │ │ └────────────────────────┼────────────────────────┘ │ ┌──────────────────▼──────────────────────┐ │ relay/adaptor.go │ │ GetAdaptor(apiType) → 具体Adaptor实例 │ └──────────────────┬──────────────────────┘ │ ┌────────────────────────┼────────────────────────┐ │ │ │ ┌─────────▼──────────┐ ┌─────────▼──────────┐ ┌─────────▼──────────┐ │ openai.Adaptor │ │ anthropic.Adaptor │ │ gemini.Adaptor │ │ ConvertRequest() │ │ ConvertRequest() │ │ ConvertRequest() │ │ DoRequest() │ │ DoRequest() │ │ DoRequest() │ │ DoResponse() │ │ DoResponse() │ │ DoResponse() │ └─────────┬──────────┘ └─────────┬──────────┘ └─────────┬──────────┘ │ │ │ └────────────────────────┼────────────────────────┘ │ ┌──────────────────▼──────────────────────┐ │ 上游大模型厂商 API │ └─────────────────────────────────────────┘ ``` ### 3.2 核心设计模式:适配器模式 **Adaptor 接口** (`relay/adaptor/interface.go`, 21 行): ```go type Adaptor interface { Init(meta *meta.Meta) // 初始化元数据 GetRequestURL(meta *meta.Meta) (string, error) // 构建请求 URL SetupRequestHeader(c, req, meta) error // 设置认证请求头 ConvertRequest(c, mode, request) (any, error) // 请求体转换 (OpenAI → 厂商) ConvertImageRequest(request) (any, error) // 图片请求转换 DoRequest(c, meta, requestBody) (*http.Response, error) // 发送 HTTP 请求 DoResponse(c, resp, meta) (usage, err) // 响应体转换 (厂商 → OpenAI) GetModelList() []string // 返回支持的模型列表 GetChannelName() string // 返回渠道名称 } ``` **9 个方法**构成最精简的适配器接口,相比 New-API 的 15+ 方法接口更聚焦。 ### 3.3 三层映射关系 项目通过三层映射将"渠道"与"转换逻辑"关联: ``` ChannelType (渠道类型) → APIType (API 类型) → Adaptor (适配器实例) (56 种) (19 种) (18 个实现) ``` - **ChannelType**: 具体的厂商/服务商标识(56 种) - **APIType**: 共享同一套转换逻辑的分组(19 种,定义在 `relay/apitype/define.go`) - **Adaptor**: 负责具体转换逻辑的实例 **映射代码**: `relay/channeltype/helper.go` 的 `ToAPIType()` 函数。 **关键设计**: 18 种 OpenAI 兼容渠道的 APIType 被映射为 `apitype.OpenAI`,直接复用 `openai.Adaptor`,无需编写独立转换逻辑。兼容渠道列表 (`relay/adaptor/openai/compatible.go`): ```go var CompatibleChannels = []int{ Azure, AI360, Moonshot, Baichuan, Minimax, Doubao, Mistral, Groq, LingYiWanWu, StepFun, DeepSeek, TogetherAI, Novita, SiliconFlow, XAI, BaiduV2, XunfeiV2, } ``` 另有 OpenRouter、AliBailian、GeminiOpenAICompatible 也有特殊映射处理。 ### 3.4 Adaptor 工厂 **文件**: `relay/adaptor.go` (69 行) `GetAdaptor(apiType int)` 映射 18 种 API 类型到具体适配器实例(Proxy 类型额外处理)。 --- ## 四、请求处理完整流程 ### 4.1 路由阶段 **文件**: `router/relay.go` (74 行) 所有 `/v1/` 下的请求都经过中间件链:`CORS() → GzipDecodeMiddleware() → RelayPanicRecover → TokenAuth → Distribute` ### 4.2 中间件阶段 #### Token 认证 (middleware/auth.go, 167 行) - 从 `Authorization` 头提取 `Bearer ` - 管理员可通过 `sk--` 指定特定渠道 - 验证 Token 有效性,提取 userId、tokenId - 从请求体解析 `model` 字段,验证模型可用性 - 支持 IP 子网限制 #### 渠道分发 (middleware/distributor.go, 102 行) - 获取用户分组 (group) - 根据 group + model 随机选择一个可用渠道 - 将渠道信息注入 `gin.Context`:渠道类型、API Key、BaseURL、ModelMapping 等 - 渠道类型转换为 APIType,存入 meta ### 4.3 控制器阶段 **文件**: `controller/relay.go` (156 行) ```go func Relay(c *gin.Context) { relayMode := relaymode.GetByPath(c.Request.URL.Path) bizErr := relayHelper(c, relayMode) // 失败时自动重试:切换到其他渠道 for i := retryTimes; i > 0; i-- { channel := CacheGetRandomSatisfiedChannel(group, model) SetupContextForSelectedChannel(c, channel, model) bizErr = relayHelper(c, relayMode) } } ``` `relayHelper` 根据 `relayMode` 分发: - `ChatCompletions / Completions / Embeddings / Moderations` → `RelayTextHelper` - `ImagesGenerations` → `RelayImageHelper` - `AudioSpeech / AudioTranscription / AudioTranslation` → `RelayAudioHelper` - `Proxy` → `RelayProxyHelper` **重试策略**: 429 和 5xx 触发重试,400 和 2xx 不重试。管理员指定渠道时不重试。 ### 4.4 转换处理阶段 — RelayTextHelper **文件**: `relay/controller/text.go` (115 行) ```go func RelayTextHelper(c *gin.Context) *model.ErrorWithStatusCode { // 1. 解析请求(统一按 OpenAI 格式解析) meta := meta.GetByContext(c) textRequest := getAndValidateTextRequest(c, meta.Mode) // 2. 模型名称映射 textRequest.Model = getMappedModelName(textRequest.Model, meta.ModelMapping) // 3. 强制系统提示词注入 setSystemPrompt(textRequest, meta) // 4. 计算配额、预扣费 promptTokens := getPromptTokens(textRequest, meta.Mode) preConsumedQuota := preConsumeQuota(...) // 用户配额 > 100x预扣时跳过 // 5. 获取对应 Adaptor adaptor := relay.GetAdaptor(meta.APIType) adaptor.Init(meta) // 6. 请求转换(OpenAI 格式 → 厂商格式) requestBody := getRequestBody(c, meta, textRequest, adaptor) // 7. 发送请求到上游 resp := adaptor.DoRequest(c, meta, requestBody) // 8. 响应转换(厂商格式 → OpenAI 格式) usage := adaptor.DoResponse(c, resp, meta) // 9. 后扣费 postConsumeQuota(usage, ...) } ``` #### 请求体透传优化 **文件**: `relay/controller/text.go` 的 `getRequestBody()` 函数 当满足以下所有条件时,**跳过请求转换**,直接透传原始请求体: - API 类型为 OpenAI - 模型名未被映射 - 渠道不是百川(百川有特殊处理) - 无强制系统提示词 - 未启用 include_usage 强制选项 ```go if meta.APIType == apitype.OpenAI && meta.OriginModelName == meta.ActualModelName && meta.ChannelType != channeltype.Baichuan && meta.ForcedSystemPrompt == "" { return c.Request.Body, nil // 直接透传,零开销 } ``` --- ## 五、各厂商转换逻辑详解 ### 5.1 OpenAI 适配器(基座) **文件**: `relay/adaptor/openai/` (9 文件) 作为项目的"基座适配器",不仅处理 OpenAI 自身,还被 18 种 OpenAI 兼容渠道复用。 **请求转换**: 基本不需要格式转换,直接透传 `GeneralOpenAIRequest`。唯一处理:流式模式下自动注入 `stream_options.include_usage = true`。 **URL 构建**: 根据渠道类型有不同逻辑: - 标准 OpenAI 兼容: `BaseURL + RequestURLPath` - Azure: `/openai/deployments/{model}/{task}?api-version=xxx` - Minimax/Doubao/Novita/BaiduV2/AliBailian/GeminiOpenAICompatible: 各有独立 URL 逻辑 **认证方式**: - 标准渠道: `Authorization: Bearer ` - Azure: `api-key: ` - OpenRouter: 额外 `HTTP-Referer` 和 `X-Title` 头 **流式处理**: 逐行解析 SSE (`data: {...}`),提取 usage 信息,支持 Cloudflare AI Gateway URL。 ### 5.2 Anthropic Claude 适配器 **文件**: `relay/adaptor/anthropic/` (4 文件, main.go 379 行) Claude 使用完全不同的 API 格式,需要大量转换工作。 **请求转换** (main.go `ConvertRequest()`): | OpenAI 字段 | Claude 字段 | 转换说明 | |---|---|---| | `messages[].role = "system"` | `system` (顶层字段) | 系统提示词提取到顶层 | | `messages[].content` (string) | `messages[].content` (Content 数组) | 包装为 `[{type:"text", text:"..."}]` | | `messages[].role = "tool"` | `messages[].role = "user"` + `type = "tool_result"` | 工具结果转为用户消息 | | `messages[].tool_calls` | `content.type = "tool_use"` | 工具调用转为 content 块 | | `tools[].function.parameters` | `tools[].input_schema` | 字段名转换 | | `tool_choice` | `tool_choice.type + name` | auto/tool/any 格式映射 | | `max_tokens` | `max_tokens` | 直接映射,默认 4096 | **认证**: `x-api-key: ` + `anthropic-version: 2023-06-01`。Claude 3.5 Sonnet 额外添加 `anthropic-beta: max-tokens-3-5-sonnet-2024-07-15`。 **URL**: `{base_url}/v1/messages` **响应转换**: | Claude 字段 | OpenAI 字段 | |---|---| | `content[].text` | `choices[].message.content` | | `content[].type = "tool_use"` | `choices[].message.tool_calls[]` | | `stop_reason: "end_turn"/"stop_sequence"` | `finish_reason: "stop"` | | `stop_reason: "max_tokens"` | `finish_reason: "length"` | | `stop_reason: "tool_use"` | `finish_reason: "tool_calls"` | | `usage.input_tokens/output_tokens` | `usage.prompt_tokens/completion_tokens` | **流式处理**: Claude 的 SSE 事件类型(`message_start`、`content_block_start`、`content_block_delta`、`message_delta`)逐事件转换为 OpenAI 的 `chat.completion.chunk` 格式。 ### 5.3 Google Gemini 适配器 **文件**: `relay/adaptor/gemini/` (4 文件, main.go 437 行) **请求转换**: | OpenAI 字段 | Gemini 字段 | 转换说明 | |---|---|---| | `messages[]` | `contents[]` | 数组结构转换 | | `role = "assistant"` | `role = "model"` | 角色名映射 | | `role = "system"` | `systemInstruction` 或 `role = "user"` | 新模型用 systemInstruction,旧模型转 user | | `tools[].function` | `tools[].functionDeclarations[]` | 字段名转换 | | `temperature/top_p/max_tokens` | `generationConfig.{temperature, topP, maxOutputTokens}` | 包装到 generationConfig | | `response_format.type = "json_object"` | `responseMimeType = "application/json"` | MIME 类型映射 | **特殊处理**: - system 消息后自动插入 `model: "Okay"` 虚拟消息(Gemini API 要求角色交替) - 安全设置设为最低 (`GeminiSafetySetting`,5 个类别) - 图片数量限制最多 16 张,转为 base64 inlineData - 支持 system instruction 的模型列表硬编码: `gemini-2.0-flash`, `gemini-2.0-flash-exp`, `gemini-2.0-flash-thinking-exp-01-21` **URL**: `{base_url}/{version}/models/{model}:{action}` - 版本选择: `gemini-2.0` 和 `gemini-1.5` 用 `v1beta`;其他用 `config.GeminiVersion` - 非流式: `generateContent` - 流式: `streamGenerateContent?alt=sse` - Embedding: `batchEmbedContents` **认证**: `x-goog-api-key: ` ### 5.4 阿里通义千问适配器 **文件**: `relay/adaptor/ali/` (5 文件, main.go 267 行) 使用阿里 DashScope API 格式。 **请求转换**: - Messages 包装到 `Input.Messages`,参数包装到 `Parameters`(含 `ResultFormat: "message"`, `IncrementalOutput`, `EnableSearch`) - 模型名后缀 `-internet` 启用联网搜索 (`EnableSearch: true`) - `top_p` 上限为 0.9999 - 图片生成使用异步模式 (`X-DashScope-Async: enable`),轮询等待(最多 20 步,2 秒间隔) **URL**: - 文本: `/api/v1/services/aigc/text-generation/generation` - Embedding: `/api/v1/services/embeddings/text-embedding/text-embedding` - 图片: `/api/v1/services/aigc/text2image/image-synthesis` **特殊头**: `X-DashScope-SSE: enable` (流式), `X-DashScope-Async: enable` (异步) ### 5.5 百度文心一言适配器 **文件**: `relay/adaptor/baidu/` (4 文件, main.go 312 行) **认证方式**: 百度不使用 API Key 直接认证,而是先通过 `client_id|client_secret` 获取 `access_token`,然后在 URL 中传递。 **access_token 缓存机制**: - `baiduTokenStore` 使用 `sync.Map` 存储 - 缓存的 token 在过期前 1 小时触发异步刷新 - API Key 格式: `client_id|client_secret`,通过 OAuth2 端点获取 token **请求转换**: 系统消息提取到 `System` 字段,`FrequencyPenalty` → `PenaltyScore` **URL**: `{base_url}/rpc/2.0/ai_custom/v1/wenxinworkshop/{suffix}?access_token={token}` - URL 中包含模型端点名称(如 `chat/completions_pro`),通过大量 switch-case 映射模型名到端点 ### 5.6 智谱 ChatGLM 适配器 **文件**: `relay/adaptor/zhipu/` (4 文件) **双版本支持**: - **v4** (`glm-*` 模型): `/api/paas/v4/chat/completions` — **OpenAI 兼容**,直接复用 OpenAI 的 StreamHandler/Handler - **v3**: `/api/paas/v3/model-api/{model}/{method}` — 自有格式 **认证**: JWT token(API Key 格式 `id.secret`,HMAC-SHA256 签名) ### 5.7 腾讯混元适配器 **文件**: `relay/adaptor/tencent/` (4 文件, main.go 307 行) - URL: `{baseURL}/` (单一端点) - 认证: **TC3-HMAC-SHA256** 签名算法(完整实现在 main.go 中) - API Key 格式: `appId|secretId|secretKey` ### 5.8 讯飞星火适配器 **文件**: `relay/adaptor/xunfei/` (5 文件, main.go 273 行) - **协议**: WebSocket(唯一非 HTTP 适配器) - `GetRequestURL()` 返回空字符串,`DoRequest()` 返回 dummy 200 - `DoResponse()` 处理实际 WebSocket 通信 - 认证: HMAC-SHA256 签名的 WebSocket URL - API Key 格式: `appId|apiSecret|apiKey` (pipe 分隔三部分) - 流式: 使用 `c.Stream()` + SSE 格式 - 非流式: 累积所有 WebSocket chunk 后返回单次响应 ### 5.9 AWS Bedrock Claude 适配器 **文件**: `relay/adaptor/aws/` (5 文件) - 使用 **AWS SDK v2** `bedrockruntime.Client`,不走 HTTP - **子适配器模式**: `registry.go` 根据模型名分派到 `aws/claude/` 或 `aws/llama3/` - `aws/claude/`: 复用 `anthropic.ConvertRequest()` 转换请求,使用 Bedrock `InvokeModel`/`InvokeModelWithResponseStream` 通信 - `aws/llama3/`: Llama3 专用转换 ### 5.10 Google Vertex AI 适配器 **文件**: `relay/adaptor/vertexai/` (5 文件) - URL: `{baseURL}/v1/projects/{project}/locations/{region}/publishers/google/models/{model}:{action}` - Claude: `rawPredict`/`streamRawPredict?alt=sse` - Gemini: `generateContent`/`streamGenerateContent?alt=sse` - **子适配器模式**: `registry.go` 分派到 `vertexai/claude/` 或 `vertexai/gemini/` - `vertexai/claude/`: 复用 `anthropic.ConvertRequest()`,设置 `anthropic_version: "vertex-2023-10-16"` - `vertexai/gemini/`: 复用 `gemini.ConvertRequest()` - 认证: Google Cloud IAM `GenerateAccessToken` (ADC),Token 缓存 50 分钟 TTL ### 5.11 其他适配器简述 | 适配器 | 文件 | 关键特征 | |-------|------|---------| | **Ollama** | `adaptor/ollama/` | 类 OpenAI 格式,`/api/chat` 或 `/api/generate` | | **Coze** | `adaptor/coze/` | 字节跳动 Coze 平台 | | **Cohere** | `adaptor/cohere/` | Cohere 自有 API 格式 | | **Cloudflare** | `adaptor/cloudflare/` | Workers AI,URL 支持 Cloudflare AI Gateway | | **DeepL** | `adaptor/deepl/` | 翻译 API,非 LLM | | **Replicate** | `adaptor/replicate/` | 异步任务模式 | | **PaLM** | `adaptor/palm/` | Google PaLM (旧版) | | **Proxy** | `adaptor/proxy/` | 通用透传代理,无转换 | --- ## 六、统一数据模型 ### 6.1 统一请求模型 (`relay/model/general.go`, 88 行) ```go type GeneralOpenAIRequest struct { Messages []Message // 聊天消息 Model string // 模型名 MaxTokens int // 最大生成 token MaxCompletionTokens int // 最大完成 token (o-series) Temperature *float64 // 温度 TopP *float64 // Top-P TopK int // Top-K Stream bool // 流式 StreamOptions *StreamOptions // 流式选项 Tools []Tool // 工具调用 ToolChoice any // 工具选择 Stop any // 停止词 ResponseFormat *ResponseFormat // 响应格式 ReasoningEffort string // 推理强度 Store *bool // 存储标记 // ... 更多字段 } ``` 这是整个项目的"通用语言"——所有厂商的请求都先解析为此格式,再由各 Adaptor 转换为厂商格式。 ### 6.2 统一消息模型 (`relay/model/message.go`, 91 行) ```go type Message struct { Role string // system / user / assistant / tool / developer Content any // 字符串 或 多模态内容数组 ReasoningContent any // 推理内容 (o1 等模型) Name *string // 消息发送者名称 ToolCalls []Tool // 工具调用结果 ToolCallId string // 工具调用 ID } ``` `Content` 支持字符串(纯文本)和数组(多模态:text + image_url),通过 `ParseContent()` 解析。 ### 6.3 统一 Usage 模型 ```go type Usage struct { PromptTokens int CompletionTokens int TotalTokens int } ``` ### 6.4 统一错误模型 所有上游错误统一转换为 OpenAI 错误格式: ```json {"error": {"message": "...", "type": "...", "param": "...", "code": "..."}} ``` `GeneralErrorResponse` 兼容多种厂商的错误格式(OpenAI 的 `error.message`、通用的 `message`、百度的 `error_msg` 等)。 --- ## 七、中转模式 (RelayMode) **文件**: `relay/relaymode/` (2 文件) 11 种中转模式,根据 URL 路径自动判断: | 模式 | URL 路径 | 说明 | |------|---------|------| | ChatCompletions | `/v1/chat/completions` | Chat 聊天补全 | | Completions | `/v1/completions` | 文本补全 | | Embeddings | `/v1/embeddings`, `/v1/engines/:model/embeddings` | 文本嵌入 | | Moderations | `/v1/moderations` | 内容审核 | | ImagesGenerations | `/v1/images/generations` | 图片生成 | | Edits | `/v1/edits` | 文本编辑 | | AudioSpeech | `/v1/audio/speech` | 语音合成 | | AudioTranscription | `/v1/audio/transcriptions` | 语音识别 | | AudioTranslation | `/v1/audio/translations` | 语音翻译 | | Proxy | `/v1/oneapi/proxy/:channelid/*target` | 通用代理 | 判断逻辑通过 `strings.HasPrefix` 匹配。 --- ## 八、关键业务逻辑 ### 8.1 配额管理 "预扣费 + 后结算"机制: 1. **预扣费**: 根据 prompt tokens 和模型倍率预先扣除估算配额 2. **后结算**: 根据 usage 的实际 token 数计算费用并调整 3. 信任优化: 用户配额超过预扣费 100 倍时跳过预扣 ### 8.2 自动重试 请求失败时 (429/5xx): 1. 选择另一个不同的渠道(随机负载均衡) 2. 重新设置上下文 3. 从缓存的原始 body 重放请求 4. 最多重试 `RetryTimes` 次 5. 429 返回特殊消息"当前分组上游负载已饱和,请稍后再试" ### 8.3 错误监控 `processChannelRelayError()` 异步记录错误,并通过 `monitor.ShouldDisableChannel()` 自动禁用频繁出错的渠道。 --- ## 九、流式 (SSE) 处理架构 ### 9.1 统一处理流程 ``` 上游 SSE 流 → Scanner 逐行扫描 → 解析厂商 JSON → 转换为 OpenAI 格式 → SSE 写回客户端 ``` ### 9.2 各厂商 SSE 格式对比 | 厂商 | SSE 前缀 | 数据格式 | 结束标记 | |------|---------|---------|---------| | OpenAI | `data: ` | `ChatCompletionsStreamResponse` | `data: [DONE]` | | Anthropic | `data:` | `StreamResponse` (type 字段区分事件) | 无显式标记 | | Gemini | `data: ` | `ChatResponse` | 无显式标记 | | 阿里 | `data:` | `ChatResponse` (`\n` 分隔) | 无显式标记 | | 百度 | `data: ` | `ChatStreamResponse` | `is_end = true` | ### 9.3 OpenAI 兼容渠道的 SSE 优化 OpenAI 兼容渠道的流式数据直接透传给客户端,仅需解析统计 usage 信息,不需要格式转换。 --- ## 十、架构总结 ### 10.1 核心设计原则 1. **统一入口,适配器分发**: 所有请求通过同一入口,由工厂模式创建对应适配器 2. **OpenAI 格式为"通用语言"**: 内部所有流转使用 OpenAI 格式,仅在"进出"时转换 3. **接口抽象**: 通过 `Adaptor` 接口 (9 方法) 隔离各厂商差异,新增厂商只需实现接口 4. **零拷贝优化**: OpenAI 兼容渠道无特殊处理时直接透传请求体 5. **关注点分离**: 认证、分发、转换、计费、重试各自独立 ### 10.2 新增厂商适配步骤 1. 在 `relay/channeltype/define.go` 添加 `ChannelType` 常量 2. 在 `relay/apitype/define.go` 添加 `APIType`(或复用已有) 3. 在 `relay/channeltype/helper.go` 添加 `ToAPIType()` 映射 4. 在 `relay/channeltype/url.go` 添加默认 BaseURL 5. 创建 `relay/adaptor//` 目录实现 `Adaptor` 接口 6. 如果复用 OpenAI 格式,只需在 `compatible.go` 的 `CompatibleChannels` 列表中添加 ### 10.3 架构特点 **优点**: - 接口精简(9 方法),扩展性强 - 18 种 OpenAI 兼容渠道零开销透传 - 自动重试 + 渠道切换 + 错误监控自动禁用 - 统一的计费和错误处理 - 子适配器模式支持 Bedrock/Vertex AI 的多云厂商模型 **局限**: - 仅支持 OpenAI 格式输入/输出(New-API 已在此基础上扩展了 Claude/Gemini 输入) - 音频处理未完全走 Adaptor 接口 - 部分适配器 SSE 解析逻辑有重复模式,可抽取公共基类 - 缺少请求/响应中间件钩子的统一注入点