개발 slecs

API 한도 초과 시 상위 모델로 자동 폴백

목차

두 개의 독립적으로 운영되던 원격 실행 시스템 간 기능 패리티를 맞춰야 하는 상황이 생겼다. 한쪽 시스템에는 이미 구현되어 있던 '모델 한도 폴백' 로직을 다른 시스템에도 이식한 작업이다.

왜 이렇게 해야 했나

API 호출 시스템에서 마주치는 일반적인 문제 중 하나가 '요청 한도(rate limit)' 또는 '토큰 한도(token limit)'다. 특히 대규모 작업을 처리할 때 기본 모델(여기선 Sonnet)의 초당 요청 수나 분당 토큰 수가 부족하면 요청이 거부된다. 이때 단순히 에러를 반환하는 대신, 더 높은 한도를 갖춘 상위 모델(Opus)로 자동 폴백하면 사용자 입장에서는 훨씬 더 안정적인 경험을 얻을 수 있다.

한 시스템에는 이미 이런 우아한 처리가 들어가 있었는데, 현재 시스템에는 없었다. 그 때문에 두 시스템의 동작이 달랐다. 팀이 한 제품을 운영하는 입장에서, 같은 상황에 마주쳤을 때 어떤 땐 성공하고 어떤 땐 실패하는 식의 불일치는 혼란을 야기한다.

폴백 로직의 설계

API 한도 폴백 패턴은 단순해 보이지만, 실은 몇 가지 고민이 담겨 있다:

고려사항 설명
폴백 순서 Sonnet → Opus처럼, 성능과 한도의 트레이드오프를 명확히 정의
언제 폴백할 것인가 rate limit 에러만 vs. token limit 에러도 포함 vs. 다른 일시적 에러까지
재시도 로직 폴백 후에도 실패하면? 무한 루프 방지
로깅/관찰성 폴백이 얼마나 자주 발생하는지 추적

이번 이식에서는 기존 시스템의 구현을 그대로 따랐다. 즉, 이미 검증된 패턴을 재현하는 방식으로 진행했다. 새로 설계하는 것보다 기존 구현을 배우고 일관성 있게 옮기는 게 훨씬 낫다는 판단이었다.

코드 상의 변경

claude_cli_remote.py에 추가된 로직은 대략 이런 흐름이다:

초기 모델 설정 (Sonnet)
  ↓
API 호출 시도
  ↓
한도 초과 에러 감지
  ↓
상위 모델로 전환 (Opus)
  ↓
재시도
  ↓
성공 또는 최종 실패

폴백이 일어나는 순간, 어디선가는 그 사실을 기록해야 한다. 팀원들이 "어? 어제는 이 작업이 빨랐는데 오늘은 느린데?"라고 물어볼 때, 로그를 보면 "아, 한도 때문에 Opus로 넘어갔네" 하고 원인을 알 수 있어야 하기 때문이다.

팀 입장에서의 의미

이건 단순한 에러 처리 개선이 아니라, 두 독립 시스템을 점진적으로 수렴시켜 나가는 과정의 일환이다. 시간이 지나면서:

  • 사용자는 예측 가능한 동작을 경험한다
  • 운영팀은 비슷한 상황에서 일관된 문제를 만난다
  • 신입이 온보딩될 때, "이 시스템은 이렇게 동작한다"는 설명이 명확해진다
  • 나중에 코드를 리뷰하거나 문제를 디버깅할 때, 한 곳의 패턴을 이해하면 다른 곳도 이해하기 쉽다

회고

이 작업은 겉보기엔 작아 보이지만, 실제론 시스템 신뢰성과 팀의 유지보수 비용을 모두 건드리는 변경이다. 특히 '패리티 맞추기'라는 관점에서는, 단순히 기능을 복사하는 게 아니라 왜 그 기능이 있어야 하는지, 어떻게 구현하는 게 맞는지를 이해한 위에서 옮기는 것이 중요하다.

한도 폴백처럼 겉으로는 '에러 핸들링'일 뿐이지만, 결국 "사용자가 뭘 원하는가"를 역으로 읽는 훈련이 된다. 모든 에러가 동등하지 않으니까. 어떤 에러는 다시 시도하면 되고, 어떤 에러는 대체 방안이 있고, 어떤 에러는 정말 말해줘야 하는 에러다. 그 구분을 정확히 하는 것이 견고한 시스템을 만드는 첫걸음이다.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.