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:

ComponentWhat it calculatesSource capsule
Input TokensCost of input tokens per request and monthlyCapsules 02, 03
Output TokensCost of output tokens (2-4x more expensive than input)Capsules 02, 03
EmbeddingsCost of generating embeddings for RAG/searchCapsules 05, 06
RetriesExtra cost from failed requests that get resentCapsule 05
Context WasteCost of tokens wasted by an inefficient context windowCapsule 05
StorageEstimated cost of storing logs and responsesCapsule 06
Multi-ProviderSame workload on OpenAI vs AnthropicCapsule 04
Baseline DocumentFormal document with date, breakdown, percentagesCapsule 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:

#SectionWhat it must contain
1General InformationDate, system, model, requests/day, retry rate
2System ParametersInput/output tokens, embeddings, storage
3Breakdown by ComponentTable with cost/req, cost/day, cost/month, % of total
4Cost DistributionASCII bar chart + pie chart data in Python
5Key MetricsMonthly total, annual, per request, most expensive component
6Reference PricingModel prices used in the calculations
7Benchmark ReferenceTemplate 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.py imports without errors
  • cost_calculator.py imports without errors
  • baseline_generator.py imports without errors
  • run_calculator.py runs 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.md was 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) and baseline_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

  1. OpenAI Pricing — Up-to-date pricing for every OpenAI model (check against PRICING_CATALOG)
  2. Anthropic Pricing — Claude pricing (check against PRICING_CATALOG)
  3. tiktoken GitHub — Official token counting library, used to validate your averages
  4. OpenAI Tokenizer Tool — Visual tool to explore how many tokens a text consumes
  5. LLM Pricing Comparison (llmprices.dev) — Up-to-date price comparison across providers
  6. AWS S3 Pricing — Reference for the storage cost used in the calculations

Created: March 2026 Version: 1.0