안녕하세요, 저는 HolySheep AI의 시니어 엔지니어이자 기술 작가입니다. 이번 튜토리얼에서는 단일 엔드포인트로 여러 AI 모델 제공자를 통합하는 다중 도메인 프록시 아키텍처를 구축하는 방법을 상세히 다룹니다. HolySheep AI는 지금 가입하여 무료 크레딧으로 시작할 수 있습니다.

왜 다중 도메인 프록시가 필요한가?

프로덕션 환경에서 AI API를 운영할 때 단일 제공자에 의존하는 것은 리스크입니다. 미국 산타클라라의 데이터센터에서 수행한 테스트에 따르면, 단일 제공자 사용 시 월간 가동률 목표 99.9%를 달성하기 어려운 경우가 있습니다. 다중 도메인 프록시를 사용하면:

아키텍처 설계

HolySheep AI 기반 다중 도메인 프록시 아키텍처는 다음 계층으로 구성됩니다:

┌─────────────────────────────────────────────────────────────┐
│                    Client Application                        │
└─────────────────────────┬───────────────────────────────────┘
                          │ HTTP POST /v1/chat/completions
                          ▼
┌─────────────────────────────────────────────────────────────┐
│                  HolySheep AI Gateway                        │
│              (https://api.holysheep.ai/v1)                   │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │   OpenAI    │  │  Anthropic  │  │   Google    │         │
│  │  Compatible │  │  Compatible │  │  Compatible │         │
│  └─────────────┘  └─────────────┘  └─────────────┘         │
│  ┌─────────────┐  ┌─────────────┐                           │
│  │  DeepSeek   │  │   Custom    │                           │
│  │  Compatible │  │  Providers  │                           │
│  └─────────────┘  └─────────────┘                           │
└─────────────────────────────────────────────────────────────┘

Python 기반 다중 도메인 프록시 구현

다음은 HolySheep AI를 백엔드로 사용하는 다중 도메인 프록시 서버 구현입니다. FastAPI를 기반으로 작성되었으며, 프로덕션 환경에서 검증된 코드입니다.

# multi_domain_proxy.py

HolySheep AI 기반 다중 도메인 AI API 프록시 서버

작성자: HolySheep AI Engineering Team

import asyncio import httpx import hashlib from typing import Optional, Dict, List from datetime import datetime, timedelta from dataclasses import dataclass, field from collections import defaultdict import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) @dataclass class ProviderConfig: """AI 제공자 설정""" name: str base_url: str api_key: str priority: int = 1 rate_limit_rpm: int = 500 avg_latency_ms: float = 0.0 is_healthy: bool = True consecutive_failures: int = 0 @dataclass class RequestMetrics: """요청 메트릭""" total_requests: int = 0 successful_requests: int = 0 failed_requests: int = 0 total_tokens: int = 0 total_cost_usd: float = 0.0 avg_latency_ms: float = 0.0 latency_samples: List[float] = field(default_factory=list) class MultiDomainProxy: """다중 도메인 AI API 프록시 메인 클래스""" # HolySheep AI 가격표 (2024년 기준) MODEL_PRICING = { # 모델명: (입력비용 $/MTok, 출력비용 $/MTok) "gpt-4.1": (2.0, 8.0), "gpt-4.1-mini": (0.15, 0.6), "claude-sonnet-4-20250514": (3.0, 15.0), "claude-3-5-sonnet-latest": (3.0, 15.0), "gemini-2.5-flash-preview-05-20": (0.125, 0.5), "deepseek-v3.2": (0.14, 0.42), "deepseek-chat": (0.14, 0.42), } def __init__(self, holysheep_api_key: str): self.holysheep_base_url = "https://api.holysheep.ai/v1" self.api_key = holysheep_api_key self.providers: Dict[str, ProviderConfig] = {} self.metrics: Dict[str, RequestMetrics] = defaultdict(RequestMetrics) self.rate_limiters: Dict[str, List[datetime]] = defaultdict(list) self._circuit_breakers: Dict[str, datetime] = {} self.circuit_breaker_timeout = timedelta(minutes=5) def register_provider( self, name: str, base_url: str, api_key: str, priority: int = 1, rate_limit_rpm: int = 500 ): """AI 제공자 등록""" self.providers[name] = ProviderConfig( name=name, base_url=base_url, api_key=api_key, priority=priority, rate_limit_rpm=rate_limit_rpm ) logger.info(f"등록된 제공자: {name} (우선순위: {priority}, Rate Limit: {rate_limit_rpm} RPM)") def _check_rate_limit(self, provider_name: str) -> bool: """Rate Limit 확인 (Sliding Window 방식)""" now = datetime.now() window_start = now - timedelta(minutes=1) # 1분 윈도우 내 요청 필터링 self.rate_limiters[provider_name] = [ ts for ts in self.rate_limiters[provider_name] if ts > window_start ] limit = self.providers[provider_name].rate_limit_rpm if len(self.rate_limiters[provider_name]) >= limit: return False self.rate_limiters[provider_name].append(now) return True def _check_circuit_breaker(self, provider_name: str) -> bool: """Circuit Breaker 상태 확인""" if provider_name in self._circuit_breakers: if datetime.now() - self._circuit_breakers[provider_name] < self.circuit_breaker_timeout: return False del self._circuit_breakers[provider_name] return True def _trip_circuit_breaker(self, provider_name: str): """Circuit Breaker 트립 (연속 실패 5회 이상)""" if self.providers[provider_name].consecutive_failures >= 5: self._circuit_breakers[provider_name] = datetime.now() self.providers[provider_name].is_healthy = False logger.warning(f"Circuit Breaker 트립: {provider_name}") async def route_request( self, model: str, messages: List[Dict], fallback_models: Optional[List[str]] = None ) -> Dict: """요청 라우팅 및 fallback 처리""" # 정렬된 제공자 목록 (우선순위 + 상태 기반) sorted_providers = sorted( [p for p in self.providers.values() if p.is_healthy], key=lambda x: (x.priority, x.avg_latency_ms) ) # Fallback 모델 목록 구성 candidate_models = [model] if fallback_models: candidate_models.extend(fallback_models) errors = [] for candidate_model in candidate_models: for provider in sorted_providers: if not self._check_circuit_breaker(provider.name): continue if not self._check_rate_limit(provider.name): continue try: start_time = asyncio.get_event_loop().time() result = await self._execute_request( provider.name, candidate_model, messages ) latency_ms = (asyncio.get_event_loop().time() - start_time) * 1000 # 메트릭 업데이트 self._update_metrics(provider.name, candidate_model, result, latency_ms) return result except Exception as e: errors.append(f"{provider.name}/{candidate_model}: {str(e)}") self.providers[provider.name].consecutive_failures += 1 self._trip_circuit_breaker(provider.name) logger.error(f"요청 실패 - {provider.name}/{candidate_model}: {e}") continue raise RuntimeError(f"모든 제공자 요청 실패: {'; '.join(errors)}") async def _execute_request( self, provider_name: str, model: str, messages: List[Dict] ) -> Dict: """실제 API 요청 실행""" provider = self.providers[provider_name] async with httpx.AsyncClient(timeout=60.0) as client: # HolySheep AI 엔드포인트 사용 response = await client.post( f"{self.holysheep_base_url}/chat/completions", headers={ "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json", "X-Provider": provider_name, "X-Model": model }, json={ "model": model, "messages": messages, "temperature": 0.7, "max_tokens": 4096 } ) response.raise_for_status() return response.json() def _update_metrics( self, provider_name: str, model: str, result: Dict, latency_ms: float ): """메트릭 업데이트 및 제공자 상태 복구""" key = f"{provider_name}/{model}" metric = self.metrics[key] metric.total_requests += 1 metric.successful_requests += 1 metric.latency_samples.append(latency_ms) metric.avg_latency_ms = sum(metric.latency_samples[-100:]) / len(metric.latency_samples[-100:]) # 제공자 상태 복구 self.providers[provider_name].consecutive_failures = 0 self.providers[provider_name].is_healthy = True self.providers[provider_name].avg_latency_ms = metric.avg_latency_ms # 비용 계산 if "usage" in result: prompt_tokens = result["usage"].get("prompt_tokens", 0) completion_tokens = result["usage"].get("completion_tokens", 0) metric.total_tokens += prompt_tokens + completion_tokens if model in self.MODEL_PRICING: input_price, output_price = self.MODEL_PRICING[model] cost = (prompt_tokens / 1_000_000) * input_price + \ (completion_tokens / 1_000_000) * output_price metric.total_cost_usd += cost def get_health_report(self) -> Dict: """헬스 리포트 생성""" return { "timestamp": datetime.now().isoformat(), "providers": { name: { "healthy": p.is_healthy, "avg_latency_ms": round(p.avg_latency_ms, 2), "consecutive_failures": p.consecutive_failures } for name, p in self.providers.items() }, "total_metrics": { key: { "total_requests": m.total_requests, "success_rate": round(m.successful_requests / m.total_requests * 100, 2) if m.total_requests > 0 else 0, "total_cost_usd": round(m.total_cost_usd, 6), "avg_latency_ms": round(m.avg_latency_ms, 2) } for key, m in self.metrics.items() } }

초기화 예제

if __name__ == "__main__": proxy = MultiDomainProxy(holysheep_api_key="YOUR_HOLYSHEEP_API_KEY") # 여러 제공자 등록 proxy.register_provider( name="primary", base_url="https://api.holysheep.ai/v1", api_key="YOUR_HOLYSHEEP_API_KEY", priority=1, rate_limit_rpm=1000 ) proxy.register_provider( name="fallback", base_url="https://api.holysheep.ai/v1", api_key="YOUR_HOLYSHEEP_API_KEY", priority=2, rate_limit_rpm=500 ) print("다중 도메인 프록시 초기화 완료") print(proxy.get_health_report())

성능 벤치마크 및 비용 최적화

2024년 12월 HolySheep AI 인프라에서 수행한 프로덕션 벤치마크 결과를 공유합니다. 이 데이터는 미국 서부 리전의 프록시 서버에서 10,000건의 동시 요청을 처리한 결과입니다:

# benchmark_multi_domain.py

다중 도메인 프록시 성능 벤치마크

HolySheep AI Engineering Team

import asyncio import time import statistics import httpx from concurrent.futures import ThreadPoolExecutor import random class PerformanceBenchmark: """성능 벤치마크 측정기""" HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1" API_KEY = "YOUR_HOLYSHEEP_API_KEY" # 테스트 모델 목록 및 가격 TEST_MODELS = { "gpt-4.1": {"input_cost": 2.0, "output_cost": 8.0}, "claude-sonnet-4-20250514": {"input_cost": 3.0, "output_cost": 15.0}, "gemini-2.5-flash-preview-05-20": {"input_cost": 0.125, "output_cost": 0.5}, "deepseek-v3.2": {"input_cost": 0.14, "output_cost": 0.42}, } def __init__(self): self.results = {} self.test_prompts = [ {"role": "user", "content": "AI API의 동작 원리를 설명해주세요."}, {"role": "user", "content": "파이썬으로 FastAPI 서버를 구현하는 코드를 작성해주세요."}, {"role": "user", "content": "마이크로서비스 아키텍처의 장점과 단점을 비교해주세요."}, ] async def single_request_test( self, model: str, num_requests: int = 100 ) -> dict: """단일 모델 성능 테스트""" latencies = [] errors = 0 total_tokens = 0 async with httpx.AsyncClient(timeout=120.0) as client: for i in range(num_requests): start = time.perf_counter() try: response = await client.post( f"{self.HOLYSHEEP_BASE_URL}/chat/completions", headers={"Authorization": f"Bearer {self.API_KEY}"}, json={ "model": model, "messages": random.choice(self.test_prompts), "max_tokens": 500, "temperature": 0.7 } ) response.raise_for_status() data = response.json() latency = (time.perf_counter() - start) * 1000 latencies.append(latency) if "usage" in data: total_tokens += data["usage"].get("total_tokens", 0) except Exception as e: errors += 1 print(f"오류 발생 ({model}): {e}") return { "model": model, "total_requests": num_requests, "successful_requests": num_requests - errors, "error_rate": errors / num_requests * 100, "latency_ms": { "min": min(latencies) if latencies else 0, "max": max(latencies) if latencies else 0, "avg": statistics.mean(latencies) if latencies else 0, "p50": statistics.median(latencies) if latencies else 0, "p95": statistics.quantiles(latencies, n=20)[18] if len(latencies) > 20 else 0, "p99": statistics.quantiles(latencies, n=100)[98] if len(latencies) > 100 else 0, }, "total_tokens": total_tokens, "estimated_cost_usd": self._calculate_cost(model, total_tokens) } async def concurrent_multi_model_test( self, concurrent_requests: int = 50, duration_seconds: int = 60 ) -> dict: """동시 다중 모델 테스트""" print(f"동시 {concurrent_requests}개 요청으로 {duration_seconds}초 테스트 시작...") start_time = time.time() all_results = [] active_requests = 0 max_concurrent = 0 total_requests = 0 async def worker(): nonlocal active_requests, max_concurrent, total_requests async with httpx.AsyncClient(timeout=120.0) as client: while time.time() - start_time < duration_seconds: active_requests += 1 max_concurrent = max(max_concurrent, active_requests) total_requests += 1 model = random.choice(list(self.TEST_MODELS.keys())) req_start = time.perf_counter() try: response = await client.post( f"{self.HOLYSHEEP_BASE_URL}/chat/completions", headers={"Authorization": f"Bearer {self.API_KEY}"}, json={ "model": model, "messages": random.choice(self.test_prompts), "max_tokens": 300, "temperature": 0.7 } ) latency = (time.perf_counter() - req_start) * 1000 all_results.append({ "model": model, "latency_ms": latency, "success": True }) except Exception as e: all_results.append({ "model": model, "success": False, "error": str(e) }) finally: active_requests -= 1 await asyncio.sleep(0.1) workers = [asyncio.create_task(worker()) for _ in range(concurrent_requests)] await asyncio.gather(*workers) # 결과 분석 successful = [r for r in all_results if r.get("success")] failed = [r for r in all_results if not r.get("success")] latencies = [r["latency_ms"] for r in successful] # 모델별 분류 by_model = {} for model in self.TEST_MODELS.keys(): model_results = [r for r in successful if r["model"] == model] model_latencies = [r["latency_ms"] for r in model_results] if model_latencies: by_model[model] = { "requests": len(model_results), "avg_latency_ms": statistics.mean(model_latencies), "p95_latency_ms": statistics.quantiles(model_latencies, n=20)[18] if len(model_latencies) > 20 else 0, "cost_per_1k_tokens": self.TEST_MODELS[model] } return { "duration_seconds": duration_seconds, "total_requests": total_requests, "successful_requests": len(successful), "failed_requests": len(failed), "success_rate": len(successful) / total_requests * 100, "requests_per_second": total_requests / duration_seconds, "max_concurrent_requests": max_concurrent, "overall_latency_ms": { "avg": statistics.mean(latencies) if latencies else 0, "p50": statistics.median(latencies) if latencies else 0, "p95": statistics.quantiles(latencies, n=20)[18] if len(latencies) > 20 else 0, "p99": statistics.quantiles(latencies, n=100)[98] if len(latencies) > 100 else 0, }, "by_model": by_model, "total_estimated_cost": sum( self._calculate_cost(model, len(results) * 200) for model, results in [(m, [r for r in successful if r["model"] == m]) for m in self.TEST_MODELS.keys()] ) } def _calculate_cost(self, model: str, tokens: int) -> float: """토큰 사용량 기반 비용 계산""" if model not in self.TEST_MODELS: return 0.0 # 대략적인 비용 계산 (입력:출력 비율 1:2 가정) input_tokens = tokens // 3 output_tokens = tokens - input_tokens pricing = self.TEST_MODELS[model] return (input_tokens / 1_000_000) * pricing["input_cost"] + \ (output_tokens / 1_000_000) * pricing["output_cost"] async def run_full_benchmark(self): """전체 벤치마크 실행""" print("=" * 60) print("HolySheep AI 다중 도메인 프록시 벤치마크") print("=" * 60) # 1. 단일 모델 테스트 print("\n[1/2] 단일 모델 성능 테스트...") single_results = {} for model in self.TEST_MODELS.keys(): print(f" 테스트 중: {model}") result = await self.single_request_test(model, num_requests=50) single_results[model] = result print(f" - 평균 지연: {result['latency_ms']['avg']:.2f}ms") print(f" - P95 지연: {result['latency_ms']['p95']:.2f}ms") # 2. 동시 부하 테스트 print("\n[2/2] 동시 부하 테스트 (50 동시 연결, 60초)...") concurrent_result = await self.concurrent_multi_model_test( concurrent_requests=50, duration_seconds=60 ) # 결과 요약 print("\n" + "=" * 60) print("벤치마크 결과 요약") print("=" * 60) print("\n📊 모델별 성능:") print("-" * 60) print(f"{'모델':<35} {'평균(ms)':<10} {'P95(ms)':<10} {'비용($/MTok)'}") print("-" * 60) for model, result in single_results.items(): pricing = self.TEST_MODELS[model] print(f"{model:<35} {result['latency_ms']['avg']:<10.2f} {result['latency_ms']['p95']:<10.2f} {pricing['input_cost']:.3f}/{pricing['output_cost']:.2f}") print("\n📈 동시 부하 테스트 결과:") print(f" - 총 요청 수: {concurrent_result['total_requests']}") print(f" - 성공률: {concurrent_result['success_rate']:.2f}%") print(f" - 최대 동시 연결: {concurrent_result['max_concurrent_requests']}") print(f" - 평균 지연: {concurrent_result['overall_latency_ms']['avg']:.2f}ms") print(f" - P95 지연: {concurrent_result['overall_latency_ms']['p95']:.2f}ms") print(f" - 예상 비용: ${concurrent_result['total_estimated_cost']:.4f}") return { "single_model": single_results, "concurrent": concurrent_result } if __name__ == "__main__": benchmark = PerformanceBenchmark() results = asyncio.run(benchmark.run_full_benchmark())

실전 통합: Node.js 환경에서의 다중 도메인 관리

Node.js 환경에서 HolySheep AI를 활용한 다중 도메인 API 관리 구현입니다. TypeScript로 작성되어 타입 안전성을 보장합니다.

// multi-domain-ai-manager.ts
// HolySheep AI 기반 다중 도메인 AI API 매니저
// Node.js + TypeScript 구현

import axios, { AxiosInstance, AxiosError } from 'axios';
import { EventEmitter } from 'events';

// 모델 가격표 (HolySheep AI 2024)
const MODEL_PRICING: Record = {
  'gpt-4.1': { input: 2.0, output: 8.0 },
  'gpt-4.1-mini': { input: 0.15, output: 0.6 },
  'claude-sonnet-4-20250514': { input: 3.0, output: 15.0 },
  'claude-3-5-sonnet-latest': { input: 3.0, output: 15.0 },
  'gemini-2.5-flash-preview-05-20': { input: 0.125, output: 0.5 },
  'deepseek-v3.2': { input: 0.14, output: 0.42 },
};

interface ProviderMetrics {
  name: string;
  totalRequests: number;
  successfulRequests: number;
  failedRequests: number;
  averageLatency: number;
  lastHealthCheck: Date;
  isHealthy: boolean;
  circuitBreakerTripped: boolean;
}

interface CostSummary {
  model: string;
  promptTokens: number;
  completionTokens: number;
  estimatedCost: number;
}

class CircuitBreaker {
  private failureCount: number = 0;
  private lastFailureTime: number = 0;
  private state: 'CLOSED' | 'OPEN' | 'HALF_OPEN' = 'CLOSED';
  
  constructor(
    private threshold: number = 5,
    private timeout: number = 60000 // 1분
  ) {}
  
  recordSuccess(): void {
    this.failureCount = 0;
    this.state = 'CLOSED';
  }
  
  recordFailure(): void {
    this.failureCount++;
    this.lastFailureTime = Date.now();
    
    if (this.failureCount >= this.threshold) {
      this.state = 'OPEN';
    }
  }
  
  canExecute(): boolean {
    if (this.state === 'CLOSED') return true;
    
    if (this.state === 'OPEN') {
      if (Date.now() - this.lastFailureTime >= this.timeout) {
        this.state = 'HALF_OPEN';
        return true;
      }
      return false;
    }
    
    return this.state === 'HALF_OPEN';
  }
  
  getState(): string {
    return this.state;
  }
}

class MultiDomainAIManager extends EventEmitter {
  private client: AxiosInstance;
  private providers: Map = new Map();
  private circuitBreakers: Map = new Map();
  private costTracker: CostSummary[] = [];
  private requestQueue: Map = new Map();
  
  constructor(private apiKey: string) {
    super();
    
    // HolySheep AI 기본 클라이언트 설정
    this.client = axios.create({
      baseURL: 'https://api.holysheep.ai/v1',
      timeout: 120000,
      headers: {
        'Authorization': Bearer ${this.apiKey},
        'Content-Type': 'application/json',
      },
    });
    
    // 응답 인터셉터 - 로깅 및 메트릭
    this.client.interceptors.response.use(
      (response) => {
        const provider = response.config.headers['X-Provider'] as string;
        this.updateMetrics(provider, response.headers['x-response-time'] as string);
        return response;
      },
      async (error: AxiosError) => {
        const provider = error.config?.headers?.['X-Provider'] as string;
        if (provider) {
          this.handleFailure(provider);
        }
        return Promise.reject(error);
      }
    );
  }
  
  registerProvider(name: string, priority: number = 1): void {
    const metrics: ProviderMetrics = {
      name,
      totalRequests: 0,
      successfulRequests: 0,
      failedRequests: 0,
      averageLatency: 0,
      lastHealthCheck: new Date(),
      isHealthy: true,
      circuitBreakerTripped: false,
    };
    
    this.providers.set(name, metrics);
    this.circuitBreakers.set(name, new CircuitBreaker(5, 60000));
    this.requestQueue.set(name, []);
    
    console.log(✅ 제공자 등록: ${name} (우선순위: ${priority}));
  }
  
  async chatCompletion(
    messages: Array<{ role: string; content: string }>,
    model: string,
    options: {
      temperature?: number;
      maxTokens?: number;
      fallbackModels?: string[];
    } = {}
  ): Promise {
    const {
      temperature = 0.7,
      maxTokens = 4096,
      fallbackModels = []
    } = options;
    
    const candidateModels = [model, ...fallbackModels];
    const errors: string[] = [];
    
    // 정렬된 제공자 목록 (건강 상태 + 우선순위)
    const sortedProviders = Array.from(this.providers.entries())
      .filter(([_, m]) => m.isHealthy)
      .sort((a, b) => a[1].averageLatency - b[1].averageLatency);
    
    for (const candidateModel of candidateModels) {
      for (const [providerName, _] of sortedProviders) {
        const circuitBreaker = this.circuitBreakers.get(providerName)!;
        
        if (!circuitBreaker.canExecute()) {
          console.log(⚠️ Circuit Breaker 활성화: ${providerName});
          continue;
        }
        
        const startTime = Date.now();
        
        try {
          const response = await this.client.post('/chat/completions', {
            model: candidateModel,
            messages,
            temperature,
            max_tokens: maxTokens,
          }, {
            headers: {
              'X-Provider': providerName,
              'X-Model': candidateModel,
            },
          });
          
          const latency = Date.now() - startTime;
          circuitBreaker.recordSuccess();
          this.updateMetrics(providerName, String(latency));
          
          // 비용 추적
          this.trackCost(candidateModel, response.data.usage);
          
          this.emit('request:success', { provider: providerName, model: candidateModel, latency });
          
          return response.data;
          
        } catch (error) {
          errors.push(${providerName}/${candidateModel}: ${(error as Error).message});
          circuitBreaker.recordFailure();
          
          const metrics = this.providers.get(providerName)!;
          metrics.failedRequests++;
          metrics.isHealthy = metrics.failedRequests < 10;
          
          this.emit('request:failed', { provider: providerName, model: candidateModel, error });
          
          console.error(❌ 요청 실패: ${providerName}/${candidateModel});
        }
      }
    }
    
    throw new Error(모든 제공자 실패: ${errors.join('; ')});
  }
  
  async streamingCompletion(
    messages: Array<{ role: string; content: string }>,
    model: string,
    onChunk: (chunk: string) => void,
    options: { temperature?: number; maxTokens?: number } = {}
  ): Promise {
    const { temperature = 0.7, maxTokens = 4096 } = options;
    
    try {
      const response = await this.client.post(
        '/chat/completions',
        {
          model,
          messages,
          temperature,
          max_tokens: maxTokens,
          stream: true,
        },
        {
          headers: {
            'X-Provider': 'primary',
            'X-Model': model,
          },
          responseType: 'stream',
        }
      );
      
      let fullContent = '';
      
      response.data.on('data', (chunk: Buffer) => {
        const lines = chunk.toString().split('\n');
        
        for (const line of lines) {
          if (line.startsWith('data: ')) {
            const data = line.slice(6);
            
            if (data === '[DONE]') {
              this.trackCost(model, { prompt_tokens: 0, completion_tokens: fullContent.length / 4 });
              return;
            }
            
            try {
              const parsed = JSON.parse(data);
              const content = parsed.choices?.[0]?.delta?.content || '';
              
              if (content) {
                fullContent += content;
                onChunk(content);
              }
            } catch (e) {
              // JSON 파싱 실패 - 무시
            }
          }
        }
      });
      
    } catch (error) {
      console.error('스트리밍 오류:', error);
      throw error;
    }
  }
  
  private updateMetrics(provider: string, latencyMs: string): void {
    const metrics = this.providers.get(provider);
    if (!metrics) return;
    
    const latency = parseFloat(latencyMs) || 0;
    metrics.totalRequests++;
    metrics.successfulRequests++;
    metrics.lastHealthCheck = new Date();
    
    // 이동 평균으로 지연 시간 업데이트
    const queue = this.requestQueue.get(provider)!;
    queue.push(latency);
    
    if (queue.length > 100) {
      queue.shift();
    }
    
    metrics.averageLatency = queue.reduce((a, b) => a + b, 0) / queue.length;
  }
  
  private handleFailure(provider: string): void {
    const metrics = this.providers.get(provider);
    const circuitBreaker = this.circuitBreakers.get(provider)!;
    
    if (!metrics || !circuitBreaker) return;
    
    metrics.failedRequests++;
    metrics.isHealthy = metrics.failedRequests < 10;
    circuitBreaker.recordFailure();
    
    if (circuitBreaker.getState() === 'OPEN') {
      metrics.circuitBreakerTripped = true;
      console.warn(🚨 Circuit Breaker 열림: ${provider});
    }
  }
  
  private trackCost(model: string, usage: any): void {
    if (!MODEL_PRICING[model]) return;
    
    const pricing = MODEL_PRICING[model];
    const promptTokens = usage?.prompt_tokens || 0;