장애 허용

장애 허용 (Fault tolerance)

딥 에이전트가 문제가 생겼을 때도 멈추지 않고 계속 동작하도록 만들어주는 게 장애 허용 미들웨어예요. 그런데 모든 에러를 똑같이 다루면 안 돼요. 네트워크 타임아웃이나 레이트리밋 같은 일시적 실패는 자동으로 재시도하고, LLM이 회복할 수 있는 에러(나쁜 도구 출력, 파싱 실패)는 모델에게 되돌려 보내며, 사람의 입력이 필요한 에러는 에이전트를 멈춰서 대기시켜야 해요.

출처: 공식문서

에러 처리 전략 (Error handling strategies)

서로 다른 에러는 서로 다른 처리 전략이 필요해요.

에러 유형 누가 해결 전략 미들웨어/기능
일시적 에러 (네트워크 문제, 레이트리밋) 시스템 (자동) 지수 백오프로 재시도 ModelRetryMiddleware, ToolRetryMiddleware
LLM 회복 가능 에러 (도구 실패, 파싱 문제) LLM 에러 ToolMessage로 변환해 모델이 조정 ToolErrorMiddleware
사용자 수정 가능 에러 (정보 부족, 지시 불명확) 사람 interrupt()로 일시 중지 Human-in-the-loop
프로바이더 중단 시스템 (자동) 대체 모델로 폴백 ModelFallbackMiddleware
과도한 호출 (runaway loop) 시스템 (자동) run별 모델/도구 호출 상한 ModelCallLimitMiddleware, ToolCallLimitMiddleware
예상치 못한 에러 개발자 그대로 버블업 미들웨어 없음; 예외 전파

각 전략을 코드 예제와 함께 아래에서 자세히 살펴볼게요.

일시적 에러 (Transient errors)

네트워크 문제와 레이트리밋을 자동으로 재시도하는 리트라이 미들웨어를 추가해요. 모델 호출과 도구 호출 각각 지수 백오프를 가진 자체 리트라이 미들웨어가 있어요.

from langchain.agents import create_agent
from langchain.agents.middleware import ModelRetryMiddleware, ToolRetryMiddleware

agent = create_agent(
    model="google_genai:gemini-3.6-flash",
    tools=[search_tool, fetch_url_tool],
    middleware=[
        ModelRetryMiddleware(max_retries=3, backoff_factor=2.0, initial_delay=1.0),
        ToolRetryMiddleware(
            max_retries=2,
            tools=["search", "fetch_url"],
            retry_on=(TimeoutError, ConnectionError),
        ),
    ],
)

LLM 회복 가능 (LLM-recoverable)

ToolErrorMiddleware로 도구 예외를 잡아 에러 ToolMessage로 변환하면 LLM이 무엇이 잘못됐는지 보고 다시 시도해요. ToolErrorMiddlewarelangchain>=1.3.14가 필요해요.

from langchain.agents import create_agent
from langchain.agents.middleware import ToolErrorMiddleware

def on_error(exc: Exception, request: ToolCallRequest) -> str | None:
    if isinstance(exc, ValueError):
        return f"Tool `{request.tool_call['name']}` failed: {type(exc).__name__}. Fix the input and retry."
    # propagate everything else

agent = create_agent(
    model="google_genai:gemini-3.6-flash",
    tools=[search_tool],
    middleware=[ToolErrorMiddleware(on_error)],
)

사용자 수정 가능 (User-fixable)

계정 ID, 주문 번호, 확인 질문 등이 필요할 때 사용자에게 정보를 수집하며 일시 정지해요. 특정 도구 호출 전에 에이전트를 멈추려면 interrupt_on을 사용해요.

from deepagents import create_deep_agent

agent = create_deep_agent(
    model="google_genai:gemini-3.6-flash",
    tools=[send_email_tool, delete_record_tool],
    interrupt_on={
        "send_email": True,
        "delete_record": True,
    },
)

전체 human-in-the-loop 가이드는 Human-in-the-loop 문서를 참고해요.

프로바이더 중단 (Provider outage)

기본 모델 프로바이더가 완전히 다운되면 ModelFallbackMiddleware로 대체 모델로 전환해요.

from langchain.agents import create_agent
from langchain.agents.middleware import ModelFallbackMiddleware

agent = create_agent(
    model="google_genai:gemini-3.6-flash",
    tools=[search_tool],
    middleware=[
        ModelFallbackMiddleware("gpt-5.5"),
    ],
)

과도한 호출 (Excessive calls)

제한이 없으면 헷갈린 에이전트가 같은 도구 호출을 반복하거나 수백 번의 모델 호출로 몇 분 만에 LLM API 예산을 태울 수 있어요. run당 모델 호출과 도구 실행 모두에 상한을 설정해요.

from langchain.agents import create_agent
from langchain.agents.middleware import ModelCallLimitMiddleware, ToolCallLimitMiddleware

agent = create_agent(
    model="google_genai:gemini-3.6-flash",
    tools=[search_tool],
    middleware=[
        ModelCallLimitMiddleware(run_limit=50),
        ToolCallLimitMiddleware(run_limit=200),
    ],
)

예상치 못한 에러 (Unexpected)

디버깅을 위해 예외를 그대로 버블업시켜요. 처리할 수 없는 것은 잡지 마세요. ToolErrorMiddleware는 명시적으로 반환 콘텐츠를 제공한 예외만 표면화하고, 나머지는 변경 없이 전파돼요.

def on_error(exc: Exception, request: ToolCallRequest) -> str | None:
    if isinstance(exc, (ValueError, KeyError)):
        # 알려진 회복 가능 에러를 모델에게 표면화
        return f"Tool `{request.tool_call['name']}` failed: {type(exc).__name__}."
    # 그 외 (예상치 못한 에러)는 전파되어 run이 중단

레이트 리밋 (Rate limiting)

리소스 사용을 제한하는 상호 보완적인 두 가지 방법이 있어요. 모델 프로바이더에 보내는 요청 비율을 제어하는 것과, run당 총 호출 수에 상한을 두는 거예요.

프로바이더 레이트 리밋

채팅 모델 프로바이더는 일정 시간 내에 만들 수 있는 호출 수에 제한을 둬요. 요청이 가는 비율을 제어하려면 모델을 rate_limiter로 초기화해요.

from langchain.rate_limiters import InMemoryRateLimiter
from langchain.chat_models import init_chat_model

rate_limiter = InMemoryRateLimiter(
    requests_per_second=0.1,  # 10초마다 1회 요청
    check_every_n_seconds=0.1,  # 요청 허용 여부를 100ms마다 확인
    max_bucket_size=10,  # 최대 버스트(burst) 크기 제어
)

model = init_chat_model(
    model="google_genai:gemini-3.6-flash",
    rate_limiter=rate_limiter,
)

agent = create_deep_agent(model=model, tools=[search_tool])

전체 설정은 Rate limiting 문서를 참고해요.

호출 상한 (Call limits)

제한이 없으면 헷갈린 에이전트가 같은 도구 호출을 반복하거나 수백 번의 모델 호출로 몇 분 만에 예산을 태울 수 있어요. run당 모델 호출과 도구 실행에 상한을 둬요.

from deepagents import create_deep_agent
from langchain.agents.middleware import ModelCallLimitMiddleware, ToolCallLimitMiddleware

agent = create_deep_agent(
    model="google_genai:gemini-3.6-flash",
    middleware=[
        ModelCallLimitMiddleware(run_limit=50),
        ToolCallLimitMiddleware(run_limit=200),
    ],
)

run_limit으로 단일 호출(턴마다 리셋) 내 호출을 상한하고, thread_limit으로 대화 전체(체크포인터 필요)에 걸친 호출을 상한해요. 전체 설정은 ModelCallLimitMiddlewareToolCallLimitMiddleware를 참고해요.

리트라이 (Retries)

일시적 실패(네트워크 타임아웃, 레이트리밋)는 자동으로 재시도해야 해요. 모델 호출과 도구 호출 각각 지수 백오프를 가진 자체 리트라이 미들웨어가 있어요.

from deepagents import create_deep_agent
from langchain.agents.middleware import ModelRetryMiddleware, ToolRetryMiddleware

agent = create_deep_agent(
    model="google_genai:gemini-3.6-flash",
    middleware=[
        # 레이트리밋, 타임아웃, 5xx 에러에서 모델 호출 재시도
        ModelRetryMiddleware(max_retries=3, backoff_factor=2.0, initial_delay=1.0),
        # 외부 API에 닿는 특정 도구만 재시도 (모든 도구가 아니라)
        ToolRetryMiddleware(
            max_retries=2,
            tools=["search", "fetch_url"],
            retry_on=(TimeoutError, ConnectionError),
        ),
    ],
)

ToolRetryMiddleware는 전부 재시도하기보다 특정 도구에만 적용 범위를 한정해요. 파일시스템 read_file이 실패해도 재시도가 별 도움이 안 되지만, 타임아웃된 웹 검색은 재시도가 도움이 될 확률이 높아요. 전체 설정은 ModelRetryMiddleware를 참고해요.

주요 통합 패키지는 표준 예외 타입(ModelAuthenticationError, ModelRateLimitError, ModelTimeoutError 등)을 발생시키고, 이들은 리트라이 미들웨어가 기본적으로 존중하는 is_retryable 플래그를 갖고 있어요. 전체 목록은 Model exceptions를 참고해요.

폴백 (Fallbacks)

기본 모델 프로바이더가 완전히 다운되면 폴백 미들웨어가 대체 모델로 전환해요.

from deepagents import create_deep_agent
from langchain.agents.middleware import ModelFallbackMiddleware

agent = create_deep_agent(
    model="google_genai:gemini-3.6-flash",
    middleware=[
        # 기본 모델이 완전히 다운되면 대체 모델로 폴백
        ModelFallbackMiddleware("gpt-5.5"),
    ],
)

전체 설정은 ModelFallbackMiddleware를 참고해요.

에러 처리 (Error handling)

도구가 실행 중 예외를 발생시키면 기본적으로 에이전트 run이 중단돼요. ToolErrorMiddleware로 특정 예외를 잡아 에러 ToolMessage로 변환하면 run을 중단시키는 대신 모델이 보고 회복할 수 있어요. ToolErrorMiddlewarelangchain>=1.3.14가 필요해요.

from deepagents import create_deep_agent
from langchain.agents.middleware import ToolErrorMiddleware

def on_error(exc: Exception, request: ToolCallRequest) -> str | None:
    if isinstance(exc, ValueError):
        return f"`{request.tool_call['name']}` failed with {type(exc).__name__}."
    # propagate everything else

agent = create_deep_agent(
    model="google_genai:gemini-3.6-flash",
    middleware=[ToolErrorMiddleware(on_error)],
)

비동기 핸들러와 리트라이 미들웨어 구성 등 전체 설정 옵션과 사용 패턴은 Prebuilt middleware를 참고해요.

더 알아보기 (Learn more)