LLM Serving: Continuous Batching, Distributed Execution, and Service-Level ObjectivesLLM 服務部署:連續批次處理、分散式執行與服務等級目標
How do you serve 10,000 concurrent users? A deep dive into continuous batching, disaggregated prefill architectures, and multi-GPU parallelism to meet strict Service-Level Objectives in production, plus a troubleshooting quick-reference.要如何同時服務一萬名並發使用者?本文深入探討連續批次處理、分離式預填充架構,以及多 GPU 平行化,說明如何在正式環境中達成嚴格的服務等級目標,並附上疑難排解快速參考。

This is the final article in a three-part series. The first article deconstructed the mathematical anatomy of a decoder-only transformer. The second article zoomed in on hardware execution, exploring how KV caching, FlashAttention, and model compression tame the strict memory-bandwidth bottlenecks of the generation loop. This article focuses on running LLMs in the production system.
But a highly optimized model is only half the battle. In a vacuum, generating tokens is an algorithmic challenge; in production, it is a distributed systems challenge.
This final article steps outside the model's architecture. We focus on the infrastructure required to turn a raw computational graph into a scalable, highly concurrent service. We will explore how to dynamically schedule continuous request queues, distribute massive models across multi-GPU clusters, and navigate the unavoidable tension between throughput, latency, and hardware costs to guarantee strict Service-Level Objectives (SLOs).
The content is structured as:
- Request orchestration: Batching strategies
- Scaling execution: Model parallelism
- The core tension: Throughput, latency, and cost
- SLO thinking and serving frameworks
- Infrastructure and system design reference
- Conclusion
1. Request orchestration: Batching strategies
Unlike traditional microservices where inputs are uniform (predictable data types or fixed-schema JSON payloads), LLM inference workloads are highly heterogeneous:
- Asynchronous arrival: Users and automated systems send prompts at entirely unpredictable intervals.
- Variable lengths: One request might be a five-token classification prompt, while the next requires processing a 10,000-token document.
If a GPU processes these requests sequentially, it sits mostly idle, starved for compute. To maximize hardware utilization, serving engines group multiple requests into batches. However, because requests do not finish at the same time, how the engine forms these batches dictates the system's performance.
The Evolution of Batching
In production, a batch usually contains independent requests from multiple users. Batching never mixes the actual text of different users; it simply groups their independent tensor operations for parallel execution on the accelerator, with each request maintaining its own sequence state, decoding parameters, and KV cache.
| Strategy | Mechanism | Production Limitation |
|---|---|---|
| Static batching | The server waits for a predefined number of requests, pads them to the length of the longest prompt, and executes them together. | Severe latency degradation; short sequences remain trapped waiting for long sequences to finish. |
| Dynamic batching | The server opens a brief time window (e.g., 50ms) to collect incoming requests into a batch before execution. | Improved throughput, but batch membership still only changes at request boundaries. |
| Continuous batching | The scheduler operates strictly at the token level. It ejects finished sequences and pulls new requests into the active batch at every single iteration step. | Requires advanced cache-aware memory management (like PagedAttention) to function. |
Continuous batching (iteration-level scheduling) is the modern industry standard. Because finished sequences leave immediately and waiting requests take their place in the very next decode step, GPU downtime drops to nearly zero. This is the key throughput innovation in vLLM and TGI. GPU utilization goes from ~40-60% (static) to ~90%+ (continuous).
Time (Iteration Steps) ──────────────────────────────────────►
Step 1: [ Req 1 | Req 2 | Req 3 | Req 4 ]
Step 2: [ Req 1 | Req 2 | Req 3 | Req 5 ] ← Req 4 finishes, Req 5 enters instantly
Step 3: [ Req 1 | Req 6 | Req 3 | Req 5 ] ← Req 2 finishes, Req 6 enters instantly
Step 4: [ Req 1 | Req 6 | Req 7 | Req 5 ] ← Req 3 finishes, Req 7 enters instantly
Result: Zero wait time at request boundaries. The GPU is always fully utilized.
Advanced Scheduling Policies
Beyond the core batching loop, schedulers must balance fairness, priority, and physical memory limits using advanced policies.
Handling Memory Exhaustion: Preemption
If active requests generate longer responses than anticipated and the GPU's KV cache pool reaches 100% capacity mid-generation, the scheduler cannot simply crash. It must trigger preemption. The engine pauses the lowest-priority request, evicts its KV cache blocks from the GPU's HBM to the slower host CPU memory (swapping), and allows the remaining requests to finish. Once VRAM frees up, the evicted request is swapped back in (or its prefix is recomputed) to resume decoding.
Mitigating Resource Contention: Chunked Prefill
When a massive new prompt arrives, processing its entire prefill phase in one go can stall the iteration loop, causing latency spikes for all other users currently in the decode phase. Chunked prefill breaks that giant prompt into smaller segments, spreading the heavy matrix multiplication across multiple scheduler steps so it does not starve the concurrent decode loop.
Bypassing Compute: Prefix-Aware Routing
In complex production environments—especially multi-agent backends or applications with massive, standardized system prompts—many requests share identical context. Prefix-aware scheduling (Prompt Caching) maps requests with shared prefixes to the exact same physical KV cache blocks in memory. Instead of executing the compute-heavy prefill phase for every request, the engine computes it once, effectively turning a slow prefill into an instantaneous decode step for all subsequent users.
Ultimately, maximizing raw throughput is not always the correct business objective. A highly aggressive batching strategy will maximize device utilization, but it heavily increases queue times and the duration of each decode iteration.
2. Scaling execution: Model parallelism
What happens when an uncompressed 70-billion parameter model (roughly 140 GB in FP16 precision) physically cannot fit into a single 80 GB GPU? Or when the KV cache for a massive continuous batch exceeds a single accelerator's memory? The model must be partitioned across a distributed cluster.
This is called Model Parallelism. Distributing an LLM solves memory and compute constraints, but introduces a massive new bottleneck: network communication overhead.
| Technique | Partition Strategy | Main communication | Primary Use Case | Hardware Limitation |
|---|---|---|---|---|
| Data parallelism | The entire model is replicated across different GPUs; user requests are divided among them. | Request routing; little per-token model communication | Scaling raw throughput for models that fit on a single GPU. | Does not solve VRAM capacity limits if the model is too large. |
| Tensor parallelism (Vertical Split) | Shards individual weight matrices (and attention heads) across GPUs within the same layer. | Collective communication at every layer boundary. | Fitting wide models and reducing single-request latency. | Requires ultra-high-bandwidth interconnects (e.g., NVLink) to prevent latency spikes. |
| Pipeline parallelism (Horizontal Split) | Shards the model sequentially; GPU A takes layers 1-16, GPU B takes 17-32. | Point-to-point passing of intermediate activations between stages. | Fitting extremely deep models across multiple physical server nodes. | Introduces "pipeline bubbles" (idle time where GPUs wait for the previous stage to finish). |
| Expert parallelism | Distinct experts in a Mixture-of-Experts (MoE) model reside on different GPUs. | Token-routing all-to-all to the right expert GPU | Serving massive MoE architectures. | Creates highly complex, bursty network routing overhead. |
| Context parallelism | A massive prompt is chunked, and different GPUs process different sequence segments.s | Attention-specific collective communication. | Processing extreme context windows (e.g., 1M+ tokens). | Substantial network traffic during the prefill phase. |
Large production deployments compose these dimensions together (e.g., using 3D parallelism: Tensor parallelism + Pipeline parallelism + Data parallelism). The governing rule of distributed inference is topology-aware placement: communication-heavy partitions (like Tensor Parallelism) must remain on the fastest available local interconnects (like intra-node NVLink), while less chatty partitions (like Pipeline Parallelism) can span across standard network boundaries (like inter-node InfiniBand). (The foundational approach to this topology is detailed in Megatron-LM).
When adding additional GPUs fails to improve token latency or throughput, engineers must measure collective time, pipeline bubbles, and interconnect saturation before adding more hardware. Parallelism solves compute constraints by accepting communication overhead; physical topology determines whether that trade is worthwhile.
3. The core tension: Throughput, latency, and cost
In LLM serving, an unqualified "tokens per second" is a meaningless metric.
The fundamental physics of an inference server are dictated by a single lever: Batch Size. Pumping more requests into a continuous batch utilizes the GPU's compute cores more efficiently and raises the system's aggregate throughput. However, because the hardware must process more sequences concurrently, the time it takes to calculate each individual token step increases. This drives up Inter-Token Latency (ITL), making the model feel sluggish to the end user.
Therefore, measuring performance requires explicitly defining the phase, the load, and the perspective of the measurement.
| Metric | Definition | Perspective |
|---|---|---|
| Time to first token (TTFT) | Request arrival to the first streamed token. | User experience (Waiting for the system to "think") |
| Inter-token latency (ITL) | Gap between consecutive streamed tokens. | User experience (Reading speed) |
| Time per output token (TPOT) | Average generation time after the first token. | System average |
| End-to-end latency | Request arrival to the final generated token. | Total transaction time |
| Input throughput | Prompt tokens processed per second. | System capacity (Prefill bound) |
| Output throughput | Generated tokens completed per second. | System capacity (Decode bound) |
| Request throughput | Requests completed per second. | Business capacity |
Increasing concurrency improves aggregate throughput until the memory, compute, scheduler, or interconnect saturates. Simultaneously, latency rises as requests queue and batches grow. The result is a Pareto frontier—there is no single optimal configuration, only a deliberate trade-off between maximizing hardware utilization and preserving user experience.
The Anatomy of a Valid Benchmark
Because of this tension, a meaningful production benchmark cannot just be a single throughput number. It must explicitly state:
- Prompt and output-length distributions
- Arrival rate and concurrency levels
- Streaming and decoding settings (e.g., greedy vs. beam search)
- Model architecture, precision, and KV cache format
- Hardware topology and interconnect bandwidth
- Serving engine version and scheduler configuration
- Latency percentiles (e.g., p90, p99), never just averages
When a live system struggles, the runtime symptoms dictate the necessary interventions:
| Observed Symptom | Likely Bottleneck | Candidate Interventions |
|---|---|---|
| Slow token streaming (High ITL) | Decode bandwidth limit, oversized batches, or slow distributed communication. | Cap the continuous batch size, apply KV-cache quantization, evaluate speculative decoding, or inspect interconnect traffic. |
| High p99 TTFT with an acceptable mean | Severe queuing or head-of-line blocking during prefill. | Implement strict admission control, fair scheduling, and chunked prefill. |
| Low accelerator utilisation | Insufficient work or scheduler overhead gaps. | Ensure continuous batching is active, increase the token budget, or utilize CUDA graph capture. |
Calculating True Cost
For a fixed deployment, the baseline infrastructure cost is straightforward:
However, the denominator (output tokens per hour) must be measured at a declared load where the service still meets its latency SLO. Driving a server beyond its sustainable arrival rate might inflate the aggregate throughput number, but it causes queuing latency to grow without bound.
Throughput that violates your user-facing latency requirements is useless. Furthermore, a complete application-level cost must also account for retries, structured-output parsing failures, and human review overhead caused by aggressive model compression or optimization regressions.
4. SLO thinking and serving frameworks
A Service-Level Objective (SLO) translates runtime behavior into a strict application contract. In production, engineers cannot simply mandate, "We want the model to be fast." That is an unmeasurable aspiration. Instead, an SLO defines exactly what "fast" means, under what precise conditions, and the statistical reliability with which the system promises to deliver it.
For example:
For interactive prompts of at most 2,000 tokens:
p95 TTFT <= 800 ms
p95 ITL <= 60 ms
error rate < 0.5%
measured over rolling 30-minute windows
The exact thresholds depend entirely on the product. The critical properties of a valid SLO are a tightly defined workload, a specific percentile, a hard threshold, and a measurement time window.
The Tail Latency Trap
"Average latency" is a massive trap in LLM serving. Because workloads are so variable (as we discussed in batching), nine users might experience lightning-fast responses while the tenth user gets stuck behind a massive 100,000-token prefill job, waiting 45 seconds for a single word.
If you average those ten users, the system looks completely healthy. But in reality, 10% of your users are experiencing an utterly broken product. This is why SREs track tail latency (p90, p95, p99). Tracking the p99 forces the engineering team to look at the absolute worst-case scenarios and optimize the system for the users waiting the longest.
Defensive Engineering
To successfully meet these SLO promises, you must aggressively defend your servers from being overwhelmed. GPU compute and KV cache memory are highly constrained resources. An enterprise-grade deployment requires strict operational safety mechanisms to prevent malformed or abusive requests from degrading the experience for everyone else:
- Bounded Contexts: Hard-cap the maximum allowed prompt and output lengths to prevent cache exhaustion.
- Admission Control & Load Shedding: Apply strict queue timeouts, enforce per-tenant rate limits, and proactively return
HTTP 429 Too Many Requestsbefore the service exhausts its VRAM. - Prompt Validation: Reject malformed inputs or unsupported modalities at the API gateway before they are ever allocated accelerator work.
- Traffic Isolation: Physically or logically separate long-running background batch jobs from latency-sensitive interactive user traffic.
The Quality Constraint: If you aggressively optimize your engine (using extreme quantization or tiny beam widths) just to hit a 10ms ITL SLO, but the model begins outputting hallucinations or broken JSON, the infrastructure has failed. Latency and throughput metrics must always be balanced against the model's actual intelligence and structural validity.
Serving Frameworks
A basic Python script can execute an LLM one token at a time, but it cannot provide the cache management, continuous scheduling, observability, or defensive overload controls required by a shared production service. Modern serving frameworks supply these capabilities natively alongside hardware-specific execution optimizations.
| Framework | Strong Fit | Notable Capabilities |
|---|---|---|
| vLLM | General high-throughput accelerator serving. | PagedAttention, continuous batching, prefix caching, quantization (AWQ/GPTQ), and distributed inference. |
| SGLang | Complex, multi-agent backend chatbot services and structured workflows. | RadixAttention for extreme prefix reuse, structured JSON output enforcement, and disaggregated serving. |
| TensorRT-LLM | NVIDIA-specific, hyper-optimized deployment. | used kernels, in-flight batching, paged cache, and maximum hardware utilization. |
| llama.cpp | Local, edge, CPU, Apple Silicon, and mixed-device inference. | GGUF quantisation, broad hardware backends, and lightweight server, continuous batching. |
(Note: While Hugging Face TGI remains present in many established deployments, its current documentation describes the project as being in maintenance mode, recommending engines such as vLLM, SGLang, and llama.cpp for new architectural deployments).
Ultimately, framework selection should be based on the target model, hardware topology, structured decoding requirements, operational support, and your measured workload—never on a single, isolated public throughput benchmark.
5. Infrastructure and system design reference
This final reference section condenses the resources, workload phases, and operational signals needed to connect theoretical model behavior with live production performance.
5.1 Production Troubleshooting
Optimisation should begin with the observed constraint.
| Symptom | Likely Bottleneck | Candidate Interventions |
|---|---|---|
| High TTFT for long prompts | Prefill compute or scheduling queue | FlashAttention, chunked prefill, prefix caching, prompt reduction, or disaggregated prefill. |
| Slow token streaming (High ITL) | Decode bandwidth or network communication | Smaller continuous batches, weight quantization, migrating to a GQA model, speculative decoding, or topology-aware parallelism. |
| Cache OOM or low concurrency | KV cache capacity | Paged cache management, models with fewer KV heads, shorter context limits, KV quantization, or adding device memory. |
| High p99 with an acceptable mean | Queuing or head-of-line blocking | Admission control, strict traffic classes, fair scheduling, and chunked prefill. |
| Low accelerator utilization | Insufficient work or scheduling gaps | Ensure continuous batching is active, increase the token budget, use CUDA graph capture, or tune the scheduler. |
| Quality regression | Compression or decoding change | Revert to higher precision, improve calibration data, lower sampling variance, and run task-level evaluations. |
5.2 Infrastructure Memory Capacity
| Component | Hardware Approximation |
|---|---|
| Model weights | Parameter count stored bytes per parameter |
| KV cache | |
| Training gradients | Parameter count gradient bytes |
| Optimiser state | Optimizer-dependent; commonly multiple values per parameter |
| Activations | Highly dependent on architecture, batch size, sequence length, checkpointing, and specific kernels |
5.3 Workload Phases
| Phase | Primary Work Unit | Persistent State | Frequent Bottleneck |
|---|---|---|---|
| Pretraining | Complete training batch | Parameters and optimiser | Compute, communication, activation memory |
| Prefill | Prompt or prompt chunk | Writes to KV cache | Compute and attention IO |
| Decode | One position per active sequence | Reads and extends KV cache | Weight/KV memory bandwidth and scheduling |
5.4 Production Monitoring
Monitoring must connect demand, scheduler behavior, cache pressure, hardware saturation, user-visible latency, and model quality. No single metric explains the system by itself.
| Monitoring Layer | Core Signals | What It Helps Answer |
|---|---|---|
| Demand and workload | Arrival rate, concurrency, queue depth, prompt/output distributions. | Is the overall traffic volume or request shape changing? |
| User-visible latency | TTFT, ITL, TPOT, and end-to-end latency at p50, p95, and p99. | Which inference phase is violating the user experience? |
| Throughput and scheduling | Input/output tokens per second, requests per second, active sequences, batched tokens per iteration. | Is the scheduler keeping the accelerator productively occupied? |
| KV-cache health | Utilization, allocation failures, preemptions, evictions, swapped blocks, and prefix-cache hit rate. | Is cache pressure limiting concurrency or causing latency spikes? |
| Accelerator and network | Compute utilization, VRAM usage, memory bandwidth, power, temperature, and interconnect traffic. | Is the hardware bottleneck rooted in compute, memory, or network? |
| Reliability | Cancellations, timeouts, overload responses (429s), OOM events, restarts, and error rates. | Is the service shedding or failing work safely? |
| Model and application quality | Task success, safety violations, structured-output validity, retries, and human-review rate. | Did an infrastructure optimization destroy useful model behavior? |
Metrics should be strictly segmented by model version, serving configuration, workload class, and traffic priority. Engineers must use histograms and percentiles rather than averages alone, alert on SLO burn rates alongside leading indicators (like queue saturation), and relentlessly correlate performance changes with quality evaluations.
6. Conclusion
The complete dependency chain is now visible. Causal attention creates reusable keys and values; their mathematical shape dictates physical cache capacity; the growth of that cache drives paged memory allocation and continuous request scheduling; and rigorous production monitoring reveals exactly which resource or policy must be adapted to meet strict SLOs.

Ultimately, exposing a raw model checkpoint to the internet does not constitute a production service. To guarantee consistent, reliable behavior at scale, a release must be treated as a fully reproducible artifact. This requires locking down every moving part of the execution pipeline: not just the model weights, but the tokenizer version, chat templates, quantization schemes, the specific serving engine, hardware kernels, and generation hyperparameters.
Before routing live traffic to an endpoint, the infrastructure must be rigorously validated against the unpredictable realities of production environments. A robust serving layer must account for:
- Operational resilience: Managing cold-start warm-ups, absorbing massive traffic spikes without crashing, and executing graceful out-of-memory (OOM) recovery when the KV cache fills up.
- Edge cases and client volatility: Handling malformed requests, gracefully truncating prompts that exceed the maximum context window, and safely halting compute when a client rapidly disconnects or cancels a request mid-generation.
- Security and execution boundaries: Strictly enforcing structured-output constraints (e.g., guaranteed JSON schema adherence) and maintaining absolute multi-tenant memory isolation to ensure different users' data remains completely separate.nally, your offline evaluation suite must also run against the live, served API.
Finally, a successful deployment requires running your offline evaluation suite directly against the live, served API. Modifying the quantization strategy, updating a GPU kernel, or swapping the serving framework can subtly alter the model's output distribution—even if your core application code remains completely untouched.
The transformer's architecture and the infrastructure serving it are not separate concerns. A model is only as deterministic as the infrastructure serving it.
本文是三部曲系列的最後一篇。第一篇文章,拆解了純解碼器 Transformer 的數學解剖結構。第二篇文章,則聚焦於硬體執行層面,探討 KV 快取、FlashAttention 與模型壓縮,如何馴服生成迴圈中嚴格的記憶體頻寬瓶頸。本文則專注於如何在正式系統中運行 LLM。
但一個高度優化的模型,只贏得了一半的戰役。在真空狀態下,生成 token 是一個演算法上的挑戰;而在正式環境中,它則是一個分散式系統的挑戰。
這最後一篇文章,會跳脫模型架構本身,聚焦於將一張原始的運算圖,轉化為可擴展、高並發服務所需要的基礎設施。我們會探討如何動態排程持續不斷的請求佇列、如何將龐大的模型分散到多 GPU 叢集之中,並且如何在吞吐量、延遲與硬體成本這三者之間,處理無可避免的張力,藉此確保嚴格的服務等級目標(SLO)得以實現。
本文結構如下:
1. 請求協調:批次處理策略
與傳統微服務不同——傳統微服務的輸入通常是均勻的(可預測的資料型別,或固定結構的 JSON 負載)——LLM 推論工作負載則高度異質:
- 非同步抵達:使用者與自動化系統,會在完全無法預測的時間點傳送提示詞。
- 長度不一:某個請求可能只是一段五個 token 的分類提示詞,下一個請求卻可能需要處理一份一萬個 token 的文件。
如果 GPU 依序處理這些請求,大部分時間都會處於閒置狀態,運算力嚴重不足。為了將硬體使用率發揮到極致,服務引擎會將多個請求分組成批次。然而,由於各個請求並不會同時完成,引擎組成批次的方式,將直接決定整個系統的效能表現。
批次處理的演進
在正式環境中,一個批次通常會包含來自多位使用者的獨立請求。批次處理絕不會混合不同使用者的實際文字內容;它只是把彼此獨立的張量運算分組在一起,以便在加速器上平行執行,而每個請求,都各自維護著自己的序列狀態、解碼參數與 KV 快取。
| 策略 | 運作機制 | 正式環境的限制 |
|---|---|---|
| 靜態批次處理 | 伺服器會等待累積到預先定義的請求數量,將它們全部填充(padding)到最長提示詞的長度,再一起執行。 | 延遲嚴重惡化;較短的序列,會被困住等待較長的序列完成。 |
| 動態批次處理 | 伺服器會開啟一段短暫的時間視窗(例如 50 毫秒),在執行前先收集陸續抵達的請求成為一個批次。 | 吞吐量有所改善,但批次的成員,仍然只會在請求的邊界處變動。 |
| 連續批次處理 | 排程器嚴格以 token 為單位運作。在每一個迭代步驟中,它都會將已完成的序列排出,並將新的請求拉進目前作用中的批次。 | 需要進階的快取感知記憶體管理(例如 PagedAttention)才能運作。 |
連續批次處理(也就是迭代層級的排程),是現今業界的標準做法。由於已完成的序列會立即離開,而等待中的請求會在緊接著的下一個解碼步驟中遞補上場,GPU 的閒置時間幾乎降到零。這正是 vLLM 與 TGI 在吞吐量上的關鍵創新——GPU 使用率能從靜態批次的約 40–60%,提升到連續批次處理的 90% 以上。
時間(迭代步驟)──────────────────────────────────────►
步驟 1:[ 請求 1 | 請求 2 | 請求 3 | 請求 4 ]
步驟 2:[ 請求 1 | 請求 2 | 請求 3 | 請求 5 ] ← 請求 4 完成,請求 5 立即遞補
步驟 3:[ 請求 1 | 請求 6 | 請求 3 | 請求 5 ] ← 請求 2 完成,請求 6 立即遞補
步驟 4:[ 請求 1 | 請求 6 | 請求 7 | 請求 5 ] ← 請求 3 完成,請求 7 立即遞補
結果:請求邊界處的等待時間為零,GPU 始終保持滿載運作。
進階排程策略
除了核心的批次處理迴圈之外,排程器還必須運用進階策略,在公平性、優先順序與實體記憶體限制之間取得平衡。
處理記憶體耗盡:搶佔
如果作用中的請求,生成的回應比預期更長,導致 GPU 的 KV 快取池在生成過程中就用滿了 100% 容量,排程器不能就這樣當機。它必須觸發搶佔機制:引擎會暫停優先順序最低的請求,將其 KV 快取區塊,從 GPU 的 HBM 驅逐到速度較慢的主機 CPU 記憶體中(也就是置換),讓其餘的請求得以繼續完成。一旦 VRAM 釋放出空間,被驅逐的請求就會被換回來(或是重新計算其前綴),繼續進行解碼。
緩解資源爭用:分塊預填充
當一個龐大的新提示詞抵達時,若一次性處理其完整的預填充階段,可能會讓迭代迴圈卡住,導致所有目前正處於解碼階段的其他使用者,出現延遲尖峰。分塊預填充,會把這個巨大的提示詞拆成較小的片段,將沉重的矩陣乘法運算,分散到多個排程步驟中執行,這樣就不會讓並行的解碼迴圈陷入資源匱乏。
繞過運算:前綴感知路由
在複雜的正式環境中——尤其是多代理(multi-agent)後端,或是採用龐大、標準化系統提示詞的應用程式——許多請求會共用完全相同的上下文。前綴感知排程(也就是提示詞快取),會把共用相同前綴的請求,映射到記憶體中完全相同的實體 KV 快取區塊。引擎不需要為每個請求都執行一次運算密集的預填充階段,只需計算一次,就能讓後續所有使用者的預填充,實質上變成一個瞬間完成的解碼步驟。
說到底,將原始吞吐量最大化,並不總是正確的商業目標。過於激進的批次處理策略,雖然能讓裝置使用率達到最高,卻也會大幅拉長佇列等候時間,以及每次解碼迭代所需要的時間。
2. 擴展執行規模:模型平行化
當一個未經壓縮、擁有 700 億參數的模型(以 FP16 精度儲存約需 140 GB),在實體上根本無法塞進單一一張 80 GB 的 GPU 時,會發生什麼事?或者,當一個龐大連續批次所需要的 KV 快取,超出單一加速器的記憶體容量時,又會如何?此時,模型必須被切分到一整個分散式叢集之中。
這就稱為模型平行化。將 LLM 分散部署,能解決記憶體與運算上的限制,卻也引入了一個龐大的全新瓶頸:網路通訊開銷。
| 技術 | 切分策略 | 主要通訊方式 | 主要使用情境 | 硬體限制 |
|---|---|---|---|---|
| 資料平行 | 整個模型會被複製到不同的 GPU 上;使用者請求則被分配到各自的 GPU 上處理。 | 請求路由;每個 token 所需的模型通訊量極少 | 為能塞進單一 GPU 的模型,擴展原始吞吐量。 | 若模型本身過大,無法解決 VRAM 容量限制的問題。 |
| 張量平行(垂直切分) | 在同一層之內,將個別的權重矩陣(以及注意力 head)切分到多張 GPU 上。 | 每個層邊界都需要進行集體通訊。 | 容納寬度較大的模型,並降低單一請求的延遲。 | 需要超高頻寬的互連技術(例如 NVLink),才能避免延遲尖峰。 |
| 管線平行(水平切分) | 依序切分模型;例如 GPU A 負責第 1–16 層,GPU B 負責第 17–32 層。 | 各階段之間,點對點傳遞中間的激活值。 | 讓極深的模型,得以跨越多個實體伺服器節點。 | 會引入「管線氣泡」(GPU 閒置等待前一階段完成的空檔時間)。 |
| 專家平行 | 專家混合模型(MoE)中,不同的專家,分別存放在不同的 GPU 上。 | token 需以 all-to-all 的方式,路由到正確的專家 GPU | 為龐大的 MoE 架構提供服務。 | 會產生高度複雜、且流量爆發性強的網路路由開銷。 |
| 上下文平行 | 將龐大的提示詞切成多塊,由不同的 GPU 分別處理不同的序列片段。 | 特定於注意力機制的集體通訊。 | 處理極長的上下文視窗(例如 100 萬個以上的 token)。 | 在預填充階段,會產生大量的網路流量。 |
大型正式環境的部署,往往會將這些維度組合運用(例如採用 3D 平行化:張量平行+管線平行+資料平行)。分散式推論的核心原則,是拓撲感知配置:通訊量大的切分方式(例如張量平行),必須維持在最快速的本地互連技術上(例如節點內的 NVLink);而通訊較少的切分方式(例如管線平行),則可以跨越標準的網路邊界(例如節點之間的 InfiniBand)。(關於這種拓撲配置的基礎方法,詳見〈Megatron-LM〉。)
當增加更多 GPU,卻無法改善 token 延遲或吞吐量時,工程師在添購更多硬體之前,必須先量測集體通訊耗時、管線氣泡,以及互連頻寬的飽和程度。平行化是靠接受通訊開銷,來解決運算限制的問題;而實體拓撲,則決定了這筆交易究竟划不划算。
3. 核心張力:吞吐量、延遲與成本
在 LLM 服務部署中,一個沒有加上任何限定條件的「每秒 token 數」,是毫無意義的指標。
推論伺服器最根本的物理限制,是由單一一個槓桿所決定的:批次大小。把更多請求塞進一個連續批次中,能讓 GPU 的運算核心運用得更有效率,並提升系統整體的吞吐量。然而,由於硬體必須同時處理更多序列,計算每一個單一 token 步驟所需要的時間,也會隨之增加。這會拉高 token 間延遲(ITL),讓終端使用者感覺模型變得遲鈍。
因此,衡量效能時,必須明確定義所處的階段、負載狀況,以及量測的視角。
| 指標 | 定義 | 視角 |
|---|---|---|
| 首個 token 生成時間(TTFT) | 從請求抵達,到第一個串流輸出的 token 為止。 | 使用者體驗(等待系統「思考」) |
| token 間延遲(ITL) | 連續串流輸出的 token 之間的間隔。 | 使用者體驗(閱讀速度) |
| 平均每個輸出 token 耗時(TPOT) | 第一個 token 之後的平均生成時間。 | 系統平均值 |
| 端對端延遲 | 從請求抵達,到最後一個生成的 token 為止。 | 總交易時間 |
| 輸入吞吐量 | 每秒處理的提示詞 token 數。 | 系統容量(受限於預填充) |
| 輸出吞吐量 | 每秒完成生成的 token 數。 | 系統容量(受限於解碼) |
| 請求吞吐量 | 每秒完成的請求數。 | 業務容量 |
提高並發程度,能改善整體吞吐量,直到記憶體、運算力、排程器或互連頻寬達到飽和為止。與此同時,隨著請求排隊、批次不斷增大,延遲也會隨之上升。最終呈現的,是一條柏拉圖前緣(Pareto frontier)——並不存在單一的最佳設定,只存在「硬體使用率最大化」與「維持使用者體驗」之間,經過深思熟慮的取捨。
有效基準測試的解剖結構
正因為存在這種張力,一個有意義的正式環境基準測試,不能只給出單一一個吞吐量數字,而必須明確說明:
- 提示詞與輸出長度的分布情況
- 抵達速率與並發程度
- 串流與解碼相關設定(例如貪婪解碼或集束搜尋)
- 模型架構、精度與 KV 快取格式
- 硬體拓撲與互連頻寬
- 服務引擎版本與排程器設定
- 延遲的百分位數(例如 p90、p99),而不能只給平均值
當上線中的系統陷入困境時,執行期出現的症狀,就決定了必須採取哪些介入措施:
| 觀察到的症狀 | 可能的瓶頸 | 可能的介入方式 |
|---|---|---|
| token 串流輸出緩慢(ITL 偏高) | 解碼頻寬受限、批次過大,或分散式通訊速度緩慢。 | 限制連續批次的大小、套用 KV 快取量化、評估推測解碼,或檢查互連流量。 |
| p99 的 TTFT 偏高,但平均值尚可接受 | 預填充階段出現嚴重排隊,或隊首阻塞(head-of-line blocking)。 | 實施嚴格的允入控制、公平排程,以及分塊預填充。 |
| 加速器使用率偏低 | 工作量不足,或排程器本身存在間隙開銷。 | 確認連續批次處理已啟用、提高 token 預算,或使用 CUDA graph 擷取。 |
計算真實成本
對於一個固定的部署方案而言,基礎的基礎設施成本相當直接:
然而,分母(每小時輸出 token 數),必須是在服務仍然符合其延遲 SLO 的宣告負載下量測出來的。把伺服器逼到超出其可承受的抵達速率,或許能墊高整體吞吐量的數字,但也會讓排隊延遲無止盡地增長。
違反面向使用者延遲要求的吞吐量,毫無意義。此外,完整的應用程式層級成本,還必須把重試次數、結構化輸出解析失敗,以及因過度積極的模型壓縮或優化倒退,所導致的人工審核開銷,都納入考量。
4. SLO 思維與服務框架
服務等級目標(SLO),會把執行期的行為,轉化成一份嚴格的應用程式契約。在正式環境中,工程師不能只是規定「我們希望模型速度快」——這是一個無法被量測的空泛願望。取而代之的是,SLO 必須明確定義「快」究竟是什麼意思、在什麼樣的精確條件下成立,以及系統承諾以多高的統計可靠度來達成它。
舉例來說:
對於長度最多 2,000 個 token 的互動式提示詞:
p95 TTFT <= 800 毫秒
p95 ITL <= 60 毫秒
錯誤率 < 0.5%
以滾動式 30 分鐘時間窗計算
確切的門檻值,完全取決於產品本身。一個有效 SLO 的關鍵要素,是明確定義的工作負載、特定的百分位數、明確的門檻值,以及量測的時間窗。
尾端延遲陷阱
「平均延遲」在 LLM 服務部署中,是一個巨大的陷阱。由於工作負載變化極大(正如我們在批次處理小節中討論過的),九位使用者可能享受到閃電般的回應速度,而第十位使用者,卻可能卡在一個十萬 token 的龐大預填充任務後面,苦等 45 秒才等到一個字。
如果把這十位使用者的數字平均起來,系統看起來完全健康。但實際上,有 10% 的使用者,正在經歷一個徹底故障的產品。這正是為什麼 SRE 要追蹤尾端延遲(p90、p95、p99)。追蹤 p99,會迫使工程團隊直視最壞情境,並針對等待最久的那些使用者,來優化整個系統。
防禦性工程
要成功實現這些 SLO 承諾,你必須積極地保護伺服器,避免其被壓垮。GPU 運算力與 KV 快取記憶體,都是高度受限的資源。一個企業級的部署方案,需要嚴格的操作安全機制,防止格式錯誤或帶有惡意的請求,拖累其他所有人的使用體驗:
- 限制上下文長度: 對允許的最大提示詞與輸出長度,設下硬性上限,避免快取被耗盡。
- 允入控制與負載卸除: 套用嚴格的佇列逾時、針對每個租戶執行速率限制,並在服務耗盡其 VRAM 之前,主動回傳
HTTP 429 Too Many Requests。 - 提示詞驗證: 在 API 閘道端,就先拒絕格式錯誤的輸入或不支援的模態,避免它們被分配到加速器的運算資源。
- 流量隔離: 從實體或邏輯層面,將長時間運行的背景批次工作,與對延遲敏感的互動式使用者流量分開。
品質限制:如果你為了達成 10 毫秒的 ITL SLO,而積極優化引擎(採用極端的量化,或極小的集束寬度),結果模型卻開始輸出幻覺內容或格式錯誤的 JSON,那麼這套基礎設施就已經失敗了。延遲與吞吐量指標,永遠都必須與模型實際的智慧程度及結構有效性相互權衡。
服務框架
一個基本的 Python 腳本,確實能一次一個 token 地執行 LLM,但它無法提供共享正式服務所需要的快取管理、連續排程、可觀測性,或防禦性過載控制。現代的服務框架,會原生提供這些能力,並搭配針對特定硬體的執行優化。
| 框架 | 最適合的場景 | 值得注意的能力 |
|---|---|---|
| vLLM | 通用型、高吞吐量的加速器服務。 | PagedAttention、連續批次處理、前綴快取、量化(AWQ/GPTQ),以及分散式推論。 |
| SGLang | 複雜的多代理後端聊天機器人服務,以及結構化工作流程。 | RadixAttention(用於極致的前綴重用)、強制結構化 JSON 輸出,以及分離式服務。 |
| TensorRT-LLM | 專屬於 NVIDIA、高度優化的部署方案。 | 融合 kernel、飛行中批次處理(in-flight batching)、分頁式快取,以及最大化的硬體使用率。 |
| llama.cpp | 本地端、邊緣裝置、CPU、Apple Silicon,以及混合裝置的推論。 | GGUF 量化、廣泛的硬體後端支援、輕量化伺服器,以及連續批次處理。 |
(附註:雖然 Hugging Face TGI 仍存在於許多既有的部署環境中,但其目前的文件,已將該專案描述為維護模式,並建議新的架構部署改用 vLLM、SGLang 或 llama.cpp 等引擎。)
說到底,框架的選擇,應該根據目標模型、硬體拓撲、結構化解碼的需求、維運支援,以及你實際量測到的工作負載來決定——而不是單憑某一個孤立的公開吞吐量基準測試。
5. 基礎設施與系統設計參考
這個最終的參考小節,濃縮了將理論上的模型行為,與實際正式環境效能連結起來所需要的資源、工作負載階段與維運訊號。
5.1 正式環境疑難排解
優化工作,應該從實際觀察到的限制開始著手。
| 症狀 | 可能的瓶頸 | 可能的介入方式 |
|---|---|---|
| 長提示詞的 TTFT 偏高 | 預填充運算量,或排程佇列 | FlashAttention、分塊預填充、前綴快取、縮減提示詞,或分離式預填充。 |
| token 串流輸出緩慢(ITL 偏高) | 解碼頻寬,或網路通訊 | 縮小連續批次、權重量化、改用具備 GQA 的模型、推測解碼,或拓撲感知的平行化。 |
| 快取記憶體不足或並發數過低 | KV 快取容量 | 分頁式快取管理、採用較少 KV head 的模型、縮短上下文限制、KV 量化,或增加裝置記憶體。 |
| p99 偏高,但平均值尚可接受 | 排隊,或隊首阻塞 | 允入控制、嚴格的流量分級、公平排程,以及分塊預填充。 |
| 加速器使用率偏低 | 工作量不足,或排程間隙 | 確認連續批次處理已啟用、提高 token 預算、使用 CUDA graph 擷取,或調校排程器。 |
| 品質衰退 | 壓縮或解碼方式的變動 | 還原至較高精度、改善校準資料、降低採樣變異度,並執行任務層級的評估。 |
5.2 基礎設施記憶體容量
| 元件 | 硬體概估 |
|---|---|
| 模型權重 | 參數量 每個參數所佔的儲存位元組數 |
| KV 快取 | |
| 訓練梯度 | 參數量 每個梯度所佔的位元組數 |
| 優化器狀態 | 依優化器而定;通常每個參數對應多個數值 |
| 激活值 | 高度取決於架構、批次大小、序列長度、checkpointing 機制,以及特定的 kernel |
5.3 工作負載階段
| 階段 | 主要工作單位 | 持續性狀態 | 常見瓶頸 |
|---|---|---|---|
| 預訓練 | 完整的訓練批次 | 參數與優化器 | 運算、通訊、激活值記憶體 |
| 預填充 | 提示詞或提示詞區塊 | 寫入 KV 快取 | 運算與注意力 IO |
| 解碼 | 每個作用中序列的一個位置 | 讀取並擴充 KV 快取 | 權重/KV 記憶體頻寬與排程 |
5.4 正式環境監控
監控工作,必須把需求、排程器行為、快取壓力、硬體飽和度、使用者可見的延遲,以及模型品質全部連結起來。沒有任何單一指標,能單獨解釋整個系統的狀況。
| 監控層級 | 核心訊號 | 有助於回答什麼問題 |
|---|---|---|
| 需求與工作負載 | 抵達速率、並發程度、佇列深度、提示詞/輸出分布。 | 整體流量或請求型態是否正在改變? |
| 使用者可見的延遲 | p50、p95、p99 的 TTFT、ITL、TPOT,以及端對端延遲。 | 是哪個推論階段,正在損害使用者體驗? |
| 吞吐量與排程 | 每秒輸入/輸出 token 數、每秒請求數、作用中序列數、每次迭代批次處理的 token 數。 | 排程器是否讓加速器持續有效地忙碌運作? |
| KV 快取健康狀態 | 使用率、配置失敗次數、搶佔次數、驅逐次數、已置換的區塊數,以及前綴快取命中率。 | 快取壓力是否正在限制並發程度,或導致延遲尖峰? |
| 加速器與網路 | 運算使用率、VRAM 使用量、記憶體頻寬、功耗、溫度,以及互連流量。 | 硬體瓶頸的根源,究竟是運算、記憶體,還是網路? |
| 可靠性 | 取消次數、逾時次數、過載回應(429)、OOM 事件、重啟次數,以及錯誤率。 | 服務是否正安全地卸除或妥善處理失敗的工作? |
| 模型與應用程式品質 | 任務成功率、安全性違規、結構化輸出的有效性、重試次數,以及人工審核比例。 | 某項基礎設施優化,是否破壞了模型原本有用的行為? |
指標必須嚴格依照模型版本、服務設定、工作負載類別與流量優先順序來區分。工程師必須採用直方圖與百分位數,而不能只看平均值;必須針對 SLO 消耗速率,以及佇列飽和度等領先指標同步發出警示;並且要持續不懈地,將效能變化與品質評估相互對照。
6. 結語
完整的依賴鏈,如今已經清晰可見。因果注意力機制,創造出可重複使用的 key 與 value;它們的數學形狀,決定了實體快取的容量;快取的成長,驅動著分頁式記憶體配置與連續請求排程;而嚴謹的正式環境監控,則精確揭示出究竟哪一項資源或策略,必須被調整,才能達成嚴格的 SLO。

說到底,把一份原始的模型檢查點直接暴露在網際網路上,並不等於一個正式服務。要在規模化的情況下,保證行為的一致性與可靠性,一次發布,就必須被當成一個完全可重現的產物來對待。這需要鎖定執行管線中的每一個活動部件:不只是模型權重,還包括 tokenizer 版本、聊天範本、量化方案、特定的服務引擎、硬體 kernel,以及生成用的超參數。
在將線上流量導向某個端點之前,基礎設施必須先經過嚴格驗證,以應對正式環境中各種難以預測的現實狀況。一個穩健的服務層,必須考量到:
- 運維韌性: 管理冷啟動預熱、在不當機的前提下吸收龐大的流量尖峰,並在 KV 快取用滿時,優雅地執行記憶體不足(OOM)復原。
- 邊界情況與用戶端的不穩定性: 處理格式錯誤的請求、優雅地截斷超出最大上下文視窗的提示詞,並在用戶端於生成過程中突然斷線或取消請求時,安全地中止運算。
- 安全性與執行邊界: 嚴格執行結構化輸出的限制(例如保證符合 JSON schema),並維持絕對的多租戶記憶體隔離,確保不同使用者的資料完全彼此分離。 最後,一個成功的部署,需要直接針對正式上線、提供服務中的 API,執行你的離線評估套件。調整量化策略、更新 GPU kernel,或更換服務框架,都可能微妙地改變模型的輸出分布——即使你的核心應用程式碼完全沒有被更動過。
Transformer 的架構,與為它提供服務的基礎設施,並不是兩個各自獨立的議題。一個模型的確定性,終究只能等同於為它提供服務的那套基礎設施的確定性。