Files
1818web-hoduan/MULTI_VENDOR_ADAPTER_DESIGN.md

243 lines
7.8 KiB
Markdown
Raw Normal View History

# 多厂商AI API适配器设计方案
## 📋 目标
支持接入多个AI服务提供商包括
1. **OpenAI格式API**当前使用的api.apiyi.com
2. **RunningHub API**
3. 未来的其他厂商
## 🏗️ 架构设计
```
┌─────────────────────────────────────────────────────────┐
│ AiTaskService │
│ (业务逻辑层,不变) │
└────────────────────┬────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ AIProviderService (新增) │
│ 根据模型配置选择对应的Provider │
└────────────────────┬────────────────────────────────────┘
┌───────────┴───────────┐
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ OpenAIProvider │ │ RunningHubProvider│
│ (适配器1) │ │ (适配器2) │
└──────────────────┘ └──────────────────┘
│ │
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ api.apiyi.com │ │ www.runninghub.cn│
│ (第三方API) │ │ (第三方API) │
└──────────────────┘ └──────────────────┘
```
## 📝 实现步骤
### 1. 定义统一的Provider接口
```java
public interface AIProvider {
/**
* 提交任务到AI服务商
* @return 统一的任务响应对象
*/
ProviderTaskResponse submitTask(ProviderTaskRequest request);
/**
* 查询任务状态
*/
ProviderTaskStatus queryTaskStatus(String providerTaskId);
/**
* 获取任务结果
*/
ProviderTaskResult getTaskResult(String providerTaskId);
/**
* 获取服务商名称
*/
String getProviderName();
}
```
### 2. 扩展数据库表
#### points_config表新增字段
```sql
ALTER TABLE `points_config`
ADD COLUMN `provider_type` VARCHAR(50) NOT NULL DEFAULT 'openai'
COMMENT 'AI服务提供商类型openai, runninghub',
ADD COLUMN `provider_config` TEXT NULL
COMMENT '服务商特定配置JSON格式';
```
#### ai_task表新增字段
```sql
ALTER TABLE `ai_task`
ADD COLUMN `provider_type` VARCHAR(50) NULL
COMMENT 'AI服务提供商类型',
ADD COLUMN `provider_task_id` VARCHAR(100) NULL
COMMENT '服务商返回的任务ID',
ADD COLUMN `provider_response` TEXT NULL
COMMENT '服务商原始响应JSON';
```
### 3. 配置文件扩展
```yaml
# application.yml
ai:
providers:
openai:
enabled: true
base-url: https://api.apiyi.com/v1/chat/completions
api-key: sk-xxx
timeout: 300000
runninghub:
enabled: true
base-url: https://www.runninghub.cn
submit-url: /task/openapi/ai-app/run
status-url: /task/openapi/status
output-url: /task/openapi/outputs
default-webapp-id: "1973555977595301890"
api-key: 5c44cef12da3470e9f24da70c63787dc
polling-interval: 5000 # 轮询间隔(毫秒)
max-polling-times: 120 # 最大轮询次数10分钟
```
## 🔧 RunningHub特殊处理
### 模型映射配置
`points_config`表中配置RunningHub模型
```sql
INSERT INTO `points_config`
(model_name, points_cost, description, is_enabled, provider_type, provider_config)
VALUES
('rh_sora2_portrait', 160, 'RunningHub Sora2 竖屏视频', 1, 'runninghub',
'{"webappId":"1973555977595301890","duration":10,"model":"portrait"}'),
('rh_sora2_landscape', 160, 'RunningHub Sora2 横屏视频', 1, 'runninghub',
'{"webappId":"1973555977595301890","duration":10,"model":"landscape"}'),
('rh_sora2_portrait_hd', 420, 'RunningHub Sora2 高清竖屏', 1, 'runninghub',
'{"webappId":"1973555977595301890","duration":10,"model":"portrait-hd"}');
```
### 异步任务处理流程
RunningHub是异步API需要特殊处理
```
1. 提交任务 → 获得taskId
2. 更新数据库provider_task_id = taskId, status = 'processing'
3. 启动轮询任务:
- 每5秒查询一次状态
- RUNNING → 继续轮询
- SUCCESS → 获取结果 → 更新status='completed'
- FAILED → 更新status='failed'
- 超时 → 更新status='failed'
```
## 📦 核心类设计
### ProviderTaskRequest统一请求
```java
@Data
public class ProviderTaskRequest {
private String modelName;
private String prompt;
private String imageUrl;
private String imageBase64;
private String aspectRatio;
private Integer duration; // 视频时长
private Map<String, Object> extraParams; // 扩展参数
}
```
### ProviderTaskResponse统一响应
```java
@Data
public class ProviderTaskResponse {
private String providerTaskId; // 服务商任务ID
private TaskSubmitStatus status; // SUBMITTED, PROCESSING, COMPLETED, FAILED
private String resultUrl; // 如果是同步返回,直接有结果
private String errorMessage;
private Map<String, Object> rawResponse; // 原始响应
}
```
### RunningHubNodeInfoRunningHub请求节点
```java
@Data
public class RunningHubNodeInfo {
private String nodeId;
private String fieldName;
private String fieldValue;
private String fieldData; // 可选
private String description;
}
```
## 🔄 任务轮询设计
### 新增定时任务
```java
@Scheduled(fixedDelay = 5000) // 每5秒执行一次
public void pollAsyncTasks() {
// 1. 查询所有 status='processing' 且 provider_type='runninghub' 的任务
// 2. 对每个任务调用 queryTaskStatus
// 3. 根据状态更新数据库
// 4. 如果完成,调用 getTaskResult 获取结果
}
```
## 📊 数据流转
### OpenAI格式同步
```
用户提交 → OpenAIProvider.submitTask()
→ 直接返回结果URL
→ 更新status='completed'
```
### RunningHub格式异步
```
用户提交 → RunningHubProvider.submitTask()
→ 返回taskIdstatus='RUNNING'
→ 定时任务轮询
→ 检测到SUCCESS
→ getTaskResult()获取结果URL
→ 更新status='completed'
```
## ⚠️ 注意事项
1. **配置隔离**:不同厂商的配置独立管理
2. **错误处理**:统一异常类型,便于业务层处理
3. **日志记录**记录每次API调用的原始请求和响应
4. **超时控制**:异步任务需要设置最大轮询次数
5. **并发控制**:轮询任务需要考虑并发和限流
6. **配置热更新**:支持动态切换服务商
## 🎯 优势
1.**扩展性**新增厂商只需实现AIProvider接口
2.**解耦**业务层无需关心底层API差异
3.**灵活性**:同一个模型类型可以配置多个厂商
4.**可维护性**:每个厂商的逻辑独立封装
5.**容错性**:某个厂商故障不影响其他厂商
## 📈 未来扩展
- 支持厂商负载均衡
- 支持厂商降级和熔断
- 支持厂商价格对比和智能选择
- 支持多厂商并行调用(取最快)