Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

LLM Cost Optimization

Overview

LLM inference is expensive. A production application processing 1M requests/month can easily spend $10K-100K+ on API costs. This page covers the practical levers for reducing spend: token economics, caching, model routing, quantization, and batching. For deep dives on quantization and batching, see dedicated pages.

Token Economics

Pricing Structure

All major providers price by token, with output tokens costing 3-5× more than input tokens:

Provider / ModelInput (per 1M tokens)Output (per 1M tokens)Ratio
GPT-4o$2.50$10.00
GPT-4o-mini$0.15$0.60
Claude 3.5 Sonnet$3.00$15.00
Claude 3 Haiku$0.25$1.25
Gemini 1.5 Pro$1.25$5.00
Gemini 1.5 Flash$0.075$0.30

Prices as of mid-2025. Always verify at OpenAI, Anthropic, Google.

Cost Per Request Estimation

cost = (input_tokens × input_price + output_tokens × output_price) / 1_000_000
ScenarioInputOutputGPT-4o CostGPT-4o-mini Cost
Simple Q&A200 tok150 tok$0.0020$0.00012
RAG (5 chunks + query)3,000 tok500 tok$0.0125$0.00075
Long document summary50,000 tok2,000 tok$0.1325$0.00795
Agent (3 tool calls)6,000 tok1,500 tok$0.0300$0.00180

Key insight: For RAG-heavy applications, input tokens dominate cost (retrieved context). For generation-heavy applications (summarization, code generation), output tokens dominate. Optimize the dominant dimension first.

Caching Strategies

Prompt Caching (Provider-Side)

Providers cache the KV cache for repeated prompt prefixes, eliminating redundant compute:

ProviderMechanismSavingsHow to Use
AnthropicExplicit cache control markers in API90% on cached tokensAdd cache_control: {type: "ephemeral"} to system prompt blocks
OpenAIAutomatic prefix caching50% on cached input tokensPut static content at the beginning of the prompt; no code changes needed
GoogleContext caching API~75%Explicitly cache context objects with TTL
vLLM (self-hosted)--enable-prefix-caching100% (no API cost, saves compute)Enable flag at launch

Best practice: Structure prompts so the system prompt, few-shot examples, and tool definitions form a static prefix that is cached across requests. Only the user query and retrieved RAG context should vary per request. Reference: Anthropic Prompt Caching.

Semantic Caching (Application-Side)

Store LLM responses keyed by the semantic similarity of the input query. When a new query is semantically similar to a cached query, return the cached response instead of calling the LLM.

Query: "What is the refund policy?" → Cache miss → Call LLM → Cache result
Query: "How do I get a refund?" → Cosine sim > 0.95 → Cache hit → Return cached response
ToolApproach
GPTCacheEmbed queries, use vector similarity for cache lookup
Custom (Redis + embeddings)Embed query, check Redis for similar vectors within threshold
LiteLLMBuilt-in semantic caching support

Trade-offs: Semantic caching saves cost and latency but risks stale responses when underlying data changes. Cache invalidation must be tied to data updates. Not suitable for highly personalized or time-sensitive queries.

Model Routing

Not every query needs the most expensive model. Route queries to the cheapest model that can handle them:

Query ComplexityModelCost Reduction vs GPT-4o
Classification, extractionGPT-4o-mini / Claude Haiku / Gemini Flash15-30×
Standard Q&A, summarizationGPT-4o / Claude 3.5 Sonnet1× (baseline)
Complex reasoning, codingGPT-4o / Claude 3.5 Sonnet / o11× (baseline)
Simple routing / intent detectionFine-tuned small model (Llama 3 8B)50-100× (self-hosted)

Router Implementation

# Simple router pattern
def route_query(query: str) -> str:
    intent = lightweight_classifier(query)  # GPT-4o-mini or local model
    if intent in ["simple_qa", "classification", "extraction"]:
        return "gpt-4o-mini"
    elif intent in ["complex_reasoning", "code_generation"]:
        return "gpt-4o"
    elif intent in ["creative_writing", "brainstorming"]:
        return "claude-3.5-sonnet"
    else:
        return "gpt-4o"  # default to capable model

Cascading routing is more sophisticated: try the cheapest model first, then fall back to a more expensive one if the output quality is insufficient (measured by a lightweight quality classifier). This maximizes savings while maintaining quality.

Quantization

Quantization reduces model precision (FP16 → INT8 → INT4) to shrink memory and compute requirements. Essential for self-hosted models; not applicable when using API providers.

MethodMemory ReductionQuality ImpactBest For
INT8<0.5% perplexity increaseProduction GPU servers
INT4 (AWQ/GPTQ)2-4% perplexity increaseConsumer GPUs, cost-constrained servers
GGUF Q4_K_M~3.5×1.5% perplexity increaseCPU/edge (Ollama)
FP8Near-losslessH100/H200 GPUs (native hardware support)

See quantization.md for full details on methods, benchmarks, and implementation.

Batching

Batching processes multiple requests simultaneously, amortizing weight loading across the batch. This is the single most impactful optimization for self-hosted model throughput.

StrategyThroughput GainLatency ImpactBest For
Static batching5-10×High (wait for batch)Offline processing
Dynamic batching (continuous batching)10-20×LowReal-time serving (vLLM, TGI)
In-flight batching15-25×Very lowHigh-concurrency serving

See batching.md for full details on continuous batching, PagedAttention, and implementation.

Cost Optimization Decision Framework

graph TD
    START[Need to reduce LLM costs?] --> FIRST{Biggest cost driver?}
    FIRST -->|API provider| CACHING[Prompt caching + semantic caching]
    FIRST -->|Self-hosted| QUANT[Quantization + batching]
    FIRST -->|Mixed workload| ROUTING[Model routing]

    CACHING --> TOKENS[Reduce input tokens: compress prompts, fewer RAG chunks]
    QUANT --> SERVE[Optimize serving: vLLM, PagedAttention, FP8]
    ROUTING --> EVAL[Evaluate: can smaller models handle some queries?]

    TOKENS --> MONITOR[Monitor: cost per request, budget alerts]
    SERVE --> MONITOR
    EVAL --> MONITOR

Interview Questions

Q1: How would you reduce LLM costs for a production RAG application spending $50K/month?

Answer: Systematic approach: (1) Profile: Identify where tokens are spent (input vs output, which queries are most expensive). (2) Prompt caching: Structure prompts with static prefix (system prompt + examples) for provider-side caching (50-90% savings on cached tokens). (3) Model routing: Classify query complexity; route simple queries to a cheaper model (GPT-4o-mini at 15× cheaper). (4) Reduce context: Rerank aggressively to use fewer retrieved chunks (5 instead of 15); truncate conversation history. (5) Semantic caching: Cache responses for common/similar queries. (6) Output length control: Set max_tokens and use concise system prompts. (7) Monitor: Track cost per request and set budget alerts. Expected savings: 50-80% without quality degradation.

Q2: When would you choose self-hosting over API-based LLMs?

Answer: Self-host when: (1) Data privacy requires keeping data on-premises (healthcare, finance, defense). (2) Volume is high enough that GPU costs are cheaper than API costs (typically >1B tokens/month for a 7B model). (3) Low latency requirements make API round-trips unacceptable (sub-100ms TTFT). (4) Customization requires fine-tuned models not available through APIs. (5) Vendor independence is critical (avoid lock-in, ensure availability). Trade-offs: self-hosting requires ML infrastructure expertise, GPU procurement, model serving engineering, and operational overhead. For most startups, APIs are cheaper until significant scale.

Q3: Explain prompt caching and semantic caching. When would you use each?

Answer: Prompt caching (provider-side): The LLM provider caches the KV cache for repeated prompt prefixes. If multiple requests share the same system prompt, the provider skips recomputing those attention layers. No code changes needed for OpenAI (automatic). Anthropic requires explicit cache markers. Best for: applications with large static system prompts and many concurrent requests. Semantic caching (application-side): Your application stores LLM responses keyed by query embeddings. When a new query is semantically similar (cosine similarity > threshold), return the cached response. Best for: FAQ-like traffic where many users ask similar questions. Key difference: prompt caching reduces compute cost per request at the provider level; semantic caching eliminates the LLM call entirely.

Q4: How does output token pricing affect system design decisions?

Answer: Output tokens cost 3-5× more than input tokens, so output length is the dominant cost factor for generation tasks. System design implications: (1) Set max_tokens to the minimum needed — don’t default to the model’s maximum. (2) Use concise system prompts (“respond in under 100 words”) to constrain output length. (3) For extraction/classification tasks, use structured outputs (JSON Schema) which produce minimal, predictable-length outputs. (4) For summarization, specify target length explicitly. (5) Monitor average output tokens per query type and set alerts on increases. A 20% increase in average output length can increase costs by 20-50% depending on the input/output ratio.

References

  1. OpenAI Pricing — https://platform.openai.com/pricing
  2. Anthropic Pricing — https://docs.anthropic.com/en/docs/about-claude/pricing
  3. Anthropic, “Prompt Caching” — https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching
  4. Google AI Pricing — https://ai.google.dev/pricing
  5. LiteLLM — https://github.com/BerriAI/litellm
  6. GPTCache — https://github.com/zilliztech/GPTCache

Cross-References