Using multiple GPUs to train models or serve production workloads is expensive. There is no single trick that fixes this — the right move depends entirely on which of the two you're doing. A parallelism strategy that speeds up a training run can actively hurt a serving system's latency; a caching trick that makes inference cheap has no equivalent during pretraining. Treating them as the same optimization problem is the most common mistake teams make when their GPU bill doesn't match expectations.
Training optimizes for throughput
A fixed, large compute budget spread across a job that runs for days or weeks. The goal is maximum useful FLOPs per GPU-hour, and the job can tolerate scheduled restarts as long as progress isn't lost.
Inference optimizes for latency and cost per request
Unpredictable, bursty traffic that has to be answered in milliseconds to seconds, one request — or one growing batch of requests — at a time, with no room for a scheduled pause.
Key Considerations for Training
Four decisions shape almost everything else about a training run's cost and reliability.
Parallelism Strategy
Choose among data, tensor, pipeline, or a mix, based on model size and hardware topology. Start with data parallelism — each GPU holds a full copy of the model and processes a different slice of the batch — when the model comfortably fits on one GPU. Once memory becomes the constraint, move to sharding or model-splitting:
- Tensor parallelism — individual layers (e.g. attention and feed-forward matrices) are split across GPUs, requiring frequent, low-latency communication between them.
- Pipeline parallelism — different layers of the model live on different GPUs, and micro-batches flow through the pipeline stage by stage.
- Sharded data parallelism (ZeRO, FSDP) — model states are partitioned across data-parallel GPUs and reassembled on demand, recovering much of data parallelism's simplicity without needing a full model copy per GPU.
Frontier-scale runs typically combine all three into 3D parallelism: tensor parallelism inside a node (where bandwidth is highest), pipeline parallelism across a small group of nodes, and data parallelism across the remaining GPUs.
Three parallelism strategies, three different communication patterns — which is why they get mapped onto different tiers of the network hierarchy.
Memory Budgeting
Weights, gradients, optimizer states, and activations all compete for the same fixed pool of GPU memory. Know this budget upfront — it's what determines which parallelism strategy is even feasible.
For standard mixed-precision training with the Adam optimizer, a widely cited rule of thumb (from the ZeRO paper) puts the non-activation memory cost at roughly 16 bytes per model parameter: 2 bytes for FP16 weights, 2 bytes for FP16 gradients, and 12 bytes for FP32 optimizer state (master weights, momentum, and variance). Activations add more on top, scaling with batch size and sequence length — which is exactly why activation checkpointing (recomputing activations during the backward pass instead of storing all of them) is a standard technique for fitting larger batches or longer contexts into the same memory budget.
The optimizer state — not the model weights — is typically the largest single consumer of training memory, which is exactly what ZeRO/FSDP sharding is built to address.
Interconnect Bandwidth
NVLink and NVSwitch deliver very high bandwidth between GPUs within a single node, while InfiniBand connects nodes to each other at a meaningfully lower bandwidth. Communication-heavy strategies — tensor parallelism above all — only make sense inside that high-bandwidth boundary; push them across InfiniBand and the communication overhead can erase the benefit of adding more GPUs entirely.
This is the practical reason 3D parallelism is laid out the way it is: tensor-parallel shards stay inside a node (NVLink), pipeline stages span a handful of nodes (moderate InfiniBand traffic, sent only at stage boundaries), and data-parallel gradient synchronization — the most bandwidth-tolerant of the three — spans the rest of the cluster.
Fault Tolerance
Long-running, multi-node jobs will eventually hit hardware failures and stragglers — at cluster scale, over a multi-week run, this isn't an edge case, it's a certainty. A checkpointing strategy and job orchestration layer are what save your progress when something breaks, rather than losing days of compute to a single failed GPU.
- Checkpointing frequency — trades recovery time (how much work is lost on failure) against overhead (I/O cost of writing large checkpoints repeatedly); asynchronous, incremental checkpointing narrows that trade-off.
- Elastic training — allows a job to keep running, at reduced parallelism, when a node drops out, rather than halting the whole run.
- Orchestration (Slurm, Kubernetes, Ray) — detects failed or straggling workers and handles restart/rescheduling automatically.
Key Considerations for Inference
Once training ends and serving begins, the bottlenecks, and the fixes, change completely. Part one covers the ten mechanics inside the model and serving engine; part two covers the production levers around them that cut cost.
Ten Inference Mechanics
From the KV cache to prefill-decode disaggregation: how each technique works, and what it costs.
KV Caching
The simplest and most foundational optimization: stop recomputing what you've already computed.
During each step of autoregressive text generation, an LLM compares the last token's Query vector against the Key vectors of every preceding token, including itself. This produces attention weights, which are used to compute a weighted sum over the corresponding Value vectors — the attention output for that token.
For example, when generating the token that follows "The capital of the U.K. is", the model:
- Converts the current token ("is") into a Query vector
- Scores it against the Key of every preceding token, finding that "capital" and "U.K." are most relevant
- Combines those tokens' Value vectors to predict that the next token is most likely "London"
This repeats at every step of generation. Recomputing Key and Value vectors for the entire sequence at each step gets expensive fast as the sequence grows — which is exactly the problem a KV cache solves.
Instead of recalculating Key and Value vectors for the whole sequence every time, the KV cache stores each token's K and V vectors once. At each new step, the model only computes (and appends) the new token's Key and Value, reusing everything else from the cache.
Green/cyan = cached and reused. Red = recomputed. The KV cache trades HBM memory for a large cut in redundant computation.
This massively reduces inference compute — but at the cost of GPU high-bandwidth memory (HBM). There's no free lunch. Still, KV caching is one of the simplest, highest-leverage techniques for improving inference speed.
Efficient Attention Mechanisms
Since the KV cache eats into HBM, shrinking it is its own optimization target.
Traditional Multi-Head Attention (MHA) gives every attention head its own Key and Value vectors. Several attention variants reduce the number of K/V vectors in use — and therefore the KV cache size:
- Multi-Query Attention (MQA) — all attention heads share one Key and Value, while each head keeps its own Query.
- Grouped Query Attention (GQA) — Query heads are grouped, and each group shares one Key/Value pair.
- Multi-head Latent Attention (MLA) — Key and Value vectors are compressed into a low-dimensional latent vector and only that is cached. The full K/V vectors are reconstructed from the latent vector when needed, using far less memory than a full-sized KV cache.
MHA vs MQA vs GQA vs MLA — fewer distinct Key/Value sets means a smaller KV cache. (Source)
Continuous Batching
Processing requests one at a time wastes GPU compute — batching fixes that, but how you batch matters.
Handling LLM requests sequentially is inefficient, since requests arrive at different times and have variable input/output lengths. Batching requests together improves overall throughput and reduces idle GPU compute — but there's more than one way to do it:
- Static batching — the system waits for a fixed number of requests to arrive before processing them together.
- Dynamic batching — the system waits only up to a maximum time limit rather than indefinitely, before starting the batch.
- Continuous (in-flight) batching — processing happens token by token. Instead of waiting for the whole batch to finish, the system evicts a completed request and immediately fills its slot with a new one.
Optimized Kernels
Decode is memory-bound — the bottleneck is moving data, not computing on it.
During inference, the Decode phase is memory-bound: the GPU spends more time moving data from memory (HBM) to its compute cores than actually computing. A kernel is a function that runs on the GPU performing parallel operations, and it can be optimized to keep data in fast on-chip memory (SRAM/registers) rather than repeatedly re-reading it from slow HBM.
Kernel fusion merges multiple individual operations into a single kernel to avoid unnecessary data movement across memory. FlashAttention is the best-known example, fusing the operations of attention computation into one kernel.
Standard attention computation moves data back and forth repeatedly: Query and Key are read from HBM and multiplied to form an attention score matrix, which is written back to HBM, re-read to apply softmax, written back again, then read once more to multiply by the Value matrix — with the final output written back to HBM one last time.
FlashAttention avoids all of this by never materializing the full attention matrix in HBM. It splits the Query, Key, and Value matrices into smaller tiles that fit in on-chip SRAM, and performs attention one tile at a time — computing attention scores and softmax on-chip, and writing only the final output back to HBM.
FlashAttention tiles Q/K/V into on-chip SRAM, computing attention block by block and writing only the final output back to HBM — minimizing slow memory round-trips.
Quantization
Store and compute in fewer bits, and both memory footprint and throughput improve.
Quantization stores and computes LLM parameters, activations, and the KV cache in lower-precision formats such as INT8 (8 bits) or INT4 (4 bits) instead of full-precision FP32 or 16-bit FP16/BF16. This shrinks memory requirements and increases throughput by reducing how much data moves from HBM to the compute cores — at the cost of a slight accuracy drop.
At FP32, a 70B-parameter model needs 280 GB — more than a single 80 GB H100 GPU. Quantizing to INT4 brings that down to 35 GB, small enough to fit on one GPU.
Quantized models are commonly labeled using the convention W(x)A(y), describing how much the weights (W) and activations (A) have been quantized:
W4A16W8A8W4A4You'll also see model names suffixed with -GPTQ or -AWQ — the two most common quantization techniques:
Prefix / Prompt Caching & RadixAttention
Many requests share the same opening tokens — compute that shared prefix once.
LLM inference has two distinct phases:
- Prefill — all input prompt tokens are processed together, which is compute-bound. Prefill determines Time-to-First-Token (TTFT), and it's when the KV cache is built.
- Decode — subsequent tokens are generated one at a time, which is memory-bound since little computation happens per step. Decode determines Time Per Output Token (TPOT).
Prefix (or prompt) caching reuses the computed KV cache for a shared prefix of the input prompt across multiple requests, cutting redundant Prefill computation and shortening TTFT. Consider a long system prompt like "System: You are a helpful assistant..." — without prefix caching, every request recomputes Prefill for the entire system prompt plus the user's question. With it, the system prompt's KV cache is computed once and reused; each request only computes Prefill for its own unique question.
RadixAttention, introduced with the SGLang serving framework, implements prefix caching efficiently using a radix tree: each path from the root represents a token sequence, and shared prefixes across requests become shared branches. For a new request, the algorithm walks the tree, matching tokens as far as possible and reusing the KV cache along that path — computing Prefill only for the tokens unique to that request.
Pruning
Not every parameter earns its keep — pruning removes the ones that don't.
Pruning removes parts of a model that contribute little to its accuracy, making it smaller and cheaper to run inference on. It comes in three flavors:
- Unstructured pruning — sets low-magnitude individual parameters to zero.
- Structured pruning — removes entire sections of the model, such as neurons, attention heads, or fully-connected layers.
- Semi-structured (N:M) pruning — sets N of every M consecutive weights to zero. NVIDIA GPUs from Ampere onward have hardware support for 2:4 sparsity, giving roughly a 2x boost in matrix multiplication throughput.
PagedAttention
Borrowed from operating systems: don't demand one giant contiguous block of memory.
PagedAttention, introduced in the vLLM serving framework, manages the KV cache's memory more efficiently by borrowing an idea from how operating systems handle memory paging.
Instead of reserving one large contiguous chunk of GPU memory for the KV cache upfront, PagedAttention stores it dynamically across many small, fixed-size, non-contiguous blocks called pages. A per-sequence block table maps logical token positions to their physical memory blocks, and the attention kernel consults this table to locate the right KV pairs on demand.
A block table maps each logical chunk of the sequence to a physical page, which can live anywhere in GPU memory — just like OS virtual memory paging.
Speculative Decoding
Use a fast, small model to guess ahead — then let the big model verify the guesses in one pass.
Speculative decoding accelerates inference with large LLMs by pairing them with a smaller model from the same family, sharing the same tokenizer and vocabulary. The smaller model — the Draft model — runs faster than the larger Target model simply because it has fewer parameters. The process works like this:
- Drafting — for a given prompt, the Draft model generates K tokens ahead of time.
- Target forward pass — those K draft tokens, plus the original prompt, are fed to the Target model. In a single forward pass, it produces a probability distribution for the next token at every drafted position, plus one more beyond it (K + 1 predictions total). Because Decode is memory-bound, this single pass costs about as much as generating just one token normally would.
- Verification — each drafted token is checked against the Target model's prediction at that position. It's accepted if they match (under greedy decoding) or if the Target model finds it likely enough via rejection sampling (under probabilistic decoding). At the first token where verification fails, that token and every token after it are discarded, the Target model supplies a replacement, and drafting resumes from that position.
If all K draft tokens are accepted, the output is K+1 tokens in one pass (best case). If the very first draft token is rejected, the result is just 1 resampled token — identical to normal decoding (worst case, no loss).
Prefill-Decode Disaggregation
Prefill and Decode want different things from hardware — so give them different hardware.
Prefill is compute-bound and determines TTFT; Decode is memory-bound and determines TPOT (also called inter-token latency). These are fundamentally different problems, and optimizing both on the same GPU is difficult — especially for prefill-heavy requests where long prompts produce short outputs, and low TTFT and low TPOT are both required at once.
Prefill-decode disaggregation is a serving architecture that solves this by moving the two inference stages onto separate, dedicated GPU pools: one pool optimized for high compute (e.g. the H100) handles Prefill, while a pool optimized for high memory throughput (e.g. the H200, which offers much faster and larger memory at similar core compute) handles Decode.
Measuring Inference in Production
Inference engineering is the discipline of keeping a model fast, stable and affordable once real traffic arrives. A LinkedIn commentary by Progressive Thinker argues it is underrated compared with training, because serving adds queueing, batching, KV-cache pressure, GPU memory limits, scheduling, communication and tail-latency problems.
Metrics that matter
| Metric | What it tells you |
|---|---|
| TTFT (time to first token) | How long a user waits before output starts; driven mainly by queueing and prefill. |
| ITL / TPOT (inter-token latency) | How smoothly tokens stream after the first; driven mainly by decode. |
| Throughput and concurrency | Aggregate tokens per second and simultaneous requests served. |
| Queueing delay and tail latency | What the slowest requests experience; averages hide it. |
| KV-cache occupancy and GPU utilization | How close the server is to its memory and compute ceilings. |
| Goodput | The share of requests that still meet the latency objective, not just raw volume. |
Where each technique fits
Prefill vs. decode. Prefill processes the prompt and builds the KV cache; it parallelizes well and is usually compute-bound. Decode generates one token at a time and is often limited by memory bandwidth at practical batch sizes. Most techniques below target one phase or the other.
- FlashAttention reduces memory traffic inside attention; PagedAttention manages the KV cache in blocks to cut fragmentation.
- MQA and GQA use fewer key/value heads, shrinking KV-cache storage and bandwidth.
- Continuous batching lets requests join and leave the active batch mid-generation; chunked prefill splits long prompts so they can run alongside decode work.
- Prefix caching reuses KV state for repeated prompt prefixes. It saves prefill compute but does not speed up later decode tokens, and it matters most for agentic workloads that resend growing prefixes.
- Quantization applies to weights (less memory and bandwidth) and to the KV cache (smaller footprint).
- Speculative decoding pays off only when the draft is cheap, acceptance rate is high and verification is efficient.
- Parallelism at scale: tensor parallelism adds communication overhead, pipeline parallelism adds scheduling bubbles, and mixture-of-experts serving adds routing and load-balancing problems.
- Prefill/decode disaggregation runs the phases on separate GPU pools at the cost of moving KV state between them.
Beyond performance, production serving also needs access control, cost tracking, token budgets and guardrails; avoiding a request altogether through caching and routing can be cheaper than optimizing GPU throughput.
Cutting Inference Cost in Production
Most enterprise AI budgets don't blow up because the model is expensive per token. They blow up because every request pays the full price of a frontier model, a cold context window, and an unbatched GPU — regardless of whether the request actually needed any of that. The fix isn't a cheaper model; it's an inference layer that only spends what a given request genuinely requires. That layer is built from a dozen or so techniques that work at different points in the request path — before the model is even called, inside the serving engine, inside the model itself, and after the response ships. Seven levers follow, grouped by where in the stack they operate.
A request first checks the cache layer, then a router picks the cheapest model tier capable of handling it, that model's quantized or distilled weights run through a serving engine doing continuous batching and speculative decoding, and the response streams back under a token cap. Observability watches spend at every stage and continuously retunes the router and the governance guardrails — it sits outside the request path entirely.
Model Right-Sizing and Intelligent Routing
The single highest-leverage decision in the whole pipeline happens before a single token is generated: which model handles this request at all. Frontier models are priced for the hardest 10-15% of tasks a system will ever see, but most production traffic is routine — classification, extraction, short summarization, templated drafting — and never needed frontier-level reasoning in the first place. A router that estimates request complexity and dispatches accordingly turns that observation into savings without touching output quality on the requests that actually matter.
This isn't theoretical. RouteLLM, a widely cited open routing framework, reported 85% cost savings while retaining 95% of GPT-4-level quality on MT-Bench, sending only 14% of queries to the stronger model. Field reports from teams running tuned routers in production land in a broad 40-85% bill-reduction range, and the math is intuitive once you model it as a traffic split: routing 70% of volume to a cheap model and 30% to a frontier model (say, Haiku-class to Opus-class) nets roughly 67% savings versus sending everything to the frontier tier; an 80/20 split nets closer to 79%. The savings compound sharply once the cheap-model share crosses 50% of total volume — which is exactly where most real workloads sit once you actually measure them.
Hybrid cloud/on-prem routing is the same idea applied to a different axis: instead of routing by model size, route by data sensitivity and predictability. Workloads with stable, well-understood shapes — and anything where sending data off-premises is itself the cost (compliance risk, egress fees, latency to a regulated data residency zone) — stay on local or on-prem inference. Genuinely open-ended reasoning still goes to a cloud frontier model when the task warrants it. Both forms of routing rest on the same principle: complexity and sensitivity, not habit, should decide where a request lands.
Serving-Layer Efficiency
Routing picks the model; the serving engine underneath still decides how much of a GPU's capacity a request wastes. Continuous batching and PagedAttention, covered above as techniques 3 and 8, are the two changes that matter most here.
Caching Strategy: Prefix, Semantic, and KV Cache
Caching shows up at three different layers of the stack, and conflating them is the most common mistake in a cost-optimization plan. Each one catches a different kind of repetition.
Prefix (prompt) caching
Prefix caching operates inside the model's attention mechanism: it stores KV-cache entries for a prompt's beginning and reuses them when a new request's prefix matches exactly, token for token. It only reduces time-to-first-token — output generation still runs, and still costs, at full price. But the TTFT effect scales with prefix length: roughly 7% improvement at a 1,024-token shared prefix, climbing to 67% at 150,000+ tokens, and around 79% TTFT reduction with a 90% cost cut on the cached portion at a 100,000-token cached prefix in benchmark testing. This is the mechanism behind the "prompt caching" discounts offered by Anthropic, OpenAI, Google, and AWS Bedrock.
Semantic caching
Semantic caching sits a layer above the model entirely. Incoming queries are converted to embeddings and compared against cached queries by cosine similarity against a configurable threshold; on a hit, the LLM is never called at all — both input and output tokens are fully saved, not just discounted. Because it matches on meaning rather than exact text, it catches paraphrased and reworded repeats that prefix caching can't touch, which is why teams report meaningfully higher hit rates and total savings in the range of 30-40%+ of LLM spend when it's tuned well. The trade-off is a small risk of a false-positive match returning a stale or subtly wrong cached answer, which is why threshold tuning and cache invalidation policy matter more here than in exact-match caching.
The two are complementary, not competing — a layered strategy runs exact-match caching first, semantic caching second, and prefix caching for whatever's left that still has to reach the model.
KV cache compression
Independent of caching strategy, the KV cache itself can be shrunk architecturally. Grouped-Query Attention (GQA) delivers 4-8x compression and is the default in Llama 3.x and Mistral; Multi-Query Attention (MQA) pushes to 32x compression at a noticeable 1-3 point quality cost; Multi-head Latent Attention (MLA), used in DeepSeek's V2 through V4 models, achieves 7-14x compression with under 0.2 points of regression. Layered on top, FP8 KV-cache quantization halves memory again for a modest 0.3-0.7 point hit. Stacked together, these compound multiplicatively — a 70B model at 1M-token context can go from 135GB of KV cache at FP16 baseline down to roughly 8GB with MLA plus FP8, a documented 4-40x reduction on long-context inference depending on which techniques are combined.
| Cache layer | What it matches | Saves |
|---|---|---|
| Exact-match cache | Identical repeated queries | Input + output tokens |
| Semantic cache | Paraphrased / similar queries (embeddings) | Input + output tokens |
| Prefix / prompt cache | Exact shared prompt prefix | Input tokens (TTFT) only |
| KV cache compression | N/A — architectural, not query-level | GPU memory for any request |
Compressing the Model: Quantization and Distillation
Routing and caching reduce how often and how much of the model runs. Quantization and distillation reduce the cost of running the model itself.
Quantization lowers the numeric precision of model weights (and optionally activations and the KV cache) from 16-bit down to 8-bit or 4-bit representations. The two dominant post-training methods differ in how they decide what to protect: GPTQ relies on layer-wise second-order weight optimization, which is computationally expensive and less targeted; AWQ (Activation-Aware Weight Quantization) instead profiles activation magnitudes during calibration to identify the roughly 1% of "salient" weight channels that matter most, scales those channels to preserve precision, and quantizes the rest aggressively — and it consistently outperforms GPTQ by 1-2 quality points at the same bit-width. The economics are substantial: a 70B model drops from roughly 140GB in BF16 to 35-40GB in AWQ INT4, a ~71% memory reduction, which in one benchmark comparison took serving cost from $0.757 per million tokens on dual A100s down to $0.253 per million tokens on a single A100 — a ~67% cost reduction — with throughput improving roughly 1.5x on top of that.
Distillation and task-specific fine-tuning attack the same problem from a different angle: instead of shrinking a general-purpose model's weights, train a much smaller student model to reproduce a larger teacher's behavior on a narrower task. This is the right call precisely when prompts are long, repetitive, and narrow in scope — sending the same lengthy context and instructions on every call is often more expensive over time than the one-time cost of fine-tuning a small model to do that one job without the context at all. The trade-off is scope: a distilled or fine-tuned model is deliberately worse at everything outside its training distribution, which is why it belongs behind a router, not in front of general traffic.
Accelerating Decode: Speculative Decoding, Async, and Streaming
Everything above reduces how much compute a request costs. This section is about latency — and, indirectly, cost, since lower latency means fewer retries and less GPU time held open per request.
Speculative decoding is covered above (technique 9): a small draft model proposes tokens that the full model verifies in one pass.
Asynchronous inference is the simpler lever: not every workload needs a synchronous, sub-second response. Batch scoring, overnight report generation, and background enrichment jobs can be queued and processed during off-peak capacity, which both improves GPU utilization and often qualifies for lower off-peak or batch API pricing where providers offer it.
Streaming responses address perceived latency rather than actual compute cost: delivering tokens as they're generated, rather than waiting for the full response, keeps a user or downstream system engaged instead of timing out or retrying — and retries are pure wasted spend, since a timed-out request that gets resent pays for the discarded generation too.
Context Engineering: Auditing What You Actually Send
Every token in the context window is compute you're paying for whether or not it helps the answer — and, on current transformer architectures, attention cost scales with context length, so a bloated context window is a compounding cost, not a flat one. Context window auditing means treating retrieval and prompt assembly as a relevance-filtering problem: pull in what a request needs, not everything a retrieval system could plausibly return. This isn't only a cost argument — models are also demonstrably worse at using information buried in the middle of an very long context than information near the start or end, so an aggressively padded prompt can simultaneously cost more and perform worse.
Output token controls close the other end of the same problem. An unbounded max_tokens setting, combined with a model that tends to over-explain, restate, or hedge, can quietly become one of the largest line items in an inference bill — and it's one of the cheapest to fix, since explicit output limits and stop sequences cost nothing to implement and directly cap the most expensive part of a request (output tokens are typically priced several times higher than input tokens across most providers).
Governance and Observability: Guardrails Before the Bill Arrives
Every technique above is a lever inside the request path. This last pair operates outside it, and it's the layer that keeps the others from silently drifting back toward waste.
Usage governance — quotas, per-team and per-application budgets, rate limits, and hard guardrails on which model tiers a given caller can even reach — has to exist before a runaway integration or an unbounded agent loop turns into a five-figure surprise, not after. A router that's technically capable of sending everything to a frontier model will do exactly that if nothing stops it, whether the cause is a misconfigured default or a legitimate but unbounded batch job.
Cost and usage observability is what makes every other technique in this piece measurable rather than assumed. Tracking spend by application, feature, team, workflow, model, and user segment turns "our AI costs went up" into "feature X's fallback path is calling the frontier model on cache misses at 3x the volume we expected" — an actionable finding instead of a vague budget alarm. This is also the feedback loop that closes back into routing and caching: a router's complexity thresholds and a semantic cache's similarity threshold are not "set once" parameters — they need retuning as traffic mix shifts, and that retuning is only possible with granular, current cost data to look at.
None of these techniques is a substitute for the others, and the diagram earlier in this piece is really the argument in full: a request should be checked against a cache before it ever reaches a model, routed to the cheapest tier actually capable of handling it, served by an engine that keeps the GPU saturated and the KV cache compressed, generated by weights that are no larger or slower than the task requires, and capped and streamed back efficiently — all while an observability layer watches spend closely enough to keep tightening every threshold in that chain. Skip any one layer and the others compensate for it by burning more of the layers around them; a brilliant router sending every request to an unquantized model on a statically-batched server still wastes most of its GPU capacity, just as the best serving engine in the world can't fix a context window stuffed with irrelevant retrieval results.
The framing this piece opened with is worth repeating as the close, because the techniques above are really just its implementation: LLM cost optimization is an architecture problem, not a model-pricing problem. The goal was never simply cheaper inference — it's intelligent routing, efficient context, appropriately sized models, strong observability, and predictable economics, working together so that AI systems can scale without their infrastructure cost scaling uncontrollably alongside them.
Training vs. Inference, Side by Side
| Dimension | Training | Inference |
|---|---|---|
| Primary objective | Maximize useful FLOPs per GPU-hour over a fixed compute budget | Minimize latency and cost per request under live, variable traffic |
| Time horizon | One long batch job — days to weeks | Milliseconds to seconds, continuously, forever |
| Main bottleneck | Interconnect bandwidth + optimizer-state memory | KV-cache HBM footprint + memory bandwidth during decode |
| Parallelism favored | Data, tensor, pipeline, and ZeRO/FSDP sharding, often combined (3D parallelism) | Tensor parallelism plus batching; pipeline parallelism is usually avoided (adds per-token latency) |
| Typical hardware pattern | Large homogeneous GPU clusters, NVLink intra-node + InfiniBand inter-node | Sometimes split pools — compute-optimized for prefill, memory-bandwidth-optimized for decode |
| Failure mode to guard against | Mid-run hardware failure losing unsaved progress → checkpointing | Traffic spikes and idle GPU cycles → continuous batching, autoscaling |
A Practical Decision Framework
- Training — does the model fit on one GPU? If yes, start with plain data parallelism. If no, add ZeRO/FSDP sharding first (simplest to operate); reach for tensor parallelism only inside a high-bandwidth NVLink domain, and pipeline parallelism only once you're spanning multiple nodes.
- Training — is the run long and multi-node? If it spans more than a handful of nodes for more than a few hours, invest in checkpointing and orchestration before optimizing throughput further — an unrecoverable failure costs more than a suboptimal parallelism choice.
- Inference — are you serving concurrent users? Continuous batching and prefix caching are almost always the first, cheapest wins — they require no model changes and directly attack idle GPU time.
- Inference — is memory the ceiling, not compute? Reach for KV-cache-focused techniques (efficient attention variants, PagedAttention) and quantization before adding more GPUs; see the ten inference mechanics above for how each works.
- Inference — is the bill the problem rather than latency? Start with routing each request to the smallest capable model and layering caches (exact, semantic, prefix); then add compression and context trimming. See cutting inference cost in production.
- Either side — measure before you optimize. Training bottlenecks show up as low GPU utilization or communication-bound step times; inference bottlenecks show up as TTFT/TPOT regressions or falling requests-per-GPU. Instrument both before reaching for a specific technique — see the LLM observability tools directory for tooling.
Frequently Asked Questions
What is the single highest-leverage optimization for LLM training?
Matching your parallelism strategy to your memory budget. Most wasted training spend comes from either over-parallelizing a model that fits on one GPU (adding needless communication overhead) or under-parallelizing one that doesn't (forcing painful gradient accumulation or out-of-memory crashes).
What is the single highest-leverage optimization for LLM inference?
Continuous batching. Moving from static or dynamic batching to continuous (in-flight) batching is usually the cheapest, highest-impact change a serving stack can make, since it keeps GPUs busy under unpredictable, bursty traffic without any change to the model itself.
Do the same techniques apply to both training and inference?
Some cross over — mixed-precision arithmetic and interconnect-aware placement, for example — but most do not. Training optimizes throughput on a large, fixed compute budget over days or weeks; inference optimizes latency and cost per request in real time. That difference in objective drives largely different tooling on each side.
How much does quantization affect model accuracy?
It depends on the technique and bit width. Well-tuned INT8 quantization is often near-lossless on standard benchmarks, while aggressive INT4 quantization (via methods like GPTQ or AWQ) typically costs a small, measurable amount of accuracy in exchange for roughly a 4x reduction in memory footprint versus FP32.
Where should I start when trying to cut LLM inference cost?
Start with routing and caching. Send each request to the smallest model that can handle it, and layer exact-match, semantic and prefix caching so repeated work never reaches the model. Then add quantization or distillation, trim the context you send, and put usage governance and cost observability around all of it.
What is the difference between prefix caching and semantic caching?
Prefix caching reuses the model's stored attention state for an identical prompt beginning, inside the serving engine. Semantic caching sits above the model and returns a stored answer when a new query is similar enough in meaning to an earlier one. They are complementary.
What is the difference between prefill and decode?
Prefill processes the prompt and builds the KV cache; it parallelizes well and is usually compute-bound. Decode generates tokens one at a time and is often limited by memory bandwidth at practical batch sizes.
Why is tokens per second a misleading inference metric?
Aggregate throughput can look strong while individual users wait too long for the first token. TTFT, inter-token latency, tail latency and goodput show whether requests actually meet the latency target.
Match the Optimization to the Bottleneck
A LinkedIn post by AI Mill (30 October 2026) makes the point that production LLM performance depends on more than model size or GPU count: it depends on how efficiently memory, compute, batching, parallelism and scheduling are managed, and the goal is more tokens per GPU-second, lower latency, higher throughput and lower cost per token. It names seven key inference optimizations and a simple bottleneck-to-technique mapping, summarized here in our own words and consistent with the mechanics above.
- Model too large for the memory you have? Quantization: lower precision means lower memory use and more efficient inference.
- Generation feels slow? KV caching, which reuses computed key-value states instead of recalculating them, and speculative decoding, where a smaller model drafts tokens that a larger model verifies.
- High concurrency? Continuous batching, which schedules requests dynamically to keep GPUs well utilized.
- Model too large for one GPU? Parallelism: tensor parallelism splits computation across GPUs, and pipeline parallelism distributes layers across GPUs for large-scale inference.
- Serving cost is the problem? Knowledge distillation transfers capabilities into a smaller model to reduce inference cost, a technique covered under compression above.
The post asks which optimization to prioritize first: KV caching, continuous batching, quantization or speculative decoding. There is no universal answer; the framework above suggests continuous batching and prefix caching as the cheapest first wins for concurrent serving, and measuring TTFT, TPOT and requests per GPU before choosing. See the post for the original.