- Remove old review reports (keep latest only) - Move docs/ to deploy/docs-backup/ - Move performance-testing/ to deploy/ - Clean up test output files - Organize root directory
747 lines
22 KiB
Markdown
747 lines
22 KiB
Markdown
# Sub2API 国产模型接入详细方案
|
|
|
|
> 版本: v1.0
|
|
> 日期: 2026-03-26
|
|
> 状态: 详细设计
|
|
|
|
---
|
|
|
|
## 一、当前模型支持现状
|
|
|
|
### 1.1 已有模型支持
|
|
|
|
| 平台 | 状态 | 实现方式 |
|
|
|------|------|---------|
|
|
| **OpenAI** | ✅ 完整 | 原生 client |
|
|
| **Anthropic** | ✅ 完整 | 原生 client |
|
|
| **Google Gemini** | ✅ 完整 | 原生 client |
|
|
| **AWS Bedrock** | ✅ 完整 | AWS SDK |
|
|
| **自定义 Upstream** | ✅ 完整 | HTTP 代理 |
|
|
| **Antigravity** | ✅ 完整 | 自定义 |
|
|
| **Sora (Claude Code)** | ✅ 完整 | 自定义 |
|
|
|
|
### 1.2 待接入模型
|
|
|
|
| 序号 | 模型 | 厂商 | API 特点 | 优先级 |
|
|
|-----|------|------|---------|--------|
|
|
| 1 | 文心一言 | 百度 | REST API | P0 |
|
|
| 2 | 通义千问 | 阿里 | OpenAI 兼容 | P0 |
|
|
| 3 | 讯飞星火 | 讯飞 | 私有协议 | P1 |
|
|
| 4 | 混元 | 腾讯 | OpenAI 兼容 | P1 |
|
|
| 5 | 豆包 | 字节 | OpenAI 兼容 | P1 |
|
|
| 6 | MiniMax | MiniMax | OpenAI 兼容 | P1 |
|
|
| 7 | DeepSeek | DeepSeek | OpenAI 兼容 | P0 |
|
|
| 8 | 智谱清言 | 智谱 | OpenAI 兼容 | P2 |
|
|
| 9 | 百川智能 | 百川 | OpenAI 兼容 | P2 |
|
|
|
|
---
|
|
|
|
## 二、技术架构设计
|
|
|
|
### 2.1 整体架构
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────────┐
|
|
│ 模型接入架构 │
|
|
├─────────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
|
│ │ Gateway (API 网关) │ │
|
|
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
|
|
│ │ │OpenAI兼容│ │Anthropic │ │ Gemini │ │ Bedrock │ │ │
|
|
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
|
|
│ └─────────────────────────────────────────────────────────────────┘ │
|
|
│ │ │
|
|
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
|
│ │ Provider Adapter Layer │ │
|
|
│ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │
|
|
│ │ │ 百川/智谱 │ │ DeepSeek │ │ 通义/豆包 │ │ 讯飞/混元 │ │ │
|
|
│ │ │(OpenAI兼容)│ │(OpenAI兼容)│ │(OpenAI兼容)│ │ (自定义) │ │ │
|
|
│ │ └────────────┘ └────────────┘ └────────────┘ └────────────┘ │ │
|
|
│ └─────────────────────────────────────────────────────────────────┘ │
|
|
│ │ │
|
|
│ ┌─────────────────────────────────────────────────────────────────┐ │
|
|
│ │ External APIs │ │
|
|
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
|
|
│ │ │ 百度 │ │ 阿里 │ │ 腾讯 │ │ 讯飞 │ │ │
|
|
│ │ │ ERNIE Bot│ │ Qwen API │ │Hunyuan API│ │ Spark API │ │ │
|
|
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
|
|
│ └─────────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 2.2 目录结构
|
|
|
|
```go
|
|
backend/internal/pkg/
|
|
├── openai/ // 现有 OpenAI 客户端
|
|
│ ├── client.go
|
|
│ ├── types.go
|
|
│ └── stream.go
|
|
├── anthropic/ // 现有 Anthropic 客户端
|
|
│ └── ...
|
|
├── models/ // 新增: 模型提供商适配器
|
|
│ ├── factory.go // 工厂模式创建 client
|
|
│ ├── interface.go // 统一接口定义
|
|
│ ├── base.go // 基础实现
|
|
│ ├── openai_compat.go // OpenAI 兼容适配器
|
|
│ │ ├── deepseek/ // DeepSeek
|
|
│ │ ├── qwen/ // 通义千问
|
|
│ │ ├── doubao/ // 豆包
|
|
│ │ ├── minimax/ // MiniMax
|
|
│ │ ├── zhipu/ // 智谱清言
|
|
│ │ └── baichuan/ // 百川智能
|
|
│ └── custom/ // 自定义协议
|
|
│ ├── baidu/ // 百度文心
|
|
│ ├── tencent/ // 腾讯混元
|
|
│ └── xfyun/ // 讯飞星火
|
|
└── oauth/ // 现有 OAuth 处理
|
|
```
|
|
|
|
---
|
|
|
|
## 三、接口设计
|
|
|
|
### 3.1 统一 Provider 接口
|
|
|
|
```go
|
|
// backend/internal/pkg/models/interface.go
|
|
|
|
package models
|
|
|
|
// Provider 模型提供商接口
|
|
type Provider interface {
|
|
// Name 返回提供商名称
|
|
Name() string
|
|
|
|
// BaseURL 返回 API 基础地址
|
|
BaseURL() string
|
|
|
|
// Models 返回支持的模型列表
|
|
Models() []Model
|
|
|
|
// Chat 发起聊天请求
|
|
Chat(ctx context.Context, req *ChatRequest) (*ChatResponse, error)
|
|
|
|
// ChatStream 发起流式聊天请求
|
|
ChatStream(ctx context.Context, req *ChatRequest) (*StreamReader, error)
|
|
|
|
// Embeddings 获取嵌入向量
|
|
Embeddings(ctx context.Context, req *EmbeddingsRequest) (*EmbeddingsResponse, error)
|
|
|
|
// ValidateKey 验证 API 密钥有效性
|
|
ValidateKey(ctx context.Context, key string) error
|
|
}
|
|
|
|
// Model 模型信息
|
|
type Model struct {
|
|
ID string `json:"id"` // 模型 ID
|
|
Name string `json:"name"` // 显示名称
|
|
Provider string `json:"provider"` // 提供商
|
|
Type string `json:"type"` // chat, embedding, image
|
|
ContextSize int `json:"context_size"` // 上下文长度
|
|
MaxTokens int `json:"max_tokens"` // 最大输出 tokens
|
|
Capabilities []string `json:"capabilities"` // streaming, vision, function_call
|
|
}
|
|
|
|
// ChatRequest 聊天请求
|
|
type ChatRequest struct {
|
|
Model string `json:"model"`
|
|
Messages []ChatMessage `json:"messages"`
|
|
Temperature float64 `json:"temperature,omitempty"`
|
|
MaxTokens int `json:"max_tokens,omitempty"`
|
|
Stream bool `json:"stream,omitempty"`
|
|
Tools []Tool `json:"tools,omitempty"`
|
|
// ... 其他参数
|
|
}
|
|
|
|
// ChatMessage 聊天消息
|
|
type ChatMessage struct {
|
|
Role string `json:"role"` // system, user, assistant, tool
|
|
Content string `json:"content"`
|
|
// ...
|
|
}
|
|
```
|
|
|
|
### 3.2 工厂模式
|
|
|
|
```go
|
|
// backend/internal/pkg/models/factory.go
|
|
|
|
package models
|
|
|
|
import (
|
|
"errors"
|
|
)
|
|
|
|
var (
|
|
ErrUnknownProvider = errors.New("unknown provider")
|
|
|
|
// provider registry
|
|
providers = make(map[string]func(cfg *ProviderConfig) Provider)
|
|
)
|
|
|
|
// RegisterProvider 注册模型提供商
|
|
func RegisterProvider(name string, factory func(cfg *ProviderConfig) Provider) {
|
|
providers[name] = factory
|
|
}
|
|
|
|
// NewProvider 创建模型提供商实例
|
|
func NewProvider(name string, cfg *ProviderConfig) (Provider, error) {
|
|
factory, ok := providers[name]
|
|
if !ok {
|
|
return nil, ErrUnknownProvider
|
|
}
|
|
return factory(cfg), nil
|
|
}
|
|
|
|
// ProviderConfig 提供商配置
|
|
type ProviderConfig struct {
|
|
APIKey string
|
|
BaseURL string
|
|
Organization string
|
|
HTTPClient *http.Client
|
|
Timeout time.Duration
|
|
}
|
|
|
|
// Init 初始化内置提供商
|
|
func Init() {
|
|
// OpenAI 兼容系列 (使用通用适配器)
|
|
RegisterProvider("deepseek", NewOpenAICompatProvider)
|
|
RegisterProvider("qwen", NewOpenAICompatProvider)
|
|
RegisterProvider("doubao", NewOpenAICompatProvider)
|
|
RegisterProvider("minimax", NewOpenAICompatProvider)
|
|
RegisterProvider("zhipu", NewOpenAICompatProvider)
|
|
RegisterProvider("baichuan", NewOpenAICompatProvider)
|
|
RegisterProvider("anthropic", NewOpenAICompatProvider) // 复用
|
|
|
|
// 自定义协议系列
|
|
RegisterProvider("baidu", NewBaiduProvider)
|
|
RegisterProvider("tencent", NewTencentProvider)
|
|
RegisterProvider("xfyun", NewXfyunProvider)
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 四、模型配置
|
|
|
|
### 4.1 模型映射配置
|
|
|
|
```yaml
|
|
# backend/config.yaml
|
|
|
|
models:
|
|
# 现有模型
|
|
- platform: openai
|
|
name: GPT-4
|
|
model_id: gpt-4
|
|
enabled: true
|
|
|
|
- platform: anthropic
|
|
name: Claude 3.5
|
|
model_id: claude-3-5-sonnet-20241022
|
|
enabled: true
|
|
|
|
# 新增国产模型
|
|
|
|
# DeepSeek (OpenAI 兼容)
|
|
- platform: deepseek
|
|
name: DeepSeek Chat
|
|
model_id: deepseek-chat
|
|
base_url: https://api.deepseek.com/v1
|
|
enabled: true
|
|
|
|
- platform: deepseek
|
|
name: DeepSeek Coder
|
|
model_id: deepseek-coder
|
|
base_url: https://api.deepseek.com/v1
|
|
enabled: true
|
|
|
|
# 通义千问 (OpenAI 兼容)
|
|
- platform: qwen
|
|
name: Qwen Turbo
|
|
model_id: qwen-turbo
|
|
base_url: https://dashscope.aliyuncs.com/compatible-mode/v1
|
|
enabled: true
|
|
|
|
- platform: qwen
|
|
name: Qwen Plus
|
|
model_id: qwen-plus
|
|
base_url: https://dashscope.aliyuncs.com/compatible-mode/v1
|
|
enabled: true
|
|
|
|
- platform: qwen
|
|
name: Qwen Max
|
|
model_id: qwen-max
|
|
base_url: https://dashscope.aliyuncs.com/compatible-mode/v1
|
|
enabled: true
|
|
|
|
# 百度文心一言 (自定义)
|
|
- platform: baidu
|
|
name: ERNIE 4.0
|
|
model_id: ernie-4.0-8k
|
|
base_url: https://qianfan.baidubce.com/v2
|
|
enabled: true
|
|
|
|
- platform: baidu
|
|
name: ERNIE 3.5
|
|
model_id: ernie-3.5-8k
|
|
base_url: https://qianfan.baidubce.com/v2
|
|
enabled: true
|
|
|
|
# 讯飞星火 (自定义)
|
|
- platform: xfyun
|
|
name: Spark Max
|
|
model_id: spark-max
|
|
base_url: https://spark-api.xf-yun.com/v3.5
|
|
enabled: true
|
|
|
|
# 腾讯混元 (OpenAI 兼容)
|
|
- platform: tencent
|
|
name: Hunyuan Turbo
|
|
model_id: hunyuan-turbo
|
|
base_url: https://hunyuan-api.tencentcloudapi.com/v1
|
|
enabled: true
|
|
|
|
# 豆包 (OpenAI 兼容)
|
|
- platform: doubao
|
|
name: Doubao Pro
|
|
model_id: doubao-pro-32k
|
|
base_url: https://ark.cn-beijing.volces.com/api/v3
|
|
enabled: true
|
|
|
|
# MiniMax (OpenAI 兼容)
|
|
- platform: minimax
|
|
name: MiniMax Text
|
|
model_id: abab6.5s-chat
|
|
base_url: https://api.minimax.chat/v1
|
|
enabled: true
|
|
|
|
# 智谱清言 (OpenAI 兼容)
|
|
- platform: zhipu
|
|
name: GLM-4
|
|
model_id: glm-4
|
|
base_url: https://open.bigmodel.cn/api/paas/v4
|
|
enabled: true
|
|
```
|
|
|
|
### 4.2 数据库模型
|
|
|
|
```go
|
|
// backend/ent/schema/platform.go
|
|
|
|
// Platform 模型平台
|
|
type Platform struct {
|
|
ent.Schema
|
|
|
|
Fields []ent.Field {
|
|
String("name").Unique().NotEmpty(), // 平台名称
|
|
String("display_name").NotEmpty(), // 显示名称
|
|
String("api_base_url").Optional(), // API 基础地址
|
|
String("documentation").Optional(), // 文档链接
|
|
Bool("enabled").Default(true), // 是否启用
|
|
JSON("capabilities", []string{}), // 能力列表
|
|
JSON("auth_config", map[string]string{}),// 认证配置
|
|
Time("created_at"),
|
|
Time("updated_at"),
|
|
}
|
|
|
|
Edges []ent.Edge {
|
|
OneToMany("models", Model.Type),
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 五、各模型接入实现
|
|
|
|
### 5.1 DeepSeek 接入 (OpenAI 兼容)
|
|
|
|
```go
|
|
// backend/internal/pkg/models/openai_compat/deepseek/deepseek.go
|
|
|
|
package deepseek
|
|
|
|
import (
|
|
"context"
|
|
"github.com/Wei-Shaw/sub2api/internal/pkg/models"
|
|
)
|
|
|
|
type DeepSeekProvider struct {
|
|
*models.OpenAICompatProvider // 嵌入通用 OpenAI 兼容实现
|
|
}
|
|
|
|
func New(cfg *models.ProviderConfig) models.Provider {
|
|
baseURL := "https://api.deepseek.com/v1"
|
|
if cfg.BaseURL != "" {
|
|
baseURL = cfg.BaseURL
|
|
}
|
|
|
|
return &DeepSeekProvider{
|
|
OpenAICompatProvider: models.NewOpenAICompatProvider(
|
|
"deepseek",
|
|
baseURL,
|
|
[]models.Model{
|
|
{ID: "deepseek-chat", Name: "DeepSeek Chat", Type: "chat", ContextSize: 32*1024},
|
|
{ID: "deepseek-coder", Name: "DeepSeek Coder", Type: "chat", ContextSize: 16*1024},
|
|
},
|
|
cfg,
|
|
),
|
|
}
|
|
}
|
|
|
|
// 注册到工厂
|
|
func init() {
|
|
models.RegisterProvider("deepseek", New)
|
|
}
|
|
```
|
|
|
|
### 5.2 百度文心接入 (自定义协议)
|
|
|
|
```go
|
|
// backend/internal/pkg/models/custom/baidu/baidu.go
|
|
|
|
package baidu
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/Wei-Shaw/sub2api/internal/pkg/models"
|
|
)
|
|
|
|
type BaiduProvider struct {
|
|
config *models.ProviderConfig
|
|
baseURL string
|
|
accessToken string
|
|
tokenExpiry time.Time
|
|
}
|
|
|
|
func New(cfg *models.ProviderConfig) models.Provider {
|
|
baseURL := "https://qianfan.baidubce.com/v2"
|
|
if cfg.BaseURL != "" {
|
|
baseURL = cfg.BaseURL
|
|
}
|
|
|
|
return &BaiduProvider{
|
|
config: cfg,
|
|
baseURL: baseURL,
|
|
}
|
|
}
|
|
|
|
func (p *BaiduProvider) Name() string { return "baidu" }
|
|
func (p *BaiduProvider) BaseURL() string { return p.baseURL }
|
|
|
|
func (p *BaiduProvider) Models() []models.Model {
|
|
return []models.Model{
|
|
{ID: "ernie-4.0-8k", Name: "ERNIE 4.0", Type: "chat", ContextSize: 8*1024, MaxTokens: 8*1024},
|
|
{ID: "ernie-3.5-8k", Name: "ERNIE 3.5", Type: "chat", ContextSize: 8*1024, MaxTokens: 8*1024},
|
|
{ID: "ernie-speed-8k", Name: "ERNIE Speed", Type: "chat", ContextSize: 8*1024, MaxTokens: 8*1024},
|
|
{ID: "ernie-text-embedding-v1", Name: "ERNIE Embedding", Type: "embedding", ContextSize: 8*1024},
|
|
}
|
|
}
|
|
|
|
// 获取 Access Token (百度需要 OAuth)
|
|
func (p *BaiduProvider) getAccessToken(ctx context.Context) (string, error) {
|
|
if p.accessToken != "" && time.Now().Before(p.tokenExpiry) {
|
|
return p.accessToken, nil
|
|
}
|
|
|
|
// 调用百度 OAuth 获取 token
|
|
// POST https://aip.baidubce.com/oauth/2.0/token
|
|
// grant_type=client_credentials&client_id=xxx&client_secret=xxx
|
|
|
|
// 这里需要从 config 中获取 client_id 和 client_secret
|
|
// 暂时简化处理,实际需要完善
|
|
return p.accessToken, nil
|
|
}
|
|
|
|
func (p *BaiduProvider) Chat(ctx context.Context, req *models.ChatRequest) (*models.ChatResponse, error) {
|
|
token, err := p.getAccessToken(ctx)
|
|
if err != nil {
|
|
return nil, errors.New("failed to get access token: " + err.Error())
|
|
}
|
|
|
|
// 构建请求
|
|
url := p.baseURL + "/chat/completions"
|
|
|
|
// 转换消息格式
|
|
messages := make([]map[string]interface{}, len(req.Messages))
|
|
for i, m := range req.Messages {
|
|
messages[i] = map[string]interface{}{
|
|
"role": m.Role,
|
|
"content": m.Content,
|
|
}
|
|
}
|
|
|
|
body := map[string]interface{}{
|
|
"model": req.Model,
|
|
"messages": messages,
|
|
}
|
|
if req.Temperature > 0 {
|
|
body["temperature"] = req.Temperature
|
|
}
|
|
if req.MaxTokens > 0 {
|
|
body["max_tokens"] = req.MaxTokens
|
|
}
|
|
|
|
jsonBody, _ := json.Marshal(body)
|
|
|
|
httpReq, _ := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(jsonBody))
|
|
httpReq.Header.Set("Content-Type", "application/json")
|
|
httpReq.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
// 发送请求...
|
|
// 处理响应...
|
|
|
|
return nil, nil // 简化,实际需要完整实现
|
|
}
|
|
|
|
func (p *BaiduProvider) ValidateKey(ctx context.Context, key string) error {
|
|
// 验证 API Key 有效性
|
|
// 可以调用 /me 接口或获取 token 测试
|
|
return nil
|
|
}
|
|
|
|
// 注册到工厂
|
|
func init() {
|
|
models.RegisterProvider("baidu", New)
|
|
}
|
|
```
|
|
|
|
### 5.3 通义千问接入 (OpenAI 兼容)
|
|
|
|
```go
|
|
// backend/internal/pkg/models/openai_compat/qwen/qwen.go
|
|
|
|
package qwen
|
|
|
|
import (
|
|
"github.com/Wei-Shaw/sub2api/internal/pkg/models"
|
|
)
|
|
|
|
type QwenProvider struct {
|
|
*models.OpenAICompatProvider
|
|
}
|
|
|
|
func New(cfg *models.ProviderConfig) models.Provider {
|
|
baseURL := "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
if cfg.BaseURL != "" {
|
|
baseURL = cfg.BaseURL
|
|
}
|
|
|
|
return &QwenProvider{
|
|
OpenAICompatProvider: models.NewOpenAICompatProvider(
|
|
"qwen",
|
|
baseURL,
|
|
[]models.Model{
|
|
{ID: "qwen-turbo", Name: "Qwen Turbo", Type: "chat", ContextSize: 8*1024},
|
|
{ID: "qwen-plus", Name: "Qwen Plus", Type: "chat", ContextSize: 32*1024},
|
|
{ID: "qwen-max", Name: "Qwen Max", Type: "chat", ContextSize: 8*1024},
|
|
{ID: "qwen-long", Name: "Qwen Long", Type: "chat", ContextSize: 320*1024},
|
|
},
|
|
cfg,
|
|
),
|
|
}
|
|
}
|
|
|
|
func init() {
|
|
models.RegisterProvider("qwen", New)
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 六、前端集成
|
|
|
|
### 6.1 模型选择下拉框
|
|
|
|
```vue
|
|
<!-- frontend/src/components/common/ModelSelect.vue -->
|
|
|
|
<template>
|
|
<Select
|
|
v-model="selectedModel"
|
|
filterable
|
|
:loading="loading"
|
|
@change="handleChange"
|
|
>
|
|
<OptionGroup :label="t('model.platform.openai')">
|
|
<Option
|
|
v-for="model in openaiModels"
|
|
:key="model.id"
|
|
:value="model.id"
|
|
:label="model.name"
|
|
>
|
|
<div class="model-option">
|
|
<span>{{ model.name }}</span>
|
|
<Tag v-if="model.status === 'beta'" size="small">Beta</Tag>
|
|
</div>
|
|
</Option>
|
|
</OptionGroup>
|
|
|
|
<OptionGroup :label="t('model.platform.anthropic')">
|
|
<Option
|
|
v-for="model in anthropicModels"
|
|
:key="model.id"
|
|
:value="model.id"
|
|
:label="model.name"
|
|
/>
|
|
</OptionGroup>
|
|
|
|
<!-- 新增国产模型 -->
|
|
<OptionGroup :label="t('model.platform.chinese')">
|
|
<Option
|
|
v-for="model in chineseModels"
|
|
:key="model.id"
|
|
:value="model.id"
|
|
:label="model.name"
|
|
/>
|
|
</OptionGroup>
|
|
</Select>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import { useI18n } from 'vue-i18n'
|
|
|
|
const { t } = useI18n()
|
|
|
|
// 按平台分组
|
|
const chineseModels = computed(() =>
|
|
props.models.filter(m =>
|
|
['deepseek', 'qwen', 'baidu', 'xfyun', 'tencent', 'doubao', 'minimax', 'zhipu'].includes(m.platform)
|
|
)
|
|
)
|
|
</script>
|
|
```
|
|
|
|
### 6.2 模型定价配置
|
|
|
|
```yaml
|
|
# backend/resources/model-pricing/model-pricing.yaml
|
|
|
|
models:
|
|
# OpenAI
|
|
gpt-4:
|
|
input: 0.03 # $/1M tokens
|
|
output: 0.06
|
|
gpt-4-turbo:
|
|
input: 0.01
|
|
output: 0.03
|
|
|
|
# Anthropic
|
|
claude-3-5-sonnet:
|
|
input: 0.003
|
|
output: 0.015
|
|
|
|
# 国产模型
|
|
deepseek-chat:
|
|
input: 0.14
|
|
output: 0.14
|
|
|
|
qwen-max:
|
|
input: 0.20
|
|
output: 0.60
|
|
|
|
ernie-4.0-8k:
|
|
input: 0.20
|
|
output: 0.60
|
|
|
|
spark-max:
|
|
input: 0.03
|
|
output: 0.05
|
|
```
|
|
|
|
---
|
|
|
|
## 七、任务拆分
|
|
|
|
### 7.1 开发任务清单
|
|
|
|
| 序号 | 任务 | 模块 | 预估工时 | 依赖 |
|
|
|-----|------|------|---------|------|
|
|
| 1 | 创建 Provider 接口和工厂 | core | 2天 | - |
|
|
| 2 | 实现 OpenAI 兼容基类 | base | 2天 | 1 |
|
|
| 3 | 接入 DeepSeek | provider | 1天 | 2 |
|
|
| 4 | 接入通义千问 | provider | 1天 | 2 |
|
|
| 5 | 接入豆包 | provider | 1天 | 2 |
|
|
| 6 | 接入 MiniMax | provider | 1天 | 2 |
|
|
| 7 | 接入智谱清言 | provider | 1天 | 2 |
|
|
| 8 | 接入百川智能 | provider | 1天 | 2 |
|
|
| 9 | 接入百度文心 (自定义) | provider | 2天 | 1 |
|
|
| 10 | 接入腾讯混元 | provider | 1天 | 2 |
|
|
| 11 | 接入讯飞星火 | provider | 2天 | 1 |
|
|
| 12 | 更新前端模型选择器 | frontend | 2天 | 3-11 |
|
|
| 13 | 添加模型定价配置 | config | 1天 | - |
|
|
| 14 | 编写使用文档 | docs | 1天 | - |
|
|
|
|
### 7.2 实施顺序
|
|
|
|
```
|
|
Week 1: 基础设施 (接口 + 工厂 + 基类)
|
|
↓
|
|
Week 2: OpenAI 兼容系列 (DeepSeek, Qwen, 豆包, MiniMax, 智谱, 百川)
|
|
↓
|
|
Week 3: 自定义协议系列 (百度, 腾讯, 讯飞)
|
|
↓
|
|
Week 4: 前端集成 + 测试 + 文档
|
|
```
|
|
|
|
---
|
|
|
|
## 八、兼容性考虑
|
|
|
|
### 8.1 与官方 Sub2API 兼容
|
|
|
|
```go
|
|
// 兼容性策略:
|
|
// 1. 不修改核心 gateway 逻辑
|
|
// 2. 保持 v1/models, v1/chat/completions API 兼容
|
|
// 3. 新增 provider 不影响现有功能
|
|
// 4. 通过配置开关控制是否启用
|
|
```
|
|
|
|
### 8.2 版本管理
|
|
|
|
```
|
|
v1.0.x - 基础功能 (当前)
|
|
v1.1.x - 国产模型接入
|
|
v1.2.x - 更多模型 + 高级特性
|
|
```
|
|
|
|
---
|
|
|
|
## 九、风险与挑战
|
|
|
|
| 风险 | 应对方案 |
|
|
|-----|---------|
|
|
| 各厂商 API 变更 | 版本化适配器,及时更新 |
|
|
| 认证方式差异 | 统一抽象认证层 |
|
|
| 响应格式不统一 | 标准化响应转换 |
|
|
| 限流/配额处理 | 实现统一的限流控制 |
|
|
|
|
---
|
|
|
|
## 十、总结
|
|
|
|
本方案详细规划了国产模型接入的完整路径:
|
|
|
|
1. **架构设计**: 工厂模式 + OpenAI兼容适配器 + 自定义协议适配器
|
|
2. **优先级**: DeepSeek/通义千问 → 豆包/MiniMax → 百度/腾讯/讯飞
|
|
3. **工作量**: 约 3-4 周完成核心接入
|
|
4. **兼容性**: 保持与官方 Sub2API 的兼容
|
|
|
|
需要我开始实现哪个模型接入吗?建议从 **DeepSeek** 开始,因为它是 OpenAI 兼容,实现难度最低。
|
|
|
|
---
|
|
|
|
*文档版本: v1.0*
|
|
*最后更新: 2026-03-26* |