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
첫 댓글 달아줘.