홈/AI 자동화/AI 에이전트 신뢰성 3편: 프로덕션 모니터링과 SLA
AI 자동화AI에이전트신뢰성

AI 에이전트 신뢰성 3편: 프로덕션 모니터링과 SLA

에이전트 SLA를 성공률·지연·비용으로 정의하고, 트레이스·알람으로 운영하는 방법.

AI 에이전트 신뢰성 3편: 프로덕션 모니터링과 SLA
목차
  1. 프로덕션 에이전트는 반드시 실패한다
  2. LLM 에이전트 장애 유형
  3. Pattern 1: Circuit Breaker
  4. Pattern 2: Fallback 체인
  5. Pattern 3: Graceful Degradation
  6. 무한 루프 방지
  7. 핵심 운영 지표
  8. SLA 예시
  9. 알람 우선순위
  10. SLA 위반이 났을 때 원인을 분리하는 절차
  11. 참고 자료
  12. 검증 환경·편집자 주
  13. 자주 묻는 질문 (FAQ)

프로덕션 에이전트는 반드시 실패한다

LLM API 타임아웃, 툴 오류, 무한 루프 — 잘 설계된 에이전트도 프로덕션에서 예상 밖의 방식으로 실패합니다. 이때 시스템 전체가 다운되지 않도록 복구 아키텍처가 필요합니다.

LLM 에이전트 장애 유형

유형예시빈도영향도
API 타임아웃OpenAI 30s 초과중간높음
모델 거부콘텐츠 정책 위반낮음중간
툴 오류DB 연결 실패높음높음
무한 루프같은 툴 반복 호출낮음치명
컨텍스트 초과토큰 한도 초과중간중간

Pattern 1: Circuit Breaker

반복 실패를 감지하면 해당 경로를 자동 차단해 전체 시스템을 보호합니다.

Python
from enum import Enum
from datetime import datetime, timedelta

class CircuitState(Enum):
    CLOSED = "closed"
    OPEN = "open"
    HALF_OPEN = "half_open"

class AgentCircuitBreaker:
    def __init__(self, failure_threshold=5, recovery_timeout=60):
        self.state = CircuitState.CLOSED
        self.failure_count = 0
        self.failure_threshold = failure_threshold
        self.recovery_timeout = recovery_timeout
        self.last_failure_time = None

    async def call(self, agent_fn, *args, **kwargs):
        if self.state == CircuitState.OPEN:
            if self._should_recover():
                self.state = CircuitState.HALF_OPEN
            else:
                raise Exception("Circuit breaker OPEN")
        try:
            result = await agent_fn(*args, **kwargs)
            self.failure_count = 0
            self.state = CircuitState.CLOSED
            return result
        except Exception:
            self.failure_count += 1
            self.last_failure_time = datetime.now()
            if self.failure_count >= self.failure_threshold:
                self.state = CircuitState.OPEN
                print(f"서킷 OPEN: {self.failure_count}회 연속 실패")
            raise

    def _should_recover(self):
        elapsed = datetime.now() - self.last_failure_time
        return elapsed > timedelta(seconds=self.recovery_timeout)

Pattern 2: Fallback 체인

메인 경로 실패 시 대안을 순차적으로 시도합니다.

Python
async def query_with_fallback(query: str) -> str:
    chain = [
        lambda q: claude_opus(q),      # 1순위: 최고 품질
        lambda q: claude_sonnet(q),    # 2순위: 빠른 모델
        lambda q: cached_response(q),  # 3순위: 캐시
        lambda q: rule_based(q),       # 4순위: 규칙 기반
    ]
    for i, fn in enumerate(chain):
        try:
            return await asyncio.wait_for(fn(query), timeout=10.0)
        except Exception as e:
            if i > 0:
                print(f"Fallback level {i} 사용")
    return "잠시 후 다시 시도해주세요."

Pattern 3: Graceful Degradation

전체를 끄는 대신 핵심 기능만 유지합니다.

Python
class DegradedService:
    def __init__(self):
        self.features = {
            "tool_use": True,
            "memory": True,
            "personalization": True
        }

    async def handle(self, request):
        if not self.features["tool_use"]:
            return await self.knowledge_only(request)
        return await self.full_agent(request)

    def disable(self, feature: str):
        self.features[feature] = False
        print(f"기능 비활성화: {feature}")

무한 루프 방지

Python
MAX_STEPS = 15

async def safe_run(agent, query):
    steps = 0
    async for step in agent.stream(query):
        steps += 1
        if steps >= MAX_STEPS:
            return {
                "result": step.partial_result,
                "warning": f"최대 스텝({MAX_STEPS}) 도달 — 중간 결과 반환"
            }
    return step.final_result

핵심 운영 지표

  • MTTR: 장애 후 복구까지 평균 시간 → 목표 < 30초
  • Circuit Open Rate: 전체 요청 중 차단 비율 → 경고 > 1%
  • Fallback Rate: 폴백 실행 비율 → 모델별 추적

이 3편 시리즈로 에이전트 신뢰성의 3층 방어(비결정성 제어→테스트→장애 복구)가 완성됩니다.

SLA 예시

지표목표 예
작업 성공률99% / 30일
p95 지연< 8s (툴 포함)
예산일 토큰 $X
TEXT
trace: request_id → llm_calls → tool_calls → outcome

알람 우선순위

  1. 성공률 급락 / 툴 전면 실패
  2. 비용 스파이크
  3. 정책 위반 급증

SLA 위반이 났을 때 원인을 분리하는 절차

에이전트 SLA 위반은 우리 코드, LLM 공급사, 외부 도구 API 중 어디서 생겼는지 빠르게 나눠야 대응이 가능합니다.

원인 분리 순서

  1. 오류 유형별 분포: 공급사 응답 코드(429 한도 초과, 5xx 서버 오류)와 우리 쪽 예외(타임아웃, 파싱 실패)를 나눠 봅니다.
  2. 구간별 지연: 트레이스에서 LLM 호출, 도구 호출, 우리 서비스 처리 구간 중 어디가 늘었는지 확인합니다.
  3. 외부 상태: 공급사 상태 페이지의 장애 공지 시각과 우리 지표 악화 시각을 비교합니다.
SQL
-- 최근 1시간 오류 유형별 건수
SELECT coalesce(provider_status::text, error_type) AS kind, count(*)
FROM agent_steps
WHERE created_at > now() - interval '1 hour' AND NOT success
GROUP BY 1 ORDER BY 2 DESC;

OpenTelemetry로 단계마다 span을 남겨 두면(예: llm.call, tool.search, agent.plan) 지연이 늘어난 구간을 트레이스 화면에서 바로 찾을 수 있습니다.

대응

  • 429가 대부분이면 동시 요청 수 제한과 백오프를 조정하고, 공급사 한도 상향이나 보조 공급사로의 폴백을 검토합니다.
  • 5xx·지연 급증이 공급사 장애와 겹치면 서킷 브레이커를 열고 축소 모드(캐시 응답, 단순 답변)로 전환합니다.
  • 우리 쪽 파싱 실패가 늘었다면 최근 프롬프트·모델 변경을 먼저 의심합니다.

재발 방지

  • SLA 보고에 원인 분류(내부/공급사/도구)를 함께 기록해, 어떤 의존성이 에러 버짓을 가장 많이 소모하는지 분기마다 검토합니다.

참고 자료

검증 환경·편집자 주

  • 2026-09. SLA는 비즈니스 합의 후에 숫자화하세요.

자주 묻는 질문 (FAQ)

Q. LLM 지연을 SLA에 넣는 게 맞나요?
사용자 체감 경로만. 배치/비동기 경로는 별도 목표를 둡니다.

✦ ✦ ✦
출처·검증 안내

글마다 출처와 확인 범위가 다릅니다. 아래에 확인일·확인 범위·출처가 기록된 글만 그 범위에서 확인된 것입니다. 기록이 없는 글은 적용 전 사용 중인 버전의 공식 문서로 직접 확인하고, 오류는 이메일로 알려주세요. 편집 정책 · 이메일로 제보

이 글에는 사람이 확인한 날짜·범위 기록이 아직 없습니다.

발행 ·

댓글

첫 번째 댓글을 남겨보세요.