LLM API Introduction#
The LLM API is a high-level Python API designed to streamline LLM inference workflows.
It supports a broad range of use cases, from single-GPU setups to multi-GPU and multi-node deployments, with built-in support for various parallelism strategies and advanced features. The LLM API integrates seamlessly with the broader inference ecosystem, including NVIDIA Dynamo.
While the LLM API simplifies inference workflows with a high-level interface, it is also designed with flexibility in mind. Under the hood, it uses a PyTorch-native and modular backend, making it easy to customize, extend, or experiment with the runtime.
Quick Start Example#
A simple inference example with TinyLlama using the LLM API:
1from tensorrt_llm import LLM, SamplingParams
2
3
4def main():
5
6 # Model could accept HF model name, a path to local HF model,
7 # or Model Optimizer's quantized checkpoints like nvidia/Llama-3.1-8B-Instruct-FP8 on HF.
8 llm = LLM(model="TinyLlama/TinyLlama-1.1B-Chat-v1.0")
9
10 # Sample prompts.
11 prompts = [
12 "Hello, my name is",
13 "The capital of France is",
14 "The future of AI is",
15 ]
16
17 # Create a sampling params.
18 sampling_params = SamplingParams(temperature=0.8, top_p=0.95)
19
20 for output in llm.generate(prompts, sampling_params):
21 print(
22 f"Prompt: {output.prompt!r}, Generated text: {output.outputs[0].text!r}"
23 )
24
25 # Got output like
26 # Prompt: 'Hello, my name is', Generated text: '\n\nJane Smith. I am a student pursuing my degree in Computer Science at [university]. I enjoy learning new things, especially technology and programming'
27 # Prompt: 'The president of the United States is', Generated text: 'likely to nominate a new Supreme Court justice to fill the seat vacated by the death of Antonin Scalia. The Senate should vote to confirm the'
28 # Prompt: 'The capital of France is', Generated text: 'Paris.'
29 # Prompt: 'The future of AI is', Generated text: 'an exciting time for us. We are constantly researching, developing, and improving our platform to create the most advanced and efficient model available. We are'
30
31
32if __name__ == '__main__':
33 main()
For more advanced usage including distributed inference, multimodal, and speculative decoding, please refer to this README.
Model Input#
The LLM() constructor accepts either a Hugging Face model ID or a local model path as input.
1. Using a Model from the Hugging Face Hub#
To load a model directly from the Hugging Face Model Hub, simply pass its model ID (i.e., repository name) to the LLM constructor. The model will be automatically downloaded:
llm = LLM(model="TinyLlama/TinyLlama-1.1B-Chat-v1.0")
You can also use quantized checkpoints (FP4, FP8, etc) of popular models provided by NVIDIA in the same way.
2. Using a Local Hugging Face Model#
To use a model from local storage, first download it manually:
git lfs install
git clone https://huggingface.co/meta-llama/Meta-Llama-3.1-8B
Then, load the model by specifying a local directory path:
llm = LLM(model=<local_path_to_model>)
Note: Some models require accepting specific license agreements. Make sure you have agreed to the terms and authenticated with Hugging Face before downloading.
Startup Metrics#
For the PyTorch backend, the beta LLM.startup_metrics property reports executor construction,
model-engine warmup, and weight-loading timings from worker rank 0. Values are wall-clock seconds.
The property returns an empty dictionary when the backend does not provide startup metrics.
llm = LLM(model="TinyLlama/TinyLlama-1.1B-Chat-v1.0")
print(llm.startup_metrics)
A typical result has the following structure (values are illustrative):
{
"initial_model_engine": {
"sampling_warmup_seconds": 0.342,
"attention_warmup_seconds": 2.911,
"general_warmup_seconds": 0.387,
"autotuner_warmup_seconds": 0.041,
"mamba_hybrid_warmup_seconds": 0.000,
"ctx_cuda_graph_warmup_seconds": 0.480,
"ctx_cuda_graph_capture_seconds": 0.320,
"post_ctx_cuda_graph_capture_warmup_seconds": 0.110,
"gen_cuda_graph_warmup_seconds": 0.566,
"gen_cuda_graph_capture_seconds": 0.950,
"dg_paged_mqa_warmup_seconds": 0.000,
"cute_dsl_radix_topk_warmup_seconds": 0.000,
"memory_pool_prepopulation_seconds": 0.094,
"kv_cache_cleanup_seconds": 0.194,
"total_warmup_seconds": 5.485
},
"final_model_engine": {
"sampling_warmup_seconds": 0.291,
"attention_warmup_seconds": 0.057,
"general_warmup_seconds": 0.492,
"autotuner_warmup_seconds": 0.046,
"mamba_hybrid_warmup_seconds": 0.000,
"gen_cuda_graph_warmup_seconds": 0.599,
"gen_cuda_graph_capture_seconds": 0.991,
"dg_paged_mqa_warmup_seconds": 0.000,
"cute_dsl_radix_topk_warmup_seconds": 0.000,
"memory_pool_prepopulation_seconds": 0.097,
"kv_cache_cleanup_seconds": 1.657,
"total_warmup_seconds": 4.230
},
"py_executor": {
"config_and_checkpoint_loader_initialization_seconds": 0.004,
"model_engine_creation_seconds": 1.554,
"sampler_creation_seconds": 1.195,
"initial_kv_cache_creation_seconds": 0.025,
"speculative_decoding_resource_manager_creation_seconds": 0.000,
"speculative_drafter_creation_seconds": 0.000,
"initial_py_executor_creation_seconds_for_kv_cache_estimation": 5.766,
"kv_cache_capacity_configuration_seconds": 0.075,
"final_kv_cache_creation_seconds": 0.057,
"final_py_executor_creation_seconds": 4.459,
"worker_start_seconds": 0.000,
"total_py_executor_creation_seconds": 13.373
},
"model_loader": {
"checkpoint_preparation_seconds": 0.719,
"weight_population_seconds": 0.272,
"checkpoint_finalization_seconds": 0.031,
"post_load_processing_seconds": 0.004,
"total_model_loading_seconds": 1.545
}
}
Some of the timing metrics may not appear or may show as a very small value if the corresponding codepath is not executed, e.g. if the prefill CUDA graphs are not enabled, its related metrics ââĶctx_cuda_graphâĶâ will not appear.
The py_executor property contains the timed scopes in create_py_executor(), which creates the PyExecutor.
PyExecutor metric |
Scope |
|---|---|
|
Initialize the model config and checkpoint loader. |
|
Construct the main model engine, which includes loading model weights. |
|
Construct guided-decoding resources. |
|
Construct the sampler. |
|
Construct the temporary KV cache used to estimate final capacity. |
|
Construct the speculative-decoding resource manager. |
|
Construct the speculative drafter. |
|
Construct the temporary PyExecutor for KV cache capacity estimation, which includes the initial model engine warmup. |
|
Determine final KV cache capacity from the temporary executor and available memory. |
|
Construct the final KV cache retained for serving. |
|
Using the final KV cache, construct the final PyExecutor retained for serving, which includes the final model engine warmup. |
|
Start the final PyExecutor worker. |
|
Total time for the |
The two model-engine properties contain times for various PyTorchModelEngine warmup stages.
initial_model_engine measures the timings for the initial model engine creation as part of the
py_executor.initial_py_executor_creation_seconds_for_kv_cache_estimation timing.
Likewise, final_model_engine measures the timings for the final model engine creation as part of
the py_executor.final_py_executor_creation_seconds timing.
Each model-engine property contains the warmup scopes below. Which scopes appear depends on the model and configuration; for example, encoder-decoder and context-parallel configurations can skip some stages.
Model-engine metric |
Scope |
|---|---|
|
Warm up sampling kernels and run |
|
Warm up the attention backend and kernels. |
|
Prepare and warm up general input shapes and release temporary workspaces. |
|
Run kernel autotuning warmup. |
|
Warm up Mamba hybrid kernels, when applicable. |
|
Run the warmup-only pass for generation and mixed encoder-decoder CUDA graphs, including LoRA autotuning and pipeline-parallel cache synchronization and cleanup. |
|
Capture generation and mixed encoder-decoder CUDA graphs for serving. |
|
Warm up prefill forwards before CUDA graph capture. |
|
Capture prefill CUDA graphs. |
|
Warm up prefill logits buffers with many requests after CUDA graph capture. |
|
Warm up DeepGEMM paged-MQA metadata, when applicable. |
|
Warm up the CuTe DSL radix top-k kernel, when applicable. |
|
Prepare maximum-shape requests and pre-populate the memory pool. |
|
Check and clear invalid KV cache values produced during warmup. |
|
Complete model-engine warmup, including KV cache cleanup. |
The model_loader property contains timings for loading the main LLM weights, including
checkpoint_finalization_seconds for checkpoint-session synchronization and cleanup after weight population.
If a draft model is used, additional fields draft_checkpoint_preparation_seconds,
draft_weight_population_seconds, and draft_checkpoint_finalization_seconds will appear.
A draft_model_loader property appears when a user-provided drafter exposes a draft_model_engine.
The py_executor.model_engine_creation_seconds timing includes the total model_loader timing.
Metric |
Description |
|---|---|
|
Time spent warming up, parsing and preparing checkpoint tensors for the model. Some checkpoint formats can populate model storage directly during this phase. |
|
Time spent copying prepared checkpoint tensors into model parameters on GPUs. This metric can be absent for formats that populate weights directly during the above checkpoint preparation phase. |
|
Time spent finalizing the checkpoint session after weight population. This includes loader-specific synchronization and cleanup. |
|
Checkpoint preparation time for draft weights loaded as part of the model loader. |
|
Weight population time for draft weights loaded as part of the model loader. |
|
Checkpoint finalization time for draft weights loaded as part of the model loader. |
|
Time spent in format-specific hooks and model finalization, including post-load weight transformation, quantization and memory cleanup. |
|
Overall model construction and loading interval measured after checkpoint configuration validation. It includes the named phases below. |
trtllm-serve exposes the same rank-0 payload in the startup_metrics field of the
GET /server_info response:
curl http://localhost:8000/server_info
{
"startup_metrics": {
"model_loader": {
"total_model_loading_seconds": 1.545,
...
}
}
}
Unified Cache for Compiled Artifacts#
Set TRTLLM_CACHE_DIR before importing TensorRT-LLM to place its compiled
artifact caches under a single root. TensorRT-LLM supplies the following
defaults. Except for the isolation behavior described below, an individually
configured environment variable takes precedence.
Environment variable |
Default cache path |
Default under |
|---|---|---|
|
Disabled |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Disabled |
|
|
|
|
Important note: while some of the caches controlled by TRTLLM_CACHE_DIR
are enabled and persisted by default (e.g., FLASHINFER_WORKSPACE_BASE),
others are disabled or with a path defaulting to /tmp (e.g., CUTE_DSL_CACHE_DIR
or TLLM_AUTOTUNER_CACHE_PATH). These caches are not validated for sharing
across model instances or long-term persistence, which may lead to errors
and other unintended behavior. As such, we recommend using distinct
TRTLLM_CACHE_DIR caches for different models, and invalidating them anytime
a component in the software stack changes.
The directories are created by their respective consumers when needed. TensorRT-LLM does not add cache locking or cleanup; per-rank isolation is enabled only for the exceptions described below. The configured values are forwarded to dynamically spawned MPI workers.
Configuring TRTLLM_DG_CACHE_DIR, either directly or through
TRTLLM_CACHE_DIR, also defaults TRTLLM_DG_JIT_DUMP_CUBIN to 1 so its
NVRTC-generated cubins are persisted. An explicitly configured dump setting
still takes precedence. See the
DeepGEMM environment variables
for details.
Note that, when TRTLLM_CACHE_DIR is set, the FlashInfer workspace isolation
mechanism described below still applies. This will prevent race conditions
during cache read/writes, at the cost of limiting cache sharing. To disable
workspace isolation, either set TRTLLM_FLASHINFER_WORKSPACE_PER_PROCESS=0,
or set FLASHINFER_WORKSPACE_BASE to a different path from the one assigned
under TRTLLM_CACHE_DIR.
Ray workers treat DG_JIT_CACHE_DIR equal to
<TRTLLM_CACHE_DIR>/deep_gemm as unified-cache-managed and isolate it by rank
and GPU, even when that value was set explicitly. Other explicit values are
preserved. Set TRTLLM_DEEP_GEMM_CACHE_PER_PROCESS=0 to preserve and share the
unified path.
Launcher process ownership#
The rank-0 trtllm-llmapi-launch shell starts a small Python guard for the MPI
communication server, task, and shutdown helper. Each guard owns a separate
process group and monitors the shell, so killing only the shell with SIGKILL
under plain mpirun still triggers cleanup of those groups. Startup registration
finishes before a command can run. Guards also clean remaining group members
when the command exits, then return its original exit status.
Cleanup sends SIGTERM, followed by SIGKILL after
TLLM_LLMAPI_LAUNCH_TERM_GRACE_SECONDS (default 5 seconds). This covers descendants
that remain in their inherited process group. A command that deliberately
creates a separate session or process group must manage those processes itself;
killing a guard independently also requires the jobâs scheduler/container to
reclaim its workload.
Remote MPI shutdown timeouts#
Configure these settings together when using trtllm-llmapi-launch:
Setting |
Default |
Scope |
|---|---|---|
|
60 seconds |
Server budget for draining a failed batch or stopping the MPI world. Final session and shared-executor teardown use the remaining budget. |
|
120 seconds |
Launcher wait for the stop helper and server after the task exits. Also used separately for guard registration and for the task to exit naturally after a server failure. |
|
5 seconds |
Additional cleanup grace between TERM and KILL for owned process groups. |
The server shutdown grace starts when it receives the stop request; an earlier
worker-failure deadline can shorten the remaining grace. The launcher also waits
for the stop helperâs Python startup and tensorrt_llm imports before that request
can be sent. Set the launcher stop timeout above the server grace by enough to
cover measured cold startup/import time, connection/send and queue cleanup, and
scheduling margin. The defaults leave 60 seconds of allowance; raising only the
server grace does not raise the launcher timeout.
For example, a 120-second server grace with a 180-second launcher timeout leaves 60 seconds for this overhead. This is an illustrative allowance: increase it if cold or loaded nodes need more time.
If task-first shutdown exhausts the launcher budget, the launcher terminates owned groups and returns 124 when the task succeeded; an existing nonzero task status takes precedence. After a server-first failure, the launcher instead preserves a naturally completed taskâs nonzero status, otherwise the serverâs failure status. TERM-to-KILL cleanup is a separate phase. Launcher waits count 100 ms sleeps, so polling and scheduling overhead add time; these settings are not a strict end-to-end wall-clock limit.
The launcher returns exit code 2 for invalid
TLLM_LLMAPI_LAUNCH_STOP_TIMEOUT or
TLLM_LLMAPI_LAUNCH_TERM_GRACE_SECONDS values; both require a positive integer
of at most six digits. A process-guard registration timeout also returns 124.
If registration of the stop helper fails after the task has exited, an existing
nonzero task status still takes precedence.
Remote MPI batch ordering#
The remote MPI server dispatches the next batch only after every future in the previous batch has completed. The task wrapper retains its entry barrier to place one task on each rank, but has no trailing barrier: an individual rank can finish or report an error while its peers are still running. Cross-batch ordering is enforced by the server; directly invoking the wrapper does not provide a collective completion barrier.
Disaggregated MPI leader failures#
The disaggregated MPI leader uses the same remote MPI server. An asynchronous worker failure is fatal to that server: it reports the worker error, stops accepting new work, and keeps the error channel available until a stop request or the original failure deadline. Final teardown can abort the MPI communicator if its remaining grace expires. This does not restart the failed service.
The leader launches its proxy through an autonomous process guard. Normal leader
cleanup signals the guard; if the leader exits through MPI_Abort or is killed,
the guard detects parent death and cleans the proxyâs inherited process group.
It allows 5 seconds between SIGTERM and SIGKILL. Descendants that create their
own session or process group still require separate ownership, as described
above. The Bash launcherâs TLLM_LLMAPI_LAUNCH_* settings do not configure this
Python launcher.
FlashInfer JIT workspaces for MPI workers#
trtllm-llmapi-launch ranks and dynamically spawned MpiPoolSession workers
isolate FlashInfer JIT workspaces by default. Each process claims a locked,
persistent cache slot under ~/.cache/tensorrt_llm/flashinfer that holds its
generated sources, compiled modules and downloaded FlashInfer artifacts, so
concurrent MPI processes never write to each otherâs compiler inputs while JIT
artifacts stay warm across launches. Set
TRTLLM_FLASHINFER_WORKSPACE_PER_PROCESS=0 before invoking the launcher or
creating the LLM instance to disable this behavior.
Persistent slots are not pruned automatically, so their count can grow with peak job concurrency. When no TensorRT-LLM processes are using the cache, the slots may be deleted safely; subsequent launches rebuild the removed JIT artifacts.
If persistent workspace setup is unavailable, each process falls back to a process-unique temporary workspace that is removed, artifacts included, when the process exits.
An explicitly configured FLASHINFER_WORKSPACE_BASE takes precedence in both
launch modes, while setting TRTLLM_CACHE_DIR does not. An explicitly configured FLASHINFER_CUBIN_DIR is propagated
unchanged to every rank and is the way to share downloaded artifacts between
ranks; populate it before the multi-rank launch, either by installing the
flashinfer-cubin package matching flashinfer-python or with a single-rank
warm-up run, and set FLASHINFER_NO_DOWNLOAD=1 so a missing artifact fails
instead of being downloaded concurrently into the shared directory.
Tips and Troubleshooting#
The following tips typically assist new LLM API users who are familiar with other APIs that are part of TensorRT-LLM:
RuntimeError: only rank 0 can start multi-node session, got 1#
There is no need to add an mpirun prefix for launching single node multi-GPU inference with the LLM API.
For example, you can run python llm_inference_distributed.py to perform multi-GPU on a single node.
Hang issue on Slurm Node#
If you experience a hang or other issue on a node managed with Slurm, add prefix mpirun -n 1 --oversubscribe --allow-run-as-root to your launch script.
For example, try mpirun -n 1 --oversubscribe --allow-run-as-root python llm_inference_distributed.py.
MPI_ABORT was invoked on rank 1 in communicator MPI_COMM_WORLD with errorcode 1.#
Because the LLM API relies on the mpi4py library, put the LLM class in a function and protect the main entrypoint to the program under the __main__ namespace to avoid a recursive spawn process in mpi4py.
This limitation is applicable for multi-GPU inference only.
Cannot quit after generation#
The LLM instance manages threads and processes, which may prevent its reference count from reaching zero. To address this issue, there are two common solutions:
Wrap the LLM instance in a function, as demonstrated in the quickstart guide. This will reduce the reference count and trigger the shutdown process.
Use LLM as a context manager, with the following code:
with LLM(...) as llm: ..., the shutdown method will be invoked automatically once it goes out of thewith-statement block.
Single node hanging when using docker run --net=host#
The root cause may be related to mpi4py. There is a workaround suggesting a change from --net=host to --ipc=host, or setting the following environment variables:
export OMPI_MCA_btl_tcp_if_include=lo
export OMPI_MCA_oob_tcp_if_include=lo
Another option to improve compatibility with mpi4py is to launch the task using:
mpirun -n 1 --oversubscribe --allow-run-as-root python my_llm_task.py
This command can help avoid related runtime issues.