Files
1818web-hoduan/MULTI_VENDOR_ADAPTER_DESIGN.md
2025-11-14 17:41:15 +08:00

243 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 多厂商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.**容错性**:某个厂商故障不影响其他厂商
## 📈 未来扩展
- 支持厂商负载均衡
- 支持厂商降级和熔断
- 支持厂商价格对比和智能选择
- 支持多厂商并行调用(取最快)