재시도할 것인가, 말 것인가? 그게 문제다.
요약
본 글은 API 실패 시나리오를 기반으로 AI 모델의 복원력(resilience) 판단 능력을 벤치마크한 내용을 다룹니다. 단순히 HTTP 상태 코드만으로는 부족하며, Idempotency key와 같은 추가 컨텍스트 이해가 중요함을 강조합니다. 이는 외부 서비스 통합 및 코딩 에이전트의 재시도 정책 생성 능력 검증에 활용될 수 있습니다.
핵심 포인트
- AI 모델은 단순한 상태 코드보다 전체 상황을 이해해야 합니다.
- Idempotency key 등 컨텍스트 정보 분석 능력이 중요합니다.
- 코딩 에이전트는 정확한 요청만 재시도할 수 있어야 합니다.
- 벤치마크는 '재시도 여부' 결정에 초점을 맞춥니다.
이 글은 Kaggle Benchmarking Challenge 제출물입니다.
제 글을 읽어본 분들은 제가 쓴 글들 상당수가 사실 어떤 것의 벤치마크라는 것을 아실 겁니다. 대부분 .NET 관련이지만, 그래도 이 도전 과제가 제가 평소에 하는 일과 상당히 비슷할 것이라고 말할 수 있을 것입니다.
하지만 실제는 정반대였습니다.
코드 벤치마크를 만들고 AI 모델을 벤치마킹하는 것은 두 개의 다른 세계입니다. 그래서 이 도전 과제를 처음 봤을 때, 제가 정확히 무엇을 벤치마크해야 할지 전혀 감이 오지 않았습니다. 코딩 작업에 대해 모델들을 비교하는 것은 너무 일반적이라고 느껴졌고, 단순히 벤치마크를 만들고 싶어서 그러는 건 아니었습니다.
그러다가 최근 몇 편의 글 주제들을 살펴보았습니다. 그중 상당수는 API, 복원성(resilience), 실패, 그리고 시스템이 무언가 잘못되었을 때 어떻게 작동하는지에 관한 것이었습니다. 그리고 그것이 저에게 하나의 실험 아이디어를 주었습니다: 아주 간단한 질문 하나에 대해 AI 모델을 벤치마크하면 어떨까? 바로 '재시도할 것인가, 말 것인가?'
503 Service Unavailable이라는 상태 코드가 재시도가 안전하다는 것을 자동으로 의미하지 않습니다. POST 요청은 이미 처리되었을 수도 있습니다. Idempotency key(멱등성 키)가 답을 완전히 바꿀 수 있습니다. 타임아웃은 서버가 아무것도 받기 전일 수도 있고, 이미 어떤 상태를 변경한 후에 발생할 수도 있습니다.
따라서 HTTP 상태 코드만으로는 종종 충분하지 않습니다. 모델은 전체 상황을 이해해야 합니다.
제가 벤치마크한 것들
아이디어는 간단합니다. 저는 요청에 대한 정보, 응답, 그리고 몇 가지 추가적인 컨텍스트를 포함하는 여러 API 실패 시나리오를 준비했습니다. 모델은 두 가지를 반환해야 합니다:
- 결정:
YES,NO, 또는YES_AFTER_DELAY - 왜 그런지 설명하는 한 문장짜리 이유
중요한 부분은 단순히 503 상태 코드만이 아닙니다. 컨텍스트를 통해 저희는 idempotency key가 제공되었으며, 동일한 키로 반복 요청을 보내도 결제가 두 번 처리되지 않을 것이라는 것을 알 수 있습니다. 하지만 AI 모델이 같은 사실을 알아챌까요? 그리고 더 중요한 것은, 시나리오가 덜 명확할 때는 어떻게 될까요?
이번 작은 실험을 위해 저는 HTTP 메서드, 상태 코드, idempotency, rate limiting 등과 같은 세부 사항에 따라 답이 달라지는 시나리오들을 준비했습니다.
모든 모델은 동일한 응답 형식을 받습니다:
Decision: YES | NO | YES_AFTER_DELAY
Reason: <한 문장>
점수를 매길 때는 Decision만 사용합니다. 이렇게 함으로써 벤치마크를 간단하고 결정론적으로 유지할 수 있습니다. Reason은 점수에 영향을 미치지 않습니다. 저는 이 이유(Reason)를 수집하는데, 이는 모델이 실제로 시나리오를 이해했는지 아니면 단순히 잘못된 이유로 정답에 도달했는지를 보여줄 수 있기 때문입니다. 이것 또한 벤치마크를 모델 간 비교하기 쉽게 만듭니다. 각 시나리오는 예상되는 결정(expected decision)을 가지고 있으므로, 최종 결과는 모델이 재시도 결정을 맞힌 비율로 간단하게 계산될 수 있습니다.
하지만 왜 아예 이런 벤치마크를 할까요?
외부 서비스를 통합하고 호출을 더 복원력 있게 만들고 싶다고 상상해 보세요. 오늘날 AI 지원 코딩의 세상에서는 코딩 에이전트가 그 작업을 수행할 가능성이 매우 높습니다. AI는 쉽게 재시도 정책(retry policy)을 생성할 수 있습니다. 더 흥미로운 질문은 다음과 같습니다: 정확한 요청만 재시도할까요? 재시도해서는 안 될 것을 재시도하는 것은 아예 재시도하지 않는 것보다 훨씬 나쁠 수 있기 때문입니다.
제가 측정하고 싶었던 것이 바로 그것이었습니다. 이제 시나리오들을 살펴보겠습니다.
시나리오
저는 Kaggle 벤치마크에서 사용된 실제 작업들을 기반으로 총 14가지 시나리오를 준비했습니다. 원래 이 모든 내용이 기사에 포함되었지만, 작은 실험을 진행하기에는 너무 길어졌습니다. 그래서 전체 시나리오는 독립형 앱으로 옮겼으며, 이곳에서 예상 답변과 설명을 함께 모든 작업을 찾아볼 수 있습니다. 그리고 직접 테스트해보고 싶다면 사람을 위한 테스트도 마련되어 있습니다. 결국, 인간들까지 벤치마킹하지 않을 이유가 있을까요? 😁
인간 벤치마크를 시도하거나 모든 시나리오를 둘러보기: To Retry or Not to Retry?
실험에 사용된 시나리오는 다음과 같습니다:
-
안전한 결제 재시도 (Safe Payment Retry) - 결제 요청이
503 Service Unavailable오류와 함께 실패했지만, Idempotency Key가 재시도가 중복 결제를 만들 수 없음을 보장합니다. -
안전하지 않은 결제 재시도 (Unsafe Payment Retry) - 결제 요청이
Retry-After헤더와 함께503 Service Unavailable을 반환하지만, Idempotency Key가 없어 재시도가 중복 청구를 만들 수 있습니다. -
멱등 PUT (Idempotent PUT) -
PUT요청은 성공적으로 전송되었지만, 응답이 도착하기 전에 연결이 끊겼습니다. -
속도 제한 주문 (Rate-Limited Order) - 주문 요청이 처리되기 전에 속도 제한(rate-limited)되어
Retry-After와 함께429 Too Many Requests를 반환합니다. -
결제 정보 충돌 (Payment Details Conflict) - 다단계 결제 흐름이
/payments/details에 도달했는데, 이곳에서transient-error: false와 함께409 Conflict가 반환됩니다. -
비멱등 PATCH (Non-Idempotent PATCH) -
PATCH요청은 재고를 증가시키지만, 클라이언트가 변경 사항이 이미 적용되었는지 알기 전에 연결이 끊겼습니다. -
멱등 DELETE (Idempotent DELETE) - 세션 삭제 요청을 보냈지만, 응답이 도착하기 전에 연결이 끊겼습니다.
-
서비스 이용 불가 (Service Unavailable) -
GET요청이Retry-After헤더와 함께503 Service Unavailable을 받았습니다. -
오래된 리소스 버전 (Stale Resource Version) - 다른 클라이언트에 의해 리소스가 업데이트되어, 오래된 ETag를 사용한
PATCH가412 Precondition Failed로 실패했습니다. -
Retry-After 헤더가 없는 속도 제한 (Rate Limit Without Retry-After) - 안전한
GET요청이 반복적으로429 Too Many Requests를 받지만, 서버에서Retry-After헤더를 제공하지 않는 경우. -
나는 티팟이야 (I'm a Teapot) - 커피 요청을 보냈더니 전설적인
418 I'm a Teapot응답을 받는 경우. -
최종 일관성 (Eventual Consistency) - 새로 생성된 리소스를 다른 서비스가 사용하려고 할 때 즉시
404 Not Found를 반환하는 경우. -
만료된 필터 워크플로우 (Expired Filter Workflow) - 임시 필터가 여러 번 시간 초과(timeout)되다가 결국
404 Not Found를 반환하여, 원래의 필터를 더 이상 사용할 수 없게 되는 경우. -
캐싱된 장바구니 옵션 (Cached Cart Options) - 장바구니 옵션을 요청했으나
504 Gateway Timeout으로 실패했지만, 최근 만료된 캐시 응답이stale-if-error를 통해 여전히 사용 가능한 경우.
테스트한 모델들
모델을 고르는 것은 꽤 간단했습니다. 먼저 제가 작업할 때 자주 사용하는 모델인 GPT-5.6 Luna와 GPT-5.6 Sol을 골랐습니다. 제 경험상, Luna가 매우 효율적입니다. Sol보다 실수를 더 많이 하지만, 토큰 사용량은 훨씬 적게 들기 때문입니다.
다음으로 Gemini 3.7 Flash와 Gemini 3.1 Pro Preview를 추가했습니다. 저는 이 두 모델을 텍스트 생성과 CSS 스타일링에 상당히 많이 사용해 왔습니다.
또한 Claude Sonnet 5와 Claude Haiku 4.5도 포함시켰습니다. 예전에는 코딩 작업에 Claude를 많이 사용했지만, 요즘은 워크플로우 측면에서 GPT-5.6이 더 효율적이라고 느껴져서 주로 GPT-5.6으로 바꿨습니다.
마지막으로, GLM-5와 DeepSeek-R1을 넣었는데, 이는 주로 얼마나 잘 작동하는지 궁금해서였습니다.
또한 Grok도 포함하려고 했지만, Grok 4.5와 Grok 4.6 모두에서 즉시 404 Not Found 오류가 발생하여 결과에 포함되지 않았습니다.
목표는 사용 가능한 모든 모델을 테스트하는 것이 아니라, 제가 이미 사용하는 몇 가지 모델과 궁금했던 몇 가지 모델을 비교하는 것이었습니다.
발견한 점들 (Findings)
좋습니다. 먼저 리더보드와 첫 번째 실행 결과를 살펴보겠습니다.
스코어 1.00을 기록한 최고의 모델은 GPT-5.6 Sol이었고, 그다음으로는 실수 한 번만 한 Gemini 3.7 Flash가 뒤를 이었습니다. 그 다음으로 네 개의 모델이 각각 두 번의 실수를 했으며, DeepSeek-R1은 세 번, 그리고 Claude Haiku 4.5는 다섯 번의 실수로 가장 마지막을 장식했습니다.
더 자세히 살펴보면, 대부분의 모델이 안전하지 않은 결제 재시도 (Unsafe Payment Retry) 작업에서 실수를 한 것을 알 수 있습니다. 이 작업 자체는 Retry-After 헤더 때문에 까다로운데, 해당 요청을 반복하면 중복 청구로 이어질 수 있기 때문입니다. 오직 GPT-5.6 Sol과 Gemini 3.1 Pro Preview만이 올바하게 답변했습니다. 나머지 모델들은 다음과 유사한 내용을 반환했습니다:
Decision: YES_AFTER_DELAY
Reason: The server explicitly requests waiting 10 seconds before attempting the request again.
따라서 대부분의 모델은 광범위한 맥락과 상충됨에도 불구하고, 눈에 띄는 HTTP 신호만을 따르는 함정에 빠졌습니다. Retry-After는 “재시도하라”고 말하지만, Idempotency(멱등성)가 없는 결제 시스템은 “아마도 하지 마라”고 말합니다. 솔직히 말해서, 대부분의 모델이 실패했다는 사실에 저는 기쁩니다. 가끔 AI를 속일 수 있는 저자에게 작은 승리입니다. 😄
또한, 멱등 PUT (Idempotent PUT) 및 **멱등 DELETE (Idempotent DELETE)**와 같은 멱등 HTTP 메서드를 가진 작업에서도 일부 모델이 실패했다는 점에 놀랐습니다. 하지만 완전히 실패한 것은 아니었습니다. 대부분은 지연 후 해결될 수 있는 일시적인 네트워크 문제를 가정했기 때문에 YES_AFTER_DELAY라고 답변했습니다.
이러한 YES 대 YES_AFTER_DELAY 사례들은 모델이 재시도가 안전하다는 것을 이해하지만, 언제 재시도할지에 대해서는 의견이 다르다는 것을 보여줍니다. 이는 시나리오를 오해하는 것과는 다릅니다. 따라서 버전 2에서는 일부 시나리오에 대해 여러 개의 유효한 Decision 값을 허용할 수 있었습니다. 이 경우 AI가 실제로 저에게 조금 교육을 시켜주었습니다.
단 한 번이 아닌 세 번의 실행 (Three Runs, Not Just One)
이것은 첫 번째 실행일 뿐이었지만, 전체 실험을 단일 실행에만 의존하고 싶지는 않았기 때문에 모델의 안정성을 확인하고 더 많은 데이터를 수집하기 위해 동일한 벤치마크를 두 번 더 실행했습니다.
| Model | Run 1 | Run 2 | Run 3 | Avg. |
|---|---|---|---|---|
| GPT-5.6 Sol | 14/14 | 14/14 | 13/14 | 13.67 |
| ... | ||||
전반적으로 결과는 실제로 상당히 안정적이었습니다. 총 112개의 모델-시나리오 조합(8개 모델 × 14개 시나리오) 중 102개가 세 번의 실행 모두에서 동일한 정답/오답 결과를 보였는데, 이는 약 **91%**에 해당합니다. 하지만 흥미로운 점은 같은 점수가 항상 같은 행동을 의미하지는 않는다는 것입니다. 일부 모델은 올바른 결정의 개수에서는 안정적이었지만, 어떤 시나리오를 틀렸는지(which)는 바뀌었습니다. 세 번의 실행 모두에서 12/14라는 점수를 받았다고 해서 반드시 매번 동일한 결정을 내렸다는 것을 의미하지는 않습니다. |
이는 특히 Expired Filter Workflow에서 두드러지게 나타났는데, 네 개의 모델이 실행 간에 결과를 변경했습니다: GPT-5.6 Sol, Gemini 3.1 Pro Preview, GLM-5, 그리고 DeepSeek-R1. 심지어 첫 두 번의 실행에서 14/14점을 받은 GPT-5.6 Sol조차도 세 번째 실행에서는 답변을 YES에서 YES_AFTER_DELAY로 변경했습니다. 여전히 요청이 재시도되어야 한다고 결정했지만, 언제에 대해서는 의견이 달랐습니다. 이것은 정확히 YES 대 YES_AFTER_DELAY 점수화가 항상 올바른 접근 방식인지 의문을 갖게 만든 시나리오입니다.
추가 실행들은 또한 Unsafe Payment Retry 발견 사항을 훨씬 더 강력하게 만들었습니다. 24번의 시도 중 단지 6번, 즉 **25%**에서만 정답으로 답변되었습니다. 더욱 흥미로운 점은 결과가 실행 전반에 걸쳐 완전히 일관적이었다는 것입니다. GPT-5.6 Sol과 Gemini 3.1 Pro Preview는 세 번 모두 맞혔지만, 나머지 여섯 개 모델은 모든 실행에서 놓쳤습니다. 따라서 이것은 무작위적인 모델 변동이라기보다는 모델들이 시나리오를 해석하는 방식에 존재하는 체계적인 함정처럼 보입니다.
반면에 14가지 시나리오 중 7가지는 모든 24회 시도에서 정확하게 답변되었습니다. 따라서 단순한 재시도 케이스는 모델들을 실제로 구분하는 요소가 아니었습니다. 차이점은 재시도 타이밍, 더 넓은 컨텍스트(context), 또는 다단계 상태(multi-step state)가 중요해지기 시작하면서 나타났습니다.
모델 효율성 (Model Efficiency)
이제 효율성을 살펴보겠습니다. 세 번의 실행에서 모델들이 대략 같은 영역에 위치했기 때문에 세 번째 실행의 그래프를 사용하겠습니다.

GPT-5.6 Luna가 가장 효율적인 모델로 보이며, 저는 놀라지 않았습니다. 제가 주로 업무에 사용하는 이유는 저렴하고 보통 최종 해결책에 근접하게 해주기 때문입니다.
Claude Haiku 4.5 역시 효율성 측면에서 좋은 위치에 있지만, 테스트된 모든 모델 중에서 최악의 결과를 보여주었으며 여전히 GPT-5.6 Luna보다 비쌌습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기