C.W.K.
Stream
Lesson 05 of 07 · published

Cost & Rate Limit Management — per-tenant ledger

~22 min · cost, rate-limits, budgets

Level 0Tokenizer
0 XP0/54 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

두 달째 받게 될 두 질문 — 'bill 왜 이렇게 비싸?' 와 '어느 customer 가 책임?'. 답은 하나 — per-tenant ledger. 매 호출의 (tenant_id, model, prompt_tokens, completion_tokens, reasoning_tokens, ts) persist. 일별 tenant 별 roll up.

Aggregate cost 만으론 부족

총합만 보면 'Customer A 가 80%' 같은 사실이 invisible. Per-tenant breakdown 없이는 bill 대화가 speculation. Persist 는 cheap 한데 나중에 추가하기 불가.

Adaptive concurrency

매 응답의 x-ratelimit-remaining-requests 읽기. 20% 밑이면 concurrency halve, 80% 위면 double. Wall 에 부딪히지 말고 wall 밑에서 cruise. Header 가 정확히 그래서 존재.

Per-tenant budget cap

Ledger 가 있으면 cap 박기 trivial — 'Customer X 의 monthly budget 은 $Y, 그 이상 호출 reject 또는 downgrade'. Cap 없으면 buggy customer 가 전체 bill 망침.

Code

Per-tenant budget tracker·python
from dataclasses import dataclass

PRICING_PER_1M = {
    "gpt-5.4": {"prompt": 2.50, "completion": 15.00},
    "gpt-4.1": {"prompt": 2.00, "completion": 8.00},
    "gpt-4o-mini": {"prompt": 0.15, "completion": 0.60},
}

@dataclass
class CostTracker:
    total_cost_usd: float = 0.0
    total_prompt_tokens: int = 0
    total_completion_tokens: int = 0
    request_count: int = 0

    def record(self, model: str, usage: dict) -> float:
        p = usage.get("prompt_tokens", 0)
        c = usage.get("completion_tokens", 0)
        pricing = PRICING_PER_1M.get(model, {"prompt": 0, "completion": 0})
        cost = p * pricing["prompt"] / 1_000_000 + c * pricing["completion"] / 1_000_000
        self.total_cost_usd += cost
        self.request_count += 1
        return cost
Header 로 adaptive concurrency·python
import asyncio, random

async def retry_with_backoff(func, max_retries=6, initial_delay=1.0):
    delay = initial_delay
    for attempt in range(max_retries + 1):
        try:
            return await func()
        except httpx.HTTPStatusError as e:
            if e.response.status_code not in (429, 500, 502, 503, 504):
                raise
            if attempt == max_retries: raise
            # Honor Retry-After header
            retry_after = e.response.headers.get("Retry-After")
            sleep_time = float(retry_after) if retry_after else delay * (0.5 + random.random())
            await asyncio.sleep(min(sleep_time, 60.0))
            delay = min(delay * 2, 60.0)

External links

Exercise

CostLedger build — 매 API call (tenant_id, model, in_tokens, out_tokens, usd) record. 일별 tenant 별 report 생성. Per-tenant cap 박을 위치 결정 + guard 추가.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.