31 KiB
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 行):
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):
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 行)
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→RelayTextHelperImagesGenerations→RelayImageHelperAudioSpeech / AudioTranscription / AudioTranslation→RelayAudioHelperProxy→RelayProxyHelper
重试策略: 429 和 5xx 触发重试,400 和 2xx 不重试。管理员指定渠道时不重试。
4.4 转换处理阶段 — RelayTextHelper
文件: relay/controller/text.go (115 行)
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 强制选项
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 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 200DoResponse()处理实际 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()转换请求,使用 BedrockInvokeModel/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 行)
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 行)
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 模型
type Usage struct {
PromptTokens int
CompletionTokens int
TotalTokens int
}
6.4 统一错误模型
所有上游错误统一转换为 OpenAI 错误格式:
{"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 配额管理
"预扣费 + 后结算"机制:
- 预扣费: 根据 prompt tokens 和模型倍率预先扣除估算配额
- 后结算: 根据 usage 的实际 token 数计算费用并调整
- 信任优化: 用户配额超过预扣费 100 倍时跳过预扣
8.2 自动重试
请求失败时 (429/5xx):
- 选择另一个不同的渠道(随机负载均衡)
- 重新设置上下文
- 从缓存的原始 body 重放请求
- 最多重试
RetryTimes次 - 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 核心设计原则
- 统一入口,适配器分发: 所有请求通过同一入口,由工厂模式创建对应适配器
- OpenAI 格式为"通用语言": 内部所有流转使用 OpenAI 格式,仅在"进出"时转换
- 接口抽象: 通过
Adaptor接口 (9 方法) 隔离各厂商差异,新增厂商只需实现接口 - 零拷贝优化: OpenAI 兼容渠道无特殊处理时直接透传请求体
- 关注点分离: 认证、分发、转换、计费、重试各自独立
10.2 新增厂商适配步骤
- 在
relay/channeltype/define.go添加ChannelType常量 - 在
relay/apitype/define.go添加APIType(或复用已有) - 在
relay/channeltype/helper.go添加ToAPIType()映射 - 在
relay/channeltype/url.go添加默认 BaseURL - 创建
relay/adaptor/<vendor>/目录实现Adaptor接口 - 如果复用 OpenAI 格式,只需在
compatible.go的CompatibleChannels列表中添加
10.3 架构特点
优点:
- 接口精简(9 方法),扩展性强
- 18 种 OpenAI 兼容渠道零开销透传
- 自动重试 + 渠道切换 + 错误监控自动禁用
- 统一的计费和错误处理
- 子适配器模式支持 Bedrock/Vertex AI 的多云厂商模型
局限:
- 仅支持 OpenAI 格式输入/输出(New-API 已在此基础上扩展了 Claude/Gemini 输入)
- 音频处理未完全走 Adaptor 接口
- 部分适配器 SSE 解析逻辑有重复模式,可抽取公共基类
- 缺少请求/响应中间件钩子的统一注入点