개발 slecs

로컬 AI 모델 토큰 사용량과 비용 추적 기능 구현

목차

로컬 개발 중에 생성되는 AI 모델 로그를 파싱해서 모델별 토큰 사용량과 비용을 추적할 수 있게 만들었다. 이건 개발팀이 실제 운영 비용을 체감하고 최적화 기회를 찾는 데 필수적인 기능이었다.

왜 이게 필요했나

팀에서 여러 AI 모델(또는 같은 모델의 다양한 버전)을 실험할 때마다 "이번엔 비용이 얼마나 나올까?"를 추측할 수 없었다. 프롬프트를 다시 쓰거나 모델을 바꿀 때도 영향도를 정량적으로 알 수가 없다. 특히 개발 단계에선 API 호출이 쌓이고, 그 중 몇십 개가 불필요한 호출이거나 중복일 수도 있는데, 이런 낭비를 발견하려면 먼저 "로컬에서 발생한 실제 토큰 수치"를 봐야 한다.

처음엔 간단히 생각했다. "응답 헤더에서 토큰 수 읽으면 되지 않을까?" 하지만 로컬 개발 환경에선 매번 API 호출할 때마다 과금되는 게 싫고, 모델 변경 실험을 빠르게 돌려야 했다. 그래서 CLI 로그나 로컬에 남겨진 요청/응답 스냅숏에서 추출하는 방식을 택했다.

구현의 핵심 포인트

파일 역할 왜 중요한가
scan-usage.ts 로컬 로그 파일 읽기 + 파싱 실제 로그 소스에서 메타데이터 추출하는 진입점
usage-types.ts 토큰/비용 데이터 타입 정의 도메인 모델이자 타입 안정성의 기초
usage-aggregate.ts 개별 호출들을 모델별로 집계 산재된 로그를 의미 있는 통계로 변환
usage-cost.ts 토큰 수 → 달러 비용 변환 비즈니스 의사결정 언어 (토큰보다 돈이 더 와닿음)
.test.ts 두 도메인 로직 검증 비용 계산 오류는 곧 팀 재정 신뢰도 문제

가장 신경 썼던 부분은 모델별 가격표 유지다. AI 모델의 input/output 토큰 가격이 다르고, 모델이 추가되면 가격표도 업데이트해야 한다. 하드코딩하면 언젠간 깨진다. 그래서 usage-cost.ts에서 모델 ID → 가격 매핑을 함수로 관리하게 했고, 테스트에서 다양한 모델 조합을 돌려봤다.

이렇게 만든 이유들

1. 집계의 중요성
개발자가 한 세션에서 "글로벌 모델 A를 10번, 로컬 최적화 모델 B를 20번 썼다"는 사실을 알아야 다음 실험 우선순위를 정한다. 로그가 있어도 흩어져 있으면 의미가 없다. usage-aggregate는 이 흐름을 구조화했다.

2. 테스트 먼저
비용 계산은 틀리면 안 된다. 팀원이 "어? 왜 이렇게 비싼데?" 하고 신뢰를 잃으면 누구도 이 도구를 안 쓴다. 그래서 집계 로직과 비용 변환을 단위 테스트로 먼저 고정했다. 엣지 케이스(예: 모델이 없는 호출, input만 있고 output 없는 경우 등)도 테스트해 봤다.

3. 도메인 모델화
단순히 "숫자 계산 함수"가 아니라, "usage", "cost", "aggregate" 같은 개념을 파일로 분리했다. 나중에 누군가 새 리포트 기능을 추가할 때도 usage-aggregateusage-cost의 API가 명확해서 쉽게 조합할 수 있다.

회고: 뭘 배웠나

이 작업을 하면서 느낀 가장 큰 점은 작은 기능이라도 팀의 의사결정을 좌우한다는 것이다. 비용 추적이 없으면 모두가 "대충 괜찮겠지" 하고 진행하지만, 숫자가 보이면 "이 모델 대신 저 모델로 바꿔볼까?" 같은 구체적 논의가 나온다.

또한 코드 리뷰할 때 팀원들이 "왜 비용 계산을 도메인 로직으로 분리했나요?"라고 물었는데, 그때 "나중에 리포팅이나 알림 기능이 추가될 때 이 로직을 재사용하려고"라고 설명했다. 한 줄짜리 계산이라도 맥락을 분명히 하면 팀이 같은 방향으로 코드를 읽게 된다.

테스트 작성 때도 "가격 변경되는 시나리오는 어떻게 처리할 건데?"라는 질문이 나왔고, 그걸 계기로 향후 마이그레이션 전략을 살짝 다듬었다. 작은 commit도 팀 대화의 출발점이 된다.


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

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

댓글 0

첫 댓글 달아줘.