happy_various AI 실전 기록

LLM 중계기 개발기 3부 · 12편 / 전체 33편

2026년 10월 1일 기준

이 글에는 제휴 링크가 없고 OpenAI·앤트로픽·구글·NVIDIA·fal과 아무 관계가 없습니다. 제가 직접 만든 중계기의 개발 기록을 바탕으로 썼습니다. 삽화는 GPT 이미지 생성, 도식은 직접 제작했습니다.

1분에 몇 번까지 부를 수 있나 — 은행 창구 번호표처럼 간격을 두는 페이서 (LLM 중계기 개발기)

창구가 하나뿐인 작은 은행을 떠올려 볼게요. 이 창구는 사정이 있어서 한 시간에 손님을 여섯 명까지만 받는다고 해 봅시다(가상의 예예요). 문이 열리는 9시 정각에 손님 여덟 명이 한꺼번에 창구로 몰려가면 어떻게 될까요? 여섯 명까지는 받아도, 일곱째와 여덟째 손님은 “이번 시간 몫은 끝났어요. 10시에 다시 오세요”라는 말을 듣고 돌아서야 해요. 헛걸음이죠.

눈치 빠른 안내원이 있다면 다르게 합니다. 번호표를 나눠 주면서 “10분 간격으로 한 분씩 불러 드릴게요”라고 말해요. 손님들은 의자에 앉아 기다리다 자기 차례에 창구로 가고, 창구는 한 번도 손님을 돌려보내지 않아요. 마지막 손님이 끝나는 시각은 크게 다르지 않은데, 헛걸음이 사라집니다.

제가 만든 LLM 중계기에도 이 안내원 같은 부품이 있어요. 이름은 페이서(pacer)예요. 마라톤에서 일정한 속도로 앞에서 달려 주는 페이스메이커처럼, 요청을 보내는 속도를 고르게 맞춰 준다는 뜻이에요.

이 글은 LLM 중계기 개발기의 12편입니다. 지난 11편 「전화를 끊었는데 상담원은 계속 대기 중」에서는 ‘그만’ 신호를 끝까지 전해야 차선이 막히지 않는다는 이야기를 했어요. 10편의 차선이 ‘동시에 몇 건’을 지키는 장치였다면, 오늘은 ‘1분에 몇 번’을 지키는 장치 이야기입니다.

은행 창구의 로봇 직원이 작은 로봇 손님에게 빈 번호표를 건네고, 뒤에서는 로봇들이 의자에 앉아 느긋하게 기다리는 모습 (GPT 이미지 생성)

결론 요약

⏱️ 1. ‘동시에 몇 건’과 ‘1분에 몇 번’은 다른 한도

10편에서 본 차선은 동시에 달릴 수 있는 요청 수였어요. 그런데 인터넷 너머의 AI 서비스는 흔히 이것 말고도 시간당 한도를 둬요. 자주 보는 두 가지가 이거예요.

이름풀어 쓰면은행으로 치면
RPM (Requests Per Minute)1분에 보낼 수 있는 요청 수한 시간에 받는 손님 수
TPM (Tokens Per Minute)1분에 주고받을 수 있는 글의 양한 시간에 처리하는 서류 장수

토큰은 AI가 글을 세는 단위예요(9편에서 잠깐 나왔어요). 내가 보낸 질문도, AI가 쓴 답도 모두 토큰으로 셉니다.

‘동시에 몇 건’과 ‘1분에 몇 번’은 서로 다른 데서 막혀요.

10편에서 NVIDIA의 차선을 늘린 이유가 두 번째였어요. 중계기 기록에는 NVIDIA 클라우드 API의 한도가 열쇠 하나당 1분에 40번으로 적혀 있어요. 1.5초에 한 번꼴이죠. 그런데 큰 코드 검토처럼 답 하나에 몇 분씩 걸리는 요청을 몇 건씩 동시에 보내는 쓰임에서는, 1분에 40번에 닿기 전에 차선이 먼저 찼어요.

두 한도의 비율은 일을 나누는 방법도 바꿔요. 횟수는 귀하고 토큰은 넉넉한 서비스라면, 긴 문서를 잘게 쪼개 여러 번 보내기보다 크게 몇 번에 나눠 보내는 편이 유리해요. 9편의 스펙 카드에 있던 ‘크게 몇 번(few-large)‘이라는 권장 방식이 이런 서비스와 잘 맞아요.

🚫 2. 넘으면 429, 그리고 ‘다시 올 시간’

한도를 넘은 요청에 AI 서비스는 보통 429로 답해요. 8편과 10편에서 본 ‘너무 많이, 너무 자주 왔다’는 번호예요. 친절한 서비스는 여기에 한 가지를 더 붙여 줘요. Retry-After, 우리말로 하면 “이만큼 뒤에 다시 와 보세요”라는 안내예요.

닫힌 창구 셔터를 향해 허둥지둥 달려가는 로봇과, 번호표를 들고 느긋하게 열린 창구로 걸어가는 로봇 (GPT 이미지 생성)

중계기는 이 안내를 버리지 않고 읽어요.

그리고 이 안내를 쓰는 쪽 프로그램에 그대로 전해요. 중계기가 돌려주는 429에는 언제나 다시 올 시간이 두 군데에 들어 있어요. 응답의 머리말(헤더)에 Retry-After로 한 번, 본문에 retry_after_ms(1000분의 1초 단위)로 한 번이에요. AI 서비스가 아무 안내도 주지 않았다면 중계기가 기본값을 채워요. 기본은 1초이고, Gemini API의 1분 한도처럼 10초로 따로 정해 둔 곳도 있어요.

중계기를 쓰는 프로그램을 만들 때 참고하라고 중계기가 내어 주는 개발 안내서에도 같은 규칙을 적어 뒀어요. ‘안정성 규칙’ 칸에 “429가 오면 다시 올 시간만큼 기다린 뒤 재시도하고, 기다리는 중이라고 화면에 표시하라”는 줄이 있어요. API 문서에는 하나가 더 붙어요. 기다릴 시간에 조금씩 다른 여유를 더하라는 거예요. 개발자들은 이걸 지터(jitter)라고 불러요. 여러 프로그램이 모두 똑같이 “정확히 1초 뒤”를 지키면, 1초 뒤에 또 한꺼번에 몰리니까요.

페이서를 모든 AI에 붙이지는 않는다

NVIDIA에는 페이서가 없어요. 1절에서 본 쓰임에서는 1분 한도보다 차선이 먼저 막혔고, 혹시 한도를 넘으면 NVIDIA가 보내는 429와 다시 올 시간을 그대로 전해서 다시 보낼지는 쓰는 쪽이 정해요. 페이서는 1분 횟수가 정말 귀한 AI를 위해 만든 부품이에요.

이 대목에는 작은 고백이 하나 있어요. 7월 21일부터 8월 8일까지, 중계기 개발 문서에는 ‘NVIDIA에도 열쇠당 1분 40번짜리 페이서가 있다’고 적혀 있었어요. 8월 8일 NVIDIA 연결을 다시 정리하던 날 코드와 맞춰 보니, 그런 페이서는 만든 적이 없었어요. 문서를 사실대로 고쳐서, 한도를 넘으면 NVIDIA의 429와 다시 올 시간이 그대로 전달된다고 적었어요. 문서와 코드가 다르면 믿을 건 코드예요.

🎫 3. 거절당하기 전에 간격을 두는 페이서

페이서가 하는 일은 두 가지예요. 최근 1분의 장부를 지키고, 요청과 요청 사이에 간격을 둬요.

최근 1분 장부 — 미끄러지는 창

페이서는 요청을 보낼 때마다 보낸 시각을 장부에 적어요. 새 요청이 오면 지금부터 거꾸로 1분 안에 적힌 기록만 세고, 1분이 지난 기록은 지워요.

여기서 ‘1분’은 시계의 정각에 맞춘 1분이 아니에요. 매 순간 ‘방금 전 1분’을 다시 잡아요. 창틀을 시간 위로 조금씩 밀면서 들여다보는 것 같아서 흔히 미끄러지는 창(sliding window)이라고 불러요. 정각마다 장부를 비우는 방식이라면 0분 59초에 한도만큼 보내고 1분 00초에 또 한도만큼 보내서, 1초 사이에 한도의 두 배가 나갈 수 있어요. 미끄러지는 창에서는 어느 1분을 잘라 봐도 한도를 넘지 않아요.

균등 간격 — 첫 줄도 몰려 나가지 않게

7월 13일 이 부품을 처음 만들었을 때는 장부만 봤어요. 최근 1분에 여유가 있으면 바로 통과시키는 방식이었죠. 그런데 여기에 빈틈이 있었어요. 한동안 조용하다가 요청이 몰리면, 장부가 비어 있으니 한도만큼이 한꺼번에 나가요. 서비스 쪽에 1분보다 짧은 ‘순간 제한’이 따로 있다면 거기에 걸릴 수 있어요.

그래서 이틀 뒤인 7월 15일, 10편의 교통정리 칸이 처음 들어온 v0.1.31에서 페이서에 균등 간격을 더했어요. 요청과 요청의 출발 사이를 ‘1분 ÷ 한도’만큼 띄우는 거예요. 예를 들어 1분에 6번까지인 서비스라면 10초, 1분에 12번이라면 5초 간격이에요.

같은 8건을 1분에 6번까지인 가상의 서비스에 보낼 때 — 한꺼번에 보내면 7·8번이 429로 거절되고, 페이서가 10초 간격으로 보내면 어느 1분을 잘라 봐도 6건 이하라 모두 통과한다 (직접 제작)

셋 중 가장 늦은 시각에 출발

요청 하나를 보내기 전에 페이서는 세 가지를 확인해요.

셋 중 가장 늦은 시각까지 기다렸다가 출발해요. 기다리는 요청들은 온 순서대로 한 줄로 서요.

도식에서 보듯 페이서가 일을 더 빨리 끝내 주지는 않아요. 마지막 요청이 출발하는 시각은 비슷하거나 오히려 조금 늦어요. 대신 거절이 없고, 언제 출발할지 미리 알 수 있어요. 쓰는 쪽 프로그램이 실패를 받아 들고 다시 보낼 궁리를 할 필요가 없죠.

기다리는 중임을 보여 주고, 취소하면 흔적 없이

📒 4. 토큰 장부 — 미리 잡아 두고, 끝나면 고쳐 적는다

횟수는 보내는 순간 셀 수 있어요. 토큰은 그렇지 않아요. 질문의 길이는 보낼 때 알지만, 답이 얼마나 길지는 답이 끝나야 알거든요.

그래서 페이서의 토큰 장부는 호텔 체크인 때의 카드 가승인처럼 움직여요. 들어갈 때 넉넉히 잡아 두고, 나갈 때 실제 금액으로 바꾸는 방식이에요.

예를 들어 1분에 토큰 10만 개까지인 서비스에, 질문과 답 상한을 합쳐 2만5천 토큰짜리 요청을 보낸다고 해 볼게요. 1분 횟수 한도가 아무리 넉넉해도 네 건이면 토큰 장부가 차요. 다섯째 요청은 첫째 요청의 기록이 1분 밖으로 빠질 때까지 기다려요. 앞선 답이 상한보다 짧게 끝나 장부를 고쳐 적으면, 그만큼 더 일찍 들어갈 수도 있고요.

1분을 기다리지 않는 시험

페이서를 시험하려고 진짜 1분씩 기다리면 시험 한 번에 몇 분이 걸려요. 그래서 페이서는 시계를 갈아 끼울 수 있게 만들었어요. 시험에서는 ‘기다린다’가 실제로 기다리는 대신 가짜 시계의 바늘만 앞으로 돌려요. 몇 분짜리 상황을 순식간에 확인할 수 있죠. 확인하는 건 이런 것들이에요.

🌙 5. ‘잠깐 붐빔’과 ‘오늘 몫을 다 씀’은 다르다

같은 429라도 성격이 둘이에요. 8편에서 한 줄로 말했던 차이를 조금 더 들여다볼게요.

잠깐 붐빔다 씀
걸린 한도1분 한도하루 한도, 계정 사용 한도, 선불 잔액
기다리면몇 초~1분이면 풀려요금방 다시 해도 안 풀려요
중계기의 이름표provider_rate_limitedinsufficient_quota
다시 올 시간짧게길게

은행으로 치면 앞은 “번호표 뽑고 잠시만 기다리세요”, 뒤는 “오늘 창구 업무는 끝났습니다. 내일 오세요”예요. 둘을 섞어서 알리면 곤란해져요. 다 쓴 걸 잠깐 붐빈 것처럼 알리면, 쓰는 쪽은 1초마다 닫힌 창구를 두드리게 되니까요.

모래시계를 든 로봇 안내원이 잠깐 기다리면 들어갈 수 있는 왼쪽 문을 가리키고, 오른쪽 문은 초승달 아래 굳게 닫혀 있다 (GPT 이미지 생성)

9월 말에 붙인 구글의 Gemini API가 이 차이를 잘 보여 줘요. 무료 등급에는 모델마다 1분 한도와 하루 한도가 따로 있어요. 거절할 때 구글은 본문에 어떤 한도에 걸렸는지 이름을 적어 보내는데, 중계기는 그 이름에 ‘분당’(PerMinute)이 들어 있는지 ‘일일’(PerDay)이 들어 있는지를 봐요.

모델별 무료 한도는 구글의 AI Studio 화면에서 확인하는 값이라, 중계기에는 추정값만 적어 두고 ‘오늘 얼마나 남았나’를 어림하는 데만 써요. 진짜 기준은 구글이 보내는 429예요. 10편에서 ‘상대가 거절하면서 직접 알려 주는 한도가 가장 정확한 측정값’이라고 했던 것과 같은 원칙이에요.

‘다 씀’은 다른 곳에도 있어요.

9월 말 버전(v0.1.105)부터는 모델 이름 대신 ‘빠른 채팅용’ 같은 역할 이름으로 부를 수도 있어요. 이렇게 부르면 중계기가 다 쓴 모델을 후보에서 빼고, 다음 요청을 곧장 다른 모델로 보내요. 다 쓴 모델은 다시 올 시간이 지나면 후보로 돌아오고요. 후보가 모두 다 썼다면 그중 가장 빨리 풀리는 시각을 알려 줘서, 쓰는 쪽이 그때까지 속도를 늦출 수 있게 해요.

정리

① AI 서비스에는 ‘동시에 몇 건’ 말고도 ‘1분에 몇 번(RPM)‘과 ‘1분에 토큰 몇 개(TPM)’ 한도가 있고, 넘으면 429와 다시 올 시간(Retry-After)이 와요. 중계기는 이 시간을 읽어 쓰는 쪽에 그대로 전해요 ② 중계기의 페이서는 최근 1분 장부를 보며 요청 출발을 ‘1분 ÷ 한도’ 간격으로 고르게 띄우고, 토큰은 미리 잡아 두었다가 끝나면 고쳐 적어요. 거절당하고 다시 보내는 대신 처음부터 거절당하지 않을 시각에 보내요 ③ 같은 429라도 ‘잠깐 붐빔’은 짧게, ‘다 씀’은 길게 다시 올 시간을 알려 주고, 역할 이름으로 부르면 다 쓴 모델을 건너뛰어요 — 다음 편은 “설정 한 줄 빠졌을 뿐인데 전멸”입니다

차선과 대기 줄 이야기는 10편에, 429 말고 401·403은 무슨 뜻인지는 8편에 있어요.


2026년 10월 1일 기준입니다. 제가 만든 중계기의 개발 기록을 바탕으로 썼고, 특정 기업·서비스의 공식 입장이 아닙니다. ‘예를 들어’로 든 한도 숫자는 설명을 위한 가상의 값이에요. NVIDIA의 1분 40번은 중계기 기록에 적어 둔 값이고, 각 서비스의 실제 한도는 서비스마다, 시기마다 다르니 쓰기 전에 그 서비스의 안내를 확인하세요.