Module 1: AI Cost Anatomy
8. Project: Cost Breakdown Calculator
Overview
Every capsule in this module gave you a piece of the puzzle: tokens and why output costs more than input (capsule 02), tiktoken for programmatic counting (capsule 03), pricing by provider (capsule 04), hidden costs like retries and context window waste (capsule 05), cost formulas by operation type (capsule 06), and projections from individual request to monthly invoice (capsule 07). Now you take all those pieces and build a real tool.
The Cost Breakdown Calculator is a Python class that takes the parameters of an AI system — model used, average tokens per request (input and output), requests per day, embedding usage, retry rate — and produces a detailed cost breakdown by component. It's not a vague estimate. It's a precise calculation that tells you: "your system spends $612/month on output tokens, $306/month on input tokens, $288/month on embeddings, $153/month on retries, and $41/month on storage." With those numbers, you know exactly where to cut first.
But the calculation tool isn't the most important deliverable. The most important deliverable is the baseline document. This formal document records your starting point: current costs broken down by component, distribution percentages, average cost per request, and monthly total. Why is it so critical? Because in Module 8, after applying prompt optimization (Module 3), Redis caching (Modules 4-5), semantic caching (Module 6), and model selection (Module 7), you'll measure again and calculate the reduction percentage. Without this baseline, there's no "before" to compare against. The portfolio statement "$2,400/month → $720/month (70% reduction)" starts here, with the number you document today.
The project supports multiple providers (OpenAI, Anthropic) so you can compare the cost of the same operation across different APIs. You don't need to call any API — the whole calculation is local, using published pricing and tiktoken to validate counts.
Objective
Build a Cost Breakdown Calculator in Python that breaks down the costs of an AI system by component, supports multiple providers, and generates a formal baseline document that will serve as the "before" reference for the cost reduction benchmark in Module 8.
By the end of this project you'll be able to:
- ✅ Calculate the cost of an individual request broken down into: input tokens, output tokens, embeddings, retries
- ✅ Project daily and monthly costs from real system parameters
- ✅ Include hidden costs (retries, context window waste) that most people ignore
- ✅ Compare costs between OpenAI and Anthropic for the same workload
- ✅ Generate a baseline document with date, components, percentages and totals
- ✅ Produce a formatted report with data ready for a pie chart
- ✅ Have the first half of your benchmark: the "before" that Module 8 needs
What You'll Build
A CostBreakdownCalculator that takes system parameters and produces:
| Component | What it calculates | Source capsule |
|---|---|---|
| Input Tokens | Cost of input tokens per request and monthly | Capsules 02, 03 |
| Output Tokens | Cost of output tokens (2-4x more expensive than input) | Capsules 02, 03 |
| Embeddings | Cost of generating embeddings for RAG/search | Capsules 05, 06 |
| Retries | Extra cost from failed requests that get resent | Capsule 05 |
| Context Waste | Cost of tokens wasted by an inefficient context window | Capsule 05 |
| Storage | Estimated cost of storing logs and responses | Capsule 06 |
| Multi-Provider | Same workload on OpenAI vs Anthropic | Capsule 04 |
| Baseline Document | Formal document with date, breakdown, percentages | Capsule 07 |
Technical Specifications
Stack
python >= 3.10
tiktoken
python-dotenv
Code structure
cost-breakdown-calculator/
├── .env # OPENAI_API_KEY (optional, unused in calculations)
├── cost_calculator.py # CostBreakdownCalculator class (core)
├── provider_pricing.py # Up-to-date pricing by provider
├── baseline_generator.py # Baseline document generator
├── run_calculator.py # Main execution script
└── baseline_report.md # Output: generated baseline document
Dependencies
pip install tiktoken python-dotenv
You don't need openai installed for this project. Every calculation is local — you use published pricing and tiktoken for token counting. No API calls, no cost.
Step by Step
Step 1: Project setup
mkdir cost-breakdown-calculator
cd cost-breakdown-calculator
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install tiktoken python-dotenv
Verify that tiktoken works:
python -c "import tiktoken; enc = tiktoken.encoding_for_model('gpt-4o'); print(f'tiktoken OK: {len(enc.encode(\"Hello world\"))} tokens')"
# Expected output:
tiktoken OK: 2 tokens
Step 2: Pricing by provider (provider_pricing.py)
This module centralizes up-to-date prices. When a provider changes prices, you only update this file.
# provider_pricing.py
from dataclasses import dataclass
@dataclass(frozen=True)
class ModelPricing:
"""Price per 1M tokens for a specific model."""
provider: str
model: str
input_per_1m: float # USD per 1M input tokens
output_per_1m: float # USD per 1M output tokens
context_window: int # Max context window size in tokens
embedding_model: str | None = None
embedding_per_1m: float = 0.0
PRICING_CATALOG: dict[str, ModelPricing] = {
# --- OpenAI ---
"gpt-4o": ModelPricing(
provider="OpenAI",
model="gpt-4o",
input_per_1m=2.50,
output_per_1m=10.00,
context_window=128_000,
embedding_model="text-embedding-3-small",
embedding_per_1m=0.02,
),
"gpt-4o-mini": ModelPricing(
provider="OpenAI",
model="gpt-4o-mini",
input_per_1m=0.15,
output_per_1m=0.60,
context_window=128_000,
embedding_model="text-embedding-3-small",
embedding_per_1m=0.02,
),
"gpt-4-turbo": ModelPricing(
provider="OpenAI",
model="gpt-4-turbo",
input_per_1m=10.00,
output_per_1m=30.00,
context_window=128_000,
embedding_model="text-embedding-3-small",
embedding_per_1m=0.02,
),
"gpt-3.5-turbo": ModelPricing(
provider="OpenAI",
model="gpt-3.5-turbo",
input_per_1m=0.50,
output_per_1m=1.50,
context_window=16_385,
embedding_model="text-embedding-3-small",
embedding_per_1m=0.02,
),
# --- Anthropic ---
"claude-sonnet-4": ModelPricing(
provider="Anthropic",
model="claude-sonnet-4",
input_per_1m=3.00,
output_per_1m=15.00,
context_window=200_000,
embedding_model=None,
embedding_per_1m=0.0,
),
"claude-3.5-haiku": ModelPricing(
provider="Anthropic",
model="claude-3.5-haiku",
input_per_1m=0.80,
output_per_1m=4.00,
context_window=200_000,
embedding_model=None,
embedding_per_1m=0.0,
),
"claude-3-opus": ModelPricing(
provider="Anthropic",
model="claude-3-opus",
input_per_1m=15.00,
output_per_1m=75.00,
context_window=200_000,
embedding_model=None,
embedding_per_1m=0.0,
),
}
def get_pricing(model: str) -> ModelPricing:
"""Get the pricing for a model. Raises KeyError if it doesn't exist."""
if model not in PRICING_CATALOG:
available = ", ".join(sorted(PRICING_CATALOG.keys()))
raise KeyError(
f"Model '{model}' not found. Available: {available}"
)
return PRICING_CATALOG[model]
def list_models_by_provider(provider: str) -> list[str]:
"""List the models available for a provider."""
return [
key for key, p in PRICING_CATALOG.items()
if p.provider.lower() == provider.lower()
]
def compare_providers(
input_tokens: int, output_tokens: int
) -> list[dict]:
"""Compare the cost of one request across every model in the catalog."""
results = []
for key, pricing in PRICING_CATALOG.items():
cost_input = (input_tokens / 1_000_000) * pricing.input_per_1m
cost_output = (output_tokens / 1_000_000) * pricing.output_per_1m
results.append({
"provider": pricing.provider,
"model": key,
"cost_input": cost_input,
"cost_output": cost_output,
"cost_total": cost_input + cost_output,
})
results.sort(key=lambda x: x["cost_total"])
return results
Step 3: Cost Breakdown Calculator (cost_calculator.py)
This is the core of the project. The class takes system parameters and calculates broken-down costs.
# cost_calculator.py
from dataclasses import dataclass, field
from datetime import datetime
from provider_pricing import get_pricing, ModelPricing, compare_providers
@dataclass
class SystemParameters:
"""Parameters that describe your AI system."""
model: str # Main model (e.g. "gpt-4o")
avg_input_tokens: int # Average input tokens per request
avg_output_tokens: int # Average output tokens per request
requests_per_day: int # Requests per day
embedding_requests_per_day: int = 0 # Embedding requests per day
avg_embedding_tokens: int = 500 # Average tokens per embedding request
retry_rate: float = 0.05 # Share of requests that get retried (0.05 = 5%)
context_waste_pct: float = 0.10 # Share of the context window that's wasted
storage_gb_per_month: float = 1.0 # GB of storage for logs/responses
storage_cost_per_gb: float = 0.023 # USD per GB/month (S3 standard pricing)
system_description: str = "" # System description for the baseline
@dataclass
class CostComponent:
"""An individual cost component."""
name: str
daily_cost: float
monthly_cost: float
cost_per_request: float
description: str
@property
def yearly_cost(self) -> float:
return self.monthly_cost * 12
@dataclass
class CostBreakdown:
"""Complete result of the cost breakdown."""
parameters: SystemParameters
pricing: ModelPricing
components: list[CostComponent] = field(default_factory=list)
calculated_at: str = field(
default_factory=lambda: datetime.now().strftime("%Y-%m-%d %H:%M:%S")
)
@property
def total_daily(self) -> float:
return sum(c.daily_cost for c in self.components)
@property
def total_monthly(self) -> float:
return sum(c.monthly_cost for c in self.components)
@property
def total_yearly(self) -> float:
return sum(c.yearly_cost for c in self.components)
@property
def avg_cost_per_request(self) -> float:
if self.parameters.requests_per_day == 0:
return 0.0
return self.total_daily / self.parameters.requests_per_day
def get_distribution(self) -> list[dict]:
"""Percentage of each component against the total."""
total = self.total_monthly
if total == 0:
return []
return [
{
"component": c.name,
"monthly_cost": c.monthly_cost,
"percentage": (c.monthly_cost / total) * 100,
}
for c in sorted(
self.components, key=lambda x: x.monthly_cost, reverse=True
)
]
class CostBreakdownCalculator:
"""
Cost breakdown calculator for AI systems.
Takes system parameters and produces a complete breakdown
by component: input tokens, output tokens, embeddings,
retries, context waste, and storage.
"""
def __init__(self, params: SystemParameters):
self.params = params
self.pricing = get_pricing(params.model)
def calculate(self) -> CostBreakdown:
"""Run the complete calculation and return the breakdown."""
breakdown = CostBreakdown(
parameters=self.params,
pricing=self.pricing,
)
breakdown.components.append(self._calc_input_tokens())
breakdown.components.append(self._calc_output_tokens())
if self.params.embedding_requests_per_day > 0:
breakdown.components.append(self._calc_embeddings())
breakdown.components.append(self._calc_retries())
breakdown.components.append(self._calc_context_waste())
breakdown.components.append(self._calc_storage())
return breakdown
def _calc_input_tokens(self) -> CostComponent:
"""Cost of input tokens."""
tokens_per_day = self.params.avg_input_tokens * self.params.requests_per_day
cost_per_day = (tokens_per_day / 1_000_000) * self.pricing.input_per_1m
cost_per_request = (
(self.params.avg_input_tokens / 1_000_000) * self.pricing.input_per_1m
)
return CostComponent(
name="Tokens Input",
daily_cost=cost_per_day,
monthly_cost=cost_per_day * 30,
cost_per_request=cost_per_request,
description=(
f"{self.params.avg_input_tokens:,} tokens/req × "
f"{self.params.requests_per_day:,} req/day × "
f"${self.pricing.input_per_1m}/1M tokens"
),
)
def _calc_output_tokens(self) -> CostComponent:
"""Cost of output tokens (typically 2-4x more expensive)."""
tokens_per_day = self.params.avg_output_tokens * self.params.requests_per_day
cost_per_day = (tokens_per_day / 1_000_000) * self.pricing.output_per_1m
cost_per_request = (
(self.params.avg_output_tokens / 1_000_000) * self.pricing.output_per_1m
)
return CostComponent(
name="Tokens Output",
daily_cost=cost_per_day,
monthly_cost=cost_per_day * 30,
cost_per_request=cost_per_request,
description=(
f"{self.params.avg_output_tokens:,} tokens/req × "
f"{self.params.requests_per_day:,} req/day × "
f"${self.pricing.output_per_1m}/1M tokens"
),
)
def _calc_embeddings(self) -> CostComponent:
"""Cost of embedding requests (for RAG, semantic search)."""
tokens_per_day = (
self.params.avg_embedding_tokens
* self.params.embedding_requests_per_day
)
cost_per_day = (tokens_per_day / 1_000_000) * self.pricing.embedding_per_1m
cost_per_request = (
(self.params.avg_embedding_tokens / 1_000_000)
* self.pricing.embedding_per_1m
)
return CostComponent(
name="Embeddings",
daily_cost=cost_per_day,
monthly_cost=cost_per_day * 30,
cost_per_request=cost_per_request,
description=(
f"{self.params.avg_embedding_tokens:,} tokens/req × "
f"{self.params.embedding_requests_per_day:,} req/day × "
f"${self.pricing.embedding_per_1m}/1M tokens"
),
)
def _calc_retries(self) -> CostComponent:
"""
Cost of retries — requests that fail and get resent.
Every retry repeats the full input + output tokens.
"""
retry_requests = int(
self.params.requests_per_day * self.params.retry_rate
)
input_cost = (
(self.params.avg_input_tokens / 1_000_000)
* self.pricing.input_per_1m
)
output_cost = (
(self.params.avg_output_tokens / 1_000_000)
* self.pricing.output_per_1m
)
cost_per_retry = input_cost + output_cost
cost_per_day = cost_per_retry * retry_requests
return CostComponent(
name="Retries",
daily_cost=cost_per_day,
monthly_cost=cost_per_day * 30,
cost_per_request=cost_per_retry if retry_requests > 0 else 0.0,
description=(
f"{self.params.retry_rate*100:.1f}% retry rate = "
f"{retry_requests} retries/day × "
f"${cost_per_retry:.6f}/retry"
),
)
def _calc_context_waste(self) -> CostComponent:
"""
Cost of a wasted context window.
When you send a long system prompt or unnecessary conversation
history, you pay for tokens that add no value.
"""
wasted_tokens_per_request = int(
self.params.avg_input_tokens * self.params.context_waste_pct
)
wasted_per_day = wasted_tokens_per_request * self.params.requests_per_day
cost_per_day = (wasted_per_day / 1_000_000) * self.pricing.input_per_1m
cost_per_request = (
(wasted_tokens_per_request / 1_000_000) * self.pricing.input_per_1m
)
return CostComponent(
name="Context Waste",
daily_cost=cost_per_day,
monthly_cost=cost_per_day * 30,
cost_per_request=cost_per_request,
description=(
f"{self.params.context_waste_pct*100:.0f}% of "
f"{self.params.avg_input_tokens:,} input tokens = "
f"{wasted_tokens_per_request:,} wasted tokens/req"
),
)
def _calc_storage(self) -> CostComponent:
"""Cost of storing logs, prompts and responses."""
monthly_cost = (
self.params.storage_gb_per_month * self.params.storage_cost_per_gb
)
daily_cost = monthly_cost / 30
cost_per_request = 0.0
if self.params.requests_per_day > 0:
cost_per_request = daily_cost / self.params.requests_per_day
return CostComponent(
name="Storage",
daily_cost=daily_cost,
monthly_cost=monthly_cost,
cost_per_request=cost_per_request,
description=(
f"{self.params.storage_gb_per_month:.1f} GB/month × "
f"${self.params.storage_cost_per_gb}/GB"
),
)
def format_report(breakdown: CostBreakdown) -> str:
"""Generate a formatted report of the cost breakdown."""
lines: list[str] = []
sep = "=" * 70
lines.append(sep)
lines.append(" COST BREAKDOWN REPORT")
lines.append(sep)
lines.append(f" Date: {breakdown.calculated_at}")
lines.append(f" Model: {breakdown.pricing.model} ({breakdown.pricing.provider})")
lines.append(
f" Requests: {breakdown.parameters.requests_per_day:,}/day"
)
if breakdown.parameters.system_description:
lines.append(f" System: {breakdown.parameters.system_description}")
lines.append(sep)
lines.append("")
lines.append(" BREAKDOWN BY COMPONENT")
lines.append(" " + "-" * 66)
lines.append(
f" {'Component':<20} {'Per Request':>14} {'Daily':>12} {'Monthly':>12}"
)
lines.append(" " + "-" * 66)
for comp in breakdown.components:
lines.append(
f" {comp.name:<20} ${comp.cost_per_request:>12.6f} "
f"${comp.daily_cost:>10.2f} ${comp.monthly_cost:>10.2f}"
)
lines.append(" " + "-" * 66)
lines.append(
f" {'TOTAL':<20} ${breakdown.avg_cost_per_request:>12.6f} "
f"${breakdown.total_daily:>10.2f} ${breakdown.total_monthly:>10.2f}"
)
lines.append("")
lines.append(" COST DISTRIBUTION (data for a pie chart)")
lines.append(" " + "-" * 50)
distribution = breakdown.get_distribution()
for item in distribution:
bar_len = int(item["percentage"] / 2)
bar = "█" * bar_len
lines.append(
f" {item['component']:<20} {item['percentage']:>5.1f}% {bar}"
)
lines.append("")
lines.append(" ANNUAL PROJECTION")
lines.append(" " + "-" * 50)
lines.append(f" Estimated annual total: ${breakdown.total_yearly:,.2f}")
lines.append(
f" Average cost per request: ${breakdown.avg_cost_per_request:.6f}"
)
lines.append(sep)
return "\n".join(lines)
def format_comparison(
input_tokens: int, output_tokens: int, requests_per_day: int
) -> str:
"""Generate a comparison table of costs across every provider."""
comparison = compare_providers(input_tokens, output_tokens)
lines: list[str] = []
lines.append("=" * 70)
lines.append(" MULTI-PROVIDER COMPARISON")
lines.append(
f" For: {input_tokens:,} input + {output_tokens:,} output tokens/req, "
f"{requests_per_day:,} req/day"
)
lines.append("=" * 70)
lines.append(
f" {'Provider':<12} {'Model':<18} {'Per Req':>10} "
f"{'Daily':>10} {'Monthly':>10}"
)
lines.append(" " + "-" * 66)
for item in comparison:
daily = item["cost_total"] * requests_per_day
monthly = daily * 30
lines.append(
f" {item['provider']:<12} {item['model']:<18} "
f"${item['cost_total']:>8.6f} ${daily:>8.2f} ${monthly:>8.2f}"
)
lines.append("=" * 70)
return "\n".join(lines)
Step 4: Baseline Document generator (baseline_generator.py)
This is the most important file in the project. The baseline document is your main deliverable — without it, Module 8 can't prove "50-80% reduction."
# baseline_generator.py
from datetime import datetime
from cost_calculator import CostBreakdown
def generate_baseline_document(
breakdown: CostBreakdown,
output_path: str = "baseline_report.md",
) -> str:
"""
Generate a formal baseline document in Markdown.
This document is the 'before' for the Module 8 benchmark.
"""
params = breakdown.parameters
pricing = breakdown.pricing
distribution = breakdown.get_distribution()
sections: list[str] = []
sections.append("# AI Cost Baseline")
sections.append("")
sections.append("> This document establishes the starting point (baseline) for the")
sections.append("> AI system's costs **before** applying optimizations. It will be used")
sections.append("> as the 'before' reference in the Module 8 benchmark.")
sections.append("")
sections.append("---")
sections.append("")
sections.append("## 1. General Information")
sections.append("")
sections.append(f"| Field | Value |")
sections.append(f"|-------|-------|")
sections.append(
f"| **Measurement date** | {breakdown.calculated_at} |"
)
sections.append(
f"| **System** | {params.system_description or 'No description'} |"
)
sections.append(
f"| **Main model** | {pricing.model} ({pricing.provider}) |"
)
sections.append(
f"| **Requests/day** | {params.requests_per_day:,} |"
)
sections.append(
f"| **Requests/month** | {params.requests_per_day * 30:,} |"
)
sections.append(
f"| **Retry rate** | {params.retry_rate * 100:.1f}% |"
)
sections.append(
f"| **Context waste** | {params.context_waste_pct * 100:.0f}% |"
)
sections.append("")
sections.append("---")
sections.append("")
sections.append("## 2. System Parameters")
sections.append("")
sections.append(f"| Parameter | Value |")
sections.append(f"|-----------|-------|")
sections.append(
f"| Average input tokens/request | {params.avg_input_tokens:,} |"
)
sections.append(
f"| Average output tokens/request | {params.avg_output_tokens:,} |"
)
sections.append(
f"| Embedding requests/day | {params.embedding_requests_per_day:,} |"
)
sections.append(
f"| Tokens per embedding request | {params.avg_embedding_tokens:,} |"
)
sections.append(
f"| Estimated storage | {params.storage_gb_per_month:.1f} GB/month |"
)
sections.append("")
sections.append("---")
sections.append("")
sections.append("## 3. Cost Breakdown by Component")
sections.append("")
sections.append(
"| Component | Cost/Request | Cost/Day | Cost/Month | % of Total |"
)
sections.append(
"|------------|--------------|-----------|-----------|-------------|"
)
dist_map = {d["component"]: d["percentage"] for d in distribution}
for comp in breakdown.components:
pct = dist_map.get(comp.name, 0.0)
sections.append(
f"| {comp.name} | ${comp.cost_per_request:.6f} | "
f"${comp.daily_cost:.2f} | ${comp.monthly_cost:.2f} | "
f"{pct:.1f}% |"
)
sections.append(
f"| **TOTAL** | **${breakdown.avg_cost_per_request:.6f}** | "
f"**${breakdown.total_daily:.2f}** | "
f"**${breakdown.total_monthly:.2f}** | **100%** |"
)
sections.append("")
sections.append("---")
sections.append("")
sections.append("## 4. Cost Distribution")
sections.append("")
sections.append("```")
for item in distribution:
bar_len = int(item["percentage"] / 2)
bar = "█" * bar_len
spaces = " " * (25 - bar_len)
sections.append(
f" {item['component']:<18} {item['percentage']:>5.1f}% {bar}{spaces}"
)
sections.append("```")
sections.append("")
sections.append("Data for a pie chart:")
sections.append("")
sections.append("```python")
sections.append("pie_chart_data = {")
for item in distribution:
sections.append(
f' "{item["component"]}": {item["percentage"]:.1f},'
)
sections.append("}")
sections.append("```")
sections.append("")
sections.append("---")
sections.append("")
sections.append("## 5. Key Baseline Metrics")
sections.append("")
sections.append(
f"- **Total monthly cost:** ${breakdown.total_monthly:.2f}"
)
sections.append(
f"- **Total annual cost (projected):** ${breakdown.total_yearly:,.2f}"
)
sections.append(
f"- **Average cost per request:** ${breakdown.avg_cost_per_request:.6f}"
)
top = distribution[0] if distribution else None
if top:
sections.append(
f"- **Most expensive component:** {top['component']} "
f"({top['percentage']:.1f}%)"
)
sections.append(
f"- **Monthly requests:** {params.requests_per_day * 30:,}"
)
sections.append("")
sections.append("---")
sections.append("")
sections.append("## 6. Reference Pricing")
sections.append("")
sections.append(f"| Item | Price |")
sections.append(f"|----------|--------|")
sections.append(
f"| {pricing.model} input | ${pricing.input_per_1m}/1M tokens |"
)
sections.append(
f"| {pricing.model} output | ${pricing.output_per_1m}/1M tokens |"
)
if pricing.embedding_model:
sections.append(
f"| {pricing.embedding_model} | "
f"${pricing.embedding_per_1m}/1M tokens |"
)
sections.append(
f"| Storage | ${params.storage_cost_per_gb}/GB/month |"
)
sections.append("")
sections.append("---")
sections.append("")
sections.append("## 7. For Module 8: Benchmark Reference")
sections.append("")
sections.append(
"This baseline is used as the 'before' reference in the capstone "
"project (Module 8)."
)
sections.append(
"After applying the optimizations from modules 3-7, a new 'after'"
)
sections.append(
"breakdown will be generated and the reduction percentage calculated."
)
sections.append("")
sections.append("```")
sections.append("Benchmark Template:")
sections.append(
f" BEFORE (this document): ${breakdown.total_monthly:.2f}/month"
)
sections.append(" AFTER (Module 8): $____/month")
sections.append(" REDUCTION: ____%")
sections.append("")
sections.append("Target portfolio statement:")
sections.append(
f' "${breakdown.total_monthly:.0f}/month → $___/month (___% reduction)"'
)
sections.append("```")
sections.append("")
sections.append("---")
sections.append("")
sections.append(
f"*Automatically generated on {breakdown.calculated_at} "
f"by Cost Breakdown Calculator — Module 1, Guide #19*"
)
content = "\n".join(sections)
with open(output_path, "w", encoding="utf-8") as f:
f.write(content)
return content
Step 5: Main script (run_calculator.py)
This is the script you run. It defines your system's parameters and generates everything.
# run_calculator.py
from cost_calculator import (
CostBreakdownCalculator,
SystemParameters,
format_report,
format_comparison,
)
from baseline_generator import generate_baseline_document
def main():
# -------------------------------------------------------
# STEP 1: Define your system's parameters
# -------------------------------------------------------
# Adjust these values to your real case.
# The example values represent a RAG chatbot
# with moderate traffic.
params = SystemParameters(
model="gpt-4o",
avg_input_tokens=800,
avg_output_tokens=400,
requests_per_day=500,
embedding_requests_per_day=600,
avg_embedding_tokens=500,
retry_rate=0.05,
context_waste_pct=0.15,
storage_gb_per_month=2.0,
storage_cost_per_gb=0.023,
system_description="Internal RAG chatbot — technical support for employees",
)
# -------------------------------------------------------
# STEP 2: Calculate the breakdown
# -------------------------------------------------------
calculator = CostBreakdownCalculator(params)
breakdown = calculator.calculate()
# -------------------------------------------------------
# STEP 3: Print the report to the console
# -------------------------------------------------------
report = format_report(breakdown)
print(report)
# -------------------------------------------------------
# STEP 4: Multi-provider comparison
# -------------------------------------------------------
print()
comparison = format_comparison(
input_tokens=params.avg_input_tokens,
output_tokens=params.avg_output_tokens,
requests_per_day=params.requests_per_day,
)
print(comparison)
# -------------------------------------------------------
# STEP 5: Generate the baseline document (THE MOST IMPORTANT)
# -------------------------------------------------------
print()
print("=" * 70)
print(" GENERATING BASELINE DOCUMENT...")
print("=" * 70)
baseline_content = generate_baseline_document(
breakdown,
output_path="baseline_report.md",
)
print()
print(" ✅ Baseline document generated: baseline_report.md")
print()
print(
" ⚠️ SAVE THIS FILE. You need it as the"
)
print(
' "before" reference for the Module 8 benchmark.'
)
print()
print(f" 📊 Baseline monthly total: ${breakdown.total_monthly:.2f}")
print(
f" 📊 Cost per request: ${breakdown.avg_cost_per_request:.6f}"
)
print()
print(" Your portfolio statement will start with:")
print(
f' "${breakdown.total_monthly:.0f}/month → $___/month (___% reduction)"'
)
print("=" * 70)
# -------------------------------------------------------
# STEP 6: Alternative scenario — what about another model?
# -------------------------------------------------------
print()
print("=" * 70)
print(" ALTERNATIVE SCENARIO: gpt-4o-mini")
print("=" * 70)
params_mini = SystemParameters(
model="gpt-4o-mini",
avg_input_tokens=params.avg_input_tokens,
avg_output_tokens=params.avg_output_tokens,
requests_per_day=params.requests_per_day,
embedding_requests_per_day=params.embedding_requests_per_day,
avg_embedding_tokens=params.avg_embedding_tokens,
retry_rate=params.retry_rate,
context_waste_pct=params.context_waste_pct,
storage_gb_per_month=params.storage_gb_per_month,
storage_cost_per_gb=params.storage_cost_per_gb,
system_description=params.system_description + " (gpt-4o-mini scenario)",
)
calc_mini = CostBreakdownCalculator(params_mini)
breakdown_mini = calc_mini.calculate()
report_mini = format_report(breakdown_mini)
print(report_mini)
savings = breakdown.total_monthly - breakdown_mini.total_monthly
savings_pct = (savings / breakdown.total_monthly) * 100 if breakdown.total_monthly > 0 else 0
print(
f"\n 💡 Switching from {params.model} to gpt-4o-mini would save "
f"${savings:.2f}/month ({savings_pct:.1f}%)"
)
print(
" (You'll explore this in depth in Module 7: Model Selection)"
)
print()
if __name__ == "__main__":
main()
Step 6: Run the project
cd cost-breakdown-calculator
python run_calculator.py
Expected Output
When you run run_calculator.py, you'll see three blocks of output:
Main report
======================================================================
COST BREAKDOWN REPORT
======================================================================
Date: 2026-03-13 14:30:00
Model: gpt-4o (OpenAI)
Requests: 500/day
System: Internal RAG chatbot — technical support for employees
======================================================================
BREAKDOWN BY COMPONENT
------------------------------------------------------------------
Component Per Request Daily Monthly
------------------------------------------------------------------
Tokens Input $ 0.002000 $ 1.00 $ 30.00
Tokens Output $ 0.004000 $ 2.00 $ 60.00
Embeddings $ 0.000010 $ 0.01 $ 0.18
Retries $ 0.006000 $ 0.15 $ 4.50
Context Waste $ 0.000300 $ 0.15 $ 4.50
Storage $ 0.000003 $ 0.00 $ 0.05
------------------------------------------------------------------
TOTAL $ 0.006615 $ 3.31 $ 99.23
COST DISTRIBUTION (data for a pie chart)
--------------------------------------------------
Tokens Output 60.5% ██████████████████████████████
Tokens Input 30.2% ███████████████
Retries 4.5% ██
Context Waste 4.5% ██
Embeddings 0.2%
Storage 0.0%
ANNUAL PROJECTION
--------------------------------------------------
Estimated annual total: $1,190.71
Average cost per request: $0.006615
======================================================================
Note: The exact numbers depend on the parameters you configure. The ones above correspond to the example scenario (RAG chatbot, 500 req/day, gpt-4o). Your output will show slightly different values depending on your system's floating-point precision.
Multi-provider comparison
======================================================================
MULTI-PROVIDER COMPARISON
For: 800 input + 400 output tokens/req, 500 req/day
======================================================================
Provider Model Per Req Daily Monthly
------------------------------------------------------------------
OpenAI gpt-4o-mini $0.000360 $ 0.18 $ 5.40
OpenAI gpt-3.5-turbo $0.001000 $ 0.50 $ 15.00
Anthropic claude-3.5-haiku $0.002240 $ 1.12 $ 33.60
OpenAI gpt-4o $0.006000 $ 3.00 $ 90.00
Anthropic claude-sonnet-4 $0.008400 $ 4.20 $ 126.00
OpenAI gpt-4-turbo $0.020000 $ 10.00 $ 300.00
Anthropic claude-3-opus $0.042000 $ 21.00 $ 630.00
======================================================================
Generated baseline document
After the run, you'll find baseline_report.md in your directory. This Markdown file contains the 7 sections of the formal baseline — it's your main deliverable.
Verifying the Baseline Document
Open baseline_report.md and verify it contains all of these sections:
| # | Section | What it must contain |
|---|---|---|
| 1 | General Information | Date, system, model, requests/day, retry rate |
| 2 | System Parameters | Input/output tokens, embeddings, storage |
| 3 | Breakdown by Component | Table with cost/req, cost/day, cost/month, % of total |
| 4 | Cost Distribution | ASCII bar chart + pie chart data in Python |
| 5 | Key Metrics | Monthly total, annual, per request, most expensive component |
| 6 | Reference Pricing | Model prices used in the calculations |
| 7 | Benchmark Reference | Template for Module 8 with BEFORE already filled in |
If any section is missing or has $0.00 values where it shouldn't, review your SystemParameters.
Customization: Use Your Real Numbers
The example scenario uses reasonable values for a RAG chatbot. But the real value of the project is in using your own numbers. Modify SystemParameters in run_calculator.py:
# If you have a content generation system with GPT-4 Turbo
params = SystemParameters(
model="gpt-4-turbo",
avg_input_tokens=2000, # Long system prompt + context
avg_output_tokens=1500, # Generates articles/reports
requests_per_day=200,
embedding_requests_per_day=0, # No RAG
retry_rate=0.08, # 8% — frequent rate limiting
context_waste_pct=0.20, # 20% of context wasted
storage_gb_per_month=5.0,
system_description="Report generation system with GPT-4 Turbo",
)
# If you have a high-volume RAG system with Claude
params = SystemParameters(
model="claude-sonnet-4",
avg_input_tokens=3000, # Document chunks + history
avg_output_tokens=600,
requests_per_day=2000,
embedding_requests_per_day=0, # Anthropic has no embeddings of its own
retry_rate=0.03,
context_waste_pct=0.12,
storage_gb_per_month=10.0,
system_description="RAG pipeline — legal documentation (Claude Sonnet)",
)
Each scenario generates its own baseline. If you operate multiple systems, generate a baseline for each one.
Troubleshooting
Error 1: ModuleNotFoundError: No module named 'tiktoken'
pip install tiktoken
# If you use venv, make sure it's activated:
source venv/bin/activate
pip install tiktoken
Error 2: KeyError: 'model-that-does-not-exist'
The model you passed in SystemParameters.model isn't in the provider_pricing.py catalog. The available models are: gpt-4o, gpt-4o-mini, gpt-4-turbo, gpt-3.5-turbo, claude-sonnet-4, claude-3.5-haiku, claude-3-opus. If you need another one, add it to PRICING_CATALOG.
Error 3: Every cost comes out as $0.00
Check that requests_per_day is greater than 0. If you use embeddings, verify that embedding_requests_per_day > 0 too. A value of 0 requests produces $0 costs — mathematically correct, but useless as a baseline.
Error 4: FileNotFoundError when importing modules
Make sure you're running from the project directory:
cd cost-breakdown-calculator
python run_calculator.py
If you run from another directory, Python won't find provider_pricing.py or baseline_generator.py.
Error 5: The baseline document isn't generated
Verify you have write permissions in the directory. generate_baseline_document() writes baseline_report.md to the current directory. If it fails silently, try an absolute path:
generate_baseline_document(breakdown, output_path="/tmp/baseline_report.md")
Error 6: The distribution percentages don't add up to 100%
This can happen from floating-point rounding. A difference of ±0.1% is normal and doesn't affect your baseline. If the difference is larger, check that you don't have components with negative costs.
Error 7: TypeError: unsupported format character
Check that you aren't using f-strings inside the report's format strings. If you modified format_report(), make sure you don't mix % with {} in the same string.
Completeness Checklist
Before calling the project done, verify every point:
Working code
-
provider_pricing.pyimports without errors -
cost_calculator.pyimports without errors -
baseline_generator.pyimports without errors -
run_calculator.pyruns end to end without errors - The report prints correctly to the console
- The multi-provider comparison prints correctly
Correct calculations
- All 6 components appear in the breakdown (Input, Output, Embeddings, Retries, Context Waste, Storage)
- Output Tokens cost more than Input Tokens (ratio ≈ 2-4x)
- The retry costs reflect the configured
retry_rate - The distribution percentages add up to approximately 100%
- Monthly cost = daily cost × 30
Baseline document (THE MOST IMPORTANT)
-
baseline_report.mdwas generated - It contains the 7 documented sections
- The measurement date is correct
- The system description is present
- The breakdown has non-zero values for active components
- The Module 8 template has the BEFORE value filled in
- The file opens and reads as valid Markdown
Multi-provider
- The comparison includes at least 4 models
- The models are sorted from cheapest to most expensive
- gpt-4o-mini appears as cheaper than gpt-4o
- claude-3-opus appears as the most expensive
Understanding
- You can explain why output tokens dominate the cost distribution
- You can identify which component to attack first to cut costs
- You understand that the baseline is the key deliverable for Module 8
Connection to the Following Modules
Module 2: Cost Analysis & Tracking
The calculator you built here is static — you use average values. In Module 2, you'll connect it to real data from your system using the monitoring stack from Guide #18. Instead of avg_input_tokens=800, you'll read the real value from your metrics. The baseline becomes more accurate.
Module 3: Prompt Optimization
You looked at the distribution and "Output Tokens" dominates. Module 3 teaches you to cut tokens 30-50% without losing quality — concise system prompts, efficient templates, targeted responses. Every token you eliminate shows up directly in your calculator.
Modules 4-6: Caching
The multi-provider comparison shows that switching models cuts costs, but there's still a cost per request. Caching eliminates entire requests — if the answer is already in the cache, the cost is $0. Semantic caching (Module 6) goes further: similar queries, not just identical ones, get served from cache.
Module 7: Model Selection
The alternative scenario with gpt-4o-mini already showed you the impact of switching models. Module 7 systematizes this with intelligent routing: simple queries go to cheap models, complex queries go to capable ones.
Module 8: Capstone Project — The Benchmark
This is the module that gives your baseline its meaning. You'll take your baseline_report.md, apply the optimizations from modules 3-7, generate a new "after" breakdown, and calculate:
Reduction = ((before - after) / before) × 100
Example:
BEFORE: $99.23/month (your baseline today)
AFTER: $29.77/month (after optimizations)
REDUCTION: 70%
Portfolio statement:
"$99/month → $30/month (70% reduction) by implementing semantic caching,
prompt optimization, and model selection routing"
Without this module's baseline, that calculation is impossible. Save baseline_report.md — it's your most valuable artifact from all of Module 1.
Summary
- The project has two deliverables: the
CostBreakdownCalculator(a reusable tool) andbaseline_report.md(a formal cost document). The second one matters more than the first. - 6 cost components get calculated: input tokens, output tokens, embeddings, retries, context waste, and storage. Each with a per-request, daily, and monthly cost.
- The cost distribution reveals that output tokens typically dominate (50-65% of the total), followed by input tokens. This distribution guides which optimization to prioritize.
- The multi-provider comparison shows differences of 10-100x between models, from gpt-4o-mini to claude-3-opus.
- The baseline document contains 7 sections with all the information needed for the Module 8 benchmark: date, parameters, breakdown, distribution, key metrics, pricing, and benchmark template.
- All the code is local — no API calls, no execution cost. The calculations use published pricing and configurable parameters.
- The baseline is the "before" of the portfolio statement: "$X/month → $Y/month (Z% reduction)." Without it, Module 8 can't demonstrate ROI.
Additional Resources
- OpenAI Pricing — Up-to-date pricing for every OpenAI model (check against
PRICING_CATALOG) - Anthropic Pricing — Claude pricing (check against
PRICING_CATALOG) - tiktoken GitHub — Official token counting library, used to validate your averages
- OpenAI Tokenizer Tool — Visual tool to explore how many tokens a text consumes
- LLM Pricing Comparison (llmprices.dev) — Up-to-date price comparison across providers
- AWS S3 Pricing — Reference for the storage cost used in the calculations
Created: March 2026 Version: 1.0