거짓말을 한 숫자: 실제로 도움이 되는 사용량 측정기(Usage Meter) 재구축하기
요약
Claude Code 사용 중 자동화 루프로 인해 예상치 못한 주간 사용 한도에 도달하여 추가 비용이 발생한 사례를 다룹니다. 이를 방지하기 위해 실시간 사용량을 모니터링할 수 있는 자체 사용량 측정기(Usage Meter)를 구축하는 과정과 교훈을 공유합니다.
핵심 포인트
- Claude Code에는 월간 한도 외에 별도의 주간 한도가 존재함
- 자율적인 자동화 작업 시 비용 제동 장치와 모델 선택이 중요함
- 구독 모델에서도 예기치 못한 비용 발생을 막기 위한 모니터링 도구 필요
결과만 빠르게 알고 싶은 분들을 위한 요약: 저는 Claude Code를 종량제(pay-as-you-go)가 아닌 월정액 구독 방식으로 사용합니다. 몇 달 동안 이 요금제는 제가 사용량을 자세히 살펴볼 이유를 주지 않았고, 그래서 저는 확인을 멈췄습니다. 그러다 하룻밤 사이에 발생한 자동화 작업이 일주일 치 사용량을 이틀 만에 다 써버렸고, 남은 기간이 4일이나 남았음에도 계정이 잠겨버렸습니다. 결국 저는 정가(list price)를 지불하고 문제를 해결해야 했습니다. 그 비용은 제가 더 많이 써도 되는지 아니면 속도를 줄여야 하는지를 평이한 언어로 알려주는 작은 사용량 측정기(usage meter)를 직접 만들게 만들기에 충분한 액수였습니다. 이 포스트의 나머지 내용은 이 측정기를 제대로 만들기 위해 시도했던 네 번의 과정과, 잘못된 시도들이 각각 어떤 교훈을 주었는지에 대한 이야기입니다.
이제 실제 이야기를 시작해 보겠습니다. 저는 주로 혼자서 약 10개의 프로젝트를 동시에 운영합니다. 클라이언트 작업, 제 개인 제품, 이메일 등 모든 것이 각 프로젝트당 하나의 터미널 탭에서 실행되는 Claude Code 세션을 통해 진행됩니다. 10개의 폴더 전체에서 무엇을 주의 깊게 살펴봐야 하는지 추적하는 것이 번거로워져서, 저는 작은 사이드 프로젝트인 '마스터 감독관(master supervisor)'을 만들었습니다. 이 프로그램은 각 프로젝트의 할 일 목록(todo queue)을 훑으며 제가 개입하지 않고도 처리할 수 있는 작업들을 골라냅니다. 저는 밤새 작동하도록 이를 루프(loop)로 설정했습니다.
정말 멋지게 작동했습니다. 딱 이틀 동안은 말이죠.
셋째 날 노트북을 열었을 때, Claude Code는 모든 프롬프트에 대해 동일한 메시지로 응답했습니다. 주간 한도(weekly limit)에 도달했다는 메시지였습니다. 한도가 얼마 남지 않은 수준이 아니었습니다. 완전히 다 썼습니다. 그리고 계정은 초기화까지 4일이 남았다고 알려주었습니다.
그 한도에 대해 언급하자면, 저 역시 놀랐습니다. Claude Code의 구독 플랜은 처음에는 월별로 측정되었습니다. Anthropic은 나중에 여기에 주간 한도를 추가했는데, 아마 제가 방금 만들어낸 것과 같은 종류의 급증을 막기 위함이었겠죠. 저는 월 단위 숫자가 어딘가에 있다는 것은 알고 있었습니다. 하지만 그 아래에 주간 한도가 작동하고 있다는 사실은 몰랐습니다. 평소 사용량으로는 두 한도 중 어느 쪽에도 근접해 본 적이 없었기에, 단지 2시간 동안 잠긴 일회성 사고로 치부했던 것 외에는요. 그래서 저는 claude.ai의 사용량 페이지를 본 적이 없습니다. 주간으로든 월간으로든 단 한 번도요. 그저 작업했을 뿐입니다. 마치 연료 게이지가 바닥난 적 없는 차에 넣는 것처럼요. 하룻밤 동안 돌린 루프가 사각지대를 만든 것이 아니라, 그냥 발견해낸 것입니다.
패닉 계산 (The panic math)
Claude Code를 4일 동안 못 쓰는 것은 저에게 불편함이 아닙니다. 그것은 제 수입 창출 시간이 대부분 사라진 것을 의미합니다. 저는 고객 마감 기한을 가지고 있고, 제가 진행 중인 프로젝트가 있으며, AI 구독 서비스 때문에 멈추지 않는 받은 편지함을 가지고 있습니다. 그래서 당연한 일을 했습니다. 계속 작업하기 위해 추가 토큰을 구매했습니다. 그것도 리셀 가격으로, 구독 할인은 적용되지 않은 상태로요.
저는 신중하게 행동했습니다. 주로 더 저렴한 모델을 사용했고, 세션을 짧게 유지했으며, 정말 급한 것만 건드렸습니다. 4일 후 저는 평소 속도의 일부를 유지하기 위해 200유로를 지출했습니다. 그 숫자가 제가 화내는 대신, 실제로 무슨 일이 일어났는지 이해하게 만든 계기가 되었습니다.
하룻밤 동안 돌린 루프는 이야기의 일부였고, 그 자체로 별개의 교훈이었습니다 (업무에 부적절한 모델 선택, 자율 작업에 대한 비용 제동 장치 부재). 저에게 더 오래 남은 것은 좀 더 어리석은 것이었습니다. 저는 이런 일이 일어날 거라고 전혀 예상하지 못했고, 살펴볼 이유를 스스로 만들지 않았던 것입니다. 2일 차에
첫 번째 버전은 주간 달러 한도 대비 주간 달러 총액을 보여주었습니다. 저는 로컬 세션 로그 (local session logs)를 바탕으로 토큰 수에 모델 가격을 곱한 뒤 모두 합산하여 직접 계산했습니다.
문제는 다음과 같습니다: 저와 같은 구독 플랜 (subscription plan)은 달러 단위로 측정되지 않습니다. 대신 주간 허용량의 백분율 (%)로 측정됩니다. 제가 비교 대상으로 삼았던 달러 한도는 제가 관찰한 단 한 번의 차단 사례를 바탕으로 보정된—처음에는 $12,000였다가 나중에 $4,690로 "수정된"—저만의 추정치 외에는 어디에도 존재하지 않는 수치였습니다.
수치가 현실과 일치하지 않기 시작하면서 비로소 이를 알아차렸습니다. 여기서 얻은 교훈은 수치가 부정확했다는 것이 아닙니다. 그 수치는 발명된 것이었으며, 마치 실제 측정값처럼 보였다는 점입니다. 지어낸 숫자는 숫자가 없는 것보다 더 나쁩니다. 왜냐하면 그것을 신뢰하게 만들기 때문입니다.
터미널 하단에 차분한 초록색으로 표시되었던, 완전히 허구였던 실제 모습은 다음과 같았습니다:
$4,690 weekly budget · $612 spent (13%) · well within budget
두 번째 시도: 올바른 숫자, 그러나 여전히 쓸모없음
그래서 저는 실제 소스를 찾아냈습니다. Anthropic은 구독 계정에 대해서는 사용량 API (usage API)를 공개하지 않고 종량제 (pay-as-you-go) 콘솔 계정에 대해서만 공개하지만, claude.ai의 사용량 페이지가 호출하는 것과 동일한 엔드포인트 (endpoint)에 세션 쿠키 (session cookie)를 사용하여 접근할 수 있습니다. 브라우저 자동화 (browser automation)도 필요 없고, 창을 계속 열어둘 필요도 없습니다. 그저 백그라운드 작업 (background job)이 15분마다 한 번씩 복호화된 쿠키를 읽기만 하면 됩니다.
이제 상태 표시줄에는 진실된 무언가가 나타났습니다:
Plan: 12% -> Mon 13:00
그리고 스스로에게 던진 첫 번째 질문은 적절했습니다. '12%가 도대체 무엇을 의미하는가?' 저는 이번 주가 언제 시작되었는지 알지 못했습니다.
단독으로 존재하는 백분율의 실제 문제는 바로 이것입니다. 첫째 날의 12%는 "너무 빠름"을 의미합니다. 마지막 날의 12%는 "지불한 금액의 88%를 방금 버렸다"는 것을 의미합니다. 같은 숫자지만 의미는 정반대입니다. 시간적 위치가 없는 백분율은 아무것도 답해주지 못합니다.
세 번째 시도: 측정기가 아닌 도달 범위
내가 실제로 알고 싶었던 것은 "얼마나 썼는가"가 아니라 "이게 얼마나 더 갈 것인가"였습니다. 리터(L) 단위의 연료 게이지는 기술적으로는 정확하지만, 운전 중에는 쓸모가 없습니다. 시속 120km로 달리는 동안 아무도 머릿속으로 리터를 계산하지 않기 때문입니다. 당신에게 필요한 것은 주행 거리(Range)입니다.
평온한 화요일, 디스플레이에는 다음과 같이 표시됩니다:
플랜: 4.2일 더 지속 · 3일 후 초기화 · 정상 속도, 여유 있음
세 가지 숫자는 그 합계에 따라 세 가지 다른 색상을 띱니다. 월요일 아침, 여유롭게 앞서가는 상태:
플랜: 6.8일 더 지속 · 5일 후 초기화 · 여유 있음, 자유롭게 사용 가능
아슬아슬한 상태, 예전에는 그저 외로운 백분율(%)로만 표시되었을 법한 유형:
플랜: 2.1일 더 지속 · 3일 후 초기화 · 촉박함, 가능하다면 속도를 줄이세요
그리고 괜찮은 척하기조차 어려운 지점:
플랜: 1.4일 더 지속 · 3일 후 초기화 · 속도 초과, 지금 즉시 속도를 줄이세요
세 가지 숫자는 모두 '지금 이 순간'을 기준으로 합니다. 즉, 현재 속도라면 남은 예산이 얼마나 지속될지, 언제 초기화되는지, 그리고 그것이 무엇을 의미하는지를 나타냅니다. 중간에 있는 숫자, 즉 초기화 시점이 첫 번째 숫자를 읽을 수 있게 만드는 핵심입니다.
그 초기화에 관한 두 가지 사실이 중요하게 작용했는데, 저는 API 필드 이름을 보고 추측하는 대신 실제 문서(Docs)를 확인하기 전까지 둘 다 틀렸습니다. 필드 이름은 seven_day로 되어 있어 이동 창(Rolling window)처럼 읽혔고, 그래서 저는 일주일 전의 사용량이 새로운 사용량이 들어옴에 따라 계속 만료될 것이라고 가정했습니다. 틀렸습니다. 그것은 계정당 고정된 주간 시계(Fixed weekly clock)였습니다. 제 경우에는 매주 월요일 13:00(현지 시간)로 동일한 날, 동일한 시간에 작동합니다. 그리고 더 중요한 점은, 아무것도 이월되지 않는다는 것입니다. Anthropic의 공식 설명에 따르면, "각 사이클마다 전체 주간 할당량을 받게 됩니다." 조용한 한 주를 보냈다고 해서 다음 주를 위해 무엇인가를 저축할 수는 없습니다.
두 번째 사실은 제가 이 전체적인 문제에 대해 생각했던 방식을 완전히 바꿨습니다. 사용하지 않은 예산이 만료된다면, 제한치보다 편안하게 낮은 수준을 유지하는 것은 성공이 아니라 지불했지만 회수하지 못한 돈입니다. 한 달 내내 절반의 용량으로 운영되는 계획은 구독료의 절반을 버리는 것과 같습니다. 지금까지 제가 만들어 본 이 측정기 버전들은 오직 한 방향, 즉 '너무 빠르다'만 경고했습니다. 그중 어느 것도 다른 진실한 측면, 즉 '너무 느리다, 돈을 남기고 있다'를 말해주지 못했습니다.
네 번째 시도: 수학적으로 제대로 계산하기
도달률(reach) 수치는 예측치입니다. 사용된 비율을 사이클 경과 시간으로 나누어 속도를 얻고, 나머지 시간을 그 속도로 나누면 도달률이 나옵니다. 감쇠가 없는 상태에서는 이것이 즉시 깨집니다. 첫날 20%를 사용하면 주간 목표 대비 140%에 도달할 것으로 예측되므로, 측정기는 단순히 바쁜 날이었을 뿐인 월요일 아침에도 '속도를 줄이라'고 경고하게 됩니다. 그런 종류의 하루는 정상적인 한 주라면 금요일까지 흡수합니다.
제 첫 번째 수정은 감쇠 계수(damping factor)를 적용하는 것이었는데, 이는 느낌에 의존하여 주 초반에 더 무겁게 설정했습니다. 저는 이 수치들을 두 번의 시도 전보다 같은 방식으로 임의로 만들었고, 설명할 수 없는 반올림 숫자는 믿지 않기로 학습했기 때문에 이번에는 배포하기 전에 알아차릴 수 있었습니다.
관찰 기간 동안의 사용량은 계수 과정(counting process)이며, 계수 과정에는 실제 통계적 처리가 있습니다. Jeffreys 사전 분포(Jeffreys prior)를 사용하면 사후 비율 분포는 Gamma(x + 0.5, t)가 되고, 그 상대적인 분산은 $1/ ext{sqrt}(x)$에 따라 줄어듭니다. 이것이 바로 '주 초반에 숫자가 더 많이 변동한다'는 직관을 수학적으로 정확하게 만든 것입니다. 따라서 측정기는 점 추정치(point estimate)를 판단하는 대신, 신뢰 구간(credible interval)의 낙관적인 가장자리를 판단합니다. 즉, 관대한 경우에도 계산이 맞지 않을 때만 경고하도록 합니다.
허용 오차 범위(tolerance)는 별도의 보정이 필요 없이 이 과정에서 자연스럽게 도출됩니다:
| 사용량 | 허용 오차 |
|---|---|
| 5% | 6.8배 |
| ... | |
| 월요일은 본질적으로 관대하고, 금요일은 본질적으로 엄격하며, 이와 관련하여 제가 설정하는 다이얼(knob) 같은 것은 아무것도 없습니다. |
체계적인 테스트가 발견했지만 사고방식으로는 절대 찾을 수 없었던 것들
저는 "이게 맞아 보이나?"라는 제 자신의 직관을 신뢰하는 것을 그만두었습니다. 대신 사이클-일(cycle-day)과 사용량 수준(usage-level)의 모든 조합, 즉 133가지 케이스를 생성한 뒤, 각 케이스를 단 하나의 질문, 즉 "숫자가 색상과 일치하는가?"에 대조하여 확인했습니다.
그 결과, 단순히 눈으로 쳐다봐서는 절대 잡아낼 수 없었을 두 가지 문제를 발견했습니다.
첫째, 제가 방금 도출한 댐핑 (damping) 기능이 단순히 결과를 완화하는 것이 아니라, 실제 판정 자체를 뒤집을 수 있다는 점이었습니다. 5일 차에 75%를 사용했을 때, 리셋까지 48시간이 남은 상황에서 예상 도달 범위가 40시간이라면 이는 실제로 계산이 맞지 않는 상황입니다. 하지만 통계적 허용 오차 (statistical tolerance) 때문에 비율이 임계치를 아주 살짝 넘어가면서, 미터기는 여전히 "정상 궤도 (on pace)"라고 표시하고 있었습니다. 불확실성 (uncertainty)은 경고의 강도를 완화할 수는 있지만, 경고의 유무 자체를 뒤집도록 허용해서는 안 됩니다. 이제 초록색은 허용 오차 여부와 상관없이, 수학적으로 실제로 계산이 맞을 때만 표시됩니다.
둘째, 그 문제를 해결하자 반대편에서 자체적인 오보 (false alarm)가 발생했습니다. 사이클의 초기 몇 시간 동안, 아직 무언가를 판단하기에 데이터가 충분하지 않은 시점에 경고가 발생하는 것이었습니다. 월요일 저녁까지 10%를 사용한 상태가 주황색으로 표시되었습니다. 위음성 (false negative)을 방지하기 위한 가드 (guard)는 이제 24시간의 관찰이 지난 후에만 작동하며, 그 이전에는 데이터가 아직 더 강력한 주장을 뒷받침하지 못하므로 권장 사항이 "정상 궤도 (on pace)"로 제한되며 그 이상의 강한 표현은 사용하지 않습니다.
이 두 가지 버그는 일반적인 사용 환경에서는 나타나지 않았을 것입니다. 오직 제가 상태 공간 (state space)의 모든 구석을 동일한 질문을 통해 강제로 통과시켰기 때문에 드러난 것들입니다.
하루 뒤, 두 번째 검토
첫 번째 테스트 스위트 (test suite)는 한 가지를 확인했습니다. 유효한 숫자가 주어졌을 때, 미터기가 올바른 내용을 말하는가? 하루 뒤에 진행한 두 번째 검토에서는 제가 미처 생각하지 못했던 질문을 던졌습니다. 숫자가 누락되었거나 오래된(stale) 경우, 미터기는 무엇이라고 말하는가?
네 가지 버그가 더 발견되었으며, 모두 동일한 계열의 문제였습니다. 미터기는 입력값이 정상적이지 않음에도 불구하고 마치 정상인 것처럼 계속 계산을 수행했고, 계속해서 안심시키는 결과만을 내놓고 있었습니다.
| 잘못된 입력 (Broken input) | 표시된 내용 (What it showed) | 숨겨진 사실 (What that hides) |
|---|---|---|
| 이미 과거인 리셋 시간 (Reset time already in the past) | "7일 더 남음, -180분 후에 리셋" | 사이클이 이미 리셋됨; 저장된 백분율(percentage)은 오래된 데이터이며, 그럼에도 불구하고 투영(projection)이 수행됨 |
| ... |
화면에 표시된 세 번째 행은 실제 측정값만큼이나 확신에 차 보였습니다:
플랜: 7.0일 더 남음 · 리셋까지: 없음 · 정상 속도, 여유 있음
이제 네 가지 상태 모두가 하나의 정직한 문장으로 수렴합니다. 즉, 미터기는 조용히 추측하는 대신, 현재로서는 알 수 없다고 말합니다.
플랜: 데이터 사용 불가 · 마지막 읽기 실패, 추측하지 않음
그리고 15분마다 이를 갱신하는 백그라운드 작업(background job)은 요청받지 않았음에도 불구하고, 6시간 전의 오래된 읽기(stale read)를 스스로 보고합니다. 왜냐하면 움직임을 멈춘 미터기는 단순히 틀린 미터기보다 더 크게 소리 내어 알려줘야 하기 때문입니다. 멈춰버린 숫자는 실제 숫자와 똑같이 보입니다. 하지만 당신이 불신하는 숫자는 최소한 확인이라도 하게 만듭니다.
이 상황이 나에게 남긴 것
4일간의 잠금(lockout)이 순수하게 밤사이의 루프 때문이었는지, 아니면 10개의 프로젝트 전반에 걸쳐 어떤 모델이 어떤 작업을 수행하는지에 대한 불일치 때문이었는지, 혹은 둘 다였는지는 여전히 모릅니다. 그 부분은 해결되지 않았으며, 저는 여기서 그렇지 않은 척하지 않겠습니다.
제가 확실히 아는 것은, 지금 제가 가진 미터기라면 둘째 날에 저에게 아주 명확한 언어로 "금요일까지 버티지 못할 속도로 이번 주 플랜을 소진하고 있다"라고 말해주었을 것이라는 점입니다. 작업 도중에 산수를 해야 하는 백분율이 아니라, 하나의 문장으로 말이죠.
이번에는 코드가 아닌 사용량 대시보드(usage dashboard)를 통해 계속해서 다시 배우고 있는 더 넓은 교훈이 있습니다. 근거 없는 그럴듯한 숫자는 명백한 공백보다 더 위험합니다. 공백은 의심을 사지만, 그럴듯한 숫자는 의심을 사지 않기 때문입니다. 그리고 입력값이 사라졌을 때 침묵하는 숫자는 단순히 틀린 숫자보다 더 나쁩니다. 침묵은 곧 동의로 읽히기 때문입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기