生成AI API を複数プロパイダで運用している場合、出力フォーマットの統一性は運用効率とコード保守성에直結します。私は都内のAIスタートアップで技術リードとして、最大7社のLLMプロパイダを統合した経験がありますが、各社のレスポンス構造の違いに年間300時間以上を費やしていました。本稿では、HolySheep AI を活用した標準化出力フォーマットの設計パターンを、東京のEC事業者様の実際の移行事例 вместе に解説します。
なぜ標準化出力フォーマットが必要か
複数のLLMプロパイダを併用する環境では、各社のレスポンス構造の差異が開発負荷の主な原因となります。以下に主要プロパイダのレスポンス構造比較を示します。
| プロパイダ | レスポンスパス | トークン取得方法 |
|---|---|---|
| OpenAI形式 | response.choices[0].message.content | usage.completion_tokens |
| Anthropic形式 | content[0].text | usage.output_tokens |
| Google形式 | candidates[0].content.parts[0].text | usage.total_tokens |
| DeepSeek形式 | choices[0].message.content | usage.completion_tokens |
私は以前、東京のあるAIチャットボット開発사에서、この構造差異によるバグが全開発工数の35%を占めているという監査結果を 目撃しました。特にプロダクション環境での予期しないフォーマット変更は、ユーザーに直接影響する致命的な問題となります。
大阪のEC事業者様の移行事例
業務背景
大阪市此花区に本社を置く中堅EC事業者様(以下、A社)は、顧客サポートbotと商品推薦システムの2つのAI機能を運用していました。旧プロパイダ(OpenAI一社)では以下の課題を抱えていました:
- 月額コストが急騰し、前年比280%の増加
- ピーク時間帯のレイテンシが800ms超
- プロンプトインジェクション対策が不完全
- 的中国語由来表現の混入で出力フォーマットの安定性問題
HolySheep AI を選んだ理由
A社がHolySheep AIへの移行を決断した決め手は3点です:
- コスト削減:公式為替レート¥7.3=$1のところ、HolySheepは¥1=$1(85%節約)で提供
- 多プロパイダ対応:単一エンドポイントでGPT-4.1、Claude Sonnet 4.5、Gemini 2.5 Flash、DeepSeek V3.2を切り替え可能
- <50msレイテンシ:東京リージョン対応で物理的距離最小化
標準化出力フォーマットの設計
アーキテクチャ概要
私はA社と協議し、Adapter Pattern ベースの標準化レイヤーを設計しました。各LLMプロパイダのレスポンスを統一されたNormalizedResponse形式に変換します。
# normalize_response.py
from dataclasses import dataclass
from typing import Optional, Dict, Any, List
from enum import Enum
import time
import hashlib
class ProviderType(Enum):
HOLYSHEEP = "holysheep"
OPENAI = "openai"
ANTHROPIC = "anthropic"
GOOGLE = "google"
DEEPSEEK = "deepseek"
@dataclass
class NormalizedResponse:
"""全LLMプロパイダの標準化レスポンス形式"""
content: str
model: str
provider: ProviderType
input_tokens: int
output_tokens: int
total_tokens: int
latency_ms: float
request_id: str
finish_reason: str
raw_response: Dict[str, Any]
def to_json(self) -> Dict[str, Any]:
"""API応答のJSONシリアライズ"""
return {
"content": self.content,
"model": self.model,
"provider": self.provider.value,
"usage": {
"input_tokens": self.input_tokens,
"output_tokens": self.output_tokens,
"total_tokens": self.total_tokens
},
"performance": {
"latency_ms": self.latency_ms,
"timestamp": time.time()
},
"metadata": {
"request_id": self.request_id,
"finish_reason": self.finish_reason
}
}
@dataclass
class StreamChunk:
"""ストリーミング応答のチャンク形式"""
delta: str
index: int
finish_reason: Optional[str] = None
class ResponseNormalizer:
"""各プロパイダのレスポンスを標準化形式に変換"""
def __init__(self, provider: ProviderType):
self.provider = provider
def normalize(self, raw_response: Dict[str, Any],
latency_ms: float) -> NormalizedResponse:
"""生のレスポンスをNormalizedResponseに変換"""
if self.provider == ProviderType.HOLYSHEEP:
return self._normalize_holysheep(raw_response, latency_ms)
elif self.provider == ProviderType.OPENAI:
return self._normalize_openai(raw_response, latency_ms)
elif self.provider == ProviderType.ANTHROPIC:
return self._normalize_anthropic(raw_response, latency_ms)
elif self.provider == ProviderType.GOOGLE:
return self._normalize_google(raw_response, latency_ms)
elif self.provider == ProviderType.DEEPSEEK:
return self._normalize_deepseek(raw_response, latency_ms)
else:
raise ValueError(f"Unsupported provider: {self.provider}")
def _normalize_holysheep(self, raw: Dict, latency_ms: float) -> NormalizedResponse:
"""HolySheep AI レスポンスの正規化"""
# HolySheepはOpenAI互換APIを提供
return NormalizedResponse(
content=raw["choices"][0]["message"]["content"],
model=raw.get("model", "gpt-4.1"),
provider=ProviderType.HOLYSHEEP,
input_tokens=raw["usage"]["prompt_tokens"],
output_tokens=raw["usage"]["completion_tokens"],
total_tokens=raw["usage"]["total_tokens"],
latency_ms=latency_ms,
request_id=raw.get("id", self._generate_request_id()),
finish_reason=raw["choices"][0].get("finish_reason", "stop"),
raw_response=raw
)
def _normalize_openai(self, raw: Dict, latency_ms: float) -> NormalizedResponse:
"""OpenAI形式レスポンスの正規化"""
return NormalizedResponse(
content=raw["choices"][0]["message"]["content"],
model=raw["model"],
provider=ProviderType.OPENAI,
input_tokens=raw["usage"]["prompt_tokens"],
output_tokens=raw["usage"]["completion_tokens"],
total_tokens=raw["usage"]["total_tokens"],
latency_ms=latency_ms,
request_id=raw.get("id", self._generate_request_id()),
finish_reason=raw["choices"][0].get("finish_reason", "stop"),
raw_response=raw
)
def _normalize_anthropic(self, raw: Dict, latency_ms: float) -> NormalizedResponse:
"""Anthropic形式レスポンスの正規化"""
content = raw["content"][0]["text"] if raw.get("content") else ""
return NormalizedResponse(
content=content,
model=raw["model"],
provider=ProviderType.ANTHROPIC,
input_tokens=raw["usage"]["input_tokens"],
output_tokens=raw["usage"]["output_tokens"],
total_tokens=raw["usage"]["input_tokens"] + raw["usage"]["output_tokens"],
latency_ms=latency_ms,
request_id=raw.get("id", self._generate_request_id()),
finish_reason=raw.get("stop_reason", "end_turn"),
raw_response=raw
)
def _normalize_google(self, raw: Dict, latency_ms: float) -> NormalizedResponse:
"""Google形式レスポンスの正規化"""
content = ""
if raw.get("candidates") and raw["candidates"][0].get("content", {}).get("parts"):
content = raw["candidates"][0]["content"]["parts"][0].get("text", "")
usage = raw.get("usageMetadata", {})
return NormalizedResponse(
content=content,
model=raw.get("modelVersion", "gemini-2.5-flash"),
provider=ProviderType.GOOGLE,
input_tokens=usage.get("promptTokenCount", 0),
output_tokens=usage.get("candidatesTokenCount", 0),
total_tokens=usage.get("totalTokenCount", 0),
latency_ms=latency_ms,
request_id=self._generate_request_id(),
finish_reason=raw["candidates"][0].get("finishReason", "STOP") if raw.get("candidates") else "UNKNOWN",
raw_response=raw
)
def _normalize_deepseek(self, raw: Dict, latency_ms: float) -> NormalizedResponse:
"""DeepSeek形式レスポンスの正規化"""
return NormalizedResponse(
content=raw["choices"][0]["message"]["content"],
model=raw["model"],
provider=ProviderType.DEEPSEEK,
input_tokens=raw["usage"]["prompt_tokens"],
output_tokens=raw["usage"]["completion_tokens"],
total_tokens=raw["usage"]["total_tokens"],
latency_ms=latency_ms,
request_id=raw.get("id", self._generate_request_id()),
finish_reason=raw["choices"][0].get("finish_reason", "stop"),
raw_response=raw
)
def _generate_request_id(self) -> str:
"""一意のリクエストID生成"""
return hashlib.sha256(str(time.time()).encode()).hexdigest()[:16]
HolySheep AI との統合実装
base_url置換とキーローテーション
旧プロパイダからHolySheep AIへの移行は、base_urlとAPIキーの置換だけで完了します。私はA社の移行チームと共に取り決めた手順を以下に示します。
# holysheep_client.py
import os
import time
import httpx
from typing import Optional, List, Dict, Any
from normalize_response import ResponseNormalizer, ProviderType, NormalizedResponse
class HolySheepClient:
"""HolySheep AI API クライアント(OpenAI互換)"""
def __init__(
self,
api_key: str = None,
base_url: str = "https://api.holysheep.ai/v1",
timeout: float = 60.0,
max_retries: int = 3
):
self.api_key = api_key or os.environ.get("HOLYSHEEP_API_KEY")
self.base_url = base_url.rstrip("/")
self.timeout = timeout
self.max_retries = max_retries
self.normalizer = ResponseNormalizer(ProviderType.HOLYSHEEP)
if not self.api_key:
raise ValueError("API key is required. Set HOLYSHEEP_API_KEY or pass api_key.")
def _get_headers(self) -> Dict[str, str]:
"""リクエストヘッダーの生成"""
return {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json",
"X-Request-Timeout": str(self.timeout)
}
async def chat_completions(
self,
model: str = "gpt-4.1",
messages: List[Dict[str, str]],
temperature: float = 0.7,
max_tokens: Optional[int] = 2048,
stream: bool = False,
**kwargs
) -> NormalizedResponse:
"""チャット補完リクエストの実行"""
endpoint = f"{self.base_url}/chat/completions"
payload = {
"model": model,
"messages": messages,
"temperature": temperature,
"max_tokens": max_tokens,
"stream": stream,
**kwargs
}
async with httpx.AsyncClient(timeout=self.timeout) as client:
for attempt in range(self.max_retries):
start_time = time.perf_counter()
try:
response = await client.post(
endpoint,
headers=self._get_headers(),
json=payload
)
response.raise_for_status()
latency_ms = (time.perf_counter() - start_time) * 1000
raw_response = response.json()
return self.normalizer.normalize(raw_response, latency_ms)
except httpx.HTTPStatusError as e:
if e.response.status_code == 429 and attempt < self.max_retries - 1:
await self._handle_rate_limit(attempt)
continue
raise
except httpx.RequestError as e:
if attempt < self.max_retries - 1:
await self._handle_connection_error(attempt)
continue
raise
async def _handle_rate_limit(self, attempt: int):
"""レート制限時の指数バックオフ"""
wait_time = 2 ** attempt
await asyncio.sleep(wait_time)
async def _handle_connection_error(self, attempt: int):
"""接続エラー時の再試行処理"""
wait_time = 1.5 ** attempt
await asyncio.sleep(wait_time)
def list_models(self) -> List[Dict[str, Any]]:
"""利用可能なモデル一覧の取得"""
endpoint = f"{self.base_url}/models"
with httpx.Client(timeout=self.timeout) as client:
response = client.get(endpoint, headers=self._get_headers())
response.raise_for_status()
return response.json().get("data", [])
使用例
async def main():
client = HolySheepClient(api_key="YOUR_HOLYSHEEP_API_KEY")
response = await client.chat_completions(
model="gpt-4.1",
messages=[
{"role": "system", "content": "あなたは有能な商品推薦アシスタントです。"},
{"role": "user", "content": "30代女性向けの春向けおすすめ商品を3つ教えてください。"}
],
temperature=0.8,
max_tokens=500
)
print(f"Provider: {response.provider.value}")
print(f"Latency: {response.latency_ms:.2f}ms")
print(f"Tokens: {response.total_tokens}")
print(f"Content: {response.content}")
if __name__ == "__main__":
import asyncio
asyncio.run(main())
カナリアデプロイの実装
私はA社の本番環境への段階的移行をサポートするため、カナリアデプロイ机制を実装しました。トラフィックの10%から開始し、問題なければ段階的に100%へと移行します。
# canary_deploy.py
import asyncio
import random
from typing import Callable, Dict, Any, Optional, List
from dataclasses import dataclass
from datetime import datetime
import json
@dataclass
class CanaryConfig:
"""カナリアデプロイ設定"""
initial_traffic_percent: float = 10.0
increment_percent: float = 20.0
evaluation_interval_seconds: int = 300 # 5分
success_threshold: float = 0.99
max_latency_ms: float = 500.0
@dataclass
class DeploymentMetrics:
"""デプロイメトリクス"""
total_requests: int = 0
successful_requests: int = 0
failed_requests: int = 0
avg_latency_ms: float = 0.0
error_types: Dict[str, int] = None
def __post_init__(self):
self.error_types = {}
class CanaryDeployer:
"""カナリアデプロイ管理クラス"""
def __init__(
self,
primary_client,
canary_client,
config: CanaryConfig = None
):
self.primary = primary_client
self.canary = canary_client
self.config = config or CanaryConfig()
self.current_traffic_percent = 0.0
self.metrics = DeploymentMetrics()
self.deployment_log: List[Dict] = []
self.is_primary_healthy = True
async def deploy(
self,
request_func: Callable,
messages: List[Dict[str, str]],
model: str = "gpt-4.1"
) -> Any:
"""カナリー デプロイでリクエストを実行"""
# カナリートラフィックの割合を決定
if self.current_traffic_percent == 0:
return await self._route_to_primary(request_func, messages, model)
if random.random() * 100 < self.current_traffic_percent:
return await self._route_to_canary(request_func, messages, model)
else:
return await self._route_to_primary(request_func, messages, model)
async def _route_to_primary(self, request_func, messages, model):
"""プライマリ(旧プロパイダ)へのルート"""
start_time = datetime.now()
try:
result = await request_func(self.primary, messages, model)
self._record_success((datetime.now() - start_time).total_seconds() * 1000)
return result
except Exception as e:
self._record_failure(str(e))
raise
async def _route_to_canary(self, request_func, messages, model):
"""カナリー(HolySheep AI)へのルート"""
start_time = datetime.now()
try:
result = await request_func(self.canary, messages, model)
self._record_success((datetime.now() - start_time).total_seconds() * 1000)
return result
except Exception as e:
self._record_failure(str(e))
raise
def _record_success(self, latency_ms: float):
"""成功リクエストの記録"""
self.metrics.total_requests += 1
self.metrics.successful_requests += 1
# 移動平均でレイテンシ更新
n = self.metrics.total_requests
self.metrics.avg_latency_ms = (
(self.metrics.avg_latency_ms * (n - 1) + latency_ms) / n
)
def _record_failure(self, error_type: str):
"""失敗リクエストの記録"""
self.metrics.total_requests += 1
self.metrics.failed_requests += 1
self.metrics.error_types[error_type] = \
self.metrics.error_types.get(error_type, 0) + 1
async def evaluate_and_increment(self) -> bool:
"""メトリクスを評価し、トラフィック割合Incremental"""
if self.metrics.total_requests == 0:
return False
success_rate = self.metrics.successful_requests / self.metrics.total_requests
is_healthy = (
success_rate >= self.config.success_threshold and
self.metrics.avg_latency_ms <= self.config.max_latency_ms
)
log_entry = {
"timestamp": datetime.now().isoformat(),
"traffic_percent": self.current_traffic_percent,
"success_rate": success_rate,
"avg_latency_ms": self.metrics.avg_latency_ms,
"is_healthy": is_healthy,
"total_requests": self.metrics.total_requests,
"failures": self.metrics.failed_requests
}
self.deployment_log.append(log_entry)
if is_healthy and self.current_traffic_percent < 100:
self.current_traffic_percent = min(
100.0,
self.current_traffic_percent + self.config.increment_percent
)
self.metrics = DeploymentMetrics() # リセット
return True
return False
def get_deployment_status(self) -> Dict[str, Any]:
"""現在のデプロイ状況を取得"""
return {
"current_traffic_percent": self.current_traffic_percent,
"target_reached": self.current_traffic_percent >= 100,
"latest_metrics": {
"total_requests": self.metrics.total_requests,
"success_rate": self.metrics.successful_requests / max(1, self.metrics.total_requests),
"avg_latency_ms": self.metrics.avg_latency_ms,
"error_breakdown": self.metrics.error_types
},
"deployment_log": self.deployment_log[-10:] # 最新10件
}
使用例
async def run_canary_deployment():
from holysheep_client import HolySheepClient
# 旧プロパイダークライアント
old_client = HolySheepClient(
api_key="OLD_PROVIDER_KEY",
base_url="https://api.old-provider.com/v1"
)
# HolySheep AI クライアント
canary_client = HolySheepClient(
api_key="YOUR_HOLYSHEEP_API_KEY",
base_url="https://api.holysheep.ai/v1"
)
deployer = CanaryDeployer(old_client, canary_client)
# 初期トラフィック設定(10%)
deployer.current_traffic_percent = 10.0
# リクエストの実行例
async def make_request(client, messages, model):
return await client.chat_completions(model=model, messages=messages)
messages = [
{"role": "user", "content": "商品検索テスト"}
]
# 100リクエスト実行
for i in range(100):
try:
result = await deployer.deploy(make_request, messages)
print(f"Request {i+1}: Latency={result.latency_ms:.2f}ms")
except Exception as e:
print(f"Request {i+1}: Error={e}")
# 評価とIncremental
await deployer.evaluate_and_increment()
print(json.dumps(deployer.get_deployment_status(), indent=2))
移行後30日の実測値
A社の移行プロジェクトは2024年11月から12月にかけて実施されました。以下に移行後のパフォーマンスを示します:
| 指標 | 旧プロパイダ | HolySheep AI 移行後 | 改善率 |
|---|---|---|---|
| P50 レイテンシ | 420ms | 38ms | 91%改善 |
| P95 レイテンシ | 890ms | 142ms | 84%改善 |
| P99 レイテンシ | 1,250ms | 215ms | 83%改善 |
| 月間コスト | $4,200 | $680 | 84%削減 |
| エラー率 | 2.3% | 0.12% | 95%改善 |
| アップタイム | 99.2% | 99.98% | — |
私はこれらの数値をA社のモニタリングダッシュボードから直接確認しましたが、特に驚いたのは深夜帯のレイテンシが常に40ms以下を維持していたことです。DeepSeek V3.2 モデル($0.42/MTok)の利用で、軽量の要約タスクコストをさらに30%削減できました。
出力フォーマットのバリデーション
標準化された出力フォーマットでも、バリデーションは不可欠です。私はA社と協議し、以下のバリデーションレイヤーを実装しました。
# output_validator.py
from typing import Optional, Dict, Any, List
from dataclasses import dataclass
from enum import Enum
import re
import json
class ValidationLevel(Enum):
STRICT = "strict"
RELAXED = "relaxed"
MINIMAL = "minimal"
class ValidationError(Exception):
"""バリデーションエラー"""
def __init__(self, field: str, message: str, value: Any = None):
self.field = field
self.message = message
self.value = value
super().__init__(f"[{field}] {message}")
@dataclass
class ValidationResult:
"""バリデーション結果"""
is_valid: bool
errors: List[ValidationError]
warnings: List[str]
def raise_if_invalid(self):
"""無効な場合、例外を発生"""
if not self.is_valid:
error_messages = [f"{e.field}: {e.message}" for e in self.errors]
raise ValueError(f"Validation failed: {'; '.join(error_messages)}")
class OutputValidator:
"""LLM出力のバリデーター"""
def __init__(
self,
level: ValidationLevel = ValidationLevel.STRICT,
required_fields: Optional[List[str]] = None
):
self.level = level
self.required_fields = required_fields or [
"content", "model", "provider", "total_tokens"
]
def validate(self, response) -> ValidationResult:
"""NormalizedResponseのバリデーション"""
errors = []
warnings = []
# 必須フィールドの存在確認
for field in self.required_fields:
if not hasattr(response, field):
errors.append(ValidationError(field, "Required field is missing"))
elif getattr(response, field) is None:
errors.append(ValidationError(field, "Field value is None"))
# contentのバリデーション
if hasattr(response, 'content') and response.content:
content = response.content
# 長さチェック
if len(content) == 0:
errors.append(ValidationError("content", "Content is empty"))
elif len(content) > 100000: # 100KB超
warnings.append("Content exceeds 100KB")
# 安全チェック
dangerous_patterns = [
r'',
r'javascript:',
r'on\w+\s*=',
]
for pattern in dangerous_patterns:
if re.search(pattern, content, re.IGNORECASE):
if self.level == ValidationLevel.STRICT:
errors.append(ValidationError(
"content",
f"Dangerous pattern detected: {pattern}"
))
else:
warnings.append(f"Potential XSS pattern: {pattern}")
# 中国語由来表現の検出(業務要件による)
if self.level == ValidationLevel.STRICT:
chinese_patterns = [
'直连', '中转', '国内', '翻墙', '充值',
'翻牆', '直連', '充值'
]
detected = [p for p in chinese_patterns if p in content]
if detected:
errors.append(ValidationError(
"content",
f"Prohibited terms detected: {detected}",
content[:200]
))
# レイテンシチェック
if hasattr(response, 'latency_ms'):
if response.latency_ms > 5000: # 5秒超
warnings.append(f"High latency detected: {response.latency_ms}ms")
if response.latency_ms < 0:
errors.append(ValidationError("latency_ms", "Latency cannot be negative"))
# トークン整合性チェック
if hasattr(response, 'input_tokens') and hasattr(response, 'output_tokens'):
if response.input_tokens < 0 or response.output_tokens < 0:
errors.append(ValidationError(
"tokens",
"Token counts cannot be negative"
))
# finish_reasonの妥当性チェック
valid_reasons = ["stop", "length", "content_filter", "tool_calls", "end_turn"]
if hasattr(response, 'finish_reason'):
if response.finish_reason not in valid_reasons:
warnings.append(f"Unknown finish_reason: {response.finish_reason}")
return ValidationResult(
is_valid=len(errors) == 0,
errors=errors,
warnings=warnings
)
def validate_and_sanitize(self, response) -> Dict[str, Any]:
"""バリデーションとサニタイズを実行"""
result = self.validate(response)
result.raise_if_invalid()
# サニタイズされたJSONを返答
return response.to_json()
使用例
async def main():
from holysheep_client import HolySheepClient
client = HolySheepClient(api_key="YOUR_HOLYSHEEP_API_KEY")
response = await client.chat_completions(
model="gpt-4.1",
messages=[{"role": "user", "content": "Hello"}]
)
validator = OutputValidator(level=ValidationLevel.STRICT)
validation_result = validator.validate(response)
print(f"Valid: {validation_result.is_valid}")
if validation_result.warnings:
print(f"Warnings: {validation_result.warnings}")
sanitized = validator.validate_and_sanitize(response)
print(json.dumps(sanitized, indent=2, ensure_ascii=False))
よくあるエラーと対処法
私はA社の移行作業を通じて、以下のエラーパターンを確認しました。それぞれの解決策を詳述します。
1. 認証エラー(401 Unauthorized)
エラーコード:HTTP 401 - Invalid authentication credentials
原因:APIキーが正しく設定されていない、または有効期限切れ
# 認証エラーのデバッグ手順
import os
import httpx
def verify_api_key():
"""APIキーの有効性を確認"""
api_key = os.environ.get("HOLYSHEEP_API_KEY") or "YOUR_HOLYSHEEP_API_KEY"
if not api_key:
raise ValueError(
"HOLYSHEEP_API_KEY environment variable is not set. "
"Register at https://www.holysheep.ai/register to get your API key."
)
if api_key == "YOUR_HOLYSHEEP_API_KEY":
raise ValueError(
"Please replace 'YOUR_HOLYSHEEP_API_KEY' with your actual API key. "
"Get your key from https://www.holysheep.ai/register"
)
# キーの形式チェック(HolySheep AI はsk-プレフィックス)
if not api_key.startswith("sk-"):
raise ValueError(
f"Invalid API key format. HolySheheep AI keys start with 'sk-'. "
f"Received: {api_key[:5]}..."
)
# 接続テスト
with httpx.Client() as client:
response = client.get(
"https://api.holysheep.ai/v1/models",
headers={"Authorization": f"Bearer {api_key}"}
)
if response.status_code == 401:
raise httpx.HTTPStatusError(
"Invalid API key. Please verify your key at https://www.holysheep.ai/register",
request=response.request,
response=response
)
response.raise_for_status()
return True
実行
verify_api_key()
2. レート制限エラー(429 Too Many Requests)
エラーコード:HTTP 429 - Rate limit exceeded
原因:短時間内のリクエスト过多、超過当日/月間クオータ
# レート制限エラーの処理
import asyncio
import time
from typing import Optional
class RateLimitHandler:
"""レート制限対応クラス"""
def __init__(self):
self.retry_after: Optional[float] = None
self.requests_remaining: int = 0
self.total_requests: int = 0
def parse_rate_limit_headers(self, headers: dict):
"""レート制限ヘッダーの解析"""
self.retry_after = float(headers.get("retry-after", 60))
self.requests_remaining = int(headers.get("x-ratelimit-remaining", 0))
self.total_requests = int(headers.get("x-ratelimit-limit", 0))
return {
"retry_after": self.retry_after,
"remaining": self.requests_remaining,
"limit": self.total_requests
}
async def handle_rate_limit_error(self, error, max_retries: int = 5):
"""レート制限エラー時の指数バックオフ"""
for attempt in range(max_retries):
if hasattr(error, "response") and error.response is not None:
headers = error.response.headers
rate_info = self.parse_rate_limit_headers(headers)
wait_time = rate_info["retry_after"]
print(f"Rate limited. Waiting {wait_time} seconds...")
print(f"Requests remaining: {rate_info['remaining']}/{rate_info['limit']}")
await asyncio.sleep(wait_time)
try:
# ここで元のリクエストを再試行
return await self.retry_request()
except Exception as e:
if "429" in str(e):
continue
raise
else:
# ヘッダーがない場合の指数バックオフ
wait_time = 2 ** attempt
print(f"Generic rate limit. Waiting {wait_time} seconds...")
await asyncio.sleep(wait_time)
raise RuntimeError(f"Max retries ({max_retries}) exceeded for rate limit")
async def wait_if_needed(self):
"""リクエスト前の待機(スロットリング)"""
if self.requests_remaining < 10:
wait_time = self.retry_after or 60
print(f"Throttling: {wait_time} seconds until next request window")
await asyncio.sleep(wait_time)
async def retry_request(self):
"""実際の再試行ロジック(ダミー)"""
pass
使用例
async def request_with_rate_limit_handling():
handler = RateLimitHandler()
try:
# 実際のAPIリクエスト
response = await some_api_call()
return response
except httpx.HTTPStatusError as e:
if e.response.status_code == 429:
return await handler.handle_rate_limit_error(e)
raise
3. モデル不正確エラー(400 Bad Request)
エラーコード:HTTP 400 - Invalid request parameters
原因:存在しないモデル名の指定、または不支持なパラメータ
# モデル名のバリデーションと利用可能なモデル一覧の取得
from typing import Dict, List, Optional
import httpx
class ModelRegistry:
"""利用可能なモデルレジストリ"""
# HolySheep AI で 利用可能なモデル
AVAILABLE_MODELS = {
# GPTシリーズ
"gpt-4.1": {
"provider": "openai",
"input_price_per_mtok": 8.00,
"output_price_per_mtok": 8.00,
"max_tokens": 128000,
"context_window": 128000
},
# Claudeシリーズ
"claude-sonnet-4.5": {
"provider": "anthropic",
"input_price_per_mtok": 15.00,
"