6 분 소요

💸 LLM API 비용 추적 3부작 — Claude · OpenAI · Gemini · Upstage, 네 곳에 흩어진 API 비용을 "과금 구조 이해 → 통합 트래커 → 공식 API 대사·알림"으로 끝까지 잡았습니다. 전체 3편.
  1. 과금 구조와 usage 필드 — 4사 가격표 한눈에
  2. 파이썬으로 4사 통합 비용 트래커 만들기
  3. 공식 비용 API 대사와 예산 알림 자동화지금 글

Summary

2편의 트래커는 우리 쪽에서 관측한 추정치예요. 잘 만들어도 청구서와 몇 % 는 어긋날 수 있습니다. 반올림 정책, 서버 도구(웹 검색·코드 실행) 과금, 프로모션 크레딧 차감 같은 건 응답 usage 에 안 보이거든요. 그래서 마지막 편은 각 사가 공식으로 집계해주는 데이터와 대사(reconciliation) 하고, 사람이 안 챙겨도 굴러가는 알림 루틴을 만드는 이야기입니다.

💡 이 글에서 다루는 것

  • Anthropic Usage & Cost Admin API — 토큰과 달러를 조직 단위로 뽑기
  • OpenAI Usage / Costs API — 프로젝트별 집계
  • 공식 API 가 없는 Gemini · Upstage 는 어떻게 하나
  • 추정치 ↔ 공식치 대사 스크립트
  • LiteLLM 게이트웨이로 키별 예산 상한 걸기
  • Slack 일일 비용 리포트 + 예산 초과 알림
  • 비용 절감 체크리스트 (캐싱 · 배치 · 모델 라우팅)



1. 왜 응답 usage 만으로는 부족한가

2편 방식(응답 usage 합산)의 빈틈을 먼저 인정하고 갑니다.

빈틈 내용
서버 도구 과금 웹 검색·코드 실행은 토큰 외 과금이라 usage 합산에 안 잡힘
누락 호출 트래커를 안 거친 호출(동료의 실험, 콘솔 Workbench)은 기록에 없음
크레딧·할인 프로모션 크레딧, 계약 단가는 우리 가격표와 다름
반올림 각 사 내부 집계와 우리 계산의 미세한 차이

그래서 운영 루틴은 이렇게 굴러갑니다 — 실시간 감시는 2편 트래커로, 정산은 공식 API 로. 둘의 차이가 일정 범위(저는 2%)를 넘으면 그때 원인을 조사해요.



2. Anthropic — Usage & Cost Admin API

네 회사 중 가장 잘 갖춰진 쪽이에요. 조직 단위 사용량과 달러 금액까지 API 로 줍니다.

먼저 준비물이 하나 있어요. 일반 API 키가 아니라 Admin API 키(sk-ant-admin01-... 형태)가 필요합니다. Console → Settings → Organization 에서 조직을 만들어야 발급되고, 개인 계정에는 없어요.

사용량 — usage_report

curl "https://api.anthropic.com/v1/organizations/usage_report/messages?\
starting_at=2026-06-29T00:00:00Z&\
ending_at=2026-07-06T00:00:00Z&\
group_by[]=model&\
bucket_width=1d" \
  --header "anthropic-version: 2023-06-01" \
  --header "x-api-key: $ANTHROPIC_ADMIN_KEY"

응답은 시간 버킷별로 비캐시 입력 · 캐시 생성 · 캐시 읽기 · 출력 토큰이 나뉘어 옵니다. group_bymodel 외에 workspace_id, api_key_id, service_tier 를 줄 수 있어서 “어느 워크스페이스가 얼마 썼나” 같은 조직 질문에 바로 답해요. 버킷 폭은 1m/1h/1d 세 가지고, 1d 는 한 번에 최대 31버킷까지 줍니다.

비용 — cost_report

curl "https://api.anthropic.com/v1/organizations/cost_report?\
starting_at=2026-06-01T00:00:00Z&\
ending_at=2026-07-01T00:00:00Z&\
group_by[]=description" \
  --header "anthropic-version: 2023-06-01" \
  --header "x-api-key: $ANTHROPIC_ADMIN_KEY"

이쪽은 아예 USD 금액을 돌려줘요(센트 단위 십진 문자열). 웹 검색·코드 실행 비용도 description 그룹으로 잡히기 때문에, 2편 트래커가 못 보는 빈틈이 여기서 메워집니다. 데이터는 호출 후 보통 5분 안에 반영되고, 폴링은 분당 1회 정도가 권장이에요. 상세 스펙은 Usage & Cost API 문서에 있습니다.



3. OpenAI — Usage / Costs API

OpenAI 도 조직 단위 집계 API 를 제공합니다. 이쪽도 일반 키가 아니라 Admin 키가 필요해요 (Settings → Organization → Admin keys).

# 토큰 사용량 (모델별, 일 버킷)
curl "https://api.openai.com/v1/organization/usage/completions?\
start_time=1751068800&bucket_width=1d&group_by=model" \
  --header "Authorization: Bearer $OPENAI_ADMIN_KEY"

# 달러 비용 (프로젝트별)
curl "https://api.openai.com/v1/organization/costs?\
start_time=1751068800&bucket_width=1d&group_by=project_id" \
  --header "Authorization: Bearer $OPENAI_ADMIN_KEY"

Anthropic 과 구조가 거의 같은데 두 가지가 달라요. 시간 파라미터가 ISO 문자열이 아니라 유닉스 타임스탬프이고, 사용량은 usage/completions 외에 usage/embeddings, usage/images 처럼 상품별 엔드포인트가 분리돼 있습니다. costs 는 일 단위 버킷만 지원해요. 상세 스펙은 OpenAI API 레퍼런스에서 확인하세요.



4. Gemini · Upstage — 공식 API 가 없을 때

여기서부터 온도차가 납니다.

Gemini 는 AI Studio 키 기준으로는 조직 사용량 API 가 따로 없어요. 콘솔의 사용량 페이지를 눈으로 보거나, Vertex AI 경유라면 Google Cloud 결제 데이터를 BigQuery 로 내보내서 SQL 로 집계하는 경로가 정석입니다. 프로젝트 라벨을 잘 달아두면 결제 데이터에서 서비스별 분리가 돼요.

Upstage 는 콘솔의 사용량 화면이 기본이고, 집계 API 는 제공 목록에서 못 찾았습니다(2026년 7월 기준).

그래서 이 두 곳은 결론이 명확해요 — 2편의 응답 기반 로깅이 사실상 유일한 상시 관측 수단입니다. 공식 API 가 없는 프로바이더일수록 호출 시점 기록을 빠뜨리면 복구할 방법이 없어요. 월 1회 콘솔 화면의 월 합계와 트래커 합계를 수동으로 맞춰보는 정도가 현실적인 대사입니다.



5. 추정치 ↔ 공식치 대사 스크립트

Anthropic 기준으로 “어제 하루” 를 맞춰보는 스크립트예요. 2편의 SQLite 와 cost_report 를 나란히 놓습니다.

import os, sqlite3, requests
from datetime import date, timedelta

def anthropic_official_cost(day):
    """cost_report 에서 특정 날짜의 총비용(USD)을 가져온다."""
    r = requests.get(
        "https://api.anthropic.com/v1/organizations/cost_report",
        params={
            "starting_at": f"{day}T00:00:00Z",
            "ending_at": f"{day + timedelta(days=1)}T00:00:00Z",
        },
        headers={
            "anthropic-version": "2023-06-01",
            "x-api-key": os.environ["ANTHROPIC_ADMIN_KEY"],
        },
    )
    r.raise_for_status()
    cents = sum(
        float(item["amount"])
        for bucket in r.json()["data"]
        for item in bucket["results"]
    )
    return cents / 100

def tracked_cost(day, provider="anthropic"):
    with sqlite3.connect("llm_usage.db") as conn:
        row = conn.execute(
            "SELECT COALESCE(SUM(cost_usd), 0) FROM llm_usage "
            "WHERE provider = ? AND substr(ts, 1, 10) = ?",
            (provider, str(day)),
        ).fetchone()
    return row[0]

yesterday = date.today() - timedelta(days=1)
official = anthropic_official_cost(yesterday)
tracked = tracked_cost(yesterday)
diff_pct = abs(official - tracked) / official * 100 if official else 0
print(f"{yesterday}  공식 ${official:.2f} vs 추정 ${tracked:.2f}  (차이 {diff_pct:.1f}%)")
2026-07-05  공식 $7.12 vs 추정 $6.94  (차이 2.5%)

차이 2.5% — 제 경우 원인은 웹 검색 도구 과금이었어요. 이렇게 차이의 원인을 한 번 규명해두면, 그 다음부터는 같은 수준의 차이는 무시하고 갑자기 벌어질 때만 조사하면 됩니다.



6. 게이트웨이로 예산 상한 걸기 — LiteLLM

추적이 되면 다음 욕심은 통제예요. “이 키는 월 $50 까지만” 같은 상한은 애플리케이션 코드가 아니라 게이트웨이 계층에서 거는 게 깔끔합니다. 오픈소스 LiteLLM 프록시가 이 용도로 가장 널리 쓰여요.

4사를 한 프록시 뒤에 두는 설정은 이렇게 생겼습니다. Upstage 는 OpenAI 호환이라 base_url 지정으로 붙어요.

# litellm_config.yaml
model_list:
  - model_name: claude-opus
    litellm_params:
      model: anthropic/claude-opus-4-8
      api_key: os.environ/ANTHROPIC_API_KEY
  - model_name: gpt-mini
    litellm_params:
      model: openai/gpt-5.4-mini
      api_key: os.environ/OPENAI_API_KEY
  - model_name: gemini-flash
    litellm_params:
      model: gemini/gemini-2.5-flash
      api_key: os.environ/GEMINI_API_KEY
  - model_name: solar-pro
    litellm_params:
      model: openai/solar-pro3          # OpenAI 호환 모드
      api_base: https://api.upstage.ai/v1
      api_key: os.environ/UPSTAGE_API_KEY

general_settings:
  master_key: os.environ/LITELLM_MASTER_KEY
  database_url: os.environ/DATABASE_URL   # 지출 기록용 Postgres

프록시를 띄운 뒤 팀원·서비스별 가상 키를 만들면서 예산을 겁니다.

curl -s http://localhost:4000/key/generate \
  -H "Authorization: Bearer $LITELLM_MASTER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"key_alias": "doc-summary-batch", "max_budget": 50.0, "budget_duration": "30d"}'

이 키로 들어오는 호출은 LiteLLM 이 자체 가격표로 지출을 집계하다가, $50 을 넘는 순간 요청을 거절해요. “월말에 알게 되는 초과”가 “그 자리에서 막히는 초과”로 바뀌는 것이 게이트웨이의 가장 큰 가치입니다. 부수 효과로 4사 호출이 한 지점을 지나니까 2편의 로깅도 게이트웨이 한 곳으로 모을 수 있어요.

⚠️ 다만 게이트웨이는 운영 부담(가용성, 버전 업, 가격표 최신화)이 생기는 선택이에요. 혼자 쓰는 프로젝트라면 2편 트래커 + 이 글의 알림으로 충분하고, 팀·조직 규모에서 키 관리가 필요해질 때 도입하는 걸 추천드립니다.



7. Slack 일일 리포트 + 예산 알림

마지막 부품이에요. 2편의 SQLite 를 읽어 아침마다 Slack 으로 쏘고, 일일 예산을 넘으면 경고를 붙입니다.

# daily_slack_report.py
import os, sqlite3, requests
from datetime import date, timedelta

DAILY_BUDGET_USD = 15.0
WEBHOOK = os.environ["SLACK_WEBHOOK_URL"]

yesterday = str(date.today() - timedelta(days=1))
with sqlite3.connect("llm_usage.db") as conn:
    rows = conn.execute(
        "SELECT provider, ROUND(SUM(cost_usd), 2), COUNT(*) FROM llm_usage "
        "WHERE substr(ts, 1, 10) = ? GROUP BY provider ORDER BY 2 DESC",
        (yesterday,),
    ).fetchall()

total = sum(r[1] for r in rows)
lines = [f"*{yesterday} LLM 비용: ${total:.2f}*"]
if total > DAILY_BUDGET_USD:
    lines[0] += f"  🚨 일일 예산 ${DAILY_BUDGET_USD:.0f} 초과!"
lines += [f"• {prov}: ${usd:.2f} ({calls}건)" for prov, usd, calls in rows]

requests.post(WEBHOOK, json={"text": "\n".join(lines)})

Slack 에는 이렇게 도착해요.

2026-07-06 LLM 비용: $7.60
• anthropic: $6.95 (142건)
• google: $0.58 (203건)
• upstage: $0.07 (67건)

crontab 에 아침 9시로 걸어두면 끝입니다.

0 9 * * * cd /path/to/project && python3 daily_slack_report.py

여기에 5장의 대사 스크립트를 주 1회 cron 으로 더하면, 사람이 하는 일은 “알림이 이상할 때만 들여다보기”로 줄어요.



8. 비용 절감 체크리스트

추적 시스템이 잡아준 데이터로 실제 비용을 줄이는 레버들이에요. 효과가 컸던 순서로 정리합니다.

  • 프롬프트 캐싱 — 시스템 프롬프트·도구 정의처럼 매 호출 반복되는 앞부분을 캐시하세요. 읽기 단가가 약 1/10이라 대화형 워크로드에서 입력 비용이 크게 줄어요. 캐시가 실제로 붙는지는 usage 의 캐시 필드로 확인하면 됩니다.
  • 모델 라우팅 — 분류·추출 같은 쉬운 작업을 플래그십에서 mini/nano/Flash/Solar 급으로 내리기. 2편 리포트에서 “비싼 모델로 가는 쉬운 트래픽”을 찾는 게 출발점이에요.
  • 배치 API — 실시간이 필요 없는 대량 작업은 Anthropic·OpenAI 모두 50% 할인. 야간 배치로 미루는 것만으로 반값입니다.
  • 출력 다이어트max_tokens 상한과 “간결하게” 지시. 출력 단가가 입력의 5~6배라는 걸 기억하세요.
  • 추론 강도 조절 — thinking/effort 를 작업 난이도에 맞게. 쉬운 작업에 높은 추론 강도는 보이지 않는 출력 토큰을 태워요.



9. 시리즈 정리

3부작이 만든 시스템을 한 그림으로 요약하면 이렇습니다.

계층 도구 답하는 질문
구조 이해 (1편) 가격표 · usage 필드 뭐가 얼마인가
상시 관측 (2편) track() + SQLite 지금 어디에 쓰고 있나
정산 대사 (3편) 공식 Usage/Cost API 청구서와 맞나
통제 (3편) 게이트웨이 예산 초과를 막을 수 있나
알림 (3편) Slack 리포트 사람이 안 봐도 되나

처음의 질문 — “이번 달 LLM 에 총 얼마 썼지?” — 이제 아침 Slack 메시지가 대신 답해줍니다. 🎉

일단 오늘은 여기까지….. 다음에는 이 비용 데이터를 Grafana 대시보드로 시각화하거나, 모델 라우팅을 자동화하는 이야기로 이어가볼게요.


← 이전 글: (2/3) LLM API 비용 추적 — 파이썬으로 4사 통합 비용 트래커 만들기