1
0

docs: 添加 API 参考文档和技术分析文档

This commit is contained in:
2026-04-19 01:43:02 +08:00
parent 2b1c5e96c3
commit b92974716f
14 changed files with 32227 additions and 0 deletions

View File

@@ -0,0 +1,667 @@
# 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 <token>`
- 管理员可通过 `sk-<token>-<channelId>` 指定特定渠道
- 验证 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 <api_key>`
- Azure: `api-key: <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: <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: <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 tokenAPI 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 AIURL 支持 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/<vendor>/` 目录实现 `Adaptor` 接口
6. 如果复用 OpenAI 格式,只需在 `compatible.go``CompatibleChannels` 列表中添加
### 10.3 架构特点
**优点**:
- 接口精简9 方法),扩展性强
- 18 种 OpenAI 兼容渠道零开销透传
- 自动重试 + 渠道切换 + 错误监控自动禁用
- 统一的计费和错误处理
- 子适配器模式支持 Bedrock/Vertex AI 的多云厂商模型
**局限**:
- 仅支持 OpenAI 格式输入/输出New-API 已在此基础上扩展了 Claude/Gemini 输入)
- 音频处理未完全走 Adaptor 接口
- 部分适配器 SSE 解析逻辑有重复模式,可抽取公共基类
- 缺少请求/响应中间件钩子的统一注入点