The Model Landscape (2024–2025)
The number of capable LLMs has exploded. Choosing the right one is now a core engineering decision — it affects cost, latency, quality, and vendor risk. Here are the major families:
Major Model Families
- GPT (OpenAI) — GPT-4o, GPT-4o-mini, o1. Best all-rounder, strong at code and reasoning. Closed source.
- Claude (Anthropic) — Claude 3.5 Sonnet, Claude 3 Opus/Haiku. Excellent at long-context, nuanced writing, and following complex instructions. Closed source.
- Llama (Meta) — Llama 3 8B/70B/405B. Top open-source model. Self-hostable. Great cost efficiency at scale.
- Mistral — Mistral 7B, Mixtral 8x7B, Mistral Large. European, open-weight (small models), strong coding performance.
- Gemini (Google) — Gemini 1.5 Pro/Flash. Massive context window (1M+), strong multimodal, tight Google Cloud integration.
Model Comparison
| Model | Context | Input $/1M tok | Output $/1M tok | Strengths |
|---|---|---|---|---|
| GPT-4o | 128K | $2.50 | $10.00 | Best all-rounder, multimodal, fast |
| GPT-4o-mini | 128K | $0.15 | $0.60 | Incredible value, good for most tasks |
| Claude 3.5 Sonnet | 200K | $3.00 | $15.00 | Long-context, coding, instruction-following |
| Claude 3 Haiku | 200K | $0.25 | $1.25 | Fast + cheap, good for classification |
| Llama 3 70B | 128K | ~$0.60* | ~$0.80* | Open source, self-hostable, no vendor lock-in |
| Mistral Large | 128K | $2.00 | $6.00 | Strong coding, multilingual, EU-based |
| Gemini 1.5 Pro | 1M+ | $1.25 | $5.00 | Massive context, multimodal, Google ecosystem |
* Llama pricing varies by hosting provider (Together, Fireworks, Groq, self-hosted).
Cost Per 1M Tokens (Input)
For 80% of production tasks, GPT-4o-mini or Claude 3 Haiku is sufficient. Reserve frontier models (GPT-4o, Claude 3.5 Sonnet) for complex reasoning, nuanced generation, or when quality directly impacts revenue. The cost difference can be 10-20x.
Understanding Benchmarks
Benchmarks give directional signal but are not the final word. Models are increasingly optimized for benchmarks specifically, reducing their predictive value for real-world tasks.
Key Benchmarks
| Benchmark | Measures | Useful For |
|---|---|---|
| MMLU | Broad knowledge (57 subjects) | General capability comparison |
| HumanEval | Python code generation (pass@1) | Coding assistant quality |
| GSM8K | Grade-school math reasoning | Multi-step logical reasoning |
| MT-Bench | Multi-turn conversation quality | Chatbot/assistant use cases |
| LMSYS Chatbot Arena | Human preference (ELO rating) | Real-world user satisfaction |
A model scoring 90% on HumanEval might still fail on your specific coding tasks. Benchmark contamination (training on test data) is a known issue. Always run your own evals on YOUR data before committing to a model.
Open Source vs Closed Source
| Factor | Open Source (Llama, Mistral) | Closed Source (GPT-4, Claude) |
|---|---|---|
| Cost at scale | Lower (self-host, no per-token fees) | Higher (pay per token always) |
| Quality (2024) | Good — 90% of frontier for most tasks | Best — still leads on complex reasoning |
| Data privacy | Full control — data never leaves your infra | Trust the provider's policies |
| Customization | Full fine-tuning, custom training | Limited fine-tuning via API |
| Ops complexity | High — GPUs, serving infra, monitoring | Low — just API calls |
| Vendor risk | None — you own the weights | API deprecation, price changes, policy shifts |
When to Go Open Source
- You process >1M tokens/day and cost matters
- Data must stay on-premise (healthcare, finance, gov)
- You need custom fine-tuning for a domain-specific task
- You can't accept vendor lock-in risk
Otherwise, start with closed-source APIs. The simplicity and quality are hard to beat for early-stage products.
Decision Framework: How to Choose a Model
Follow this flowchart to narrow your choice:
- What's your budget? If ultra-low → GPT-4o-mini or Claude Haiku. If cost isn't primary → continue.
- Do you need the absolute best quality? Yes → GPT-4o or Claude 3.5 Sonnet. No → continue.
- Is data privacy critical? Yes → Llama 3 (self-hosted) or Azure OpenAI (enterprise agreement). No → continue.
- Do you need massive context (>200K)? Yes → Gemini 1.5 Pro. No → continue.
- Is latency critical (<500ms)? Yes → GPT-4o-mini, Groq (Llama), or Claude Haiku. No → use the best within budget.
- Default answer: Start with GPT-4o-mini. Upgrade to GPT-4o or Claude 3.5 Sonnet only where quality gaps appear in your evals.
Latency Tradeoffs
Model size directly correlates with latency. Here are typical time-to-first-token (TTFT) values:
For interactive applications (chat, copilots), target <1 second TTFT. For batch processing (classification, extraction), latency matters less — optimize for cost instead.
Mini-Project: Model Comparison Benchmark
🛠️ Build a Model Benchmark Script
Compare models on your own test cases — measuring quality, latency, and cost. This is how you make data-driven model decisions.
"""
Model Comparison Benchmark
Compare multiple models on the same prompts, measuring quality, latency, and cost.
"""
import os
import time
import json
from dataclasses import dataclass, asdict
from openai import OpenAI
import anthropic
@dataclass
class BenchmarkResult:
model: str
prompt_name: str
response: str
latency_ms: float
input_tokens: int
output_tokens: int
estimated_cost: float
# ─── Configuration ───────────────────────────────────────────
OPENAI_MODELS = ["gpt-4o", "gpt-4o-mini"]
ANTHROPIC_MODELS = ["claude-sonnet-4-20250514", "claude-3-haiku-20240307"]
# Pricing per 1M tokens
PRICING = {
"gpt-4o": {"input": 2.50, "output": 10.00},
"gpt-4o-mini": {"input": 0.15, "output": 0.60},
"claude-sonnet-4-20250514": {"input": 3.00, "output": 15.00},
"claude-3-haiku-20240307": {"input": 0.25, "output": 1.25},
}
# Test prompts — adjust these to match YOUR use case
TEST_PROMPTS = {
"code_generation": {
"system": "You are a Python expert. Write clean, well-commented code.",
"user": "Write a function that finds the longest palindromic substring in a string. Include type hints and a docstring.",
},
"summarization": {
"system": "You summarize text concisely.",
"user": "Summarize in 2-3 sentences: Machine learning operations (MLOps) is a set of practices that aims to deploy and maintain machine learning models in production reliably and efficiently. The word is a compound of machine learning and the continuous development practice of DevOps. MLOps involves automating and monitoring all steps of ML system construction, including integration, testing, releasing, deployment, and infrastructure management.",
},
"reasoning": {
"system": "You solve logic puzzles step by step.",
"user": "If all roses are flowers, and some flowers fade quickly, can we conclude that some roses fade quickly? Explain your reasoning.",
},
"classification": {
"system": "Classify the sentiment as positive, negative, or neutral. Reply with ONE word only.",
"user": "The product works fine but the customer service was absolutely terrible and I waited 3 hours on hold.",
},
}
# ─── Benchmark Functions ─────────────────────────────────────
def benchmark_openai(model: str, system: str, user: str) -> BenchmarkResult:
"""Benchmark a single OpenAI model call."""
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
start = time.perf_counter()
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": system},
{"role": "user", "content": user},
],
temperature=0,
max_tokens=500,
)
latency = (time.perf_counter() - start) * 1000
usage = response.usage
cost = (
(usage.prompt_tokens / 1_000_000) * PRICING[model]["input"]
+ (usage.completion_tokens / 1_000_000) * PRICING[model]["output"]
)
return BenchmarkResult(
model=model,
prompt_name="",
response=response.choices[0].message.content,
latency_ms=round(latency, 1),
input_tokens=usage.prompt_tokens,
output_tokens=usage.completion_tokens,
estimated_cost=round(cost, 6),
)
def benchmark_anthropic(model: str, system: str, user: str) -> BenchmarkResult:
"""Benchmark a single Anthropic model call."""
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
start = time.perf_counter()
response = client.messages.create(
model=model,
max_tokens=500,
system=system,
messages=[{"role": "user", "content": user}],
temperature=0,
)
latency = (time.perf_counter() - start) * 1000
usage = response.usage
cost = (
(usage.input_tokens / 1_000_000) * PRICING[model]["input"]
+ (usage.output_tokens / 1_000_000) * PRICING[model]["output"]
)
return BenchmarkResult(
model=model,
prompt_name="",
response=response.content[0].text,
latency_ms=round(latency, 1),
input_tokens=usage.input_tokens,
output_tokens=usage.output_tokens,
estimated_cost=round(cost, 6),
)
def run_benchmark() -> list[BenchmarkResult]:
"""Run all benchmarks and return results."""
results = []
for prompt_name, prompt in TEST_PROMPTS.items():
print(f"\n{'='*60}")
print(f" Testing: {prompt_name}")
print(f"{'='*60}")
for model in OPENAI_MODELS:
print(f" Running {model}...", end=" ", flush=True)
result = benchmark_openai(model, prompt["system"], prompt["user"])
result.prompt_name = prompt_name
results.append(result)
print(f"{result.latency_ms}ms, ${result.estimated_cost:.6f}")
for model in ANTHROPIC_MODELS:
print(f" Running {model}...", end=" ", flush=True)
result = benchmark_anthropic(model, prompt["system"], prompt["user"])
result.prompt_name = prompt_name
results.append(result)
print(f"{result.latency_ms}ms, ${result.estimated_cost:.6f}")
return results
def print_summary(results: list[BenchmarkResult]):
"""Print a summary table of results."""
print(f"\n\n{'='*80}")
print(" BENCHMARK SUMMARY")
print(f"{'='*80}\n")
# Group by prompt
prompts = list(TEST_PROMPTS.keys())
models = OPENAI_MODELS + ANTHROPIC_MODELS
# Latency summary
print(f"{'Model':<30} {'Avg Latency':<15} {'Avg Cost':<15} {'Avg Tokens Out'}")
print("-" * 75)
for model in models:
model_results = [r for r in results if r.model == model]
if not model_results:
continue
avg_latency = sum(r.latency_ms for r in model_results) / len(model_results)
avg_cost = sum(r.estimated_cost for r in model_results) / len(model_results)
avg_tokens = sum(r.output_tokens for r in model_results) / len(model_results)
print(f"{model:<30} {avg_latency:>8.0f}ms ${avg_cost:<12.6f} {avg_tokens:.0f}")
# Save full results
output_file = "benchmark_results.json"
with open(output_file, "w") as f:
json.dump([asdict(r) for r in results], f, indent=2)
print(f"\nFull results saved to {output_file}")
if __name__ == "__main__":
results = run_benchmark()
print_summary(results)
Running the Benchmark
# Install dependencies
pip install openai anthropic
# Set API keys
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."
# Run benchmark
python model_benchmark.py
Exercises
- Add your own test prompts that match your actual use case
- Add a quality scoring mechanism (e.g., check if code compiles, if classification is correct)
- Run the benchmark 3 times and compute standard deviation for latency
- Add Gemini or Mistral models via their respective SDKs
- Create a cost projection: "If I make 10K calls/day with this prompt, what's my monthly bill per model?"
Practical Recommendations
The Multi-Model Strategy
Production systems often use multiple models:
- Routing — Simple classifier (GPT-4o-mini) decides which model handles each request
- Tiered quality — Use cheap models for easy tasks, frontier models for hard ones
- Fallback chains — Primary model → fallback model → cached response
- A/B testing — Compare models in production with real user feedback
Deploy with GPT-4o-mini everywhere first. Monitor quality. Upgrade specific prompts/tasks to frontier models only where you see quality gaps. This approach often cuts costs by 80% compared to using GPT-4o for everything.
Key Takeaways
- Model choice is an engineering decision — evaluate on YOUR data, not just benchmarks
- Cost varies 10-100x between models; match model capability to task difficulty
- Open source gives control and cost savings; closed source gives simplicity and quality
- Benchmarks are directional signals, not guarantees — always run your own evals
- Use a multi-model strategy: route easy tasks to cheap models, hard tasks to frontier models
- Default starting point: GPT-4o-mini for most tasks, upgrade based on eval results