Notes on AI Engineering, chapter 9: Inference optimisation

Nov 24, 2025

This blog post consists of notes based on the Kindle highlights I made while reading Chip Huyen's AI Engineering.


An owl perched on a log
An owl perched on a log by Tim Zänkert

There is no single best way to optimize inference. The right solution depends on the model, the available hardware, the serving workload, the task, and the performance requirements.

Inference can be optimized at three levels:

  • Model - change or compress the model, its decoding process, or its attention mechanism.
  • Hardware - choose and use accelerators suited to the workload.
  • Service - improve how requests, memory, and compute resources are managed.

Chapter 9 introduces metrics for evaluating inference efficiency and then examines optimization techniques, experiments, and research results. Although it discusses all three levels conceptually, its detailed optimization techniques focus mainly on the model and inference service levels.

Measuring inference efficiency

“Fast” is too vague to describe an inference system. Several metrics are needed.

  • Latency: The time required to process a request.
  • Time to first token (TTFT): The time between submitting a prompt and receiving the first output token.
  • Time per output token (TPOT): The average time required to produce each subsequent output token.
  • Throughput: The amount of work processed per unit of time, such as requests per second or tokens per second.
  • Goodput: The portion of throughput that satisfies a service requirement, such as a latency limit.

An approximate latency relationship is:

total latency ≈ TTFT + TPOT × (number of output tokens - 1)

Input length primarily affects prefill and TTFT. Output length determines the number of sequential decoding steps and therefore has a large effect on total latency.

FLOPs and FLOP/s

  • A FLOP is one floating-point operation.
  • FLOPs can describe the quantity of computation required.
  • FLOP/s measures the rate at which hardware performs floating-point operations.
  • TFLOP/s means trillions of floating-point operations per second.

The distinction matters: the amount of computation a model needs is different from the rate at which hardware can execute it.

Prefill and decode

LLM inference has two phases with different resource profiles.

PhaseWhat happensTypical bottleneckMain metric affected
PrefillProcess input tokens in parallel and populate the initial KV cacheComputeTTFT
DecodeGenerate output tokens sequentially while reading weights and cached statesMemory bandwidthTPOT

The model weights are normally already stored in accelerator memory during decoding. However, every decoding step needs to transfer/read the weights from high-bandwidth memory into the compute units. This repeated data movement, combined with relatively little computation for a single token, makes decoding memory-bandwidth-bound.

Because prefill and decode have different resource requirements, a large serving system can place them on different instances. This prevents compute-heavy prefill jobs from interfering with active decoding jobs and allows each group of machines to be optimized independently. The trade-off is the cost and complexity of transferring intermediate state, especially the KV cache, between instances.

Model-level optimization

Model compression

Quantization represents model values with fewer bits. It reduces the memory footprint and can increase throughput. Weight-only quantization is popular because it is effective and relatively easy to apply, although aggressive quantization can affect model quality.

Distillation trains a smaller student model to imitate a larger teacher model. This produces a genuinely smaller model that can be cheaper and faster, but it might not preserve all of the teacher’s capabilities.

Pruning removes neural-network components or sets less useful parameters to zero. It can create a smaller or sparser model, but practical speed improvements depend on whether the hardware can exploit the resulting sparsity.

Speculative decoding

Speculative decoding addresses the sequential generation bottleneck:

  • A fast draft model proposes several tokens.
  • The target model evaluates those tokens in parallel.
  • It accepts the longest valid prefix and generates an additional token.
  • The process repeats from the new position.

The target model is not checking whether the draft is factually correct. It checks whether the proposed tokens are compatible with what the target model would generate.

This can be faster because verifying several tokens in parallel is more efficient than generating them one at a time with the target model. It works best when the draft model is fast and its acceptance rate is high. Structured outputs such as code can have high acceptance rates because many tokens are relatively predictable.

Speculative decoding is not automatically faster or cheaper. If many draft tokens are rejected, the system pays for draft generation and verification while making little progress.

Attention and the KV cache

During inference, the KV cache stores the key and value vectors of previous tokens so the model does not recompute them at every decoding step. It trades memory for computation.

Key and value vectors are computed during both training and inference, but the growing KV cache is an inference mechanism. During training, all tokens are available and their computations can be parallelized.

KV-cache memory grows with:

  • Sequence length
  • Batch size
  • Number of transformer layers
  • Model dimension
  • Numerical precision

Consequently, long prompts, long conversations, and high concurrency can make the KV cache a major memory bottleneck. Available memory can limit context length, batch size, or the number of simultaneous requests.

Attention optimization falls into three broad groups:

  • Redesign the attention mechanism

    • Local windowed attention
    • Multi-query attention
    • Grouped-query attention
    • Cross-layer attention
  • Manage or compress the KV cache

    • PagedAttention
    • KV-cache quantization
    • Adaptive compression
    • Selective caching
  • Optimize attention computation

    • Specialized kernels such as FlashAttention
    • Operator fusion and improved memory-access patterns

PagedAttention divides the cache into non-contiguous blocks, which reduces fragmentation and enables more flexible memory use. Kernel optimization solves a related but different problem: it accelerates computation and reduces unnecessary data movement rather than primarily shrinking the cache.

Service-level optimization

Batching

Batching improves throughput by processing multiple requests together, but it introduces a latency trade-off.

TypeHow it worksMain trade-off
Static batchingWait for a fixed number of requestsFull batches, but early requests might wait a long time
Dynamic batchingProcess when the batch is full or a timer expiresBounds waiting time, but batches may be partially filled
Continuous batchingRemove completed requests and replace them immediatelyBetter utilization, but more complex scheduling

Continuous batching is similar to a bus that can drop off one passenger and immediately use the free seat for another. It is particularly useful for LLM requests because response lengths vary substantially.

Prompt caching

Prompt caching, also called prefix or context caching, reuses the processed state of overlapping prompt prefixes. For example, a long system prompt can be processed once and reused across many requests.

It is valuable for:

  • Long, repeated system prompts
  • Multiple questions about the same document or codebase
  • Many-shot prompts with repeated examples
  • Multi-turn conversations whose earlier messages remain unchanged

Prompt caching can reduce TTFT and input-processing cost. Like other caches, it trades memory for computation and introduces storage, eviction, invalidation, and implementation concerns.

Parallelism

StrategyWhat is duplicated or split?Primary benefitMain cost
Replica parallelismComplete model copiesServe more requests concurrentlyEach replica requires memory for the whole model
Tensor parallelismTensor operations within layersFit large models and potentially reduce latencyFrequent communication between devices
Pipeline parallelismConsecutive model layers or stagesFit large models and improve pipeline throughputCommunication and potentially greater request latency

If the model fits on one GPU but traffic is too high, replica parallelism is a natural choice. If the model cannot fit on one GPU, tensor parallelism is commonly preferred for latency-sensitive inference. Pipeline parallelism can also make large models fit, but is especially common in training, where throughput is often more important than individual request latency.

Personal conclusion

The most important lesson is that inference optimization is workload-dependent. There is no fixed collection of techniques that is always best. An optimization that helps one application can hurt another by increasing latency, memory use, engineering complexity, or quality degradation.

The decision should begin with questions such as:

  • What model are we serving?
  • What hardware is available?
  • Are inputs or outputs usually long?
  • Do prompts contain repeated prefixes?
  • Is the workload interactive or asynchronous?
  • Is latency, throughput, cost, or output quality the highest priority?
  • Which service-level objective must requests satisfy?

Optimization should follow measurement. First identify the actual bottleneck, then choose a technique whose trade-offs match the task.