LeetLLM
My PlanLearnGlossaryTracksPracticeBlog
LeetLLM

Your go-to resource for mastering AI & LLM systems.

Product

  • Learn
  • Glossary
  • Tracks
  • Practice
  • Blog
  • RSS

Legal

  • Terms of Service
  • Privacy Policy

© 2026 LeetLLM. All rights reserved.

All Topics
Your Progress
0%

0 of 196 articles completed

🛠️Computing Foundations0/9
Git, Shell, Linux for AIDocker for Reproducible AIPython for AI EngineeringNumPy and Tensor ShapesCUDA for ML TrainingMPS & Metal for ML on MacData Structures for AISQL and Data ModelingAlgorithms for ML Engineers
📊Math & Statistics0/9
Gradients and BackpropVectors, Matrices & TensorsLinear Algebra for MLAdam, Momentum, SchedulersProbability for Machine LearningBayesian Inference from EvidenceStatistics and UncertaintyDistributions and SamplingHypothesis Tests, Intervals, and pass@k
📚Preparation & Prerequisites0/13
Neural Networks from ScratchCNNs from ScratchTraining & BackpropagationSoftmax, Cross-Entropy & OptimizationRNNs, LSTMs, GRUs, and Sequence ModelingAutoencoders and VAEsThe Transformer Architecture End-to-EndLanguage Modeling & Next TokensFrom GPT to Modern LLMsPrompt Engineering FundamentalsCalling LLM APIs in ProductionFirst AI App End-to-EndThe LLM Lifecycle
🧮ML Algorithms & Evaluation0/15
Linear Regression from ScratchLogistic Regression and MetricsDecision Trees, Forests, and BoostingReinforcement Learning BasicsValidation and LeakageStatistical Learning and GeneralizationConformal Prediction and UncertaintyClustering and PCAProbabilistic Generative ModelsCore Retrieval AlgorithmsDecoding AlgorithmsExperiment Design and A/B TestingCausal Inference and CounterfactualsPyTorch Training LoopsDataset Pipelines and Data Quality
📦Production ML Systems0/6
Feature Engineering for Production MLBatch and Streaming Feature PipelinesGradient Boosted Trees in ProductionRanking and Recommendation SystemsForecasting and Anomaly DetectionMonitoring Predictive Models
🧪Core LLM Foundations0/8
The Bitter Lesson & ComputeBPE, WordPiece, and SentencePieceStatic to Contextual EmbeddingsPerplexity & Model EvaluationFile Ingestion for AIChunking StrategiesLLM Benchmarks & LimitationsInstruction Tuning & Chat Templates
🧰Applied LLM Engineering0/25
Dimensionality Reduction for EmbeddingsCoT, ToT & Self-Consistency PromptingFunction Calling & Tool UseMCP & Tool Protocol StandardsContext EngineeringPrompt Injection DefenseResponsible AI GovernancePrivacy-Preserving Machine LearningData Labeling and Human FeedbackEvaluating AI AgentsProduction RAG PipelinesHybrid Search: Dense + SparseReranking and Cross-Encoders for RAGRAG Evaluation for Reliable AnswersLLM-as-a-Judge EvaluationBias & Fairness in LLMsHallucination Detection & MitigationLLM Observability & MonitoringExperiment Tracking with MLflow and W&BPrompt Optimization with DSPyModel Versioning & DeploymentSemantic Caching & Cost OptimizationLLM Cost Engineering & Token EconomicsModel Gateways, Routing, and FallbacksDesign an Automated Support Agent
🎓Portfolio Capstones0/9
Capstone: Delivery ETA PredictionCapstone: Product RankingCapstone: Demand ForecastingCapstone: Image Damage ClassifierCapstone: Production ML PipelineCapstone: Document QACapstone: Eval DashboardCapstone: Fine-Tuned ClassifierCapstone: Reproducible ML Study
🧠Transformer Deep Dives0/8
Sentence Embeddings & Contrastive LossEmbedding Similarity & QuantizationScaled Dot-Product AttentionVision Transformers and Image EncodersPositional Encoding: RoPE & ALiBiLayer Normalization: Pre-LN vs Post-LNMechanistic InterpretabilityDecoding Strategies: Greedy to Nucleus
🧬Advanced Training & Adaptation0/17
Scaling Laws & Compute-Optimal TrainingPre-training Data at ScaleBuild GPT from Scratch LabJAX for PyTorch ResearchersContinued Pretraining for Domain ShiftSynthetic Data PipelinesSupervised Fine-Tuning PipelineMixed Precision TrainingDistributed Training: FSDP & ZeROLoRA & Parameter-Efficient TuningTraining Run OperationsReward Modeling from Preference DataRLHF & DPO AlignmentConstitutional AI & Red TeamingRLVR & Verifiable RewardsKnowledge Distillation for LLMsModel Merging and Weight Interpolation
🤖Advanced Agents & Retrieval0/16
Vector DB Internals: HNSW & IVFAdvanced RAG: HyDE & Self-RAGGraphRAG & Knowledge GraphsRAG Security & Access ControlStructured Output GenerationReAct & Plan-and-ExecuteGuardrails & Safety FiltersCode Generation & SandboxingComputer-Use / GUI / Browser AgentsHuman-in-the-Loop Agent ArchitectureAI Coding Workflow with AgentsAgent Memory & PersistenceAgent Failure & RecoveryRecursive Language Models (RLM)Multi-Agent OrchestrationCapstone: Production Agent
⚡Inference & Production Scale0/31
Inference: TTFT, TPS & KV CacheMulti-Query & Grouped-Query AttentionKV Cache & PagedAttentionPrefix Caching and Prompt CachingFlashAttention & Memory EfficiencyContinuous Batching & SchedulingScaling LLM InferenceModel Parallelism for LLM InferenceAccelerator Architecture Field GuideCorrect GPU Profiling and BenchmarkingGPU Kernel Performance Engineering LabGPU Parallel Primitives LabGPU Compilers and Kernel LanguagesGEMM From Naive CUDA to Tensor CoresLow-Precision GPU ProgrammingGPU Runtime Execution LabAI-Generated Kernel EngineeringModel Quantization: GPTQ, AWQ & GGUFLocal LLM DeploymentSLM Specialization & Edge DeploymentSpeculative DecodingLong Context Window ManagementMixture of Experts ArchitectureMamba & State Space ModelsReasoning & Test-Time ComputeAdvanced MLOps & DevOps for AIGPU Serving & AutoscalingGPU Failure OperationsDistributed Inference Data PlaneServing Benchmark EngineeringA/B Testing for LLMs
🏗️System Design Capstones0/9
Content Moderation SystemCode Completion SystemMulti-Tenant LLM PlatformLLM-Powered Search EngineVision-Language Models & CLIPMultimodal LLM ArchitectureDiffusion Models: Images & TextReal-Time Voice AI AgentReasoning Agent System Design
🎤AI Lab Interviewing0/4
AI Lab Coding Interview: Python SystemsAI Lab System Design InterviewAI Lab Behavioral InterviewAI Lab Technical Presentation
🔬Project Deep Dives0/17
Deep Dive - vLLMDeep Dive - SkyRLDeep Dive - FlashAttentionDeep Dive - FlashInferDeep Dive - DeepGEMMDeep Dive - NCCLDeep Dive - MegatronDeep Dive - DeepSpeedDeep Dive - RayDeep Dive - MLflowDeep Dive - PyTorchDeep Dive - TransformersDeep Dive - SGLangDeep Dive - slimeDeep Dive - DeepEPDeep Dive - TinkerDeep Dive - Light-PEFT
Back to Topics
LearnCore LLM FoundationsThe Bitter Lesson & Compute
📈MediumReasoning & Scaling

The Bitter Lesson & Compute

Use Sutton's Bitter Lesson to compare rules, learning, and search, then allocate training FLOPs without treating compute as a slogan.

19 min read
Learning path
Step 53 of 196 in the full curriculum
Monitoring Predictive ModelsBPE, WordPiece, and SentencePiece

Personalize this lesson

Adapt explanations and teaching visuals to your background and preferred voice.

An incident router is a small service that sends each failure report to an engineering queue. Today it receives: “Decode latency spiked after yesterday's search deploy,” even though the report never says timeout. A keyword rule can cover today's wording, a learner can absorb labeled reports, or a search procedure can spend more compute comparing candidate actions against evidence. Which choice keeps improving when tomorrow's report uses words nobody anticipated?

The last chapter put freshness checks, delayed-label quality checks, and promotion rules around a job-risk model. Those gates still matter. Here the question moves inside them: what should produce a route when the input is messy language?

Rich Sutton's 2019 essay The Bitter Lesson points to a recurring pattern: as computation becomes cheaper, general methods that can keep using it often overtake systems whose core behavior is hand-authored. He names two such methods: learning, which updates behavior from experience, and search, which spends computation comparing possible choices.[1]Reference 1The Bitter Lesson.http://www.incompleteideas.net/IncIdeas/BitterLesson.html

The lab makes that claim measurable. Watch a three-keyword router miss familiar ideas in unfamiliar words, teach a tiny learner, then spend request-time compute on candidate actions. Judge each upgrade by evidence, not by how sophisticated it sounds.

Rules, learning, and search

Keep that report as the running artifact. Yesterday's search deploy is a reranker, a second-stage model that reorders retrieved documents. The router must choose a queue: serving latency, answer quality, or access/auth.

Rules answer only what someone has anticipated. A check such as if "latency" in text: route_to("latency") maps a known phrase to a queue.

Learning fits patterns from labeled issues. It might see TTFT spike (time to first token, the delay before a serving stack emits its first output token), unsupported citation, and OAuth callback failed, then infer route associations from examples.

Search postpones the decision. It can generate several actions, check each against evaluation evidence, and commit to the best-supported route.

Each method puts a different object in human hands:

ApproachWhat a human specifiesWhat can improve laterFailure to watch
RulesKeywords and branchesMore rulesNew phrasing escapes the rulebook
LearningData, objective, evaluationMore clean labels and training computeBad labels or leakage teach the wrong behavior
SearchCandidates and a checkerMore candidate or verification budgetA weak checker rewards the wrong answer

The table isn't a verdict against deterministic code. Sutton's claim is about which approach compounds as compute becomes available, not a ban on rules. Keep a promotion gate or human approval when an action carries risk. Don't make a growing rulebook carry the messy task's core interpretation.

See a rulebook reach its boundary

Start with three exact keywords: timeout, citation, and password. The six reports below mix those matches with paraphrases. Predict how many route correctly before running the cell.

01-rules-have-boundaries.py
1cases = [ 2 ("decode timeout in prod", "latency"), 3 ("tokens arrive slowly", "latency"), 4 ("answer cites wrong doc", "quality"), 5 ("citation points to stale source", "quality"), 6 ("password reset please", "access"), 7 ("can't authenticate", "access"), 8] 9 10def rule_route(text: str) -> str: 11 text = text.lower() 12 rules = {"timeout": "latency", "citation": "quality", "password": "access"} 13 for keyword, route in rules.items(): 14 if keyword in text: 15 return route 16 return "manual_review" 17 18predictions = [(text, expected, rule_route(text)) for text, expected in cases] 19correct = sum(expected == predicted for _, expected, predicted in predictions) 20misses = [text for text, expected, predicted in predictions if expected != predicted] 21 22print(f"correct={correct}/{len(cases)}") 23print("misses:", misses) 24assert correct == 3
Rule router baseline
1correct=3/6 2misses: ['tokens arrive slowly', 'answer cites wrong doc', "can't authenticate"]

Read 3/6 as a boundary, not a mystery. Exact phrases route quickly; tokens arrive slowly and can't authenticate contain the same operational ideas but none of the words this map knows.

A faster CPU can evaluate the same conditions sooner. It can't add an unencoded condition.

Patch the map until all six old reports pass, but keep three new phrasings untouched. Ask yourself whether the added entries recognize TTFT spiked today, response used unsupported claim, or OAuth callback fails again.

02-rule-churn.py
1old_cases = [ 2 ("decode timeout in prod", "latency"), 3 ("tokens arrive slowly", "latency"), 4 ("answer cites wrong doc", "quality"), 5 ("citation points to stale source", "quality"), 6 ("password reset please", "access"), 7 ("can't authenticate", "access"), 8] 9new_cases = [ 10 ("TTFT spiked today", "latency"), 11 ("response used unsupported claim", "quality"), 12 ("OAuth callback fails again", "access"), 13] 14 15expanded_rules = { 16 "timeout": "latency", 17 "tokens": "latency", 18 "cites": "quality", 19 "citation": "quality", 20 "stale source": "quality", 21 "password": "access", 22 "authenticate": "access", 23} 24 25def route(text: str) -> str: 26 lowered = text.lower() 27 for keyword, label in expanded_rules.items(): 28 if keyword in lowered: 29 return label 30 return "manual_review" 31 32old_score = sum(route(text) == label for text, label in old_cases) 33new_score = sum(route(text) == label for text, label in new_cases) 34print(f"rules={len(expanded_rules)} old_set={old_score}/6 new_set={new_score}/3") 35print("new misses:", [text for text, label in new_cases if route(text) != label]) 36assert old_score == 6 and new_score == 0
Rule churn under new wording
1rules=7 old_set=6/6 new_set=0/3 2new misses: ['TTFT spiked today', 'response used unsupported claim', 'OAuth callback fails again']

On the old set, patching works: 6/6. On the new set, it still scores 0/3. Engineer time bought a memory of six reports, not a procedure that can transfer to unseen wording. If branch additions move only the known-set score, the system is accumulating exceptions.

Side-by-side routing scores from the keyword lab. On yesterday's six issues, three keywords get 3 of 6 and seven keywords get 6 of 6. On tomorrow's three new phrasings, both rulebooks score 0 of 3.
The left bars are the original six issues: patching the keyword list lifts the score from 3/6 to 6/6. The right bars are tomorrow's wording. Both rulebooks score 0/3, so the extra keywords never bought a method that generalizes.

Replace phrases with evidence from examples

Switch the source of behavior from branches to examples. Before tokenization gets its own lesson, use a deliberately crude representation: lowercase word tokens. Each report becomes a set of observed terms, and the training pass counts which route each term appeared with. No synonym handling yet.

03-token-evidence.py
1import re 2from collections import Counter 3 4training = [ 5 ("decode latency timeout", "latency"), 6 ("ttft spike tokens", "latency"), 7 ("wrong citation unsupported answer", "quality"), 8 ("stale source hallucination", "quality"), 9 ("password login access", "access"), 10 ("oauth callback auth", "access"), 11] 12 13def tokens(text: str) -> list[str]: 14 return re.findall(r"[a-z]+", text.lower()) 15 16by_label = {} 17for text, label in training: 18 by_label.setdefault(label, Counter()).update(tokens(text)) 19 20print("quality evidence:", sorted(by_label["quality"])) 21print("latency evidence:", sorted(by_label["latency"])) 22assert by_label["quality"]["citation"] == 1
Issue tokens
1quality evidence: ['answer', 'citation', 'hallucination', 'source', 'stale', 'unsupported', 'wrong'] 2latency evidence: ['decode', 'latency', 'spike', 'timeout', 'tokens', 'ttft']

Look at citation: no routing branch declared it special. It appears in quality-labeled reports, so the learner carries it forward as evidence. The representation is primitive and exact-match, but knowledge now enters through examples.

Turn those counts into a tiny classifier. Score each label by the counts of words it shares with a new report. The held-out list includes four paraphrased issues and one deliberate abstention, so a correct score includes knowing when evidence is missing. Predict which report should return manual_review before running the next cell.

04-learn-from-labeled-issues.py
1import re 2from collections import Counter, defaultdict 3 4training = [ 5 ("decode latency timeout", "latency"), 6 ("ttft spike tokens", "latency"), 7 ("wrong citation unsupported answer", "quality"), 8 ("stale source hallucination", "quality"), 9 ("password login access", "access"), 10 ("oauth callback auth", "access"), 11] 12held_out = [ 13 ("latency spike tokens", "latency"), 14 ("unsupported citation answer", "quality"), 15 ("reset password", "access"), 16 ("stale source answer", "quality"), 17 ("bad graph query", "manual_review"), 18] 19 20def tokenize(text: str) -> list[str]: 21 return re.findall(r"[a-z]+", text.lower()) 22 23counts = defaultdict(Counter) 24for text, label in training: 25 counts[label].update(tokenize(text)) 26 27def predict(text: str) -> str: 28 words = tokenize(text) 29 scores = {label: sum(counter[word] for word in words) for label, counter in counts.items()} 30 best_score = max(scores.values()) 31 winners = [label for label, score in scores.items() if score == best_score] 32 return winners[0] if best_score > 0 and len(winners) == 1 else "manual_review" 33 34results = [(text, label, predict(text)) for text, label in held_out] 35correct = sum(expected == predicted for _, expected, predicted in results) 36print(f"held_out={correct}/{len(held_out)}") 37print("predictions:", [predicted for _, _, predicted in results]) 38assert correct == 5
Learned router evaluation
1held_out=5/5 2predictions: ['latency', 'quality', 'access', 'quality', 'manual_review']

Don't mistake this toy for an LLM. Its job is to isolate one change: a general procedure can absorb a labeled example without a developer adding a condition for each phrase. When evidence is absent or tied, abstention keeps uncertainty visible for review instead of turning a list order into a production decision.

Why does bad graph query go to manual_review instead of whichever route appears first?

Answer

None of its words provide route evidence in the training examples, so every route ties at zero. A deterministic tie-break would look reproducible while still inventing a production decision. Abstention preserves the uncertainty for review and future labeling.

Now make the abstention useful. Add one reviewed correction, retrain the same procedure, and predict what happens to bad graph query before running the next cell.

05-add-one-correction.py
1import re 2from collections import Counter, defaultdict 3 4base = [ 5 ("timeout tokens", "latency"), 6 ("wrong citation", "quality"), 7 ("password reset", "access"), 8] 9issue = "bad graph query" 10 11def train_and_predict(rows: list[tuple[str, str]], text: str) -> str: 12 counts = defaultdict(Counter) 13 for example, label in rows: 14 counts[label].update(re.findall(r"[a-z]+", example.lower())) 15 words = re.findall(r"[a-z]+", text.lower()) 16 scores = {label: sum(counter[word] for word in words) for label, counter in counts.items()} 17 best_score = max(scores.values()) 18 winners = [label for label, score in scores.items() if score == best_score] 19 return winners[0] if best_score > 0 and len(winners) == 1 else "manual_review" 20 21before = train_and_predict(base, issue) 22after = train_and_predict(base + [("bad graph query citation", "quality")], issue) 23print(f"before_correction={before}") 24print(f"after_correction={after}") 25assert before == "manual_review" and after == "quality"
Correction becomes training data
1before_correction=manual_review 2after_correction=quality

The correction moves bad graph query from manual_review to quality, proving only that this learner can absorb one new association. It doesn't prove generalization: the corrected issue is no longer untouched. Keep evaluating on fresh issues, as you did for datasets and training loops. The useful operational change is that feedback becomes data for a future release instead of another permanent branch.

Feedback now has an owner. Resolved outcomes return to the training set only after the route and its policy or evidence checks have been recorded.

Diagram showing Resolved issues fit router, New issue candidate route, Verify policy evidence, and Route or escalate log outcome.
Resolved issues fit router, New issue candidate route, Verify policy evidence, and Route or escalate log outcome.

Search spends compute after training

Learning changes a release. Search keeps that release fixed and spends compute after the request arrives. Search is one form of test-time compute: propose several actions, check evidence for each, and commit only to the best-supported route.

Suppose a retrieval-augmented generation (RAG) evaluation, where model answers are grounded in retrieved documents, flags citation_precision on run R42. The search procedure can inspect several candidate actions, some with no evidence and one with both the run ID and metric. Predict what happens when the budget exposes only the first one or two candidates.

Train-time compute fits six labeled issues into one router release that scores 5 of 5 on held-out issues. Inference-time search on the citation_precision failure scores four candidates 0, negative 1, 1, and 2; budget 4 selects the trace-and-block action with two pieces of evidence.
Training pays once to fit a release that scores 5/5 on the held-out issues. For the hard eval failure, request-time search spends a budget of 4 and keeps the only candidate with both run and metric evidence.

The next loop keeps candidate generation and verification explicit. It shows when extra request-time work exposes a better candidate and when it only repeats weak ones. Predict what budgets 1, 2, and 4 will select before running the cell.

06-search-with-a-verifier.py
1issue = "RAG answer failed citation_precision on run R42" 2candidates = [ 3 ("quality", "Retry later.", []), 4 ("promote", "Promote anyway.", []), 5 ("quality", "Open eval trace.", ["run R42"]), 6 ("quality", "Open eval trace; block promotion until citation_precision recovers.", ["run R42", "citation_precision"]), 7] 8 9def verifier(candidate: tuple[str, str, list[str]]) -> int: 10 route, _, evidence = candidate 11 if route != "quality": 12 return -1 13 return len(evidence) 14 15for budget in (1, 2, 4): 16 selected = max(candidates[:budget], key=verifier) 17 print(f"budget={budget} route={selected[0]} evidence={len(selected[2])} action={selected[1]}") 18 19assert verifier(max(candidates, key=verifier)) == 2
Inference-time search budget
1budget=1 route=quality evidence=0 action=Retry later. 2budget=2 route=quality evidence=0 action=Retry later. 3budget=4 route=quality evidence=2 action=Open eval trace; block promotion until citation_precision recovers.

Budgets 1 and 2 never expose an evidence-backed action, so the verifier keeps the first quality candidate with score 0. Budget 4 reveals trace-and-block with score 2. If candidate generation misses a valid action or the checker rewards the wrong one, extra search makes the mistake more expensive.

Snell and collaborators tested this trade-off on MATH with PaLM 2 models tuned for revision and verification. Their prompt-dependent allocation sometimes beat best-of-NNN with about 4×4\times4× less test-time compute; easier questions benefited more from revisions, while harder questions favored more independent search or tree search. In their equal-compute comparison, harder question bins and heavier inference loads often favored more pretraining. That result is conditional on task, model, and checker, not a license to make every request think longer.[2]Reference 2Scaling LLM Test-Time Compute Optimally Can Be More Effective Than Scaling Model Parameters.https://arxiv.org/abs/2408.03314

Training FLOPs and how to split them

The toy router makes train-time and request-time budgets visible. Language-model pretraining puts the same choice on a larger surface: how much training budget goes into parameters or tokens, and how much request-time budget remains for inference.

Kaplan and collaborators measured smooth empirical power-law relationships between cross-entropy loss, model size, dataset size, and training computation for the Transformer models they studied.[3]Reference 3Scaling Laws for Neural Language Modelshttps://arxiv.org/abs/2001.08361 Within that experimental regime, more scale produced predictable loss improvements.

One allocation consequence was striking: their compute-efficient fits favored very large models trained on relatively little data, with dataset size growing as D∼C0.27D \sim C^{0.27}D∼C0.27.[3]Reference 3Scaling Laws for Neural Language Modelshttps://arxiv.org/abs/2001.08361 Hoffmann later revisited that split.

Before using the formula, anchor it with a concrete plan: 7B parameters trained on 140B tokens. For a dense decoder-only Transformer, the common planning approximation is six floating-point operations per parameter for each training token, so total work is:

C≈6NDC \approx 6NDC≈6ND

Here, CCC is total training floating-point operations (FLOPs), NNN is the parameter count, and DDD is the training-token count. Kaplan reports the per-token estimate C≈6NC \approx 6NC≈6N; multiplying by DDD yields 6ND6ND6ND. The factor 6 approximates a forward pass plus a backward pass that costs about twice as much. It estimates arithmetic, not wall-clock time, hardware throughput, or model quality.[3]Reference 3Scaling Laws for Neural Language Modelshttps://arxiv.org/abs/2001.08361[4]Reference 4Training Compute-Optimal Large Language Models.https://arxiv.org/abs/2203.15556

The next cell keeps that arithmetic visible for two plans and prints zettaFLOPs. It doesn't model device throughput. Predict how the number changes when both parameter and token counts grow.

07-estimate-training-flops.py
1def dense_training_flops(parameters: int, tokens: int) -> int: 2 return 6 * parameters * tokens 3 4plans = [ 5 ("small study", 1_000_000_000, 20_000_000_000), 6 ("larger run", 7_000_000_000, 140_000_000_000), 7] 8 9for name, parameters, tokens in plans: 10 flops = dense_training_flops(parameters, tokens) 11 print(f"{name}: {flops / 1e21:.2f} zettaFLOPs") 12 13assert dense_training_flops(7_000_000_000, 140_000_000_000) == 5_880_000_000_000_000_000_000
Training FLOPs estimate
1small study: 0.12 zettaFLOPs 2larger run: 5.88 zettaFLOPs

Arithmetic scales with the parameter-token product, so the larger plan uses 49 times more estimated training work. That still says nothing about whether its data or model size is the better use of a fixed budget.

In fits from over 400 models, Hoffmann and collaborators found that parameter count and training-token count should scale together under their compute-optimal fits: doubling one calls for roughly doubling the other, near N∝C0.50N \propto C^{0.50}N∝C0.50 and D∝C0.50D \propto C^{0.50}D∝C0.50, against Kaplan's N∝C0.73N \propto C^{0.73}N∝C0.73 and D∝C0.27D \propto C^{0.27}D∝C0.27.[4]Reference 4Training Compute-Optimal Large Language Models.https://arxiv.org/abs/2203.15556 They tested the revised split by training Chinchilla, a 70B-parameter model on 1.4T tokens, at the same training-FLOP budget as Gopher (280B). Chinchilla outperformed the larger Gopher model on the downstream tasks they reported.[4]Reference 4Training Compute-Optimal Large Language Models.https://arxiv.org/abs/2203.15556

Now hold budget equal to the 7B/140B plan. The next cell changes only NNN and reports how many tokens remain, so it exposes an arithmetic tradeoff without claiming model quality. Predict the 14B row before running it.

08-allocate-a-fixed-training-budget.py
1budget = 6 * 7_000_000_000 * 140_000_000_000 2model_sizes = [1_000_000_000, 7_000_000_000, 14_000_000_000] 3 4for parameters in model_sizes: 5 affordable_tokens = budget // (6 * parameters) 6 print(f"N={parameters / 1e9:.0f}B -> D={affordable_tokens / 1e9:.0f}B tokens") 7 8assert budget // (6 * 14_000_000_000) == 70_000_000_000
Fixed-budget tradeoff
1N=1B -> D=980B tokens 2N=7B -> D=140B tokens 3N=14B -> D=70B tokens

At 14B, affordable tokens fall to 70B. Holding the parameter-token product fixed makes the larger model spend its budget faster. Hoffmann's training-optimal fit says this kind of data starvation is usually poor; Kaplan's earlier fit made a different recommendation. Those exponents don't decide a serving objective.

Llama 3 supplies a serving-oriented counterweight. Its 405B flagship was pretrained on 15.6T tokens, and its authors describe that size as approximately compute-optimal for training. They trained smaller models much longer than training-optimal because those models performed better at the same inference budget.[5]Reference 5The Llama 3 Herd of Models.https://arxiv.org/abs/2407.21783

Training-optimal and serving-optimal answer different questions. A research team must ask how to allocate the budget, what evaluation will reveal, and which bottleneck an extra unit of compute addresses: undertrained weights, too little data, or too little search at request time.

History is evidence, not a slogan

Now pressure-test the pattern against history. Sutton's examples support a direction; they don't support every stronger claim people attach to it.

DomainWhat the source supportsWhat you shouldn't claim from it
Chess and GoSutton points to 1997 chess as scaled search (learning played little role in the program that beat Kasparov) and to Go as search plus self-play learning. AlphaZero, given only the game rules, reached superhuman chess, shogi, and Go from self-play within 24 hours.[1]Reference 1The Bitter Lesson.http://www.incompleteideas.net/IncIdeas/BitterLesson.html[6]Reference 6Mastering Chess and Shogi by Self-Play with a General Reinforcement Learning Algorithm.https://arxiv.org/abs/1712.01815That search eliminates every useful prior or safety rule
Speech and visionSutton points to statistical and deep-learning methods replacing increasingly elaborate human feature engineering.[1]Reference 1The Bitter Lesson.http://www.incompleteideas.net/IncIdeas/BitterLesson.htmlThat modern architectures contain no inductive biases
Language modelsScaling studies measure Transformer loss as model size, tokens, and compute change. Sutton later argued that pretraining on internet text uses massive compute and packed-in human knowledge, so LLMs aren't a clean instance of the Bitter Lesson.[3]Reference 3Scaling Laws for Neural Language Modelshttps://arxiv.org/abs/2001.08361[4]Reference 4Training Compute-Optimal Large Language Models.https://arxiv.org/abs/2203.15556[7]Reference 7Richard Sutton on whether LLMs are a dead end (Dwarkesh Podcast)https://www.dwarkesh.com/p/richard-suttonThat LLM pretraining proves Sutton's full claim about agents learning from experience

The language-model row marks a boundary. Internet text carries human-produced knowledge, so next-token training can be a scalable general procedure and still depend on human data. Sutton's later view is that LLMs scale with compute up to the limits of internet data, while systems that learn from their own experience might scale further.[7]Reference 7Richard Sutton on whether LLMs are a dead end (Dwarkesh Podcast)https://www.dwarkesh.com/p/richard-sutton

Use that caveat as a design constraint, not a dismissal. Prefer methods that can absorb more evidence and compute, then test whether the extra budget addresses your actual bottleneck.

Keep rules where they belong

Put the human-written rule where it protects an action, not where it has to guess every intent. In an AI release system, a learned component can suggest promote; an explicit policy can require review when an eval gate fails or evidence is missing.

Classify a request along two axes before looking at the matrix: how ambiguous is its meaning, and how costly is a wrong action? Deterministic lookup fits structured, low-risk facts. Free-form, high-consequence actions usually need both learned interpretation and an explicit gate.

Ambiguity-by-consequence grid: run-ID lookup for structured low-risk facts, learned routing for free-form low-risk issues, an explicit 0.95 eval-score policy for structured high-risk actions, and a hybrid cell that learns promotion intent then gates it. The worked request classifies ship candidate at score 0.91 and the policy gate sends it to human review.
Use learning where meaning is ambiguous, rules where execution risk is explicit, and both when a free-form request can trigger a costly action. Here the model identifies promotion intent; the policy gate sends the 0.91 candidate to review.

The policy gate is deliberately boring. Predict three outputs: a high-scoring promotion with evidence, a low-scoring promotion with evidence, and a high-scoring promotion without evidence.

09-keep-policy-gates.py
1def release_action(proposed_route: str, eval_score: float, evidence: set[str]) -> str: 2 if proposed_route == "promote" and eval_score < 0.95: 3 return "human_review_failed_gate" 4 if proposed_route == "promote" and "eval_report" not in evidence: 5 return "request_evidence" 6 return proposed_route 7 8examples = [ 9 ("promote", 0.98, {"eval_report"}), 10 ("promote", 0.91, {"eval_report"}), 11 ("promote", 0.98, set()), 12] 13decisions = [release_action(*example) for example in examples] 14print("decisions:", decisions) 15assert decisions == ["promote", "human_review_failed_gate", "request_evidence"]
Guardrail around capability
1decisions: ['promote', 'human_review_failed_gate', 'request_evidence']

Read these outputs as ownership boundaries. The model proposes a route; the gate checks consequences and evidence; human review owns the exception. Learning handles varied phrasing, while the rule enforces action policy.

Before leaving the lab, write a receipt. This fixture records a small experiment, not a launch approval. A compute decision isn't ready for production review until it names the evaluated split, training procedure, inference budget, verifier, policy gates, and escalation monitor.

10-log-the-compute-decision.py
1from hashlib import sha256 2from json import dumps 3 4evaluation = { 5 "split": "incident-router-held-out-v1", 6 "correct": 5, 7 "total": 5, 8 "manual_review_routes": 1, 9} 10evaluation["accuracy"] = evaluation["correct"] / evaluation["total"] 11receipt = { 12 "component": "incident-router-word-overlap-v1", 13 "training": { 14 "procedure": "token-overlap-counts-v1", 15 "examples": 6, 16 }, 17 "evaluation": evaluation, 18 "search": { 19 "candidate_budget": 4, 20 "verifier": "eval-evidence-v1", 21 }, 22 "policy_gates": ["promotion_below_0_95_requires_review", "promotion_requires_eval_report"], 23 "monitor": "manual_escalation_rate", 24} 25payload = dumps(receipt, sort_keys=True, separators=(",", ":")) 26 27print(dumps(receipt, indent=2, sort_keys=True)) 28print("receipt sha256:", sha256(payload.encode()).hexdigest()[:12]) 29assert receipt["search"]["candidate_budget"] == 4 30assert receipt["evaluation"]["accuracy"] == 1.0
Compute decision receipt
1{ 2 "component": "incident-router-word-overlap-v1", 3 "evaluation": { 4 "accuracy": 1.0, 5 "correct": 5, 6 "manual_review_routes": 1, 7 "split": "incident-router-held-out-v1", 8 "total": 5 9 }, 10 "monitor": "manual_escalation_rate", 11 "policy_gates": [ 12 "promotion_below_0_95_requires_review", 13 "promotion_requires_eval_report" 14 ], 15 "search": { 16 "candidate_budget": 4, 17 "verifier": "eval-evidence-v1" 18 }, 19 "training": { 20 "examples": 6, 21 "procedure": "token-overlap-counts-v1" 22 } 23} 24receipt sha256: 957f864a4562

Turn the lesson into a design test

The Bitter Lesson isn't “throw compute at every problem.” Use four questions to audit any compute decision:

  1. Can fresh labeled evidence improve capability without a new handwritten branch?
  2. Can extra search or verification budget be measured on held-out work?
  3. Do policy gates protect an action rather than encode every possible meaning?
  4. Can the team report the budget and evaluation that justified it?

One boundary remains. Our learner treated lowercase, whitespace-separated words as the units worth learning. Tokenization is where you can ask the same question again: which reusable pieces emerge from corpus counts, and which mistakes become permanent in the vocabulary?

Mastery check

Checkpoints

What exactly does Sutton name as the two general methods that can make use of large amounts of computation?

Answer

Search and learning. Learning uses computation to improve a model from data or experience; search uses computation while choosing among possible actions or outputs.

Why doesn't a promotion approval threshold contradict the Bitter Lesson?

Answer

A threshold can enforce a policy boundary around a learned component. It doesn't try to recognize every way a teammate can ask to ship a candidate. The brittle pattern is using growing capability rules instead of learning from evaluated examples.

What does C≈6NDC \approx 6NDC≈6ND tell you, and what can't it tell you?

Answer

It gives a rough dense-Transformer training FLOPs estimate from parameter count NNN and training tokens DDD, with the factor 6 approximating a forward pass plus a more expensive backward pass. It can't tell you model quality, sustained hardware speed, data cleanliness, or which allocation is best without experiments or an empirical scaling model.

Kaplan's compute-efficient fits and Hoffmann's compute-optimal fits disagree about how to split a training budget. What changed, and why might a later production run ignore both?

Answer

Kaplan recommended scaling parameters much faster than data (D∼C0.27D \sim C^{0.27}D∼C0.27). Hoffmann's fits, from over 400 models, said NNN and DDD should grow together, and Chinchilla (70B, 1.4T tokens) beat a larger Gopher trained at the same FLOP budget. A serving-heavy lab may still train a smaller model much longer than training-optimal, as Llama 3 did, because inference cost favors the smaller model.

When can extra inference-time search hurt instead of help?

Answer

When candidate generation misses valid actions, the verifier rewards incorrect outputs, or additional latency and cost outweigh measured quality gains. Search needs evaluation and a trustworthy checker.

Evaluation rubric

  • Foundational: State Sutton's thesis and distinguish learning from search.
  • Practical: Run the incident-router examples and explain why a correction is data for a learner but rule debt for a keyword router.
  • Quantitative: Estimate dense-model training FLOPs, compare model/token allocations under a fixed budget, and separate Kaplan, Hoffmann, and serving-optimal splits.
  • Production: Design one learned component, one policy gate, and one logged metric for an automated AI-operations workflow.

Common pitfalls

"Compute will fix bad data"

  • Symptom: You enlarge a model or sample more candidates while labels leak or contradict one another.
  • Cause: General methods can amplify the data and objectives they're given.
  • Fix: Keep the dataset-quality and held-out evaluation discipline from the earlier data and production-ML lessons.

"Rules are forbidden"

  • Symptom: You let a learned router auto-promote low-score candidates without a policy boundary.
  • Cause: You've confused scalable capability with unconstrained execution.
  • Fix: Use rules for auditable gates and learning for messy recognition.

"More search always improves an answer"

  • Symptom: Cost and latency rise, but accepted answers don't improve.
  • Cause: Candidate generation or verification is too weak for added budget to help.
  • Fix: Evaluate budget levels on held-out tasks and stop spending where gains vanish.

"A deterministic tie-break is safe"

  • Symptom: An unseen issue is sent to the first route in a sorted label list.
  • Cause: The classifier turns missing evidence into a reproducible but unsupported action.
  • Fix: Abstain when no route has positive evidence or when several routes share the best score.

"Chinchilla's ratio is a law"

  • Symptom: You freeze an equal parameter/token split and ignore serving cost, data quality, and later scaling evidence.
  • Cause: You've treated one compute-optimal fit as a universal constant.
  • Fix: Use Hoffmann's split as a training-budget hypothesis, then measure. Serving can justify training a smaller model longer, as Llama 3 did.
Complete the lesson

Mastery Check

Answer every question, then check your score. Score 75% or higher to mark this lesson complete.

1.A keyword incident router catches phrases like timeout and citation, but it misses tokens arrive slowly, answer cites wrong doc, and tomorrow's new wording. The team wants future corrections to improve routing without adding one permanent branch per phrase. Which change shifts the core capability from handwritten rules to a method that can improve from evaluated labeled evidence?

Correct answer: Collect clean labeled issues, train and evaluate a learner from those examples, and let resolved issues become evidence for later training runs.

A fixed rule only handles wording a person encoded, and more CPU time doesn't expand its conditions. A learner can absorb associations from new labeled issues, provided the labels, held-out evaluation, and deployment feedback remain trustworthy.

2.An AI-release learned router proposes the route promote. Company policy says candidates below 0.95 eval score require human review, and any promotion without an eval report should request evidence first. Which design correctly separates learned intent recognition from auditable execution policy?

Correct answer: Let the learned component recognize messy promotion language, then apply gates for failed eval scores and missing evidence before releasing the action.

Learning is appropriate for recognizing varied language, while the threshold and evidence requirement constrain what action may be executed. Removing those gates confuses scalable capability with unconstrained authority, while phrase-by-phrase rules recreate the brittle rulebook.

3.An engineer uses C approx 6ND for a dense decoder-only Transformer, where N is parameter count and D is training-token count. They then claim the number proves the model's quality and expected wall-clock runtime. Which statement correctly describes what this formula does and doesn't justify?

Correct answer: The formula is a rough training-FLOPs estimate, but quality, hardware throughput, data cleanliness, and the best allocation still require measurement.

Kaplan wrote C ≈ 6N FLOPs per training token; multiplying by token count D gives 6ND. The factor 6 approximates forward and backward training work for a dense Transformer. FLOPs aren't sustained hardware speed, model quality, data quality, or a complete optimization rule, so those claims require empirical evidence.

4.An AI-operations agent uses inference-time search: it generates candidate actions and scores each with an eval-evidence verifier. For a failed RAG eval, increasing the budget from 2 to 4 candidates reveals an action with both run R42 and citation_precision evidence. Which conclusion correctly describes when extra inference-time search is useful?

Correct answer: Extra search helped because a stronger candidate became available and the verifier rewarded relevant evidence; with bad candidates or a weak verifier, more budget could hurt.

Search spends compute after training by exploring alternatives. It improves the decision only if useful candidates enter the search set and the verifier scores them according to the right evidence. Otherwise, extra budget can amplify mistakes or add cost and latency without quality gains.

5.A word-overlap router was trained on timeout tokens -> latency, wrong citation -> quality, and password reset -> access. For a new issue, it sums exact observed word counts per label and returns a label only when one label has a positive top score. What should it return for bad graph query before any correction is added?

Correct answer: manual_review, because all exact-word scores are zero and choosing the first label would invent an unsupported decision.

The classifier has no semantic synonym mechanism: none of the issue's words occurred in training. Every label therefore scores zero, and the unique-positive-score rule requires abstention rather than a reproducible but unsupported route.

6.A team has the same training FLOP budget as a 7B-parameter dense Transformer trained on 140B tokens, using C≈6NDC \approx 6NDC≈6ND. If it instead trains a 14B-parameter model under the same budget, how many tokens can it afford, and what trade-off does that show?

Correct answer: 70B tokens. Under a fixed compute budget, doubling the parameter count halves the affordable training-token count, so a larger model can consume the budget needed for data exposure.

Holding C fixed holds the product ND fixed. Thus D = 7B * 140B / 14B = 70B tokens. This exposes the allocation trade-off but doesn't by itself prove whether the 14B or 7B model is the better use of the budget.

7.A word-overlap router sends bad graph query to manual review. The team adds the labeled example bad graph query citation -> quality, retrains, and then tests the original issue again. It now predicts quality. What conclusion is justified?

Correct answer: Treat it as evidence the learner can absorb a correction, then test on untouched issues before claiming generalization.

The changed prediction demonstrates that a correction can become training evidence rather than a permanent branch. Rechecking the corrected case isn't independent evidence of generalization, so the team must still evaluate on issues that weren't used to fit the router.

8.A team observes smooth held-out cross-entropy scaling as model size, tokens, and compute increase across its clean Transformer experiments. Another project has leaked labels and no promotion approval gates. What does the scaling evidence justify?

Correct answer: It justifies testing scalable learning with clean held-out evaluation, not assuming compute will repair leakage or replace policy gates.

The reported scaling relationships are empirical results within specified Transformer experiments. They don't make leaked evaluation trustworthy, convert a learning objective into an execution policy, or show that added compute removes the need for safety gates.

9.An AI-operations team is preparing a production experiment for a learned router with inference-time search. The team must make its compute decision reproducible and auditable. Which record should it log?

Correct answer: The component version, evaluated split and results, training procedure, candidate budget and verifier, policy gates, and escalation monitor.

A compute decision is auditable only when the record connects the component and training procedure to held-out evidence, inference budget, verification rule, execution constraints, and an operational monitor. Training accuracy, resource totals, or a successful demonstration omit the evidence needed to reproduce and evaluate the decision.

10.Kaplan's 2020 compute-efficient fits said dataset size should grow slowly with compute (about D ~ C^0.27). Hoffmann's 2022 fits, from over 400 models, said parameters and tokens should grow together. Llama 3's paper later says its smaller models were trained much longer than compute-optimal because they performed better at the same inference budget. What design lesson follows?

Correct answer: Treat Hoffmann's training-optimal split as a hypothesis, then measure; serving cost can justify training a smaller model longer than training-optimal.

Hoffmann revised Kaplan's split for training-optimal dense Transformers, and Chinchilla is the concrete test. Training-optimal is still not serving-optimal: Llama 3 reports that smaller models trained past the training-optimal point beat compute-optimal models at the same inference budget. The papers are evidence, not a substitute for measurement.

10 questions remaining.

Next Step
Continue to BPE, WordPiece, and SentencePiece

Methods that absorb more data and computation tend to outrun a growing rulebook, and a frozen word list is still a rule. Next you'll build the text-to-token contract that makes language-model learning possible and measure the tradeoffs it introduces.

PreviousMonitoring Predictive Models
Share this article
XFacebookLinkedInBlueskyRedditHacker NewsEmail
References

The Bitter Lesson.

Sutton, R. S. · 2019

http://www.incompleteideas.net/IncIdeas/BitterLesson.html

Scaling LLM Test-Time Compute Optimally Can Be More Effective Than Scaling Model Parameters.

Snell, C., et al. · 2024 · arXiv preprint

https://arxiv.org/abs/2408.03314

Scaling Laws for Neural Language Models

Kaplan et al. · 2020

https://arxiv.org/abs/2001.08361

Training Compute-Optimal Large Language Models.

Hoffmann, J., et al. · 2022 · NeurIPS 2022

https://arxiv.org/abs/2203.15556

The Llama 3 Herd of Models.

Dubey, A., et al. · 2024 · arXiv preprint

https://arxiv.org/abs/2407.21783

Mastering Chess and Shogi by Self-Play with a General Reinforcement Learning Algorithm.

Silver, D., et al. · 2017 · arXiv preprint

https://arxiv.org/abs/1712.01815

Richard Sutton on whether LLMs are a dead end (Dwarkesh Podcast)

Patel, D. (host) & Sutton, R. · 2025

https://www.dwarkesh.com/p/richard-sutton

Discussion

Questions and insights from fellow learners.

Discussion loads when you reach this section.