Agentic AI Design Patterns

CH12-넘어져도 다시 일어서는 AI — 예외 처리와 복구(Exception Handling & Recovery)

빌드 피벗(Build Pivot) 2026. 6. 9. 07:29
반응형
AGENTIC AI DESIGN PATTERNS · 12
넘어져도 다시 일어서는 AI — 예외 처리와 복구(Exception Handling & Recovery)
에러를 감지·처리·복구하는 3단계 접근법: 지수 백오프 재시도, 폴백 체인, Graceful Degradation, 서킷 브레이커, State Rollback과 LangGraph의 State-Driven Error Tracking·ToolNode with Fallback, 순수 Python + LangGraph 구현 2종, CRM·ERP·Groupware 적용까지
🟢 입문~중급 ⏱️ 약 20분 🔧 Python · LangGraph · Gemini 🏢 엔터프라이즈 🗓️ 최종 검토 2026-06-09

TL;DR — 스스로 채점하고 고쳐 쓰는 에이전트도 결국 외부에 의존합니다. DB가 죽고, API가 타임아웃 나고, 응답 파싱이 깨지죠. 예외 처리와 복구는 이런 장애에도 에이전트가 죽지 않고 우아하게 대응하게 만드는 패턴 — 3단계(감지→처리→복구), 재시도+지수 백오프, 폴백 체인, Graceful Degradation, 서킷 브레이커입니다. 감지 → 처리(재시도·폴백·저하) → 복구(롤백·자가수정·에스컬레이션) 핵심은 "모든 에러를 잡는 것"이 아니라 재시도할 에러와 빨리 포기할 에러를 구분하는 것입니다.

1. 왜 예외 처리인가 — 점검하는 AI에서 넘어져도 일어서는 AI로

지난 편에서 에이전트는 자기 출력을 스스로 채점하고 합격선까지 고쳐 쓰는 능력을 얻었습니다. 그런데 그 "재시도"가 향하는 외부 세계는 언제든 무너집니다 — DB 서버 다운, LLM API 타임아웃, JSON 파싱 실패, 예측 못 한 입력. 예외 처리 없는 에이전트는 바로 그 순간 크래시합니다.

교재의 한 장면이 차이를 압축합니다. 사용자가 "내 주문 상태 알려줘"라고 했을 때, 예외 처리가 없으면 DB 조회 → 서버 다운 → 💥 크래시 → 사용자: ???로 끝납니다. 예외 처리가 있으면 재시도(3회) → 실패 → "잠시 후 다시 시도해주세요" → 관리자 알림으로 이어지죠. 예외 처리와 복구(Exception Handling and Recovery) 패턴은 에이전트에 안전장치를 다는 일입니다.

🧨 무방비 에이전트 (No Handling)
장애 = 즉시 크래시 — 예외가 그대로 전파
일시 장애도 영구 실패로 처리
기술적 에러 메시지가 사용자에게 노출
장애 기록 없음 — 원인 추적 불가
🛡️ 복원력 에이전트 (Resilient)
재시도 → 폴백 → 저하로 다층 방어
일시/영구 구분 — 재시도 가치를 판단
친화적 대체 응답으로 사용자 보호
모든 에러 로깅 + 알림으로 추적·복구
그림 1. 무방비 vs 복원력 — 빨강은 크래시, 초록은 살아남는 에이전트

2025년 엔터프라이즈 AI가 이 패턴에 주목하는 이유는 분명합니다. 24/7 무중단(새벽 3시에 죽으면 안 됨), 비용 관리(무한 재시도 = 무한 API 비용), 신뢰성(95% → 99.9% 성공률), 규제 준수(금융·의료는 장애도 감사 로그 필수) — 네 가지를 동시에 요구하기 때문이죠.

2. 개념과 오해 — "예외를 잡는 것"과 "처리하는 것"은 다르다

📌 한 줄 정의 — AI 에이전트가 예기치 않은 오류를 감지하고, 적절히 대응하며, 안정적인 상태로 복구하는 능력을 갖추게 하는 패턴. 본질은 "예외가 발생해도 시스템이 죽지 않고, 가능한 한 정상 동작을 계속하거나 안전하게 종료하는 것"입니다.

주니어 개발자가 이 패턴에서 가장 많이 빠지는 오해 네 가지를 먼저 짚고 갑니다.

오해 ① "try-catch만 있으면 된다"
예외를 잡는 것처리하는 것은 다릅니다. except: pass는 잡기만 할 뿐 아무것도 처리하지 않죠. 잡고 나서 무엇을 할지(재시도·폴백·알림)가 본질입니다.
오해 ② "모든 예외를 잡아야 한다"
복구 불가능한 예외(인증 실패·권한 없음)는 빨리 실패(Fail Fast)하는 게 낫습니다. 무엇이든 다 잡으면 진짜 버그가 숨어버립니다.
오해 ③ "에러 = 버그"라는 혼동
네트워크 타임아웃은 버그가 아니라 정상적인 예외 상황입니다. 분산 시스템에서 장애는 예외가 아니라 기본값이죠.
오해 ④ "Retry하면 해결된다"
무한 재시도는 과부하 서버를 더 악화시킵니다(Thundering Herd). 지수 백오프와 멈출 줄 아는 한계가 함께 있어야 재시도가 약이 됩니다.

기억하기 쉬운 비유는 항공기 조종사의 체크리스트입니다. 계기판 경고등이 켜지면 문제를 감지(Detection), 상황별 비상 절차 매뉴얼로 대응(Handling), 대체 공항에 착륙하거나 회항해 안전 상태로 복귀(Recovery), 그래도 안 되면 관제탑에 비상 상황을 알려 인간 개입을 요청(Escalation)합니다. 에이전트도 똑같이 동작합니다.

3. 3단계 접근법 — Detection → Handling → Recovery

패턴의 골격은 3단계입니다. "무엇이 잘못됐나?"(감지) → "어떻게 대응할까?"(처리) → "정상으로 돌아가자"(복구). 색으로 역할을 구분해 보면 — 빨강은 문제 감지, 파랑은 대응 실행, 초록은 정상 복귀입니다.

1
Detection · 감지
무엇이 잘못됐나?
API 에러코드 · 타임아웃
파싱 실패 · 비즈니스 에러
LLM 환각
2
Handling · 처리
어떻게 대응할까?
로깅 · 재시도(백오프)
폴백 · Graceful Degradation
알림
3
Recovery · 복구
정상으로 돌아가자
상태 롤백 · 진단
자기 수정(Self-Correction)
에스컬레이션
각 단계는 독립적이지만 순차적입니다 — 감지 없이는 처리할 수 없고, 처리 없이는 복구할 수 없습니다.
그림 2. 예외 처리·복구의 3단계 접근법

2단계 처리가 다섯 갈래로 펼쳐지는 게 이 패턴의 핵심 두께입니다. 로깅(디버깅·감사), 재시도(일시 오류에 지수 백오프), 폴백(주 방법 실패 시 대체), Graceful Degradation(전체 실패 대신 부분 기능), 알림(운영자·다른 시스템에 통지) — 어느 한 갈래에서 막혀도 다음 갈래가 받아냅니다. 이 다층 방어(Defense in Depth)가 4절의 핵심 원칙으로 이어집니다.

4. 에러 분류가 먼저다 — 재시도할 에러 vs 포기할 에러

"어떻게 대응할까?"의 답은 에러 종류에 따라 다릅니다. 인증 실패를 재시도하는 건 시간·비용 낭비고, 네트워크 끊김을 영구 실패로 처리하는 건 과민 반응이죠. 그래서 처리 이전에 분류가 옵니다. 같은 키로 전략이 갈립니다.

에러 유형 예시 처리 전략
TRANSIENT (일시) 네트워크 끊김, 서버 일시 장애 재시도 (지수 백오프)
RATE_LIMIT API 호출 한도 초과 대기 후 재시도 (더 긴 대기)
TIMEOUT 응답 시간 > 30초 타임아웃 늘려 재시도
PARSE_ERROR JSON 파싱 실패, 스키마 불일치 형식 변경 후 재생성
PERMANENT (영구) 인증 실패, API Key 오류 재시도 금지 → 즉시 에스컬레이션
BUSINESS "잔액 부족", "권한 없음" 사용자에게 안내 (자기 수정)
그림 3. 에러 유형별 처리 전략 — 초록은 재시도 가치 있음, 빨강은 빨리 포기

이 분류 위에 세 가지 핵심 원칙이 얹힙니다. 이 셋이 "에러를 잡는 코드"를 "복원력 있는 시스템"으로 끌어올립니다.

① Fail Fast, Recover Gracefully — 빨리 실패하고 우아하게 복구
복구 불가능한 에러는 빨리 감지·통보하고, 복구 가능한 에러는 사용자 영향을 최소화한다.
② Defense in Depth — 다층 방어
Primary → Fallback → Graceful Degradation. 어느 단계에서 실패해도 다음 단계가 대응한다.
③ Learn from Failures — 실패에서 학습
모든 에러를 로깅·분석해 반복되는 패턴을 파악하고 예방 조치로 연결한다.

5. 구현 ① 순수 Python — 분류·데코레이터·폴백 체인

프레임워크 없이 Gemini API만으로 패턴의 뼈대를 봅니다. 설계 철학은 분류 우선(처리 전에 에러를 나눈다), 책임 분리(Detection/Handling/Recovery를 명확히), 데코레이터 활용(재시도 로직을 비즈니스 로직과 분리)입니다. 먼저 에러를 유형으로 못 박고 분류 함수를 둡니다.

PYTHON · 에러 분류 (Detection)
class ErrorType(Enum): # 총 7종 — 분류가 모든 전략의 출발점 TRANSIENT = "transient" # 일시적 → 재시도 가능 PERMANENT = "permanent" # 영구적 → 재시도 불가 RATE_LIMIT = "rate_limit"; TIMEOUT = "timeout"; PARSE_ERROR = "parse_error" BUSINESS_ERROR = "business"; UNKNOWN = "unknown" def classify_error(exception: Exception) -> ErrorInfo: error_str = str(exception).lower() # 문자열 매칭으로 통합 처리 if "rate" in error_str and "limit" in error_str: return ErrorInfo(ErrorType.RATE_LIMIT, ..., retry_possible=True) if "auth" in error_str or "api key" in error_str: return ErrorInfo(ErrorType.PERMANENT, ..., retry_possible=False) # 재시도 금지 if "json" in error_str or "parse" in error_str: return ErrorInfo(ErrorType.PARSE_ERROR, ..., retry_possible=True) return ErrorInfo(ErrorType.UNKNOWN, ..., retry_possible=True)

재시도는 데코레이터로 분리합니다. 비즈니스 함수는 깨끗이 두고, @retry_with_backoff만 붙이면 지수 백오프가 자동으로 걸리죠. 대기 시간 계산과 지터는 7절에서 따로 깊게 봅니다.

PYTHON · 지수 백오프 재시도 데코레이터 (Handling)
def retry_with_backoff(max_retries=3, base_delay=1.0, max_delay=60.0, exponential_base=2.0, jitter=True): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): for attempt in range(max_retries + 1): try: return func(*args, **kwargs) # 성공 → 즉시 반환 except retryable_exceptions as e: if attempt == max_retries: raise # 한계 도달 → 포기 # 대기 = min(base * 2^attempt, max_delay) delay = min(base_delay * (exponential_base ** attempt), max_delay) if jitter: delay *= 0.5 + random.random() # 0.5~1.5배 분산 time.sleep(delay) return wrapper return decorator

마지막으로 폴백 체인입니다. 주 모델이 실패하면 백업 모델, 그것도 실패하면 캐시된 응답 — 성공할 때까지 순차 시도합니다. FallbackChain에 핸들러를 등록하고 execute()만 부르면 됩니다(폴백 설계는 8절에서 깊게).

PYTHON · FallbackChain + ResilientAgent 조립
class FallbackChain: def execute(self, *args, **kwargs): for item in self.handlers: # 등록된 순서대로 try: return item["handler"](*args, **kwargs) # 첫 성공 즉시 반환 except Exception as e: self.execution_log.append({"handler": item["name"], "status": "failed"}) continue # 실패 → 다음 핸들러 raise NonRetryableException("모든 폴백 핸들러 실패") # Resilient Agent 안에서 3단 폴백 구성 chain = FallbackChain() chain.add(lambda: self._call_primary(prompt), "Primary Model") # 재시도 적용 chain.add(lambda: self._call_fallback(prompt), "Fallback Model") # 백업 모델 chain.add(lambda: self._get_cached_response(prompt), "Cached") # 최후 안전망 response = chain.execute()

여기에 Graceful Degradation(필수/선택 컴포넌트 구분)과 StateManager(checkpoint()/rollback())까지 더하면 기본기는 완성입니다. 다만 재시도·폴백·분기·상태가 데코레이터·지역 변수·if문에 흩어져 있어, 노드가 늘고 흐름이 복잡해지면 추적이 어렵습니다. 그래서 LangGraph가 등장합니다.

6. 구현 ② LangGraph — State에 에러를 새기는 복원력 그래프

2025년 LangChain 팀이 권장하는 LangGraph는 에러 정보를 State에 저장해 모든 노드에서 추적합니다(State-Driven Error Tracking). 재시도·복구·에스컬레이션은 if문이 아니라 조건부 엣지로 선언하죠. 먼저 에러를 품은 상태를 정의합니다.

PYTHON · State-Driven Error Tracking
class AgentState(TypedDict): messages: Annotated[list[BaseMessage], add_messages] # 리듀서로 누적 # ── 에러 추적 ── error: ErrorRecord | None # 현재 에러 error_history: list[ErrorRecord] # 누적 기록 (디버깅·진단) retry_count: int # 재시도 횟수 max_retries: int # ── 복구 상태 ── recovery_attempted: bool fallback_used: bool final_response: str | None status: str # running | success | failed | escalated

도구 실행 에러는 ToolNode with Fallback으로 잡습니다. 예외를 삼켜 ToolMessage로 바꿔 LLM에게 돌려주면, LLM이 에러를 인식하고 다른 접근을 시도(자기 수정)할 수 있죠.

PYTHON · ToolNode with Fallback
def handle_tool_error(state: AgentState) -> dict: error = state.get("error") # 예외를 ToolMessage(에러)로 변환 → LLM이 보고 다른 방법 시도 error_messages = [ToolMessage( content=f"에러 발생: {repr(error)}\n다른 방법을 시도해주세요.", tool_call_id=tc["id"], status="error") for tc in tool_calls] record = ErrorRecord(error_type=type(error).__name__, recoverable=True) return {"messages": error_messages, "error": record, "retry_count": state.get("retry_count", 0) + 1} # State 갱신 def create_tool_node_with_fallback(tools): return ToolNode(tools).with_fallbacks( [RunnableLambda(handle_tool_error)], exception_key="error") # 폴백 연결

마지막으로 노드를 조건부 엣지로 엮습니다. recovery 노드는 재시도 가능하면 agent로 되돌리고, Critical이면 escalation으로, 일반 실패면 종료합니다 — 재시도 루프와 에스컬레이션이 그래프로 표현됩니다.

PYTHON · 복구·에스컬레이션 라우팅 + 그래프 빌드
def route_after_recovery(state) -> Literal["agent", "escalation", "__end__"]: if state["recovery_attempted"] and state["retry_count"] < state["max_retries"]: return "agent" # 재시도 가능 → 다시 시도 if state["error"] and state["error"].severity == "critical": return "escalation" # Critical → 인간 개입 return END # 일반 실패 → 친화 메시지로 종료 builder = StateGraph(AgentState) builder.add_node("tools", create_tool_node_with_fallback(tools)) builder.add_conditional_edges("agent", route_after_agent, {"tools": "tools", "validator": "validator", "recovery": "recovery"}) builder.add_conditional_edges("recovery", route_after_recovery, {"agent": "agent", "escalation": "escalation", END: END}) graph = builder.compile()

5절의 try/except노드와 엣지로, 데코레이터 재시도가 recovery→agent 루프로, 지역 변수가 State로 바뀌었습니다. 그 대가로 상태 추적·시각화·체크포인트 재시작(실패 지점부터 resume)이 전부 따라옵니다.

7. 백오프와 서킷 브레이커 — 재시도가 독이 되지 않게

재시도는 양날의 검입니다. 잘 쓰면 일시 장애를 넘기지만, 잘못 쓰면 죽어가는 서버에 부하를 더해 완전히 죽입니다. 두 가지 안전장치가 이를 막습니다 — 지수 백오프(점점 더 오래 기다림)와 서킷 브레이커(연속 실패 시 아예 차단).

📈 지수 백오프 — 재시도 간격을 2배씩: 1 → 2 → 4초
시도 1
즉시
❌ 실패
시도 2
1초 대기
❌ 실패
시도 3
2초 대기
❌ 실패
시도 4
4초 대기
✅ 성공!
대기를 늘릴수록 과부하 서버에 회복 시간을 줍니다 — 단, max_retries로 멈출 줄도 알아야 합니다.
그림 4. 지수 백오프 — 즉시 → 1초 → 2초 → 4초로 대기 시간을 2배씩

여기에 지터(Jitter)를 더합니다. 같은 순간 장애가 나면 모든 클라이언트가 동시에 재시도하는 Thundering Herd 문제가 생기는데, 대기 시간을 0.5~1.5배로 무작위 분산하면 부하가 흩어집니다.

⚠️ 지터 없이
서버 장애 → 1000개 클라이언트가 모두 1초 후 동시 재시도 → 1000개 동시 요청 → 다시 장애 → 영원히 못 일어남
🛡️ 지터 있으면
클라이언트가 0.5~1.5초 사이로 분산 재시도 → 부하가 흩어짐 → 서버가 점진적으로 회복
그림 5. 지터로 Thundering Herd 방지 — delay *= 0.5 + random.random()

마지막 장치는 서킷 브레이커(Circuit Breaker)입니다. 전기 회로의 두꺼비집처럼, 연속 실패가 임계치를 넘으면 회로를 열어(OPEN) 더 이상 호출하지 않고 즉시 실패시킵니다. 일정 시간 뒤 HALF-OPEN으로 한 번 시험 호출을 보내, 성공하면 CLOSED(정상)로 복귀하죠. 적용전략의 RetryEngine은 재시도가 한계에 닿을 때 circuit_breaker.record_failure()를 호출하고, 회로가 열려 있으면 재시도 자체를 건너뛰어 재시도 폭주를 원천 차단합니다.

8. 폴백과 우아한 저하 — 전부 아니면 전무를 거부한다

재시도가 시간 축의 방어라면, 폴백 체인은 공간 축의 방어입니다. 주 방법이 막히면 다음 대안으로, 그것도 막히면 그다음으로 — LLM 서비스 장애를 상정한 다단계 폴백입니다.

Primary
주 LLM
(Gemini)
✕→
Backup
백업 LLM
(GPT-4o)
✕→
Template
템플릿
응답
✕→
Escalation
상담원
연결
✕ = 실패 시 다음 단계로. 첫 성공에서 멈춥니다 — 최후엔 사람에게 위임(Human-in-the-Loop).
그림 6. 다단계 폴백 체인 — Primary → Backup → Template → Escalation

폴백이 "대안을 갈아탄다"면, Graceful Degradation은 "전체 대신 부분이라도 살린다"입니다. 핵심은 컴포넌트를 필수(Required)선택(Optional)으로 나누는 것 — 필수가 실패하면 전체 실패지만, 선택이 실패하면 경고만 남기고 계속 진행합니다.

컴포넌트 구분 실패 시 동작
고객 기본 정보 필수 전체 실패 → 즉시 반환
주문 이력 선택 경고 추가 + None으로 계속
추천 상품 선택 기본 추천으로 대체
그림 7. Graceful Degradation — 필수는 막고, 선택은 흘려보낸다

결과는 "내 정보 보여줘"에 전체 에러 대신 기본 정보 + ⚠️ "주문 이력은 잠시 후 확인해주세요"를 돌려주는 것. 사용자는 부분적이라도 답을 받습니다.

9. 두 구현 비교 — 같은 복원력, 다른 추상화

순수 Python과 LangGraph는 같은 복원력 패턴을 구현하지만 추상화 수준이 다릅니다. 단순한 호출이면 Python이 빠르고, 노드가 늘거나 재시작·시각화·HITL이 필요하면 LangGraph가 유리합니다.

측면 ① 순수 Python ② LangGraph
에러 추적 예외 + 데코레이터 State-Driven(error_history)
재시도 @retry_with_backoff recovery→agent 루프
분기 if-else Conditional Edge
상태 StateManager(수동) StateGraph (TypedDict)
폴백 FallbackChain ToolNode.with_fallbacks
복구 재시작 수동 checkpoint/rollback Checkpointer(자동 resume)
시각화 불가 Mermaid 지원
학습 곡선 낮음 중간
그림 8. 순수 Python vs LangGraph — 같은 패턴, 다른 추상화 수준

세 번째 선택지로 Google ADK도 있습니다. 교재가 소개한 패턴은 SequentialAgent(sub_agents=[primary_handler, fallback_handler, response_agent]) — 1차 핸들러 실패 시 2차 핸들러로 넘기는 폴백을 에이전트 조합으로 표현하죠. 핵심은 어느 추상화든 결국 "재시도·폴백·복구"라는 같은 골격을 담는다는 점입니다.

10. 엔터프라이즈 — CRM·ERP·Groupware의 복원력 ROI

레거시 시스템의 고통점은 공통적으로 "장애 한 번에 전부 멈춘다"입니다. CRM은 외부 서비스 장애 시 고객 응대 불가, ERP는 배치 중 오류 나면 전체 롤백(부분 처리 불가), Groupware는 외부 캘린더 연동 실패 시 핵심 기능 마비. 복원력 패턴은 이를 다층 방어 + 부분 복구로 바꿉니다.

⚠️ 아래 수치는 적용 전략 문서의 도입 기대효과(목표치)이며 특정 기업의 실측 결과가 아닙니다.
시스템 핵심 적용 기대효과(목표치)
CRM
고객 상담
Retry + 폴백 체인(백업 LLM→템플릿→상담원) 가용성 99.95%(월 22분↓) · 자동 복구 85% · 이탈률 5% 미만
ERP
배치 처리
Checkpoint + 건별 격리(전체 롤백 회피) 부분 처리 99% · 복구 4시간→30분 · 자동 복구 70%
Groupware
일정 연동
다중 캘린더 폴백 + 지연 동기화 연동 성공률 80%→99.5% · NPS +20 · 동기화 99.9%
그림 9. CRM·ERP·Groupware 적용과 기대효과(목표치)
💰 12개월 ROI (목표치)
총 비용 $322,000 (초기 $230K + 운영 $92K)
총 효과 $490,000 (이탈 방지·인건비·운영 효율)
ROI 52.2% · 투자 회수 7.9개월
📈 3단계 도입 로드맵
Phase 1 (1~3개월) CRM 챗봇 · 가용성 99→99.5%
Phase 2 (4~6개월) +ERP 배치 · 성공률 95→99%
Phase 3 (7~12개월) +Groupware · 전사 99.95%
그림 10. ROI와 단계별 도입 로드맵 (목표치 기준)

기술 스택은 LangGraph(워크플로우), Gemini·GPT(다중 Provider 폴백), Redis(체크포인트), LangSmith+Grafana(관측), PagerDuty(알림)가 권장 조합입니다. 핵심 성공 요인은 에러 분류 정확성(Transient vs Permanent), 지수 백오프 + 지터, 3단계 이상 폴백, 체크포인트 재시작, 그리고 Critical 에러의 Human-in-the-Loop입니다.

11. 케이스 스터디 — CRM 상담봇, DB 장애를 견디다

DB 서버가 일시 장애인 상황에서, 고객이 "내 주문 #12345 배송 상태 알려줘"라고 묻습니다. 3단계가 어떻게 한 흐름으로 작동하는지 따라가 봅니다.

① Detection — DB 조회 시도 → ConnectionError 발생 → TRANSIENT로 분류
② Handling — Retry — 1초·2초·4초 간격 3회 재시도 → 여전히 실패
② Handling — Fallback — 캐시 확인 → 없음 → Graceful Degradation: "현재 시스템 점검 중입니다. 주문 #12345는 평균 2~3일 내 배송됩니다."
② Notification — 운영팀에 Slack 알림 전송(민감 정보 마스킹)
③ Recovery — DB 복구 후 자동으로 정상 모드 전환 → 밀린 조회 요청 처리

고객은 크래시 화면 대신 유용한 대체 응답을 받았고, 운영팀은 즉시 인지했으며, 시스템은 사람 손 없이 정상화됐습니다. "장애가 없었던 것"이 아니라 "장애가 사용자에게 보이지 않은 것" — 이것이 복원력의 목표입니다.

12. 베스트 프랙티스 — 언제 무엇을 쓸까

예외 처리는 "많이 넣을수록 좋은 것"이 아닙니다. 복구 가능한 에러에는 적극적으로, 복구 불가능한 에러에는 빠르게 포기하는 균형이 핵심입니다.

✅ 도입 체크리스트
☐ 에러를 유형별로 분류(Transient/Permanent/RateLimit…)하고, 재시도 가능 여부를 먼저 판단한다
☐ 재시도엔 반드시 지수 백오프 + 지터 + 상한(max_retries)을 둔다 (무한 재시도 금지)
최소 3단계 폴백 체인을 구성한다 (주 모델 → 백업 → 템플릿/상담원)
☐ 연속 실패엔 Circuit Breaker로 호출을 일시 차단한다
☐ 트랜잭션은 Checkpoint & Rollback으로 일관성을 지킨다
☐ 에러 로그에서 민감 정보를 마스킹하고, 사용자에겐 친화적 메시지만 노출한다
☐ Critical 에러는 사람에게 에스컬레이션한다 (On-call 체계)
★ 마치며

순서대로 쪼개고(체이닝), 갈래를 나누고(라우팅), 병렬로 돌리고(병렬화), 스스로 비평하고(리플렉션), 도구를 쥐고(도구 사용), 계획하고(플래닝), 팀을 이루고(멀티 에이전트), 기억하고(메모리), 배우고(학습), 표준으로 연결되고(MCP), 스스로 채점하던(목표 설정) 에이전트 — 이번엔 넘어져도 다시 일어서는 법(예외 처리·복구)을 배웠습니다. 다음 편은 Human-in-the-Loop: 자동화가 멈춰야 할 그 순간, 사람을 어떻게 설계에 끼워 넣는가입니다.

#예외처리 #ExceptionHandling #지수백오프 #Fallback #CircuitBreaker #LangGraph #복원력 #AI에이전트
📚 참고 자료 · 공식 문서
본문 ROI·효과 수치는 학습 자료 기반 도입 기대효과(목표치)이며 특정 기업의 실측이 아닙니다.

 

반응형