광산 산업에서 컨베이어 벨트 이상은 심각한停产事故와 인명 피해로 이어질 수 있습니다. 저는 3개 광산의 IoT 모니터링 시스템을 구축하면서 HolySheep AI의 멀티 모델 통합 기능을 활용해 진동 센서 데이터 기반 실시간 이상 检测 시스템을 성공적으로 배포했습니다. 이 글에서는 HolySheep AI를 활용한 스마트 광산 컨베이어 벨트 이상 检测 Agent의 전체 아키텍처와 구현 방법을 상세히 설명드리겠습니다.

HolySheep AI vs 공식 API vs 기타 중개 서비스 비교

비교 항목 HolySheep AI 공식 API 직접 사용 기타 중개 서비스
지원 모델 GPT-4.1, Claude, Gemini, DeepSeek 등 20개 이상 단일 공급업체 모델만 제한된 모델 선택
API 엔드포인트 https://api.holysheep.ai/v1 (통합) 공급업체별 개별 URL 자체 중개 서버
Gemini 2.5 Flash $2.50/MTok $3.50/MTok $4.00/MTok
결제 방식 해외 신용카드 불필요, 로컬 결제 국제 신용카드 필수 다양하지만 복잡
장애 조치 자동 모델 전환 수동 구현 필요 제한적
한국어 지원 전문 기술 지원 제한적 불규칙적
Circuit Breaker 내장 지원 직접 구현 구현 불안정

이런 팀에 적합 / 비적용

✅ HolySheep AI가 적합한 팀

❌ HolySheep AI가 부적합한 팀

시스템 아키텍처 개요

스마트 광산 컨베이어 벨트 이상 检测 시스템은 다음 4단계 파이프라인으로 구성됩니다:

  1. 데이터 수집: 진동 센서에서 실시간 주파수 스펙트럼 데이터 수집
  2. 전처리: Gemini 2.5 Flash로 스펙트럼 패턴 분석 및 특징 추출
  3. 분류 및 경보: GPT-5로 이상 类型 분류 및 심각도 평가
  4. 장애 조치: Circuit Breaker 패턴으로 모델 실패 시 자동 전환

핵심 구현 코드

1. HolySheep AI 기본 설정 및 의존성

# requirements.txt
openai>=1.12.0
anthropic>=0.18.0
redis>=5.0.0
pydantic>=2.5.0
prometheus-client>=0.19.0

설치

pip install -r requirements.txt

2. HolySheep AI 멀티 模型 클라이언트 설정

import os
from openai import OpenAI
from anthropic import Anthropic

HolySheep AI 설정 - 반드시 https://api.holysheep.ai/v1 사용

HOLYSHEEP_API_KEY = os.getenv("YOUR_HOLYSHEEP_API_KEY") HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1"

Gemini용 OpenAI 클라이언트 (HolySheep 경유)

gemini_client = OpenAI( api_key=HOLYSHEEP_API_KEY, base_url=HOLYSHEEP_BASE_URL )

GPT-5용 별도 클라이언트 (같은 HolySheep 엔드포인트)

gpt_client = OpenAI( api_key=HOLYSHEEP_API_KEY, base_url=HOLYSHEEP_BASE_URL )

Claude 백업용 Anthropic 클라이언트

claude_client = Anthropic( api_key=HOLYSHEEP_API_KEY, base_url=HOLYSHEEP_BASE_URL ) print(f"HolySheep AI 게이트웨이 연결 완료") print(f"Base URL: {HOLYSHEEP_BASE_URL}")

3. 진동 주파수 스펙트럼 분석 (Gemini 2.5 Flash)

import json
from typing import List, Dict, Any
from dataclasses import dataclass

@dataclass
class VibrationSpectrum:
    frequencies: List[float]  # Hz 단위
    amplitudes: List[float]   # 진동 크기
    timestamp: str
    sensor_id: str

def analyze_spectrum_with_gemini(spectrum: VibrationSpectrum) -> Dict[str, Any]:
    """
    Gemini 2.5 Flash로 진동 스펙트럼 분석
    HolySheep AI 경유 - 비용: $2.50/MTok
    """
    # 스펙트럼 데이터를 주파수-크기 쌍으로 포맷팅
    spectrum_data = "\n".join([
        f"{freq:.1f}Hz: {amp:.4f}" 
        for freq, amp in zip(spectrum.frequencies, spectrum.amplitudes)
    ])
    
    prompt = f"""광산 컨베이어 벨트 진동 스펙트럼 분석 결과를 제공합니다.

센서 ID: {spectrum.sensor_id}
타임스탬프: {spectrum.timestamp}
주파수-진폭 데이터:
{spectrum_data}

분석 요구사항:
1. 주요 공명 주파수 식별 (피크 3개)
2. 정상 패턴 vs 이상 패턴 분류
3. 의심되는 고장 类型 (軸受 파손, 벨트 이완, 이물질 혼입 등)
4. 신뢰도 점수 (0.0 ~ 1.0)

JSON 형식으로 응답해주세요."""

    try:
        response = gemini_client.chat.completions.create(
            model="gemini-2.5-flash",  # HolySheep에서 매핑된 모델명
            messages=[
                {
                    "role": "system", 
                    "content": "당신은 광산 설비 진단 전문가입니다. 반드시 유효한 JSON만 반환하세요."
                },
                {"role": "user", "content": prompt}
            ],
            temperature=0.3,
            max_tokens=800,
            response_format={"type": "json_object"}
        )
        
        result = json.loads(response.choices[0].message.content)
        
        # HolySheep AI 응답 메타데이터 로깅
        print(f"[HolySheep/Gemini] 토큰 사용: {response.usage.total_tokens}")
        print(f"[HolySheep/Gemini] 응답 시간: {response.response_ms}ms")
        
        return result
        
    except Exception as e:
        print(f"[HolySheep/Gemini] 분석 실패: {e}")
        raise

사용 예시

sample_spectrum = VibrationSpectrum( frequencies=[10.0, 20.5, 35.2, 50.0, 75.8, 100.3, 150.0, 200.5], amplitudes=[0.001, 0.002, 0.15, 0.003, 0.08, 0.25, 0.02, 0.12], timestamp="2026-05-29T01:53:00Z", sensor_id="CONV-001-VIB" ) analysis_result = analyze_spectrum_with_gemini(sample_spectrum) print(f"스펙트럼 분석 결과: {json.dumps(analysis_result, indent=2, ensure_ascii=False)}")

4. 경보 분류 및 심각도 평가 (GPT-5)

import asyncio
from enum import Enum
from typing import Optional

class AlertSeverity(Enum):
    CRITICAL = "CRITICAL"    # 즉시 정지 필요
    HIGH = "HIGH"           # 1시간 내 조치
    MEDIUM = "MEDIUM"       # 24시간 내 조치
    LOW = "LOW"             # 계획된 정비 포함

class AlertClassification:
    """경보 분류 및 우선순위 결정"""
    
    def __init__(self, gpt_client: OpenAI):
        self.client = gpt_client
    
    async def classify_alert(
        self, 
        spectrum_analysis: Dict[str, Any],
        historical_data: List[Dict]
    ) -> Dict[str, Any]:
        """
        GPT-5로 경보 분류 및 심각도 평가
        HolySheep AI 경유 - 비용: $8.00/MTok
        응답 시간 목표: < 500ms
        """
        historical_summary = "\n".join([
            f"- {h['timestamp']}: {h['type']} (심각도: {h['severity']})"
            for h in historical_data[-5:]
        ])
        
        prompt = f"""광산 컨베이어 벨트 경보 분석 결과를 분류해주세요.

현재 스펙트럼 분석 결과:
{json.dumps(spectrum_analysis, indent=2, ensure_ascii=False)}

최근 경보 이력:
{historical_summary}

분류 요구사항:
1. 경보 심각도: CRITICAL, HIGH, MEDIUM, LOW 중 하나
2. 권장 조치 내용
3. 정지 필요 여부 (true/false)
4. 예상 고장 类型

JSON 형식으로 응답해주세요."""

        try:
            response = await asyncio.to_thread(
                self.client.chat.completions.create,
                model="gpt-4.1",  # HolySheep에서 GPT-5로 매핑 가능
                messages=[
                    {
                        "role": "system",
                        "content": "당신은 광산 설비 안전 전문가입니다. 응답은 반드시 유효한 JSON이어야 합니다."
                    },
                    {"role": "user", "content": prompt}
                ],
                temperature=0.2,
                max_tokens=600,
                response_format={"type": "json_object"}
            )
            
            result = json.loads(response.choices[0].message.content)
            
            print(f"[HolySheep/GPT] 토큰 사용: {response.usage.total_tokens}")
            print(f"[HolySheep/GPT] 응답 시간: {response.response_ms}ms")
            
            return result
            
        except Exception as e:
            print(f"[HolySheep/GPT] 분류 실패: {e}")
            raise

사용 예시

classifier = AlertClassification(gpt_client) sample_analysis = { "peak_frequencies": [{"freq": 100.3, "amplitude": 0.25, "type": "軸受 共振"}], "anomaly_detected": True, "fault_type": "軸受 파손 의심", "confidence": 0.87 } historical = [ {"timestamp": "2026-05-28T10:00:00Z", "type": "미세 진동 증가", "severity": "LOW"}, {"timestamp": "2026-05-28T22:00:00Z", "type": "소음 변조", "severity": "MEDIUM"} ] classification = await classifier.classify_alert(sample_analysis, historical) print(f"경보 분류 결과: {json.dumps(classification, indent=2, ensure_ascii=False)}")

5. Circuit Breaker 패턴 구현

import time
import asyncio
from enum import Enum
from typing import Callable, Any, Optional
from dataclasses import dataclass, field
from collections import defaultdict

class CircuitState(Enum):
    CLOSED = "CLOSED"      # 정상 동작
    OPEN = "OPEN"          # 차단됨
    HALF_OPEN = "HALF_OPEN" # 테스트 중

@dataclass
class CircuitBreakerConfig:
    failure_threshold: int = 5      # OPEN 전환 실패 횟수
    recovery_timeout: float = 30.0   # 복구 시도 간격 (초)
    success_threshold: int = 2       # CLOSED 전환 성공 횟수

@dataclass
class CircuitBreaker:
    name: str
    config: CircuitBreakerConfig = field(default_factory=CircuitBreakerConfig)
    state: CircuitState = field(default=CircuitState.CLOSED)
    failure_count: int = field(default=0)
    success_count: int = field(default=0)
    last_failure_time: float = field(default_factory=time.time)
    next_recovery_attempt: float = field(default=0)
    
    def record_success(self):
        self.failure_count = 0
        if self.state == CircuitState.HALF_OPEN:
            self.success_count += 1
            if self.success_count >= self.config.success_threshold:
                self.state = CircuitState.CLOSED
                print(f"[CircuitBreaker/{self.name}] CLOSED로 전환 - 복구 성공")
        else:
            self.success_count = 0
    
    def record_failure(self):
        self.failure_count += 1
        self.success_count = 0
        
        if self.state == CircuitState.HALF_OPEN:
            self.state = CircuitState.OPEN
            self.next_recovery_attempt = time.time() + self.config.recovery_timeout
            print(f"[CircuitBreaker/{self.name}] OPEN 전환 - 복구 실패")
        elif self.failure_count >= self.config.failure_threshold:
            self.state = CircuitState.OPEN
            self.next_recovery_attempt = time.time() + self.config.recovery_timeout
            print(f"[CircuitBreaker/{self.name}] OPEN 전환 - 실패 임계값 초과")
    
    def can_attempt(self) -> bool:
        if self.state == CircuitState.CLOSED:
            return True
        
        if self.state == CircuitState.OPEN:
            if time.time() >= self.next_recovery_attempt:
                self.state = CircuitState.HALF_OPEN
                print(f"[CircuitBreaker/{self.name}] HALF_OPEN 전환 - 복구 시도")
                return True
            return False
        
        return True  # HALF_OPEN

class MultiModelRouter:
    """다중 모델 라우터 + Circuit Breaker"""
    
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.breakers = {
            "gemini": CircuitBreaker("gemini", CircuitBreakerConfig(failure_threshold=3)),
            "gpt": CircuitBreaker("gpt", CircuitBreakerConfig(failure_threshold=5)),
            "claude": CircuitBreaker("claude", CircuitBreakerConfig(failure_threshold=3))
        }
        self.client = OpenAI(api_key=api_key, base_url=HOLYSHEEP_BASE_URL)
    
    async def call_with_fallback(
        self,
        primary_model: str,
        fallback_model: str,
        prompt: str,
        **kwargs
    ) -> Optional[dict]:
        """Circuit Breaker와 함께 기본 모델 시도, 실패 시 폴백"""
        
        primary_breaker = self.breakers.get(primary_model.split("-")[0])
        
        # 기본 모델 시도
        if primary_breaker and primary_breaker.can_attempt():
            try:
                response = self.client.chat.completions.create(
                    model=primary_model,
                    messages=[{"role": "user", "content": prompt}],
                    **kwargs
                )
                if primary_breaker:
                    primary_breaker.record_success()
                return response
            except Exception as e:
                print(f"[MultiModelRouter] {primary_model} 실패: {e}")
                if primary_breaker:
                    primary_breaker.record_failure()
        
        # 폴백 모델 시도
        fallback_breaker = self.breakers.get(fallback_model.split("-")[0])
        if fallback_breaker and fallback_breaker.can_attempt():
            try:
                response = self.client.chat.completions.create(
                    model=fallback_model,
                    messages=[{"role": "user", "content": prompt}],
                    **kwargs
                )
                if fallback_breaker:
                    fallback_breaker.record_success()
                return response
            except Exception as e:
                print(f"[MultiModelRouter] {fallback_model} 폴백도 실패: {e}")
                if fallback_breaker:
                    fallback_breaker.record_failure()
        
        # 모든 모델 실패
        return None
    
    def get_breaker_status(self) -> Dict[str, Any]:
        return {
            name: {
                "state": breaker.state.value,
                "failures": breaker.failure_count,
                "next_attempt": breaker.next_recovery_attempt
            }
            for name, breaker in self.breakers.items()
        }

사용 예시

router = MultiModelRouter(HOLYSHEEP_API_KEY) async def analyze_with_fallback(spectrum_data: str): """폴백을 통한 스펙트럼 분석""" prompt = f"다음 진동 스펙트럼을 분석해주세요: {spectrum_data}" # Gemini -> GPT -> Claude 순서로 시도 result = await router.call_with_fallback( primary_model="gemini-2.5-flash", fallback_model="gpt-4.1", prompt=prompt, max_tokens=500, temperature=0.3 ) print(f"Circuit Breaker 상태: {router.get_breaker_status()}") return result

6. 재시도 로직과 지수 백오프

import asyncio
import random
from typing import TypeVar, Callable
from functools import wraps

T = TypeVar('T')

def exponential_backoff_retry(
    max_retries: int = 3,
    base_delay: float = 1.0,
    max_delay: float = 30.0,
    exponential_base: float = 2.0
):
    """지수 백오프 재시도 데코레이터"""
    
    def decorator(func: Callable[..., T]) -> Callable[..., T]:
        @wraps(func)
        async def async_wrapper(*args, **kwargs) -> T:
            last_exception = None
            
            for attempt in range(max_retries + 1):
                try:
                    return await func(*args, **kwargs)
                except Exception as e:
                    last_exception = e
                    
                    if attempt == max_retries:
                        print(f"[Retry] 최대 재시도 횟수 ({max_retries}) 초과")
                        raise
                    
                    # 지수 백오프 계산 + 지터 추가
                    delay = min(
                        base_delay * (exponential_base ** attempt),
                        max_delay
                    )
                    jitter = random.uniform(0, delay * 0.1)
                    actual_delay = delay + jitter
                    
                    print(f"[Retry] {attempt + 1}번째 실패, {actual_delay:.2f}초 후 재시도")
                    await asyncio.sleep(actual_delay)
            
            raise last_exception
        
        @wraps(func)
        def sync_wrapper(*args, **kwargs) -> T:
            last_exception = None
            
            for attempt in range(max_retries + 1):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    last_exception = e
                    
                    if attempt == max_retries:
                        print(f"[Retry] 최대 재시도 횟수 ({max_retries}) 초과")
                        raise
                    
                    delay = min(
                        base_delay * (exponential_base ** attempt),
                        max_delay
                    )
                    jitter = random.uniform(0, delay * 0.1)
                    actual_delay = delay + jitter
                    
                    print(f"[Retry] {attempt + 1}번째 실패, {actual_delay:.2f}초 후 재시도")
                    time.sleep(actual_delay)
            
            raise last_exception
        
        if asyncio.iscoroutinefunction(func):
            return async_wrapper
        return sync_wrapper
    
    return decorator

사용 예시

@exponential_backoff_retry(max_retries=3, base_delay=2.0) async def analyze_with_retry(spectrum: VibrationSpectrum) -> Dict[str, Any]: """재시도 로직이 포함된 스펙트럼 분석""" try: return analyze_spectrum_with_gemini(spectrum) except Exception as e: print(f"[분석] 일시적 오류 발생: {e}") raise # 재시도 로직에서 처리

재시도 시나리오 테스트

async def test_retry_scenario(): print("=== 재시도 시나리오 테스트 ===") test_spectrum = VibrationSpectrum( frequencies=[50.0, 100.0, 150.0, 200.0], amplitudes=[0.01, 0.5, 0.02, 0.3], timestamp="2026-05-29T01:53:00Z", sensor_id="CONV-TEST-001" ) try: result = await analyze_with_retry(test_spectrum) print(f"분석 성공: {result}") except Exception as e: print(f"재시도 모두 실패: {e}") asyncio.run(test_retry_scenario())

7. 완전한 이상 检测 Agent 통합

import asyncio
from datetime import datetime
from typing import List, Dict, Any
from dataclasses import dataclass, asdict
import json

@dataclass
class AnomalyAlert:
    alert_id: str
    timestamp: str
    severity: str
    fault_type: str
    recommended_action: str
    immediate_stop_required: bool
    confidence: float
    sensor_id: str
    model_used: str
    processing_time_ms: float

class ConveyorBeltAnomalyAgent:
    """컨베이어 벨트 이상 检测 Agent - 완전한 파이프라인"""
    
    def __init__(self, api_key: str):
        self.router = MultiModelRouter(api_key)
        self.classifier = AlertClassification(gpt_client)
        self.metrics = {"total_requests": 0, "successful": 0, "failed": 0}
    
    async def detect_anomaly(
        self, 
        spectrum: VibrationSpectrum,
        historical_data: List[Dict]
    ) -> AnomalyAlert:
        """완전한 이상 检测 파이프라인 실행"""
        
        start_time = time.time()
        alert_id = f"ALERT-{spectrum.sensor_id}-{datetime.now().strftime('%Y%m%d%H%M%S')}"
        
        try:
            # 1단계: 스펙트럼 분석 (Gemini + 폴백)
            spectrum_prompt = self._build_spectrum_prompt(spectrum)
            spectrum_response = await self.router.call_with_fallback(
                primary_model="gemini-2.5-flash",
                fallback_model="gpt-4.1",
                prompt=spectrum_prompt,
                max_tokens=800,
                temperature=0.3
            )
            
            if not spectrum_response:
                raise Exception("모든 모델 스펙트럼 분석 실패")
            
            spectrum_result = json.loads(spectrum_response.choices[0].message.content)
            model_used = spectrum_response.model
            
            # 2단계: 경보 분류 (GPT-5)
            classification_result = await self.classifier.classify_alert(
                spectrum_result,
                historical_data
            )
            
            processing_time = (time.time() - start_time) * 1000
            
            alert = AnomalyAlert(
                alert_id=alert_id,
                timestamp=datetime.now().isoformat(),
                severity=classification_result.get("severity", "UNKNOWN"),
                fault_type=spectrum_result.get("fault_type", "미확인"),
                recommended_action=classification_result.get("action", "점검 필요"),
                immediate_stop_required=classification_result.get("stop_required", False),
                confidence=spectrum_result.get("confidence", 0.0),
                sensor_id=spectrum.sensor_id,
                model_used=model_used,
                processing_time_ms=processing_time
            )
            
            self.metrics["total_requests"] += 1
            self.metrics["successful"] += 1
            
            return alert
            
        except Exception as e:
            self.metrics["total_requests"] += 1
            self.metrics["failed"] += 1
            print(f"[Agent] 이상 检测 실패: {e}")
            raise
    
    def _build_spectrum_prompt(self, spectrum: VibrationSpectrum) -> str:
        spectrum_data = "\n".join([
            f"{freq:.1f}Hz: {amp:.4f}" 
            for freq, amp in zip(spectrum.frequencies, spectrum.amplitudes)
        ])
        
        return f"""광산 컨베이어 벨트 진동 스펙트럼을 분석해주세요.

센서: {spectrum.sensor_id}
타임스탬프: {spectrum.timestamp}

주파수 데이터:
{spectrum_data}

JSON으로 응답:
{{
  "peak_frequencies": [{{"freq": 숫자, "amplitude": 숫자, "type": "설명"}}],
  "anomaly_detected": true/false,
  "fault_type": "고장 유형",
  "confidence": 0.0~1.0
}}"""

전체 시스템 테스트

async def main(): print("=== HolySheep AI 스마트 광산 이상 检测 Agent ===\n") agent = ConveyorBeltAnomalyAgent(HOLYSHEEP_API_KEY) # 테스트 스펙트럼 데이터 test_spectrum = VibrationSpectrum( frequencies=[10.0, 25.5, 50.0, 75.3, 100.0, 125.8, 150.0, 175.2, 200.0], amplitudes=[0.002, 0.003, 0.15, 0.008, 0.35, 0.012, 0.05, 0.02, 0.28], timestamp="2026-05-29T01:53:00Z", sensor_id="CONV-BELT-01-VIB" ) test_history = [ {"timestamp": "2026-05-28T14:00:00Z", "type": "미세 진동 이상", "severity": "LOW"}, {"timestamp": "2026-05-28T20:00:00Z", "type": "주파수 스파이크", "severity": "MEDIUM"} ] try: alert = await agent.detect_anomaly(test_spectrum, test_history) print("\n=== 检测 결과 ===") print(f"경보 ID: {alert.alert_id}") print(f"심각도: {alert.severity}") print(f"고장 유형: {alert.fault_type}") print(f"권장 조치: {alert.recommended_action}") print(f"즉시 정지: {'예' if alert.immediate_stop_required else '아니오'}") print(f"신뢰도: {alert.confidence:.2%}") print(f"처리 시간: {alert.processing_time_ms:.0f}ms") print(f"사용 모델: {alert.model_used}") print(f"\n=== 누적 지표 ===") print(f"총 요청: {agent.metrics['total_requests']}") print(f"성공: {agent.metrics['successful']}") print(f"실패: {agent.metrics['failed']}") except Exception as e: print(f"Agent 실행 실패: {e}") if __name__ == "__main__": asyncio.run(main())

가격과 ROI

구성 요소 모델 월간 예상 사용량 HolySheep 비용 공식 API 비용 월간 절감
스펙트럼 분석 Gemini 2.5 Flash 500만 토큰 $12.50 $17.50 $5.00 (28%)
경보 분류 GPT-4.1 200만 토큰 $16.00 $24.00 $8.00 (33%)
백업 모델 Claude Sonnet 4.5 50만 토큰 $7.50 $11.25 $3.75 (33%)
총 합계 $36.00 $52.75 $16.75 (31%)

ROI 분석: 광산 컨베이어 벨트 고장 1건의 평균 수리 비용은 $15,000 ~ $50,000입니다. HolySheep AI 월 비용 $36로 월 1건의 고장을 사전에 检测하면 연간 최대 $600,000의 비용을 절감할 수 있습니다. HolySheep의 31% 비용 절감 효과를 고려하면 투자 대비 수익률은 극대화됩니다.

왜 HolySheep를 선택해야 하나

자주 발생하는 오류와 해결

오류 1: "Circuit Breaker OPEN 상태로 인한 요청 실패"

# 문제: Circuit Breaker가 OPEN 상태에서 모든 요청이 거부됨

원인: 연속 실패로 인해 차단됨

해결 1: 브레이커 상태 수동 리셋

router = MultiModelRouter(HOLYSHEEP_API_KEY) router.breakers["gemini"].state = CircuitState.CLOSED router.breakers["gemini"].failure_count = 0 print("브레이커 수동 리셋 완료")

해결 2: recovery_timeout 조정으로 복구 시간 단축

router.breakers["gemini"].config.recovery_timeout = 10.0 # 30초 -> 10초

해결 3: HolySheep API 상태 확인 후 재시도

import requests response = requests.get("https://api.holysheep.ai/status") if response.ok: router.breakers["gemini"].state = CircuitState.HALF_OPEN

오류 2: "JSON 파싱 오류 - Invalid JSON format"

# 문제: Gemini/GPT 응답이 유효한 JSON이 아님

원인: temperature太高 또는 프롬프트 불명확

해결 1: response_format 명시적 설정

response = client.chat.completions.create( model="gemini-2.5-flash", messages=[{"role": "user", "content": prompt}], response_format={"type": "json_object"} # 반드시 추가 )

해결 2: JSON 유효성 검사 및 재시도 로직

import json def parse_json_with_fallback(text: str) -> dict: try: return json.loads(text) except json.JSONDecodeError: # ``json`` 블록 추출 시도 import re match = re.search(r'``(?:json)?\s*(\{.*?\})\s*``', text, re.DOTALL) if match: return json.loads(match.group(1)) # 불완전한 JSON 복구