AI 에이전트 장애 복구: 재시도, 타임아웃, 백오프, 서킷 브레이커 패턴

AI 에이전트 오류 복구를 위한 재시도, 타임아웃, 백오프, 서킷 브레이커 패턴. 모의 환경에서 429 및 500 오류를 강제로 발생시켜 에이전트가 백오프하고 이중 전송을 하지 않음을 증명하는 방법.

Ashley Innocent

Ashley Innocent

21 July 2026

AI 에이전트 장애 복구: 재시도, 타임아웃, 백오프, 서킷 브레이커 패턴

Apidog 엔터프라이즈

온프레미스 배포

SSO & RBAC

SOC 2 준수

Apidog Enterprise 살펴보기

에이전트가 API를 호출합니다. API가 429 응답을 반환합니다. 에이전트는 즉시 재시도하고, 또 다른 429를 받으며, 다시 재시도합니다. 그러면 실행이 중단되거나 요금이 폭증할 때까지 스로틀링된 서비스를 계속해서 공격하는 루프가 발생합니다. 아무도 이 루프를 의도적으로 작성하지 않았습니다. 이는 "오류 처리"의 순진한 버전에서 비롯된 것이며, Anthropic SDK 토론 게시판에서 개발자들이 가장 흔하게 묻는 문제입니다.

오류 복구는 에이전트 구축에서 깔끔한 데모와 누군가에게 호출해야 할 문제를 구분 짓는 부분입니다. 모델 자체가 문제는 아닙니다. 문제는 도구 호출이 느리거나, 스로틀링되거나, 작동하지 않을 때 코드가 어떻게 동작하는지입니다. 복구를 제대로 하면 불안정한 의존성이 사용자가 전혀 눈치채지 못하는 짧은 일시 정지가 됩니다. 잘못하면 500 오류 하나가 사고로 이어집니다. 이 가이드에서는 대부분의 부담을 처리하는 네 가지 패턴인 백오프를 사용한 재시도, 타임아웃, 서킷 브레이커, 멱등성 키에 대해 다룹니다. 그런 다음 사용자가 문제점을 발견하기 전에 모의 환경에서 이러한 패턴을 테스트하는 방법을 보여줍니다. 에이전트가 실패하는 더 넓은 그림을 보려면 AI 에이전트가 프로덕션에서 고장나는 이유부터 시작하세요.

버튼

정상적인 API를 대상으로 복구를 테스트할 수 없습니다

여기에 함정이 있습니다. 개발 환경에서는 의존성이 잘 작동합니다. 에이전트를 작성하고, 호출이 성공하며, 데모는 깔끔하고, 배포합니다. 복구 코드는 한 번도 실행되지 않았습니다. 왜냐하면 정상적인 API는 처리해야 할 오류를 결코 반환하지 않기 때문입니다. 백오프 로직이 처음 실행되는 시점은 실제 중단 상황에서 실제 사용자들이 지켜보는 프로덕션 환경입니다. 이는 재시도 루프에서 오타를 발견하기에 최악의 장소입니다.

따라서 규칙은 간단합니다. 복구를 테스트하려면 의도적으로 오류를 발생시킵니다. 에이전트가 호출하는 API의 모의 환경을 설정하고, 429, 500, 타임아웃 또는 잘못된 형식의 본문을 반환하도록 프로그래밍한 다음, 에이전트를 모의 환경으로 연결하고 어떻게 작동하는지 관찰하십시오. 실패는 새벽 3시에 당신을 호출하는 대신 테스트에서 당신이 유발하는 것이 됩니다. Apidog은 해당 모의 환경을 설정하고 응답을 스크립팅하며, 마지막 테스트 섹션을 통해 실행됩니다.

지수 백오프 및 지터(Jitter)를 사용한 재시도

재시도는 첫 번째 방어선이며, 순진한 방식은 함정입니다. 오류를 잡고 즉시 다시 호출합니다. 일시적인 문제에는 작동하지만, 부하가 걸린 서비스에는 상황을 악화시킵니다. 왜냐하면 실패한 모든 클라이언트가 동시에 재시도하여 서비스가 다운된 상태를 유지시키기 때문입니다.

두 가지 해결책이 함께 사용됩니다. 지수 백오프는 시도 간격을 넓힙니다. 1초, 2초, 4초, 8초 등으로 최대치까지 두 배씩 늘려 기다립니다. 서비스는 즉각적인 재시도들의 벽 대신 복구할 공간을 얻습니다. 지터는 각 대기 시간에 무작위 오프셋을 추가하여 동시에 실패한 수천 개의 클라이언트가 동시에 재시도하지 않도록 합니다. 지터가 없으면 백오프는 여전히 동기화된 파도를 생성합니다.

두 가지를 제한하세요. 시도 간에 몇 분씩 기다리지 않도록 지연 시간을 제한하고, 영구적인 실패가 무한히 재시도하는 대신 포기하도록 시도 횟수를 제한하세요. 3~5회 시도는 거의 모든 일시적인 오류를 포괄합니다. 그 이상은 일반적으로 성공하지 못할 것을 재시도하는 것입니다. Anthropic SDK는 자체 호출에 대해 이 중 상당 부분을 처리합니다. 연결 오류 및 특정 상태 코드를 지수 백오프로 재시도하며, 최대 재시도 옵션으로 상한을 설정할 수 있습니다. 하지만 에이전트의 도구가 사용하는 다른 API는 포함하지 않으므로, 직접 래핑해야 합니다. 재시도를 통해 금전적인 거래를 처리하는 팀은 이를 일찍 배우게 되며, 고위험 API를 위한 재시도 로직에 대한 저희 분석은 부주의한 재시도가 실제 손해를 초래할 수 있는 지점을 보여줍니다.

모든 호출에 타임아웃 설정

재시도는 요청이 실패할 때만 도움이 됩니다. 더 까다로운 경우는 응답이 전혀 돌아오지 않는 요청입니다. 의존성이 연결을 수락했지만 멈춰버리는 경우입니다. 타임아웃이 없으면 도구 호출이 블록되고, 전체 실행이 하나의 죽은 소켓 뒤에 멈춰버립니다. 오류도, 복구도 없으며, 그저 아무것도 하지 않으면서 실제 시간과 토큰 예산을 소모하는 멈춰버린 에이전트만 남습니다.

모든 외부 호출에는 타임아웃이 필요합니다. 연결을 설정하기 위한 연결 타임아웃과 응답을 기다리기 위한 읽기 타임아웃을 설정하고, 그 다음 전체 에이전트 실행에 대한 총 예산을 설정하여 느리지만 합법적인 호출들의 연결이 사용자 인내심을 넘어서지 않도록 합니다. 타임아웃이 발생하면 다른 재시도 가능한 오류처럼 처리하십시오. 즉, 백오프하고 설정된 한도까지 다시 시도하십시오.

추측이 아닌 실제 지연 시간에서 숫자를 선택하십시오. 각 타임아웃을 의존성의 p99보다 약간 더 여유 있게 설정하십시오. 너무 짧으면 성공했을 호출을 중단시키게 됩니다. 너무 길면 멈춰버린 의존성이 에이전트를 유용성 지점보다 훨씬 오래 묶어둡니다. 긴 완료는 합법적으로 느리므로 짧은 고정 타임아웃은 중간에 이를 중단시키기 때문에 스트리밍 응답에는 자체 예산을 할당하십시오.

의존성이 다운되었을 때 서킷 브레이커 작동

백오프는 일시적으로 바쁜 서비스를 처리합니다. 완전히 다운된 서비스에는 잘못된 도구입니다. 의존성이 1분 동안 실패했다면 다음 요청도 거의 확실히 실패할 것이며, 이를 재시도하면 이미 고장 난 것에 더 많은 부하를 가하면서 사용자는 예측할 수 있었던 실패를 기다리게 됩니다.

서킷 브레이커는 세 가지 상태로 이 문제를 해결합니다. '닫힘(Closed)'은 정상 상태로, 요청이 흐르고 브레이커는 실패 횟수를 계산합니다. 실패 횟수가 임계값을 넘으면 '열림(Open)'으로 전환됩니다. 이 상태에서는 요청 전송을 중단하고 쿨다운 기간 동안 빠르게 실패를 반환하여, 죽은 서비스에 대한 모든 호출에 대해 타임아웃 비용을 지불하지 않도록 합니다. 쿨다운 기간 후에는 '반개방(Half-Open)' 상태가 되어 단일 프로브를 허용합니다. 프로브가 성공하면 브레이커는 '닫힘' 상태로 돌아가 트래픽이 재개됩니다. 실패하면 다시 '열림' 상태가 되어 대기합니다.

에이전트의 경우, 브레이커는 "결제 API가 다운되었습니다"를 토큰 예산과 시간을 소모하는 40번의 느린 타임아웃 대신, 에이전트가 처리할 수 있는 하나의 빠르고 깔끔한 실패로 바꿉니다. 전역적으로가 아닌 의존성별로 연결하여, 죽은 검색 API가 에이전트가 정상적인 청구 API를 사용하는 것을 막지 않도록 하세요.

멱등성 키로 재시도를 안전하게 만들기

지금까지의 모든 패턴은 재시도가 안전하다고 가정합니다. 하지만 종종 그렇지 않습니다. 에이전트가 POST /charge를 보내고, 서버가 이를 처리하지만, 응답이 돌아오는 도중에 타임아웃됩니다. 에이전트는 성공을 보지 못했으므로 재시도하고, 이제 고객은 두 번 청구됩니다. 재시도는 당신이 요구한 대로 정확히 작동했습니다. 설계 자체가 버그였습니다.

멱등성 키는 이 간극을 메웁니다. 클라이언트는 논리적 동작당 고유한 키를 생성하여 요청과 함께 전송합니다. 일반적으로 Idempotency-Key 헤더로 보냅니다. 서버는 첫 수신 시 키를 기록하고, 동일한 키를 다시 받으면 작업을 두 번 수행하는 대신 원래 결과를 반환합니다. 이제 재시도는 구조적으로 안전합니다. 동일한 키를 가진 두 번째 POST /charge는 첫 번째 청구 결과를 반환하는 무작동(no-op)이 됩니다.

키는 동일한 동작의 재시도 전반에 걸쳐 안정적으로 유지되어야 하며, 다른 동작 사이에서는 변경되어야 합니다. 재시도 루프 내부가 아닌 요청을 생성할 때 한 번 생성해야 합니다. 그렇지 않으면 모든 시도마다 새로운 키가 생성되어 중복 제거가 작동하지 않습니다. 상태를 생성하거나 변경하는 모든 도구 호출(청구, 주문, 이메일, 기록)에는 멱등성 키가 필요합니다. 멱등성 키에 대한 저희 가이드에서 생성 및 서버 측 처리에 대해 자세히 다룹니다.

속도 제한 및 RateLimitError 루프에서 살아남기

속도 제한은 지침과 함께 제공되므로 자체적으로 처리해야 합니다. 속도 제한 초과 응답은 일반적으로 Retry-After 헤더를 포함한 429로 도착하며, 이는 얼마나 오래 기다려야 하는지(초 또는 날짜 형식으로) 정확히 알려줍니다. 이를 존중하십시오. 서버가 30초를 기다리라고 했는데 2초 만에 재시도하면 또 다른 429를 받게 되며, 이는 SDK 토론 게시판을 가득 채우는 RateLimitError 루프를 만든 것입니다. 즉, 제한을 감지하고 너무 빨리 재시도하여 더 심한 제한을 받고, 실행이 중단될 때까지 반복하는 것입니다. 별도의 SDK 스레드는 개발자들이 여기에서 겪는 동일한 문제에 대해 다룹니다.

해결책은 서버가 속도를 설정하도록 하는 것입니다. 429를 받으면 Retry-After를 읽고 최소한 그 시간만큼 기다린 후에 재시도하십시오. 헤더가 없으면 지터가 있는 지수 백오프로 폴백합니다. 지속적인 제한이 무한 대기 대신 깔끔한 실패로 끝나도록 시도 횟수를 제한하십시오. Anthropic SDK는 이미 자체 호출에 대해 Retry-After를 준수합니다. 문제는 에이전트가 사용하는 다른 속도 제한 API에도 동일한 규칙을 적용하는 것입니다.

사전 예방적인 측면도 있습니다. 제공업체가 분당 특정 수의 요청을 허용하는 경우, 토큰 버킷으로 자체 호출을 측정하여 스로틀링되어 한계에 도달하는 대신 한도 내에서 유지하십시오. 복구는 도달한 제한을 처리하고, 페이싱은 제한에 도달하는 것을 방지합니다.

복구 경로 테스트 방법

이제 종합해봅시다. 위의 패턴은 실행 증명이 있을 때만 유효하며, 증명은 정상적인 API가 제공하지 않을 실패를 강제로 발생시키는 테스트입니다. 모든 시나리오에서 재사용되는 형태는 다음과 같습니다.

  1. 의존성을 모의합니다. 에이전트 도구가 호출하는 API의 모의 환경을 설정하여, 모든 상태 코드, 헤더, 본문 및 지연을 제어하고 테스트 중에 실제 요금 청구나 이메일 발송이 발생하지 않도록 합니다.
  2. 시퀀스를 프로그래밍합니다. 모의 환경이 순서대로 일련의 호출에 응답하도록 스크립팅합니다. 먼저 Retry-After: 2가 있는 429, 그 다음 500, 그 다음 유효한 본문이 있는 200을 반환하도록 합니다. 하나의 엔드포인트, 세 가지 스크립팅된 응답, 단일 실행으로 완전한 복구 아크를 테스트합니다.
  3. 에이전트를 모의 환경으로 실행합니다. 에이전트의 도구를 실제 서비스 대신 모의 URL로 지정하고 시나리오를 처음부터 끝까지 실행합니다.
  4. 동작을 단언(assert)합니다. 중요한 사항을 확인합니다. 에이전트가 429 이후 최소 2초를 기다린 후 재시도했는지, 500 이후 재시도했는지, 세 번째 호출에서 성공했는지, 그리고 시도 횟수 제한을 초과하지 않았는지 확인합니다.

이 하나의 시나리오는 백오프와 Retry-After를 한 번에 증명합니다. 포기 경로를 위한 두 번째 시나리오를 추가하십시오. 모의 환경이 매번 실패하도록 스크립팅하고 에이전트가 제한에 도달하여 루프에 빠지지 않고 깔끔한 오류를 반환하는지 단언하십시오. 서킷 브레이커를 위한 세 번째 시나리오를 추가하십시오. 충분히 많은 호출이 연속으로 실패하도록 하고 에이전트가 작동하여 모든 시도에서 타임아웃 비용을 지불하는 대신 빠르게 실패하는지 단언하십시오.

멱등성 확인은 사람들이 건너뛰는 부분이지만, 바로 이 부분이 비용을 절약합니다. 모의 환경이 변경 호출을 수락하도록 스크립팅하고, 응답을 버려 에이전트가 실패했다고 생각하게 한 다음, 재시도를 수락합니다. 이제 요청 형태에 대해 단언합니다. 두 요청 모두 동일한 Idempotency-Key를 가지고 있었고, 모의 환경은 두 번의 논리적 동작이 아닌 하나의 논리적 동작을 보았는지 확인합니다. 재시도 시 새로운 키가 생성되거나 중복 호출이 발생했다는 것은 고객이 발견하기 전에 이중 전송을 발견했음을 의미합니다. API를 호출하는 에이전트 테스트에 대한 더 넓은 방법은 테스트 하네스를 End-to-End로 설정합니다.

오류 복구 체크리스트

에이전트를 프로덕션에 배포하기 전에 이 목록을 확인하십시오.

이 일곱 가지를 모두 확인하면 에이전트가 운이 아닌 의도적으로 복구됩니다.

Apidog의 적합한 지점 (그리고 그렇지 않은 지점)

도구의 역할을 솔직하게 유지하십시오. Apidog는 에이전트 프레임워크, 모델 호스트 또는 런타임이 아닙니다. 에이전트를 구축하거나 실행하거나 오케스트레이션하지 않으며, 모델의 출력을 평가하지도 않습니다. Apidog가 담당하는 것은 에이전트가 호출하는 API 계층이며, 이는 복구가 성공하거나 실패하는 바로 그 지점입니다.

이는 세 가지 역할을 부여합니다. 첫째, 에이전트가 사용하는 의존성을 모의하여 실제 서비스 대신 제어 가능한 대체 환경을 제공합니다. 둘째, 실제 API가 명령에 따라 생성하지 않는 실패 응답(429와 Retry-After, 500, 타임아웃, 잘못된 형식의 본문)을 프로그래밍하여 복구 연습을 할 수 있게 합니다. 셋째, 모의 환경이 받는 요청(멱등성 키 존재 및 안정성, 올바른 형태, 예상 호출 횟수)을 검증하여, 고객이 아닌 테스트에서 이중 전송이나 누락된 헤더로 인해 실패하도록 합니다. 이것이 솔직한 적합성입니다. Apidog는 에이전트가 견뎌야 하는 실패를 모의하고 에이전트가 무엇을 다시 보내는지 확인합니다.

자주 묻는 질문

Anthropic SDK가 재시도를 자동으로 처리해주지 않나요? 자체 호출에 대해서는 그렇습니다. SDK는 지수 백오프를 사용하여 특정 오류를 재시도하고 Retry-After를 준수하며, max-retries 옵션으로 상한을 설정할 수 있습니다. 하지만 에이전트 도구가 호출하는 다른 API는 포함하지 않습니다. 해당 API에는 동일한 패턴을 직접 적용해야 합니다.

멱등성 키는 언제 필요하나요? 상태를 생성하거나 변경하는 모든 호출에 필요합니다. 즉, 청구, 주문, 메시지 발송, 새로운 기록 등입니다. 읽기 전용 호출은 멱등성 키 없이 재시도해도 안전합니다. 재시도 전반에 걸쳐 안정적으로 유지되도록 동작당 한 번만 키를 생성하십시오.

이번 주에 한 가지 실패를 연습해 보세요

네 가지 패턴을 한 번에 모두 구축할 필요는 없습니다. 가장 큰 피해를 줄 수 있는 패턴(대개 속도 제한 루프나 멱등하지 않은 재시도)을 선택하여 모의 환경에서 연습해 보세요. 429를 프로그래밍하고, 응답을 드롭한 다음, 에이전트가 무엇을 보내는지 지켜보세요. 이중 청구를 걱정했던 곳에서 깔끔한 백오프와 단일 멱등성 키를 처음 보게 되면, 성공적인 데모보다 더 나은 이유로 에이전트를 신뢰하게 될 것입니다.

Apidog를 다운로드하여 실패를 모의하고, 시퀀스를 스크립팅하며, API가 반발할 때 에이전트가 무엇을 하는지 단언하십시오.

버튼

Apidog에서 API 설계-첫 번째 연습

API를 더 쉽게 구축하고 사용하는 방법을 발견하세요