架构设计容错高可用

AI API 多供应商容错架构设计:避免单点故障的最佳实践

2026-04-23 · 约 13 分钟阅读

AI API 多供应商容错架构设计:避免单点故障的最佳实践

把所有鸡蛋放在一个篮子里是危险的——依赖单一 AI API 供应商更是如此。服务中断、价格上涨、政策变化……任何一个因素都可能让你的应用瘫痪。本文介绍 AI API 多供应商容错架构设计,帮你构建高可用的系统。

为什么需要多供应商?

风险单一供应商多供应商
服务中断❌ 应用瘫痪✅ 自动切换
价格上涨❌ 被迫接受✅ 灵活选择
配额限制❌ 用完就完✅ 分散压力
区域不可用❌ 无法访问✅ 多区域部署
政策变化❌ 措手不及✅ 有备无患

多供应商架构模式

#### 1. 主备模式(Active-Passive)

用户请求 → 主供应商(OpenAI)
              ↓(失败时)
           备供应商(Anthropic)

特点:

  • 平时只用主供应商
  • 主供应商失败时切换到备用
  • 实现简单,成本可控

适用场景:

  • 预算有限
  • 对成本敏感
  • 备用供应商只是应急

#### 2. 负载均衡模式(Active-Active)

用户请求 → 负载均衡器
              ├─→ 供应商 A(40%)
              ├─→ 供应商 B(30%)
              └─→ 供应商 C(30%)

特点:

  • 同时使用多个供应商
  • 按比例分配流量
  • 分散风险,避免单点

适用场景:

  • 高可用性要求
  • 配额分散使用
  • 成本优化

#### 3. 能力路由模式(Capability-Based)

用户请求 → 能力路由器
              ├─→ 代码生成 → Claude
              ├─→ 快速响应 → GPT-4o Mini
              ├─→ 中文场景 → 通义千问
              └─→ 图片生成 → DALL-E 3

特点:

  • 根据任务选择最佳供应商
  • 发挥各供应商优势
  • 性能和成本最优

适用场景:

  • 多样化任务
  • 追求最佳性价比
  • 有明确的能力需求

#### 4. 混合模式(Hybrid)

用户请求 → 能力路由器
              ├─→ 代码生成 → Claude(主)+ GPT-4o(备)
              ├─→ 快速响应 → GPT-4o Mini(主)+ Claude Haiku(备)
              └─→ 中文场景 → 通义千问(主)+ 豆包(备)

特点:

  • 结合能力路由和主备
  • 每个能力都有备份
  • 最高可用性

适用场景:

  • 企业级应用
  • 99.9%+ 可用性要求
  • 关键业务系统

实现多供应商架构

#### 1. 统一接口抽象

首先定义统一的接口,屏蔽供应商差异:

// 统一的消息格式
interface Message {
  role: 'system' | 'user' | 'assistant';
  content: string;
}

// 统一的响应格式
interface ChatResponse {
  content: string;
  model: string;
  provider: string;
  usage: {
    inputTokens: number;
    outputTokens: number;
  };
}

// 统一的供应商接口
interface AIProvider {
  name: string;
  priority: number;
  enabled: boolean;
  chat(messages: Message[], options?: ChatOptions): Promise<ChatResponse>;
  isHealthy(): Promise<boolean>;
}

// Chat 选项
interface ChatOptions {
  model?: string;
  temperature?: number;
  maxTokens?: number;
  timeout?: number;
}

#### 2. 实现各供应商适配器

// OpenAI 适配器
class OpenAIProvider implements AIProvider {
  name = 'openai';
  priority = 1;
  enabled = true;
  private client: OpenAIClient;

  constructor(apiKey: string) {
    this.client = new OpenAIClient(apiKey);
  }

  async chat(messages: Message[], options?: ChatOptions): Promise<ChatResponse> {
    const response = await this.client.chat.completions.create({
      model: options?.model || 'gpt-4o-mini',
      messages: messages.map(m => ({
        role: m.role,
        content: m.content
      })),
      temperature: options?.temperature,
      max_tokens: options?.maxTokens
    });

    return {
      content: response.choices[0].message.content,
      model: response.model,
      provider: this.name,
      usage: {
        inputTokens: response.usage.prompt_tokens,
        outputTokens: response.usage.completion_tokens
      }
    };
  }

  async isHealthy(): Promise<boolean> {
    try {
      await this.client.models.list();
      return true;
    } catch {
      return false;
    }
  }
}

// Anthropic 适配器
class AnthropicProvider implements AIProvider {
  name = 'anthropic';
  priority = 2;
  enabled = true;
  private client: AnthropicClient;

  constructor(apiKey: string) {
    this.client = new AnthropicClient(apiKey);
  }

  async chat(messages: Message[], options?: ChatOptions): Promise<ChatResponse> {
    const response = await this.client.messages.create({
      model: options?.model || 'claude-3-5-sonnet-20241022',
      messages: messages.filter(m => m.role !== 'system').map(m => ({
        role: m.role,
        content: m.content
      })),
      system: messages.find(m => m.role === 'system')?.content,
      temperature: options?.temperature,
      max_tokens: options?.maxTokens || 4096
    });

    return {
      content: response.content[0].text,
      model: response.model,
      provider: this.name,
      usage: {
        inputTokens: response.usage.input_tokens,
        outputTokens: response.usage.output_tokens
      }
    };
  }

  async isHealthy(): Promise<boolean> {
    try {
      await this.client.messages.create({
        model: 'claude-3-haiku-20240307',
        messages: [{ role: 'user', content: 'hi' }],
        max_tokens: 1
      });
      return true;
    } catch {
      return false;
    }
  }
}

#### 3. 实现多供应商路由器

class MultiProviderRouter {
  private providers: AIProvider[];
  private circuitBreakers: Map<string, CircuitBreaker>;
  private healthCheckInterval: NodeJS.Timeout;

  constructor(providers: AIProvider[]) {
    this.providers = providers;
    this.circuitBreakers = new Map();
    
    // 为每个供应商创建熔断器
    for (const provider of providers) {
      this.circuitBreakers.set(
        provider.name,
        new CircuitBreaker({
          failureThreshold: 0.5,
          windowSize: 60000,
          openTimeout: 30000
        })
      );
    }

    // 定期健康检查
    this.startHealthChecks();
  }

  private startHealthChecks() {
    this.healthCheckInterval = setInterval(async () => {
      for (const provider of this.providers) {
        const healthy = await provider.isHealthy();
        provider.enabled = healthy;
      }
    }, 60000); // 每分钟检查一次
  }

  private getAvailableProviders(): AIProvider[] {
    return this.providers
      .filter(p => p.enabled)
      .filter(p => {
        const breaker = this.circuitBreakers.get(p.name);
        return breaker?.canAttemptCall() ?? true;
      })
      .sort((a, b) => a.priority - b.priority);
  }

  async chat(messages: Message[], options?: ChatOptions): Promise<ChatResponse> {
    const available = this.getAvailableProviders();
    
    if (available.length === 0) {
      throw new Error('No available providers');
    }

    let lastError: Error | null = null;

    for (const provider of available) {
      const breaker = this.circuitBreakers.get(provider.name)!;
      
      try {
        const response = await breaker.execute(
          () => provider.chat(messages, options)
        );
        return response;
      } catch (error) {
        lastError = error as Error;
        continue;
      }
    }

    throw lastError || new Error('All providers failed');
  }

  async destroy() {
    clearInterval(this.healthCheckInterval);
  }
}

#### 4. 能力路由实现

interface CapabilityRouterConfig {
  [capability: string]: {
    primary: string;
    fallback: string[];
  };
}

class CapabilityBasedRouter {
  private multiProviderRouter: MultiProviderRouter;
  private config: CapabilityRouterConfig;
  private providers: Map<string, AIProvider>;

  constructor(
    providers: AIProvider[],
    config: CapabilityRouterConfig
  ) {
    this.multiProviderRouter = new MultiProviderRouter(providers);
    this.config = config;
    this.providers = new Map(providers.map(p => [p.name, p]));
  }

  private getProviderForCapability(capability: string): AIProvider[] {
    const config = this.config[capability];
    if (!config) {
      // 默认返回所有供应商
      return Array.from(this.providers.values());
    }

    const result: AIProvider[] = [];
    
    // 主供应商
    const primary = this.providers.get(config.primary);
    if (primary) result.push(primary);
    
    // 备用供应商
    for (const name of config.fallback) {
      const provider = this.providers.get(name);
      if (provider) result.push(provider);
    }

    return result;
  }

  async chat(
    messages: Message[],
    capability: string = 'default',
    options?: ChatOptions
  ): Promise<ChatResponse> {
    const providers = this.getProviderForCapability(capability);
    const router = new MultiProviderRouter(providers);
    return router.chat(messages, options);
  }
}

// 配置示例
const capabilityConfig: CapabilityRouterConfig = {
  'code-generation': {
    primary: 'anthropic',
    fallback: ['openai']
  },
  'fast-response': {
    primary: 'openai',
    fallback: ['anthropic']
  },
  'chinese': {
    primary: 'qwen',
    fallback: ['doubao', 'openai']
  }
};

成本优化策略

#### 1. 价格感知路由

interface PricePerToken {
  input: number;  // 美元 / 1K tokens
  output: number;
}

const providerPrices: Record<string, PricePerToken> = {
  'openai-gpt-4o-mini': { input: 0.00015, output: 0.0006 },
  'anthropic-haiku': { input: 0.00025, output: 0.00125 },
  'qwen-plus': { input: 0.00008, output: 0.0002 }
};

class PriceAwareRouter extends MultiProviderRouter {
  async chatWithBudget(
    messages: Message[],
    maxCost: number,
    options?: ChatOptions
  ): Promise<ChatResponse> {
    const available = this.getAvailableProviders();
    
    // 按价格排序
    const sortedByPrice = available.sort((a, b) => {
      const priceA = providerPrices[a.name] || { input: 999, output: 999 };
      const priceB = providerPrices[b.name] || { input: 999, output: 999 };
      return (priceA.input + priceA.output) - (priceB.input + priceB.output);
    });

    for (const provider of sortedByPrice) {
      try {
        const response = await provider.chat(messages, options);
        
        // 计算成本
        const price = providerPrices[provider.name];
        const cost = (response.usage.inputTokens / 1000 * price.input) +
                     (response.usage.outputTokens / 1000 * price.output);
        
        if (cost <= maxCost) {
          return response;
        }
      } catch {
        continue;
      }
    }

    throw new Error('No provider within budget');
  }
}

#### 2. 配额分散使用

interface QuotaInfo {
  used: number;
  limit: number;
  resetTime: Date;
}

class QuotaAwareRouter extends MultiProviderRouter {
  private quotas: Map<string, QuotaInfo> = new Map();

  updateQuota(providerName: string, usage: number) {
    const quota = this.quotas.get(providerName) || {
      used: 0,
      limit: 1000000,
      resetTime: new Date(Date.now() + 24 * 60 * 60 * 1000)
    };
    quota.used += usage;
    this.quotas.set(providerName, quota);
  }

  private getQuotaUsage(providerName: string): number {
    const quota = this.quotas.get(providerName);
    if (!quota) return 0;
    return quota.used / quota.limit;
  }

  override getAvailableProviders(): AIProvider[] {
    const available = super.getAvailableProviders();
    
    // 按配额使用率排序,优先用配额多的
    return available.sort((a, b) => {
      return this.getQuotaUsage(a.name) - this.getQuotaUsage(b.name);
    });
  }
}

监控和可观测性

#### 关键指标

指标说明
供应商可用性每个供应商的健康状态
切换次数供应商切换的频率
请求分布每个供应商的请求比例
成本分布每个供应商的成本占比
延迟对比各供应商的响应时间

最佳实践

#### 1. 渐进式迁移

  • 不要一开始就切换所有流量
  • 先用 10% 流量测试新供应商
  • 确认稳定后再逐步增加

#### 2. 供应商评估

定期评估各供应商:

  • 性能(延迟、成功率)
  • 成本
  • 功能丰富度
  • 服务稳定性

#### 3. 灾备演练

定期进行灾备演练:

  • 模拟主供应商故障
  • 验证切换是否正常
  • 测试备用供应商能力

总结

多供应商架构是高可用系统的基石:

  • ✅ 避免单点故障
  • ✅ 灵活应对价格变化
  • ✅ 分散配额压力
  • ✅ 选择最佳供应商组合
  • ✅ 提高系统整体可用性

建议:

1. 从主备模式开始,逐步演进

2. 统一接口抽象,屏蔽供应商差异

3. 结合熔断和重试,提高弹性

4. 监控指标,持续优化

5. 定期评估和演练

可在本站查看更多 AI API 中转平台,找到适合你的多供应商组合。

找到最适合你的 AI API 中转站

收录 125+ 服务商,按价格、模型、标签一键筛选

查看所有中转站 →