方寸 Portal

AI Engineer Portal

Your personal operating system for career transition.

Private mode

Exercise

Implement token counting and cost tracking

Implement Token Counting and Cost Tracking

Token usage is the billing unit for every major LLM API. Without explicit tracking, AI features run with no cost visibility until the monthly invoice arrives. Engineers who track token usage per request can answer "which feature costs the most?", "is this prompt getting more expensive over time?", and "what is the P95 cost per user session?"

What to build

Implement a CostTracker class that records token usage across multiple LLM calls and computes cost summaries:

  1. record(model: str, input_tokens: int, output_tokens: int, feature: str) method — records one LLM call with its token usage and the product feature that made the call.
  2. total_cost_usd() method — returns the total USD cost across all recorded calls.
  3. cost_by_feature() method — returns a dict mapping feature name to total USD cost.
  4. cost_by_model() method — returns a dict mapping model name to total USD cost.
  5. summary() method — returns a dict with total_calls, total_input_tokens, total_output_tokens, total_cost_usd, cost_by_feature, cost_by_model.

Also implement MODEL_COSTS: dict[str, dict] — a lookup table mapping model name to {"input_per_1k": float, "output_per_1k": float}. Include at minimum:

  • "gpt-4o": input $0.0025/1k, output $0.01/1k
  • "gpt-4o-mini": input $0.00015/1k, output $0.0006/1k
  • "claude-3-5-sonnet": input $0.003/1k, output $0.015/1k

Why this matters

Token tracking is required for cost attribution in multi-feature products, budget alerts before hitting billing limits, and deciding which model tier to use based on actual usage patterns. A tracker that is easy to integrate (one .record() call per LLM response) gets adopted; a complex one gets bypassed.

Constraints

  • Raise ValueError for unknown model names.
  • All costs should be computed from the MODEL_COSTS table, not hardcoded.
  • The summary() method should return costs rounded to 6 decimal places.

Python Refresh / medium / Step 11 of 16

Practice stage

Core runtime habits

Hint

Normalize the boundary first, keep return shapes stable, and make the middle of the function boring on purpose.

Success criteria
  • - Returns one stable shape across branches
  • - Makes failure handling obvious
  • - Keeps the core logic readable in under a minute
Review checklist
  • - Did I make the input and output shapes explicit?
  • - Would a teammate know where validation happens?
  • - Did I avoid silent mutation or vague branching?

Practice

Generate a variation

Generate a new exercise variation to deepen understanding or practice a related concept.

Attempt history

Recent submissions

Before you submit, decide what a strong answer should make obvious to the reviewer.

No attempts yet.