대시보드가 스스로를 비난하다
요약
Claude Code 토큰 지출을 추적하는 오픈 소스 엔진 CodeBurn의 비용 산정 오류 사례를 다룹니다. 프로젝트 초기 단계의 높은 토큰 사용량을 단순 낭비로 오판한 대시보드의 범주 오류를 분석하고 이를 수정하는 과정을 설명합니다.
핵심 포인트
- CodeBurn은 Claude Code 세션 로그를 기반으로 비용을 추정함
- 프로젝트 초기 구축 단계의 높은 토큰 사용량은 일반 유지보수와 비교 대상이 아님
- 잘못된 비교 로직(범주 오류)으로 인해 대시보드가 비용 이상치를 오판함
- 오픈 소스 엔진의 버그를 식별하고 소스 코드를 통해 수정하는 개발 과정 공유
우리의 자체 비용 대시보드(cost dashboard)는 탄생한 당일을 26.5배의 초과 지출로 표시했습니다. 하지만 트랜스크립트(transcript)의 내용은 달랐습니다. 이런 일이 다른 누구에게도 일어나지 않도록 보장하기 위해 버그 리포트(bug report)를 작성했고, 3일 후 수정 사항이 배포되었습니다.
우리는 많은 작은 내부 대시보드들을 구축합니다. 그중 하나는 이 머신에 있는 프로젝트 전반에 걸친 Claude Code 토큰 지출을 추적합니다. 이 대시보드는 CodeBurn이라는 오픈 소스(open-source) 엔진에 의존합니다. 이는 무료이며, 로컬 전용(local-only)이고, 세션 로그(session logs)를 읽어 각 세션이 종량제(pay-as-you-go) 가격 기준으로 얼마의 비용이 들었을지 추정합니다. CodeBurn에는 최적화(optimize)라고 불리는 패널이 있으며, 이 패널의 역할은 낭비를 찾아내는 것입니다. 즉, 명확한 이유 없이 프로젝트 자체 평균보다 훨씬 더 많은 비용이 든 세션들을 표시하는 것입니다.
어느 날, 이 패널은 자기 집 내부의 무언가를 지목했습니다. 대시보드의 빌드 세션(build session), 즉 그것이 존재하게 된 그날이 26.5배의 비용 이상치(outlier)로 표시되어 있었습니다. 프로젝트 자체 평균의 26.5배였습니다. 이는 보는 사람을 움찔하게 만들 정도로 설계된 수치입니다.
우리는 움찔하지 않았습니다. 우리는 가공되지 않은 트랜스크립트(raw transcript)를 추출했습니다.
실제로 그 안에 무엇이 있었나
그 세션은 1,070개의 이벤트(events)를 실행했습니다. 브레인스토밍(brainstorm), 계획, 24개의 빌드 에이전트(build agents) 파견, 그리고 대시보드를 첫 번째 실제 버전으로 승격시킨 최종 커밋(commit)까지 포함되었습니다. 그것이 창립 세션(founding session)이었고, 창립 세션은 비용이 많이 듭니다. 창립 세션 하나만으로 1,045,640개의 토큰(tokens)을 사용했는데, 이는 이후에 이어진 12개의 형제 세션 평균인 62,940개와 비교했을 때, 비용 산정을 따지기도 전에 토큰 양에서만 16.6배의 차이가 나는 수치였습니다.
프로젝트가 무(無)에서 유(有)로 넘어가는 날은 그 이후의 어떤 날보다 더 많은 비용이 듭니다. 집의 기초를 다지는 비용은 방 하나를 다시 칠하는 비용보다 많이 들며, 아무도 그것을 낭비 항목으로 분류하지 않습니다. 패널은 창립 당일을 그 이후의 조용한 유지보수(maintenance) 기간과 비교하여 그 비율을 낭비라고 불렀습니다. 이는 측정의 문제라기보다는 범주 오류(category error)입니다. 그 비교는 결코 동일 선상(apples to apples)에 있지 않았으며, 산술 계산이 시작되기 전부터 잘못된 비교는 그 어떤 비용 임계값(cost threshold)으로도 바로잡을 수 없습니다.
따라서 패널(panel)이 질문을 던진 것은 옳았습니다. 다만 그 답변이 틀렸을 뿐입니다.
두 가지 쉬운 탈출구
우리는 그 경고(flag)를 무시할 수도 있었습니다. 로컬에서 해당 경고를 묵인(silence)하고 그냥 넘어갈 수도 있었으며, 우리에게는 그것만으로도 충분했을 것입니다. 하지만 그렇게 했다면, CodeBurn을 초기 단계의 프로젝트(young project)에 실행하는 다른 모든 사용자들에게는 버그가 그대로 남겨졌을 것입니다. 그리고 모든 프로젝트는 언젠가 초기 단계에 놓이게 됩니다.
그래서 우리는 대신 CodeBurn의 소스 코드를 읽었습니다. 비교 로직은 src/optimize.ts 파일 내의 detectSessionOutliers라는 함수에 들어 있었습니다. 코드를 읽어보니 유용한 부분을 발견할 수 있었습니다. 코드베이스에는 이미 수정에 필요한 메커니즘이 갖춰져 있었습니다. 패널의 다른 곳에서 정확히 이와 같은 역할을 수행하고 있는 outlierExclusions라는 작은 제외 목록(exclusion list)이 바로 그곳에 있었습니다.
덕분에 우리는 단순한 불만 대신 더 나은 것을 제출할 수 있었습니다. Issue #664: 어떤 일이 발생하는지, 왜 잘못되었는지, 그리고 수정해야 할 구체적인 라인들을 정리하여 제출했습니다.
유지 관리자의 수정안이 우리의 것보다 나았다
CodeBurn에는 활발하게 활동하는 유지 관리자(maintainer)가 있었고, 다음 날 아침 바로 풀 리퀘스트(pull request)가 열렸습니다.
우리가 구상한 초안은 모든 프로젝트의 초기 세션(founding session)을 영구적으로 제외하는 방식이었습니다. 유지 관리자의 버전은 더 정교했습니다. 프로젝트가 초기 단계일 때만 초기 세션을 제외하며, '초기 단계'를 판단하는 기준은 실제 경과 시간(wall-clock age)이 아니라 해당 프로젝트가 거쳐온 비용 발생 세션(costed sessions)의 수로 측정했습니다.
그 차이가 바로 핵심적인 수정 사항입니다. 우리의 버전대로라면, 정말로 낭비적인 초기 세션이라 할지라도 면제 조항 뒤에 영원히 숨겨졌을 것입니다. 하지만 유지 관리자의 버전에서는 6번의 비용 발생 세션이 지나면 의심의 여지 없이 제외됩니다. 생성된 지 2주 된 프로젝트의 초기 세션은 제외 대상이 됩니다. 하지만 몇 달간의 기록을 가진 성숙한 프로젝트에서의 동일한 세션은 제외되지 않습니다. 실제 경과 시간(wall-clock age)을 기준으로 했다면 이를 놓쳤을 것입니다. 프로젝트는 오래되었지만 거의 사용되지 않을 수도 있기 때문이며, 평균값이 의미를 갖게 만드는 것은 바로 '사용량'입니다.
세 개의 새로운 테스트가 추가되었습니다. 86개의 테스트 스위트가 모두 통과(green)되었습니다.
전체 과정은 3일이 걸렸습니다. 14일에 보고되었고, 15일에 메인테이너(maintainer)의 풀 리퀘스트(pull request)가 열렸으며, 16일에 머지(merged)되었고, 17일 v0.9.16 버전으로 출시되었습니다. 해당 릴리스 노트(release notes)에는 아주 명확한 문구로, 이제 어린 프로젝트의 초기 세션이 비용 이상치(cost outlier)로 더 이상 표시되지 않는다고 적혀 있습니다. CodeBurn을 실행하고 업데이트하면 해당 버그는 사라집니다.
무엇이 필요했는가
이 모든 과정에 운은 필요하지 않았습니다. 무서운 숫자를 액면 그대로 믿지 않고, 그 아래에 있는 데이터를 읽어내는 태도가 필요했습니다. 나머지는 버그 리포트(bug report)를 본인이 받고 싶은 방식으로 작성하는 것이었습니다. 즉, 정확한 코드 경로(code path), 증상이 아닌 근본 원인(root cause), 그리고 바로 검토할 수 있는 수정안(fix)을 제공하는 것이었습니다.
도구가 틀렸고, 그 오류는 제대로 설명할 만한 가치가 있는 방식이었습니다. 로컬(locally)에서 플래그(flag)를 억제했다면 우리의 대시보드는 정상으로 보였을 것입니다. 하지만 그렇게 했다면 버그는 정확히 그 자리에 그대로 남아 있었을 것입니다.
원문은 thekilted.dev/dashboard-accused-itself에서 게시되었습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기