結論:AI API 调用に熔断器(サーキットブレーカー)を実装することで、ベンダーがダウンしてもサービスを継続できます。HolySheep AI は月額85%のコスト削減(¥1=$1)と50ms未満のレイテンシで、微細な障害でも即座に代替策へ切り替えられる信頼性を実現します。本稿では、Hystrix パターンに基づいた熔断器の実装方法を具体的に解説し、HolySheep との統合によるベストプラクティスを提供します。
HolySheep AI・公式API・競合サービスの比較
| 項目 | HolySheep AI | OpenAI 公式 | Anthropic 公式 | Google AI |
|---|---|---|---|---|
| 為替レート | ¥1 = $1(85%節約) | ¥7.3 = $1 | ¥7.3 = $1 | ¥7.3 = $1 |
| GPT-4.1 出力 | $8/MTok | $60/MTok | — | — |
| Claude Sonnet 4.5 出力 | $15/MTok | — | $18/MTok | — |
| Gemini 2.5 Flash 出力 | $2.50/MTok | — | — | $3.50/MTok |
| DeepSeek V3.2 出力 | $0.42/MTok | — | — | — |
| レイテンシ | <50ms | 100-500ms | 150-800ms | 80-300ms |
| 決済手段 | WeChat Pay / Alipay / クレジットカード | クレジットカード(海外) | クレジットカード(海外) | クレジットカード(海外) |
| 無料クレジット | 登録時付与 | $5分 | $5分 | $300相当 |
| 熔断器対応 | 複数モデル自動Fallback | 単一モデル | 単一モデル | 単一モデル |
向いている人・向いていない人
向いている人
- 本番環境にAI機能を組み込んでいる開発者:API障害時のサービス継続が不可欠
- コスト最適化を重視するチーム:月額コストを85%削減したい企业
- 中国本土ユーザー:WeChat Pay/Alipayで 즉시決済可能
- 複数モデルを使い分けたい人:GPT-4.1、Claude Sonnet、Gemini Flash、DeepSeek V3.2 を熔断器で切り替え
- 低レイテンシが求められるアプリケーション:<50msの応答速度
向いていない人
- 極めて機密性の高いデータを取り扱う場合:データガバナンス要件を事前に確認要
- 公式サポート密切対応が必要な場合: SLA の確認が必要
- 実験・学習目的のみ:無料枠で十分な場合がある
熔断器パターンとは
熔断器パターン(Circuit Breaker Pattern)は、Netflix が Hystrix ライブラリで 대중化した設計パターンです。外部API呼び出しを監視し、故障が続く場合に即座に代替処理へフォールバックします。
熔断器の3つの状態
┌─────────────────────────────────────────────────────────────┐
│ 熔断器状态遷移 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ 故障率超過 ┌──────────┐ タイムアウト │
│ │ CLOSED │ ───────────────▶ │ OPEN │ ───────────────▶ │
│ │ 正常稼働 │ │ 遮断中 │ │
│ └──────────┘ └──────────┘ │
│ ▲ │ │
│ │ 半数開門 │ │
│ │◀─────────────────────────────┘ │
│ ┌──────────┐ │
│ │HALF-OPEN │ ◀──────────────────── 恢复確認 │
│ │ 試験稼働 │ │
│ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
- CLOSED:通常動作、リクエストを正常に通過させる
- OPEN:遮断状態、リクエストを即座にフォールバックさせる
- HALF-OPEN:試験状態、少数のリクエストを許可して恢复を試みる
価格とROI
コスト比較シミュレーション
月間1億トークン使用の場合:
┌────────────────────────────────────────────────────────────┐
│ Provider │ 単価(¥/$7.3) │ 月間コスト │ 年間コスト │
├────────────────────────────────────────────────────────────┤
│ OpenAI 公式 │ $60/MTok │ ¥438,000 │ ¥5,256,000 │
│ Anthropic 公式 │ $18/MTok │ ¥131,400 │ ¥1,576,800 │
│ HolySheep AI │ $8/MTok(GPT4) │ ¥58,400 │ ¥700,800 │
├────────────────────────────────────────────────────────────┤
│ 【HolySheep节约額】OpenAI比: ¥379,600/月 (86%OFF) │
│ 【HolySheep节约額】Anthropic比: ¥73,000/月 (55%OFF) │
└────────────────────────────────────────────────────────────┘
月間1,000万トークン使用の場合(DeepSeek V3.2):
HolySheep AI: $0.42/MTok × 10 = $4.2/月 ≈ ¥31
ROI分析
- 開発工数投資対効果:熔断器実装に20時間かけた場合、1ヶ月で開発コストを回収可能
- 障害時の損失防止:API障害によるサービス停止を熔断器で防止、売上損失を回避
- コスト削減効果:複数モデルへの分散で最適なコストパフォーマンスを実現
HolySheep AIを選ぶ理由
- 圧倒的なコスト優位性:¥1=$1の固定レートで、公式比85%節約
- 複数モデル対応:GPT-4.1、Claude Sonnet 4.5、Gemini 2.5 Flash、DeepSeek V3.2 を1つのエンドポイントで利用可能
- 超低レイテンシ:<50msの応答速度でリアルタイムアプリケーションに対応
- 柔軟な決済:WeChat Pay、Alipayに対応し、日本円建てで簡単精算
- 熔断器統合の最適性:複数モデルの自動Fallbackにより可用性を最大化
Java + Spring Boot での Hystrix 熔断器実装
まずは、Java Spring Boot 环境下で HolySheep AI API 用の熔断器を実装します。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.holysheep.example</groupId>
<artifactId>ai-circuit-breaker</artifactId>
<version>1.0.0</version>
<properties>
<java.version>17</java.version>
<spring-cloud.version>2023.0.0</spring-cloud.version>
</properties>
<dependencies>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Cloud Circuit Breaker (Resilience4j) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<!-- HTTP Client (WebClient) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- JSON Processing -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
</project>
package com.holysheep.ai.config;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CircuitBreakerConfiguration {
@Bean
public CircuitBreaker holySheepCircuitBreaker() {
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
// 熔断器を開く閾値(失敗率50%超でOPEN)
.failureRateThreshold(50)
// OPEN状態持续時間(10秒後にHALF-OPENに)
.waitDurationInOpenState(java.time.Duration.ofSeconds(10))
// HALF-OPEN状態での許可リクエスト数
.permittedNumberOfCallsInHalfOpenState(3)
// スライディングウィンドウサイズ(10件のリクエストで判定)
.slidingWindowSize(10)
// 最小呼び出し回数(5件以上)
.minimumNumberOfCalls(5)
// 例外発生時の自動OPEN
.recordExceptions(
java.io.IOException.class,
java.util.concurrent.TimeoutException.class,
org.springframework.web.reactive.function.client.WebClientResponseException.class
)
.build();
return CircuitBreaker.of("holySheepAI", config);
}
@Bean
public CircuitBreaker anthropicCircuitBreaker() {
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.waitDurationInOpenState(java.time.Duration.ofSeconds(15))
.permittedNumberOfCallsInHalfOpenState(3)
.slidingWindowSize(10)
.minimumNumberOfCalls(5)
.build();
return CircuitBreaker.of("anthropicAI", config);
}
@Bean
public CircuitBreaker googleCircuitBreaker() {
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.waitDurationInOpenState(java.time.Duration.ofSeconds(20))
.permittedNumberOfCallsInHalfOpenState(3)
.slidingWindowSize(10)
.minimumNumberOfCalls(5)
.build();
return CircuitBreaker.of("googleAI", config);
}
}
package com.holysheep.ai.service;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Mono;
import reactor.core.publisher.Flux;
import java.time.Duration;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@Service
public class MultiModelAIService {
private static final String HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1";
private static final String API_KEY = "YOUR_HOLYSHEEP_API_KEY";
private final WebClient holySheepClient;
private final WebClient anthropicClient;
private final WebClient googleClient;
private final CircuitBreakerRegistry circuitBreakerRegistry;
// フォールバック順序の定義
private static final List<String> FALLBACK_ORDER = Arrays.asList(
"holySheep",
"anthropic",
"google"
);
@Autowired
public MultiModelAIService(WebClient.Builder webClientBuilder,
CircuitBreakerRegistry circuitBreakerRegistry) {
this.circuitBreakerRegistry = circuitBreakerRegistry;
this.holySheepClient = webClientBuilder
.baseUrl(HOLYSHEEP_BASE_URL)
.defaultHeader("Authorization", "Bearer " + API_KEY)
.defaultHeader("Content-Type", "application/json")
.build();
this.anthropicClient = webClientBuilder
.baseUrl("https://api.anthropic.com/v1")
.defaultHeader("x-api-key", "YOUR_ANTHROPIC_API_KEY")
.defaultHeader("Content-Type", "application/json")
.build();
this.googleClient = webClientBuilder
.baseUrl("https://generativelanguage.googleapis.com/v1beta")
.defaultHeader("Authorization", "Bearer YOUR_GOOGLE_API_KEY")
.defaultHeader("Content-Type", "application/json")
.build();
}
public Mono<String> generateWithFallback(String prompt, String systemPrompt) {
// 熔断器の状態確認とログ出力
logCircuitBreakerStatus();
// HolySheepをまず尝试
return callHolySheep(prompt, systemPrompt)
.onErrorResume(e -> {
CircuitBreaker breaker = circuitBreakerRegistry.circuitBreaker("holySheepAI");
breaker.recordFailure(e);
System.err.println("[HolySheep Fallback] 原因: " + e.getMessage());
// Anthropicにフォールバック
return callAnthropic(prompt, systemPrompt)
.onErrorResume(e2 -> {
CircuitBreaker anthropicBreaker = circuitBreakerRegistry.circuitBreaker("anthropicAI");
anthropicBreaker.recordFailure(e2);
System.err.println("[Anthropic Fallback] 原因: " + e2.getMessage());
// Googleに最終フォールバック
return callGoogle(prompt, systemPrompt)
.onErrorResume(e3 -> {
CircuitBreaker googleBreaker = circuitBreakerRegistry.circuitBreaker("googleAI");
googleBreaker.recordFailure(e3);
System.err.println("[Google Fallback] 原因: " + e3.getMessage());
// 全て失敗した場合
return Mono.error(new RuntimeException(
"全てのAI Providerが利用不可: " + e3.getMessage()
));
});
});
})
.timeout(Duration.ofSeconds(30))
.doOnSuccess(result -> {
System.out.println("[成功] レスポンスサイズ: " + result.length() + " 文字");
});
}
private Mono<String> callHolySheep(String prompt, String systemPrompt) {
CircuitBreaker breaker = circuitBreakerRegistry.circuitBreaker("holySheepAI");
// 熔断器がOPENの場合は即座に例外をスロー
if (breaker.getState() == CircuitBreaker.State.OPEN) {
return Mono.error(new RuntimeException("HolySheep Circuit Breaker is OPEN"));
}
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("model", "gpt-4.1");
requestBody.put("messages", Arrays.asList(
Map.of("role", "system", "content", systemPrompt),
Map.of("role", "user", "content", prompt)
));
requestBody.put("max_tokens", 2000);
requestBody.put("temperature", 0.7);
Supplier<Mono<String>> supplier = () -> holySheepClient
.post()
.uri("/chat/completions")
.bodyValue(requestBody)
.retrieve()
.bodyToMono(Map.class)
.map(response -> {
@SuppressWarnings("unchecked")
List<Map<String, Object>> choices = (List<Map<String, Object>>) response.get("choices");
if (choices != null && !choices.isEmpty()) {
@SuppressWarnings("unchecked")
Map<String, Object> message = (Map<String, Object>) choices.get(0).get("message");
return (String) message.get("content");
}
return "No response content";
});
return CircuitBreaker.decorateSupplier(breaker, supplier)
.get();
}
private Mono<String> callAnthropic(String prompt, String systemPrompt) {
CircuitBreaker breaker = circuitBreakerRegistry.circuitBreaker("anthropicAI");
if (breaker.getState() == CircuitBreaker.State.OPEN) {
return Mono.error(new RuntimeException("Anthropic Circuit Breaker is OPEN"));
}
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("model", "claude-sonnet-4-20250514");
requestBody.put("messages", Arrays.asList(
Map.of("role", "user", "content", "System: " + systemPrompt + "\n\nUser: " + prompt)
));
requestBody.put("max_tokens", 2000);
Supplier<Mono<String>> supplier = () -> anthropicClient
.post()
.uri("/messages")
.bodyValue(requestBody)
.retrieve()
.bodyToMono(Map.class)
.map(response -> {
@SuppressWarnings("unchecked")
Map<String, Object> content = (Map<String, Object>) ((List<?>)response.get("content")).get(0);
return (String) content.get("text");
});
return CircuitBreaker.decorateSupplier(breaker, supplier)
.get();
}
private Mono<String> callGoogle(String prompt, String systemPrompt) {
CircuitBreaker breaker = circuitBreakerRegistry.circuitBreaker("googleAI");
if (breaker.getState() == CircuitBreaker.State.OPEN) {
return Mono.error(new RuntimeException("Google Circuit Breaker is OPEN"));
}
Map<String, Object> requestBody = Map.of(
"contents", Arrays.asList(
Map.of("parts", Arrays.asList(
Map.of("text", systemPrompt + "\n\n" + prompt)
))
),
"generationConfig", Map.of(
"maxOutputTokens", 2000,
"temperature", 0.7
)
);
Supplier<Mono<String>> supplier = () -> googleClient
.post()
.uri(uri -> uri.path("/models/gemini-2.0-flash:generateContent").build())
.bodyValue(requestBody)
.retrieve()
.bodyToMono(Map.class)
.map(response -> {
@SuppressWarnings("unchecked")
List<Map<String, Object>> candidates = (List<Map<String, Object>>) response.get("candidates");
if (candidates != null && !candidates.isEmpty()) {
@SuppressWarnings("unchecked")
List<Map<String, Object>> parts = (List<Map<String, Object>>)
((Map<String, Object>)candidates.get(0).get("content")).get("parts");
if (parts != null && !parts.isEmpty()) {
return (String) parts.get(0).get("text");
}
}
return "No response content";
});
return CircuitBreaker.decorateSupplier(breaker, supplier)
.get();
}
private void logCircuitBreakerStatus() {
System.out.println("\n=== Circuit Breaker Status ===");
for (String name : FALLBACK_ORDER) {
CircuitBreaker breaker = circuitBreakerRegistry.circuitBreaker(name + "AI");
CircuitBreaker.State state = breaker.getState();
CircuitBreaker.Metrics metrics = breaker.getMetrics();
System.out.printf("[%s] State: %-8s | Failure Rate: %.1f%% | Calls: %d%n",
name.toUpperCase(),
state,
metrics.getFailureRate(),
metrics.getNumberOfSuccessfulCalls() + metrics.getNumberOfFailedCalls()
);
}
System.out.println("==============================\n");
}
// 熔断器の手動リセット(管理画面用)
public void resetCircuitBreaker(String provider) {
CircuitBreaker breaker = circuitBreakerRegistry.circuitBreaker(provider + "AI");
breaker.reset();
System.out.println("[Circuit Breaker Reset] " + provider + " AI");
}
// 全熔断器の状态取得
public Map<String, String> getAllCircuitBreakerStates() {
return FALLBACK_ORDER.stream()
.collect(Collectors.toMap(
name -> name,
name -> circuitBreakerRegistry.circuitBreaker(name + "AI")
.getState().toString()
));
}
}
package com.holysheep.ai.controller;
import com.holysheep.ai.service.MultiModelAIService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;
import java.util.Map;
@RestController
@RequestMapping("/api/ai")
public class AIController {
private final MultiModelAIService aiService;
@Autowired
public AIController(MultiModelAIService aiService) {
this.aiService = aiService;
}
@PostMapping("/chat")
public Mono<ResponseEntity<Map<String, Object>>> chat(
@RequestBody Map<String, String> request) {
String prompt = request.getOrDefault("prompt", "");
String systemPrompt = request.getOrDefault("systemPrompt", "あなたは有帮助なAssistantです。");
return aiService.generateWithFallback(prompt, systemPrompt)
.map(response -> ResponseEntity.ok(Map.of(
"success", true,
"response", response,
"provider", "auto-fallback"
)))
.onErrorResume(e -> Mono.just(ResponseEntity.ok(Map.of(
"success", false,
"error", e.getMessage(),
"providers", aiService.getAllCircuitBreakerStates()
))));
}
@GetMapping("/health")
public ResponseEntity<Map<String, Object>> health() {
return ResponseEntity.ok(Map.of(
"status", "healthy",
"circuitBreakers", aiService.getAllCircuitBreakerStates()
));
}
@PostMapping("/admin/reset-breaker/{provider}")
public ResponseEntity<Map<String, String>> resetBreaker(
@PathVariable String provider) {
aiService.resetCircuitBreaker(provider);
return ResponseEntity.ok(Map.of(
"message", provider + " AIの熔断器をリセットしました"
));
}
}
Python + Resilience4j-Py での熔断器実装
# requirements.txt
pip install pybreaker httpx fastapi uvicorn
import pybreaker
import httpx
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Optional, List, Dict, Any
import asyncio
import logging
from datetime import datetime
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = FastAPI(title="AI Circuit Breaker Service")
========================================
熔断器の設定
========================================
def create_breaker(name: str, fail_max: int = 5, reset_timeout: int = 30):
"""熔断器の生成"""
breaker = pybreaker.CircuitBreaker(
fail_max=fail_max, # 失敗回数閾値
reset_timeout=reset_timeout, # リセットまでの秒数
exclude=[httpx.TimeoutException, httpx.ConnectError]
)
# 状态变化的イベントハンドラ
@breaker.add_state_changed_listener
def state_changed(state):
logger.warning(f"[{name}] Circuit Breaker 状態変更: {state}")
return breaker
各Provider用の熔断器
holy_sheep_breaker = create_breaker("HolySheep", fail_max=5, reset_timeout=30)
anthropic_breaker = create_breaker("Anthropic", fail_max=3, reset_timeout=60)
google_breaker = create_breaker("Google", fail_max=3, reset_timeout=60)
========================================
APIクライアントクラス
========================================
class AIServiceClient:
def __init__(self, name: str, base_url: str, api_key: str, breaker, model: str):
self.name = name
self.base_url = base_url
self.api_key = api_key
self.breaker = breaker
self.model = model
async def call(self, prompt: str, system_prompt: str) -> Dict[str, Any]:
"""API呼び出し(熔断器内)"""
async with httpx.AsyncClient(timeout=30.0) as client:
if self.name == "HolySheep":
response = await client.post(
f"{self.base_url}/chat/completions",
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
},
json={
"model": self.model,
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": prompt}
],
"max_tokens": 2000,
"temperature": 0.7
}
)
response.raise_for_status()
data = response.json()
return {
"content": data["choices"][0]["message"]["content"],
"provider": "HolySheep"
}
elif self.name == "Anthropic":
response = await client.post(
f"{self.base_url}/messages",
headers={
"x-api-key": self.api_key,
"anthropic-version": "2023-06-01",
"Content-Type": "application/json"
},
json={
"model": self.model,
"messages": [
{"role": "user", "content": f"System: {system_prompt}\n\nUser: {prompt}"}
],
"max_tokens": 2000
}
)
response.raise_for_status()
data = response.json()
return {
"content": data["content"][0]["text"],
"provider": "Anthropic"
}
elif self.name == "Google":
response = await client.post(
f"{self.base_url}/models/{self.model}:generateContent",
headers={
"Content-Type": "application/json"
},
params={"key": self.api_key},
json={
"contents": [{
"parts": [{"text": f"{system_prompt}\n\n{prompt}"}]
}],
"generationConfig": {
"maxOutputTokens": 2000,
"temperature": 0.7
}
}
)
response.raise_for_status()
data = response.json()
return {
"content": data["candidates"][0]["content"]["parts"][0]["text"],
"provider": "Google"
}
========================================
Provider 实例化
========================================
providers: List[AIServiceClient] = [
AIServiceClient(
name="HolySheep",
base_url="https://api.holysheep.ai/v1",
api_key="YOUR_HOLYSHEEP_API_KEY",
breaker=holy_sheep_breaker,
model="gpt-4.1"
),
AIServiceClient(
name="Anthropic",
base_url="https://api.anthropic.com/v1",
api_key="YOUR_ANTHROPIC_API_KEY",
breaker=anthropic_breaker,
model="claude-sonnet-4-20250514"
),
AIServiceClient(
name="Google",
base_url="https://generativelanguage.googleapis.com/v1beta",
api_key="YOUR_GOOGLE_API_KEY",
breaker=google_breaker,
model="gemini-2.0-flash"
)
]
========================================
熔断器付きAI服务
========================================
class MultiModelAIService:
def __init__(self, providers: List[AIServiceClient]):
self.providers = providers
async def generate(self, prompt: str, system_prompt: str = "あなたは有帮助なAssistantです。") -> Dict[str, Any]:
"""フォールバック対応のAI生成"""
errors = []
for provider in self.providers:
breaker = provider.breaker
# 熔断器状态确认
if breaker.current_state == pybreaker.STATE_OPEN:
logger.warning(f"[{provider.name}] Circuit Breaker OPEN - スキップ")
errors.append(f"{provider.name}: Circuit OPEN")
continue
try:
logger.info(f"[{provider.name}] API呼び出し開始")
start_time = datetime.now()
# 熔断器内でAPI呼び出し
result = await breaker.call(provider.call, prompt, system_prompt)
elapsed = (datetime.now() - start_time).total_seconds() * 1000
logger.info(f"[{provider.name}] 成功 ({elapsed:.0f}ms)")
return result
except pybreaker.CircuitBreakerError:
logger.error(f"[{provider.name}] Circuit Breaker Error")
errors.append(f"{provider.name}: Circuit OPEN")
except httpx.HTTPStatusError as e:
logger.error(f"[{provider.name}] HTTP Error: {e.response.status_code}")
errors.append(f"{provider.name}: HTTP {e.response.status_code}")
# 熔断器に失敗を記録
breaker.open()
except Exception as e:
logger.error(f"[{provider.name}] Error: {str(e)}")
errors.append(f"{provider.name}: {str(e)}")
try:
breaker.open()
except:
pass
# 全Provider失敗
raise HTTPException(
status_code=503,
detail={
"error": "全AI Providerが利用不可",
"details": errors,
"circuit_breakers": {
"HolySheep": holy_sheep_breaker.current_state,
"Anthropic": anthropic_breaker.current_state,
"Google": google_breaker.current_state
}
}
)
ai_service = MultiModelAIService(providers)
========================================
APIエンドポイント
========================================
class ChatRequest(BaseModel):
prompt: str
system_prompt: Optional[str] = "あなたは有帮助なAssistantです。"
class ChatResponse(BaseModel):
success: bool
content: Optional[str] = None
provider: Optional[str] = None
error: Optional[str] = None
circuit_breakers: Optional[Dict[str, str]] = None
@app.post("/api/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
try:
result = await ai_service.generate(request.prompt, request.system_prompt)
return ChatResponse(
success=True,
content=result["content"],
provider=result["provider"]
)
except HTTPException as e:
return ChatResponse(
success=False,
error=e.detail.get("error"),
circuit_breakers=e.detail.get("circuit_breakers")
)
@app.get("/api/health")
async def health():
return {
"status": "healthy",
"circuit_breakers": {
"HolySheep": holy_sheep_breaker.current