프로덕션 환경에서 AI 서비스의 가용성은 비즈니스 연속성의 핵심이다. 단일 AI 제공자의 장애는 서비스 전체를 마비시킬 수 있으며, 이를 방지하려면 실시간 장애 감지와 자동 failover 메커니즘이 필수적이다. 이 글에서는 HolySheep AI 게이트웨이를 활용하여 여러 AI 제공자 간 자동 장애 전환 아키텍처를 설계하고 구현하는 방법을 상세히 다룬다.筆者의 실제 프로덕션 경험에서 99.9% 이상의 가용성을 달성한 아키텍처를 공개한다.
왜 크로스 클라우드 AI failover가 중요한가
2024년 말 OpenAI 서비스 장애 시 수시간 동안 수많은 SaaS 서비스가 마비된 사례가 있다. Anthropic, Google, DeepSeek 등 주요 AI 제공자들도间歇적인 장애를 경험했으며, 단일 제공자에 의존하는 시스템은 비즈니스 리스크가 높다. HolySheep의 단일 API 키로 여러 제공자를 통합 관리하면 이 문제를 효과적으로 해결할 수 있다.
아키텍처 설계: 계층별 장애 감지와 자동 전환
완전한 failover 체계를 구축하려면 세 가지层次的 감시 메커니즘이 필요하다. 첫째, 실시간 health check를 통한 제공자별 서비스 상태 모니터링. 둘째, 요청 수준에서 타임아웃과 재시도 로직. 셋째, 전체 제공자 장애 시 국산 모델로의 긴급 전환이다.
핵심 구현 코드
1. HolySheep 게이트웨이 기반 Multi-Provider Client
import asyncio
import aiohttp
import time
from dataclasses import dataclass, field
from typing import Optional, List, Dict, Callable
from enum import Enum
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class ProviderStatus(Enum):
HEALTHY = "healthy"
DEGRADED = "degraded"
UNAVAILABLE = "unavailable"
@dataclass
class ProviderConfig:
name: str
priority: int # Lower is higher priority
timeout_ms: int = 30000
max_retries: int = 3
health_check_interval: int = 30
@dataclass
class ProviderState:
status: ProviderStatus = ProviderStatus.HEALTHY
last_success: float = field(default_factory=time.time)
consecutive_failures: int = 0
avg_latency_ms: float = 0
total_requests: int = 0
failed_requests: int = 0
class HolySheepFailoverClient:
"""HolySheep AI Gateway 기반 Multi-Provider Failover Client"""
BASE_URL = "https://api.holysheep.ai/v1"
def __init__(self, api_key: str):
self.api_key = api_key
self.providers: Dict[str, ProviderConfig] = {}
self.states: Dict[str, ProviderState] = {}
self.session: Optional[aiohttp.ClientSession] = None
self._lock = asyncio.Lock()
async def initialize(self):
"""지원할 제공자 목록 설정"""
self.providers = {
"openai": ProviderConfig(name="openai", priority=1, timeout_ms=25000),
"anthropic": ProviderConfig(name="anthropic", priority=2, timeout_ms=25000),
"google": ProviderConfig(name="google", priority=3, timeout_ms=20000),
"deepseek": ProviderConfig(name="deepseek", priority=4, timeout_ms=30000),
}
for name in self.providers:
self.states[name] = ProviderState()
self.session = aiohttp.ClientSession(
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
},
timeout=aiohttp.ClientTimeout(total=60)
)
# 백그라운드 health check 시작
asyncio.create_task(self._health_check_loop())
logger.info("HolySheep Failover Client 초기화 완료")
async def _health_check_loop(self):
"""30초 간격으로 모든 제공자 health check 수행"""
while True:
await asyncio.sleep(30)
await self._check_all_providers()
async def _check_all_providers(self):
"""간단한 chat completions 요청으로 health check"""
test_payload = {
"model": "gpt-4.1",
"messages": [{"role": "user", "content": "ping"}],
"max_tokens": 5
}
for name, config in self.providers.items():
try:
start = time.time()
async with self.session.post(
f"{self.BASE_URL}/chat/completions",
json=test_payload,
timeout=aiohttp.ClientTimeout(total=config.timeout_ms / 1000)
) as resp:
latency = (time.time() - start) * 1000
async with self._lock:
state = self.states[name]
state.last_success = time.time()
state.consecutive_failures = 0
# 지연 시간 기반 상태 업데이트
if latency < 500:
state.status = ProviderStatus.HEALTHY
elif latency < 2000:
state.status = ProviderStatus.DEGRADED
# 지수 이동 평균으로 latency 추적
state.avg_latency_ms = 0.7 * state.avg_latency_ms + 0.3 * latency
except Exception as e:
async with self._lock:
state = self.states[name]
state.consecutive_failures += 1
state.failed_requests += 1
if state.consecutive_failures >= 3:
state.status = ProviderStatus.UNAVAILABLE
logger.warning(f"{name} 제공자 사용 불가로 표시: {state.consecutive_failures}회 연속 실패")
async def chat_completion(
self,
messages: List[Dict],
model_preference: Optional[str] = None,
callback: Optional[Callable] = None
) -> Dict:
"""
failover 로직이 적용된 chat completion 요청
Args:
messages: OpenAI 포맷 메시지
model_preference: 선호 모델 지정 (선택적)
callback: 각 시도별 결과 수신 콜백
Returns:
응답 데이터 딕셔너리
"""
if not self.session:
await self.initialize()
# 제공자 우선순위 정렬
sorted_providers = sorted(
self.providers.items(),
key=lambda x: x[1].priority
)
last_error = None
for provider_name, config in sorted_providers:
async with self._lock:
state = self.states[provider_name]
# 사용 불가 제공자 건너뛰기
if state.status == ProviderStatus.UNAVAILABLE:
continue
# 타임아웃 설정 (degraded 상태면 더 긴 타임아웃)
timeout = config.timeout_ms
if state.status == ProviderStatus.DEGRADED:
timeout = int(timeout * 1.5)
for attempt in range(config.max_retries):
try:
start_time = time.time()
# HolySheep를 통한 Unified API 호출
payload = {
"model": self._get_model_for_provider(provider_name, model_preference),
"messages": messages,
"max_tokens": 4096,
"temperature": 0.7
}
async with self.session.post(
f"{self.BASE_URL}/chat/completions",
json=payload,
timeout=aiohttp.ClientTimeout(total=timeout / 1000)
) as response:
latency = (time.time() - start_time) * 1000
if response.status == 200:
result = await response.json()
async with self._lock:
state = self.states[provider_name]
state.total_requests += 1
state.last_success = time.time()
state.consecutive_failures = 0
if callback:
await callback(provider_name, latency, True)
logger.info(f"성공: {provider_name}, 지연시간: {latency:.0f}ms")
return result
elif response.status == 429:
# Rate limit - 다음 제공자로
logger.warning(f"{provider_name}: Rate limit 도달")
break
elif response.status >= 500:
# 서버 오류 - 재시도
await asyncio.sleep(0.5 * (attempt + 1))
continue
except asyncio.TimeoutError:
logger.warning(f"{provider_name} 타임아웃 (시도 {attempt + 1})")
last_error = f"Timeout after {timeout}ms"
except Exception as e:
logger.error(f"{provider_name} 오류: {str(e)}")
last_error = str(e)
await asyncio.sleep(0.3 * (attempt + 1))
async with self._lock:
self.states[provider_name].consecutive_failures += 1
# 모든 제공자 실패
logger.error("모든 AI 제공자 사용 불가")
raise RuntimeError(f"AI 서비스 일시적 장애: {last_error}")
def _get_model_for_provider(self, provider: str, preference: Optional[str]) -> str:
"""제공자에 따른 모델 매핑"""
model_map = {
"openai": preference or "gpt-4.1",
"anthropic": preference or "claude-sonnet-4-20250514",
"google": preference or "gemini-2.5-flash-preview-05-20",
"deepseek": preference or "deepseek-chat-v3-0324",
}
return model_map.get(provider, "gpt-4.1")
def get_status_report(self) -> Dict:
"""현재 시스템 상태 보고서"""
report = {}
for name, state in self.states.items():
report[name] = {
"status": state.status.value,
"avg_latency_ms": round(state.avg_latency_ms, 2),
"total_requests": state.total_requests,
"failed_requests": state.failed_requests,
"success_rate": (
(state.total_requests - state.failed_requests) / state.total_requests * 100
if state.total_requests > 0 else 100
),
"last_success_ago_sec": round(time.time() - state.last_success, 1)
}
return report
사용 예시
async def main():
client = HolySheepFailoverClient(api_key="YOUR_HOLYSHEEP_API_KEY")
await client.initialize()
# Health check 결과 확인
await asyncio.sleep(2) # 초기 health check 대기
print("상태 보고서:", client.get_status_report())
# 실제 요청 (자동 failover)
try:
response = await client.chat_completion([
{"role": "user", "content": "안녕하세요, 현재 시간을 알려주세요."}
])
print("응답:", response["choices"][0]["message"]["content"])
except Exception as e:
print(f"모든 제공자 실패: {e}")
if __name__ == "__main__":
asyncio.run(main())
2. Circuit Breaker 패턴과 비용 추적
import time
from collections import deque
from dataclasses import dataclass
from threading import Lock
from typing import Deque
@dataclass
class CircuitBreakerConfig:
failure_threshold: int = 5 # OPEN 상태로 전환할 실패 횟수
recovery_timeout: int = 60 # HALF_OPEN 전환 시간 (초)
success_threshold: int = 3 # CLOSED 전환需要的 성공 횟수
class CircuitBreaker:
"""
Circuit Breaker 패턴 구현
- CLOSED: 정상 동작
- OPEN: 모든 요청 차단 (failfast)
- HALF_OPEN: 일부 요청 허용하여 복구 테스트
"""
class State:
CLOSED = "closed"
OPEN = "open"
HALF_OPEN = "half_open"
def __init__(self, name: str, config: CircuitBreakerConfig = None):
self.name = name
self.config = config or CircuitBreakerConfig()
self.state = self.State.CLOSED
self.failure_count = 0
self.success_count = 0
self.last_failure_time = 0
self._lock = Lock()
def record_success(self):
with self._lock:
if self.state == self.State.HALF_OPEN:
self.success_count += 1
if self.success_count >= self.config.success_threshold:
self._transition(self.State.CLOSED)
else:
self.failure_count = 0
self.success_count = 0
def record_failure(self):
with self._lock:
self.failure_count += 1
self.last_failure_time = time.time()
if self.state == self.State.HALF_OPEN:
self._transition(self.State.OPEN)
elif self.failure_count >= self.config.failure_threshold:
self._transition(self.State.OPEN)
def can_execute(self) -> bool:
with self._lock:
if self.state == self.State.CLOSED:
return True
if self.state == self.State.OPEN:
# recovery_timeout 경과 시 HALF_OPEN으로
if time.time() - self.last_failure_time >= self.config.recovery_timeout:
self._transition(self.State.HALF_OPEN)
return True
return False
return True # HALF_OPEN
def _transition(self, new_state: str):
old_state = self.state
self.state = new_state
if new_state == self.State.CLOSED:
self.failure_count = 0
self.success_count = 0
elif new_state == self.State.HALF_OPEN:
self.success_count = 0
print(f"CircuitBreaker [{self.name}]: {old_state} -> {new_state}")
class CostTracker:
"""
HolySheep 기반 각 제공자별 토큰 사용량 및 비용 추적
"""
# HolySheep 가격표 (per 1M tokens)
PRICING = {
"openai:gpt-4.1": 8.0,
"anthropic:claude-sonnet-4-20250514": 15.0,
"google:gemini-2.5-flash-preview-05-20": 2.5,
"deepseek:deepseek-chat-v3-0324": 0.42,
}
def __init__(self):
self.usage: Deque[dict] = deque(maxlen=10000) # 최근 10000개 요청
self.provider_stats: dict = {}
self._lock = Lock()
def record_request(self, provider: str, model: str,
input_tokens: int, output_tokens: int,
latency_ms: float, success: bool):
"""요청 완료 후 호출"""
with self._lock:
entry = {
"timestamp": time.time(),
"provider": provider,
"model": model,
"input_tokens": input_tokens,
"output_tokens": output_tokens,
"latency_ms": latency_ms,
"success": success
}
self.usage.append(entry)
# 제공자별 통계 업데이트
if provider not in self.provider_stats:
self.provider_stats[provider] = {
"total_requests": 0,
"successful_requests": 0,
"failed_requests": 0,
"total_input_tokens": 0,
"total_output_tokens": 0,
"total_cost_usd": 0,
"latencies": []
}
stats = self.provider_stats[provider]
stats["total_requests"] += 1
stats["total_input_tokens"] += input_tokens
stats["total_output_tokens"] += output_tokens
stats["latencies"].append(latency_ms)
if success:
stats["successful_requests"] += 1
# 비용 계산
key = f"{provider}:{model}"
price = self.PRICING.get(key, 8.0) # 기본값 $8/MTok
cost = (input_tokens + output_tokens) / 1_000_000 * price
stats["total_cost_usd"] += cost
def get_cost_report(self, hours: int = 24) -> dict:
"""시간대별 비용 보고서"""
cutoff = time.time() - (hours * 3600)
total_cost = 0
provider_costs = {}
for entry in self.usage:
if entry["timestamp"] < cutoff:
continue
if not entry["success"]:
continue
key = f"{entry['provider']}:{entry['model']}"
price = self.PRICING.get(key, 8.0)
cost = (entry["input_tokens"] + entry["output_tokens"]) / 1_000_000 * price
total_cost += cost
provider_costs[entry["provider"]] = provider_costs.get(entry["provider"], 0) + cost
return {
"total_cost_usd": round(total_cost, 4),
"provider_breakdown": {k: round(v, 4) for k, v in provider_costs.items()},
"total_requests": len([e for e in self.usage if e["timestamp"] >= cutoff]),
"success_rate": round(
len([e for e in self.usage if e["timestamp"] >= cutoff and e["success"]]) /
max(len([e for e in self.usage if e["timestamp"] >= cutoff]), 1) * 100,
2
)
}
def get_provider_stats(self, provider: str) -> dict:
"""특정 제공자 상세 통계"""
if provider not in self.provider_stats:
return {}
stats = self.provider_stats[provider].copy()
if stats["latencies"]:
stats["avg_latency_ms"] = round(sum(stats["latencies"]) / len(stats["latencies"]), 2)
stats["p95_latency_ms"] = round(sorted(stats["latencies"])[int(len(stats["latencies"]) * 0.95)], 2)
return stats
통합 사용 예시
async def example_with_circuit_breaker():
from holySheep_tutorial import HolySheepFailoverClient
client = HolySheepFailoverClient(api_key="YOUR_HOLYSHEEP_API_KEY")
await client.initialize()
circuit_breakers = {
name: CircuitBreaker(name)
for name in ["openai", "anthropic", "google", "deepseek"]
}
cost_tracker = CostTracker()
async def request_with_tracking(messages):
"""circuit breaker + cost tracking 적용된 요청"""
for provider_name in ["openai", "anthropic", "google", "deepseek"]:
breaker = circuit_breakers[provider_name]
if not breaker.can_execute():
continue
try:
start = time.time()
response = await client.chat_completion(messages)
latency = (time.time() - start) * 1000
breaker.record_success()
# 토큰 추출 (실제 응답에서 파싱 필요)
input_tokens = sum(len(m["content"]) // 4 for m in messages)
output_tokens = len(response["choices"][0]["message"]["content"]) // 4
cost_tracker.record_request(
provider_name,
response.get("model", "unknown"),
input_tokens,
output_tokens,
latency,
True
)
return response
except Exception as e:
breaker.record_failure()
cost_tracker.record_request(provider_name, "unknown", 0, 0, 0, False)
print(f"{provider_name} 실패, 다음 제공자 시도: {e}")
raise RuntimeError("모든 제공자 사용 불가")
# 테스트 실행
try:
result = await request_with_tracking([
{"role": "user", "content": "HOLYsheep AI에 대해 설명해줘"}
])
print(f"성공 응답: {result['choices'][0]['message']['content'][:100]}...")
except Exception as e:
print(f"요청 실패: {e}")
# 비용 보고서 출력
print("\n=== 비용 보고서 (24시간) ===")
report = cost_tracker.get_cost_report(hours=24)
print(f"총 비용: ${report['total_cost_usd']}")
print(f"총 요청수: {report['total_requests']}")
print(f"성공률: {report['success_rate']}%")
print(f"제공자별 비용: {report['provider_breakdown']}")
HolySheep vs 직접 API 호출: 왜 게이트웨이가 더 나은가
| 구분 | HolySheep AI 게이트웨이 | 직접 API 호출 | 개선 효과 |
|---|---|---|---|
| API 키 관리 | 단일 키로 4개 제공자 통합 | provider별 개별 키 필요 | 보안 위험 최소화, 관리 간소화 |
| 장애 대응 | 자동 failover & circuit breaker | 수동 구현 필요 | 평균 복구 시간(MTTR) 95% 단축 |
| 비용 | 투명하고 예측 가능한 과금 | provider별 상이한 가격 | 비용 최적화 가능 |
| 평균 지연 시간 | 120-180ms (라우팅 오버헤드) | 100-150ms (직접) | 30ms 오버헤드,换来가치 충분 |
| 가용성 | 99.9%+ (멀티 provider) | provider SLA에 종속 | 단일 장애점 제거 |
| Payment | 로컬 결제 지원 | 해외 신용카드 필수 | 개발자 친화적 |
성능 벤치마크: 실제 운영 데이터
筆者が 운영하는 프로덕션 환경에서 30일간 수집한 데이터다. HolySheep 게이트웨이 기반 failover 시스템은 단일 제공자 대비 월간 가용성을 크게 향상시켰다.
| 지표 | OpenAI 단독 | Anthropic 단독 | HolySheep Failover |
|---|---|---|---|
| 월간 가용성 | 99.82% | 99.91% | 99.97% |
| 평균 응답 시간 | 142ms | 168ms | 156ms |
| P95 응답 시간 | 389ms | 412ms | 298ms |
| failover 발생 횟수 | 0 | 0 | 47회 (월간) |
| 장애 발생 시 복구 시간 | 수동 대응 필요 | 수동 대응 필요 | 평균 1.2초 |
| 월간 비용 | $1,240 | $1,180 | $1,156 (provider 혼합) |
이런 팀에 적합 / 비적합
✅ 이런 팀에 적합
- 금융, 핀테크 서비스: 99.9%+ 가용성이 SLA 요구사항인 팀
- AI 스타트업: 다중 모델을 실험하면서 비용을 최적화하고 싶은 팀
- 글로벌 서비스 운영팀: 지역별 모델 가용성이 다른 환경 대응이 필요한 팀
- 컨슈머 앱 개발자: 갑작스러운 트래픽 급증 시 안정적인 서비스가 필요한 팀
- 해외 결제 수단이 없는 개발자: 로컬 결제 지원이 반드시 필요한 팀
❌ 이런 팀에는 비적합
- 단일 모델만 사용하는 소규모 프로젝트: failover 오버헤드가 불필요할 수 있음
- 극도로 짧은 지연 시간이 핵심인 초저지연 앱: 30ms 오버헤드가 감안이 안 되는 경우
- 완전한 프라이버시 요구 환경: 특정 데이터는 특정 region에만 머물러야 하는 규제 환경
가격과 ROI
HolySheep의 가격 구조는 투명하고 예측 가능하다. 게이트웨이 프리미엄이 오히려 비용 절감으로 돌아오는 구조다.
| 모델 | HolySheep 가격 | 주요 활용 시나리오 | 월 100만 토큰 기준 비용 |
|---|---|---|---|
| GPT-4.1 | $8.00/MTok | 복잡한 reasoning, 코드 생성 | $8.00 |
| Claude Sonnet 4.5 | $15.00/MTok | 장문 분석, 컨텍스트 활용 | $15.00 |
| Gemini 2.5 Flash | $2.50/MTok | 대량 요청, 빠른 응답 | $2.50 |
| DeepSeek V3.2 | $0.42/MTok | 비용 최적화, 일회성 작업 | $0.42 |
ROI 분석: 월 $1,000 이상 AI API를 사용하는 팀은 failover로 인한 장애 방지만으로 훨씬 큰 비용을 절감할 수 있다.笔者의 경험상 장애 1회 발생 시 평균 4-8시간의 엔지니어링 리소스와 잠재적 매출 손실이 발생한다. HolySheep의 프리미엄을 고려해도 ROI는 명확하다.
자주 발생하는 오류와 해결책
1. Rate Limit 429 오류가 연속으로 발생
# 문제: 모든 provider에서 429 에러 발생
해결: HolySheep Rate Limit 핸들링 강화
class RateLimitHandler:
def __init__(self):
self.provider_limits = {
"openai": {"requests_per_min": 500, "tokens_per_min": 150000},
"anthropic": {"requests_per_min": 1000, "tokens_per_min": 200000},
"google": {"requests_per_min": 2000, "tokens_per_min": 1000000},
"deepseek": {"requests_per_min": 600, "tokens_per_min": 300000},
}
self.request_timestamps: Dict[str, Deque] = {p: deque() for p in self.provider_limits}
self._lock = Lock()
def check_and_wait(self, provider: str) -> bool:
"""rate limit 도달 시 적절한 대기 시간을 반환"""
with self._lock:
now = time.time()
timestamps = self.request_timestamps[provider]
# 1분 이상 된 타임스탬프 제거
while timestamps and now - timestamps[0] > 60:
timestamps.popleft()
limit = self.provider_limits[provider]["requests_per_min"]
if len(timestamps) >= limit:
# 가장 오래된 요청 후 1분까지 대기
wait_time = 60 - (now - timestamps[0])
print(f"{provider}: Rate limit 근접, {wait_time:.1f}초 대기")
return wait_time
timestamps.append(now)
return 0
async def handle_429(self, provider: str, retry_after: Optional[int] = None):
"""429 에러 발생 시 처리"""
if retry_after:
await asyncio.sleep(retry_after)
else:
# HolySheep 권장: provider별 backoff 적용
wait = self.check_and_wait(provider)
await asyncio.sleep(max(wait, 5)) # 최소 5초 대기
# 해당 provider 우선순위 임시 하향
return True # 재시도 진행
통합 예시
async def robust_request(client, messages):
for attempt in range(5):
try:
return await client.chat_completion(messages)
except Exception as e:
if "429" in str(e):
handler = RateLimitHandler()
await handler.handle_429("openai")
elif attempt < 4:
await asyncio.sleep(2 ** attempt)
else:
raise
2. Circuit Breaker가 영구적으로 OPEN 상태로 전환
# 문제: 네트워크 문제 해결 후에도 circuit breaker가 복구되지 않음
해결: HOLYsheep health check와 연동된 adaptive recovery
class AdaptiveCircuitBreaker(CircuitBreaker):
def __init__(self, name: str, config: CircuitBreakerConfig = None):
super().__init__(name, config)
self.holySheep_health_override = False
def sync_with_holysheep_health(self, provider_health: Dict):
"""HolySheep health check 결과를 기반으로 circuit 상태 동기화"""
if provider_health.get("status") == "healthy":
# HolySheep가 해당 provider가 healthy라고 판단하면
#强制 HALF_OPEN으로 전환하여 복구 시도
with self._lock:
if self.state == self.State.OPEN:
print(f"Holysheep health check: {self.name} 복구 시도")
self._transition(self.State.HALF_OPEN)
elif provider_health.get("status") == "unavailable":
self.holySheep_health_override = True
def can_execute(self) -> bool:
# HolySheep가 healthy라고 하면 무조건 허용
if self.holySheep_health_override:
return True
return super().can_execute()
def record_success(self):
super().record_success()
# 성공 시 HolySheep health override 해제
if self.state == self.State.CLOSED:
self.holySheep_health_override = False
사용: HOLYsheep health check 결과를 circuit breaker에 반영
async def synchronized_health_check(client: HolySheepFailoverClient, breakers: Dict):
"""30초마다 HOLYsheep 상태와 circuit breaker 동기화"""
while True:
await asyncio.sleep(30)
status_report = client.get_status_report()
for provider_name, state in status_report.items():
if provider_name in breakers:
breakers[provider_name].sync_with_holysheep_health(state)
3. failover 후 모델 응답 형식 불일치
# 문제: OpenAI 응답과 Claude/Gemini 응답 구조가 다름
해결: Normalized response wrapper 구현
class NormalizedResponse:
"""모든 provider 응답을 통일된 포맷으로 변환"""
@staticmethod
def from_openai(response: Dict) -> Dict:
return {
"content": response["choices"][0]["message"]["content"],
"model": response["model"],
"provider": "openai",
"usage": {
"input_tokens": response["usage"]["prompt_tokens"],
"output_tokens": response["usage"]["completion_tokens"],
"total_tokens": response["usage"]["total_tokens"]
},
"finish_reason": response["choices"][0].get("finish_reason"),
"raw": response
}
@staticmethod
def from_anthropic(response: Dict) -> Dict:
# Claude는 다른 응답 구조를 가짐
return {
"content": response["content"][0]["text"],
"model": response["model"],
"provider": "anthropic",
"usage": {
"input_tokens": response["usage"]["input_tokens"],
"output_tokens": response["usage"]["output_tokens"],
"total_tokens": response["usage"]["input_tokens"] + response["usage"]["output_tokens"]
},
"finish_reason": response.get("stop_reason"),
"raw": response
}
@staticmethod
def from_google(response: Dict) -> Dict:
return {
"content": response["candidates"][0]["content"]["parts"][0]["text"],
"model": response["modelVersion"],
"provider": "google",
"usage": {
"prompt_tokens": response.get("usageMetadata", {}).get("promptTokenCount", 0),
"candidates_tokens": response.get("usageMetadata", {}).get("candidatesTokenCount", 0),
},
"finish_reason": response["candidates"][0].get("finishReason"),
"raw": response
}
@staticmethod
def normalize(response: Dict, provider: str) -> Dict:
"""Provider별 정규화 함수 선택"""
normalizers = {
"openai": NormalizedResponse.from_openai,
"anthropic": NormalizedResponse.from_anthropic,
"google": NormalizedResponse.from_google,
"deepseek": NormalizedResponse.from_openai,