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

7.8 KiB
Raw Blame 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接口

public interface AIProvider {
    /**
     * 提交任务到AI服务商
     * @return 统一的任务响应对象
     */
    ProviderTaskResponse submitTask(ProviderTaskRequest request);
    
    /**
     * 查询任务状态
     */
    ProviderTaskStatus queryTaskStatus(String providerTaskId);
    
    /**
     * 获取任务结果
     */
    ProviderTaskResult getTaskResult(String providerTaskId);
    
    /**
     * 获取服务商名称
     */
    String getProviderName();
}

2. 扩展数据库表

points_config表新增字段

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表新增字段

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. 配置文件扩展

# 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模型

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统一请求

@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统一响应

@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请求节点

@Data
public class RunningHubNodeInfo {
    private String nodeId;
    private String fieldName;
    private String fieldValue;
    private String fieldData;  // 可选
    private String description;
}

🔄 任务轮询设计

新增定时任务

@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. 容错性:某个厂商故障不影响其他厂商

📈 未来扩展

  • 支持厂商负载均衡
  • 支持厂商降级和熔断
  • 支持厂商价格对比和智能选择
  • 支持多厂商并行调用(取最快)