main
py 3,166 lines 133 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 import argparse
5 import copy
6 import dataclasses
7 import functools
8 import json
9 import os
10 import sys
11 import warnings
12 from collections.abc import Callable
13 from dataclasses import MISSING, asdict, dataclass, fields, is_dataclass
14 from types import UnionType
15 from typing import (
16 TYPE_CHECKING,
17 Annotated,
18 Any,
19 Literal,
20 TypeAlias,
21 TypeVar,
22 Union,
23 cast,
24 get_args,
25 get_origin,
26 is_typeddict,
27 )
28
29 import huggingface_hub
30 import regex as re
31 import torch
32 from pydantic import TypeAdapter, ValidationError
33 from pydantic.fields import FieldInfo
34 from typing_extensions import TypeIs
35
36 import vllm.envs as envs
37 from vllm.config import (
38 AttentionConfig,
39 AuxOutputConfig,
40 CacheConfig,
41 CompilationConfig,
42 ConfigType,
43 DeviceConfig,
44 DiffusionConfig,
45 ECTransferConfig,
46 EncoderCacheManagerConfig,
47 EngramConfig,
48 EPLBConfig,
49 FaultToleranceConfig,
50 KernelConfig,
51 KVEventsConfig,
52 KVTransferConfig,
53 LoadConfig,
54 LoggingConfig,
55 LoRAConfig,
56 MambaConfig,
57 ModelConfig,
58 MultiModalConfig,
59 ObservabilityConfig,
60 OffloadConfig,
61 ParallelConfig,
62 PoolerConfig,
63 PrefetchOffloadConfig,
64 ProfilerConfig,
65 ReasoningConfig,
66 SchedulerConfig,
67 SpeculativeConfig,
68 StructuredOutputsConfig,
69 UVAOffloadConfig,
70 VllmConfig,
71 WeightTransferConfig,
72 get_attr_docs,
73 )
74 from vllm.config.cache import (
75 CacheDType,
76 KVOffloadingBackend,
77 MambaCacheMode,
78 MambaDType,
79 PrefixCachingHashAlgo,
80 )
81 from vllm.config.device import Device
82 from vllm.config.kernel import (
83 IrOpPriorityConfig,
84 LinearBackend,
85 MoEBackend,
86 SparseIndexerTopkBackend,
87 )
88 from vllm.config.load import SafetensorsLoadStrategy
89 from vllm.config.logging import LogLevel
90 from vllm.config.lora import MaxLoRARanks
91 from vllm.config.mamba import MambaBackendEnum, MambaSSUAlgorithm
92 from vllm.config.model import (
93 ConvertOption,
94 HfOverrides,
95 LogprobsMode,
96 ModelDType,
97 RunnerOption,
98 TokenizerMode,
99 )
100 from vllm.config.multimodal import (
101 MMCacheType,
102 MMEncoderTPMode,
103 MMHasherAlgorithm,
104 MMProcessorDevice,
105 MMTensorIPC,
106 )
107 from vllm.config.observability import DetailedTraceModules
108 from vllm.config.parallel import (
109 All2AllBackend,
110 DataParallelBackend,
111 DCPCommBackend,
112 DistributedExecutorBackend,
113 ExpertPlacementStrategy,
114 )
115 from vllm.config.scheduler import SchedulerPolicy
116 from vllm.config.utils import get_field
117 from vllm.config.vllm import OptimizationLevel, PerformanceMode
118 from vllm.config.watermarking import WatermarkConfig
119 from vllm.logger import configure_logging_if_needed, init_logger, suppress_logging
120 from vllm.platforms import CpuArchEnum, current_platform
121 from vllm.plugins import load_general_plugins
122 from vllm.ray.lazy_utils import is_in_ray_actor, is_ray_initialized
123 from vllm.transformers_utils.config import maybe_override_with_speculators
124 from vllm.transformers_utils.repo_utils import get_model_path
125 from vllm.transformers_utils.utils import is_cloud_storage
126 from vllm.utils.argparse_utils import (
127 FlexibleArgumentParser,
128 human_readable_int,
129 human_readable_int_or_auto,
130 )
131 from vllm.utils.mem_constants import GiB_bytes
132 from vllm.utils.network_utils import get_ip
133 from vllm.utils.torch_utils import resolve_kv_cache_dtype_string
134 from vllm.v1.attention.backends.registry import AttentionBackendEnum
135 from vllm.v1.sample.logits_processor import LogitsProcessor
136 from vllm.version import __version__ as VLLM_VERSION
137
138 if TYPE_CHECKING:
139 from vllm.config.quantization import QuantizationConfigArgs
140 from vllm.model_executor.layers.quantization import QuantizationMethods
141 from vllm.model_executor.model_loader import LoadFormats
142 from vllm.usage.usage_lib import UsageContext
143 from vllm.v1.executor import Executor
144 else:
145 Executor = Any
146 QuantizationMethods = str
147 LoadFormats = str
148 UsageContext = Any
149
150
151 logger = init_logger(__name__)
152
153 # object is used to allow for special typing forms
154 T = TypeVar("T")
155 TypeHint: TypeAlias = type[Any] | object
156 TypeHintT: TypeAlias = type[T] | object
157
158
159 def parse_type(return_type: Callable[[str], T]) -> Callable[[str], T]:
160 def _parse_type(val: str) -> T:
161 try:
162 return return_type(val)
163 except ValueError as e:
164 raise argparse.ArgumentTypeError(
165 f"Value {val} cannot be converted to {return_type}."
166 ) from e
167
168 return _parse_type
169
170
171 def optional_type(return_type: Callable[[str], T]) -> Callable[[str], T | None]:
172 def _optional_type(val: str) -> T | None:
173 if val == "" or val == "None":
174 return None
175 return parse_type(return_type)(val)
176
177 return _optional_type
178
179
180 def union_dict_and_str(val: str) -> str | dict[str, str] | None:
181 if not re.match(r"(?s)^\s*{.*}\s*$", val):
182 return str(val)
183 return optional_type(json.loads)(val)
184
185
186 def is_type(type_hint: TypeHint, type: TypeHintT) -> TypeIs[TypeHintT]:
187 """Check if the type hint is a specific type."""
188 return type_hint is type or get_origin(type_hint) is type
189
190
191 def is_dict_subclass(type_hint: TypeHint) -> bool:
192 """Check if the type hint is a subclass of `dict`.
193
194 `TypedDict`s are excluded because they do not support class checks.
195 """
196 return (
197 isinstance(type_hint, type)
198 and not is_typeddict(type_hint)
199 and issubclass(type_hint, dict)
200 )
201
202
203 def contains_type(type_hints: set[TypeHint], type: TypeHintT) -> bool:
204 """Check if the type hints contain a specific type."""
205 return any(is_type(type_hint, type) for type_hint in type_hints)
206
207
208 def get_type(type_hints: set[TypeHint], type: TypeHintT) -> TypeHintT:
209 """Get the specific type from the type hints."""
210 return next((th for th in type_hints if is_type(th, type)), None)
211
212
213 def literal_to_kwargs(type_hints: set[TypeHint]) -> dict[str, Any]:
214 """Get the `type` and `choices` from a `Literal` type hint in `type_hints`.
215
216 If `type_hints` also contains `str`, we use `metavar` instead of `choices`.
217 """
218 type_hint = get_type(type_hints, Literal)
219 options = get_args(type_hint)
220 option_type = type(options[0])
221 if not all(isinstance(option, option_type) for option in options):
222 raise ValueError(
223 "All options must be of the same type. "
224 f"Got {options} with types {[type(c) for c in options]}"
225 )
226 kwarg = "metavar" if contains_type(type_hints, str) else "choices"
227 return {"type": option_type, kwarg: sorted(options)}
228
229
230 def collection_to_kwargs(type_hints: set[TypeHint], type: TypeHint) -> dict[str, Any]:
231 type_hint = get_type(type_hints, type)
232 types = get_args(type_hint)
233 elem_type = types[0]
234
235 # Handle Ellipsis
236 assert all(t is elem_type for t in types if t is not Ellipsis), (
237 f"All non-Ellipsis elements must be of the same type. Got {types}."
238 )
239
240 # Handle Union types
241 if get_origin(elem_type) in {Union, UnionType}:
242 # Union for Union[X, Y] and UnionType for X | Y
243 assert str in get_args(elem_type), (
244 "If element can have multiple types, one must be 'str' "
245 f"(i.e. 'list[int | str]'). Got {elem_type}."
246 )
247 elem_type = str
248
249 return {
250 "type": elem_type,
251 "nargs": "+" if type is not tuple or Ellipsis in types else len(types),
252 }
253
254
255 def is_not_builtin(type_hint: TypeHint) -> bool:
256 """Check if the class is not a built-in type."""
257 return type_hint.__module__ != "builtins"
258
259
260 def get_type_hints(type_hint: TypeHint) -> set[TypeHint]:
261 """Extract type hints from Annotated or Union type hints."""
262 type_hints: set[TypeHint] = set()
263 origin = get_origin(type_hint)
264 args = get_args(type_hint)
265
266 if origin is Annotated:
267 type_hints.update(get_type_hints(args[0]))
268 elif origin in {Union, UnionType}:
269 # Union for Union[X, Y] and UnionType for X | Y
270 for arg in args:
271 type_hints.update(get_type_hints(arg))
272 else:
273 type_hints.add(type_hint)
274
275 return type_hints
276
277
278 NEEDS_HELP = (
279 any("--help" in arg for arg in sys.argv) # vllm SUBCOMMAND --help
280 or "mkdocs" in sys.modules # mkdocs SUBCOMMAND
281 )
282
283
284 def _maybe_add_docs_url(cls: Any) -> str:
285 """Generate API docs URL for a vllm config class."""
286 import vllm.config
287
288 name = cls.__name__
289 if getattr(vllm.config, name, None) is not cls:
290 return ""
291 version = f"v{VLLM_VERSION}" if "dev" not in VLLM_VERSION else "latest"
292 return f"\n\nAPI docs: https://docs.vllm.ai/en/{version}/api/vllm/config/#vllm.config.{name}"
293
294
295 def _expand_json_human_readable_numbers(val: str) -> str:
296 """Expand human-readable number suffixes in a JSON string.
297
298 Based on :func:`human_readable_int` so that the ``k/m/g/t`` (decimal) and
299 ``K/M/G/T`` (binary) conventions work out the box.
300 Also works inside JSON config arguments such
301 as ``--kv-transfer-config '{"cpu_bytes_to_use": 80m}'``.
302
303 Only bare (unquoted) tokens are replaced so that JSON string values
304 like ``"model_name"`` are never modified.
305 """
306 # Split on quoted strings so we only touch non-string regions.
307 parts = re.split(r'("(?:[^"\\]|\\.)*")', val)
308 for i in range(0, len(parts), 2): # even indices = outside strings
309 parts[i] = re.sub(
310 r"\b\d+(?:\.\d+)?[kKmMgGtT]\b",
311 lambda m: str(human_readable_int(m.group())),
312 parts[i],
313 )
314 return "".join(parts)
315
316
317 @functools.lru_cache(maxsize=30)
318 def _compute_kwargs(cls: ConfigType) -> dict[str, dict[str, Any]]:
319 # Save time only getting attr docs if we're generating help text
320 cls_docs = get_attr_docs(cls) if NEEDS_HELP else {}
321 kwargs = {}
322 for field in fields(cls):
323 # Get the set of possible types for the field
324 type_hints: set[TypeHint] = get_type_hints(field.type)
325 # Subclasses of dict (e.g. MultiModalDummyOptions) are CLI dicts
326 type_hints = {dict if is_dict_subclass(th) else th for th in type_hints}
327
328 # If the field is a dataclass, we can use the model_validate_json
329 generator = (th for th in type_hints if is_dataclass(th))
330 dataclass_cls = next(generator, None)
331
332 # Get the default value of the field
333 if field.default is not MISSING:
334 default = field.default
335 # Handle pydantic.Field defaults
336 if isinstance(default, FieldInfo):
337 if default.default_factory is None:
338 default = default.default
339 else:
340 # VllmConfig's Fields have default_factory set to config classes.
341 # These could emit logs on init, which would be confusing.
342 with suppress_logging():
343 default = default.default_factory() # type: ignore[call-arg]
344 elif field.default_factory is not MISSING:
345 default = field.default_factory()
346
347 # Get the help text for the field
348 name = field.name
349 help = cls_docs.get(name, "").strip()
350 # Escape % for argparse
351 help = help.replace("%", "%%")
352
353 # Initialise the kwargs dictionary for the field
354 kwargs[name] = {"default": default, "help": help}
355
356 # Set other kwargs based on the type hints
357 json_tip = (
358 "Should either be a valid JSON string or JSON keys passed individually."
359 )
360 if dataclass_cls is not None:
361
362 def parse_dataclass(val: str, cls=dataclass_cls) -> Any:
363 try:
364 val = _expand_json_human_readable_numbers(val)
365 return TypeAdapter(cls).validate_json(val)
366 except ValidationError as e:
367 raise argparse.ArgumentTypeError(repr(e)) from e
368
369 kwargs[name]["type"] = parse_dataclass
370 kwargs[name]["help"] += _maybe_add_docs_url(dataclass_cls)
371 kwargs[name]["help"] += f"\n\n{json_tip}"
372 elif type_hints == {bool, str, type(None)}:
373 # Optional-valued flag: bare flag -> True, value -> str.
374 kwargs[name]["type"] = str
375 kwargs[name]["nargs"] = "?"
376 kwargs[name]["const"] = True
377 elif contains_type(type_hints, bool):
378 # Creates --no-<name> and --<name> flags
379 kwargs[name]["action"] = argparse.BooleanOptionalAction
380 elif contains_type(type_hints, Literal):
381 kwargs[name].update(literal_to_kwargs(type_hints))
382 elif contains_type(type_hints, tuple):
383 kwargs[name].update(collection_to_kwargs(type_hints, tuple))
384 elif contains_type(type_hints, list):
385 kwargs[name].update(collection_to_kwargs(type_hints, list))
386 elif contains_type(type_hints, set):
387 kwargs[name].update(collection_to_kwargs(type_hints, set))
388 elif contains_type(type_hints, int):
389 # Arguments that accept human-readable integer strings (e.g., 1K, 2M, 1G)
390 human_readable_int_args = {
391 "max_num_batched_tokens",
392 "max_num_scheduled_tokens",
393 "kv_cache_memory_bytes",
394 "safetensors_prefetch_block_size",
395 "max_num_queued_tokens",
396 }
397 if name == "max_model_len":
398 kwargs[name]["type"] = human_readable_int_or_auto
399 kwargs[name]["help"] += f"\n\n{human_readable_int_or_auto.__doc__}"
400 elif name in human_readable_int_args:
401 kwargs[name]["type"] = human_readable_int
402 kwargs[name]["help"] += f"\n\n{human_readable_int.__doc__}"
403 else:
404 kwargs[name]["type"] = int
405 elif contains_type(type_hints, float):
406 kwargs[name]["type"] = float
407 elif contains_type(type_hints, dict) and (
408 contains_type(type_hints, str)
409 or any(is_not_builtin(th) for th in type_hints)
410 ):
411 kwargs[name]["type"] = union_dict_and_str
412 elif contains_type(type_hints, dict):
413 kwargs[name]["type"] = parse_type(json.loads)
414 kwargs[name]["help"] += f"\n\n{json_tip}"
415 elif contains_type(type_hints, str) or any(
416 is_not_builtin(th) for th in type_hints
417 ):
418 kwargs[name]["type"] = str
419 else:
420 raise ValueError(f"Unsupported type {type_hints} for argument {name}.")
421
422 # If the type hint was a sequence of literals, use the helper function
423 # to update the type and choices
424 if get_origin(kwargs[name].get("type")) is Literal:
425 kwargs[name].update(literal_to_kwargs({kwargs[name]["type"]}))
426
427 # If None is in type_hints, make the argument optional.
428 # But not if it's a bool, argparse will handle this better.
429 if type(None) in type_hints and not contains_type(type_hints, bool):
430 kwargs[name]["type"] = optional_type(kwargs[name]["type"])
431 if kwargs[name].get("choices"):
432 kwargs[name]["choices"].append(None)
433 return kwargs
434
435
436 def get_kwargs(cls: ConfigType) -> dict[str, dict[str, Any]]:
437 """Return argparse kwargs for the given Config dataclass.
438
439 If `--help` or `mkdocs` are not present in the command line command, the
440 attribute documentation will not be included in the help output.
441
442 The heavy computation is cached via functools.lru_cache, and a deep copy
443 is returned so callers can mutate the dictionary without affecting the
444 cached version.
445 """
446 return copy.deepcopy(_compute_kwargs(cls))
447
448
449 _LOG_CONFIG_FILE_DEPRECATION_MESSAGE = (
450 "--log-config-file is deprecated and will be removed in v0.33.0. "
451 "Use --logging-config.pylogging_config_file instead."
452 )
453
454
455 class DeprecatedLogConfigFileAction(argparse.Action):
456 """Warn when the legacy ``--log-config-file`` option is used."""
457
458 def __call__(self, parser, namespace, values, option_string=None):
459 warnings.warn(_LOG_CONFIG_FILE_DEPRECATION_MESSAGE, stacklevel=1)
460 setattr(namespace, self.dest, values)
461
462
463 @dataclass
464 class EngineArgs:
465 """Arguments for vLLM engine."""
466
467 model: str = ModelConfig.model
468 # Public compatibility argument. Canonical runtime state lives in
469 # AuxOutputConfig.
470 enable_return_routed_experts: bool = False
471 return_sampling_mask: bool = ModelConfig.return_sampling_mask
472 model_weights: str = ModelConfig.model_weights
473 served_model_name: str | list[str] | None = ModelConfig.served_model_name
474 tokenizer: str | None = ModelConfig.tokenizer
475 hf_config_path: str | None = ModelConfig.hf_config_path
476 runner: RunnerOption = ModelConfig.runner
477 convert: ConvertOption = ModelConfig.convert
478 skip_tokenizer_init: bool = ModelConfig.skip_tokenizer_init
479 enable_prompt_embeds: bool = ModelConfig.enable_prompt_embeds
480 tokenizer_mode: TokenizerMode | str = ModelConfig.tokenizer_mode
481 trust_remote_code: bool = ModelConfig.trust_remote_code
482 allowed_local_media_path: str = ModelConfig.allowed_local_media_path
483 allowed_media_domains: list[str] | None = ModelConfig.allowed_media_domains
484 download_dir: str | None = LoadConfig.download_dir
485 safetensors_load_strategy: SafetensorsLoadStrategy | None = (
486 LoadConfig.safetensors_load_strategy
487 )
488 safetensors_prefetch_num_threads: int = LoadConfig.safetensors_prefetch_num_threads
489 safetensors_prefetch_block_size: int = LoadConfig.safetensors_prefetch_block_size
490 load_format: str | LoadFormats = LoadConfig.load_format
491 config_format: str = ModelConfig.config_format
492 dtype: ModelDType = ModelConfig.dtype
493 kv_cache_dtype: CacheDType = CacheConfig.cache_dtype
494 seed: int = ModelConfig.seed
495 max_model_len: int = ModelConfig.max_model_len
496 cudagraph_capture_sizes: list[int] | None = (
497 CompilationConfig.cudagraph_capture_sizes
498 )
499 max_cudagraph_capture_size: int | None = get_field(
500 CompilationConfig, "max_cudagraph_capture_size"
501 )
502 ir_op_priority: IrOpPriorityConfig = get_field(KernelConfig, "ir_op_priority")
503 # Note: Specifying a custom executor backend by passing a class
504 # is intended for expert use only. The API may change without
505 # notice.
506 distributed_executor_backend: (
507 str | DistributedExecutorBackend | type[Executor] | None
508 ) = ParallelConfig.distributed_executor_backend
509 # number of P/D disaggregation (or other disaggregation) workers
510 pipeline_parallel_size: int = ParallelConfig.pipeline_parallel_size
511 master_addr: str = ParallelConfig.master_addr
512 master_port: int = ParallelConfig.master_port
513 nnodes: int = ParallelConfig.nnodes
514 node_rank: int = ParallelConfig.node_rank
515 distributed_timeout_seconds: int | None = ParallelConfig.distributed_timeout_seconds
516 cpu_distributed_timeout_seconds: int | None = (
517 ParallelConfig.cpu_distributed_timeout_seconds
518 )
519 numa_bind: bool = ParallelConfig.numa_bind
520 numa_bind_nodes: list[int] | None = ParallelConfig.numa_bind_nodes
521 numa_bind_cpus: list[str] | None = ParallelConfig.numa_bind_cpus
522 device_ids: list[int | str] | None = None
523 tensor_parallel_size: int = ParallelConfig.tensor_parallel_size
524 prefill_context_parallel_size: int = ParallelConfig.prefill_context_parallel_size
525 decode_context_parallel_size: int = ParallelConfig.decode_context_parallel_size
526 dcp_comm_backend: DCPCommBackend | None = ParallelConfig.dcp_comm_backend
527 dcp_q_replicate: bool | None = ParallelConfig.dcp_q_replicate
528 dcp_kv_cache_interleave_size: int = ParallelConfig.dcp_kv_cache_interleave_size
529 cp_kv_cache_interleave_size: int | None = None
530 data_parallel_size: int = ParallelConfig.data_parallel_size
531 data_parallel_rank: int | None = None
532 data_parallel_start_rank: int | None = None
533 data_parallel_size_local: int | None = None
534 data_parallel_address: str | None = None
535 data_parallel_rpc_port: int | None = None
536 data_parallel_hybrid_lb: bool = False
537 data_parallel_external_lb: bool = False
538 data_parallel_multi_port_external_lb: bool = False
539 data_parallel_backend: DataParallelBackend = ParallelConfig.data_parallel_backend
540 enable_expert_parallel: bool = ParallelConfig.enable_expert_parallel
541 enable_batch_sharded_sampling: bool | None = (
542 ParallelConfig.enable_batch_sharded_sampling
543 )
544 enable_ep_weight_filter: bool = ParallelConfig.enable_ep_weight_filter
545 moe_backend: MoEBackend = KernelConfig.moe_backend
546 linear_backend: LinearBackend = KernelConfig.linear_backend
547 sparse_indexer_topk_backend: SparseIndexerTopkBackend = (
548 KernelConfig.sparse_indexer_topk_backend
549 )
550 all2all_backend: All2AllBackend = ParallelConfig.all2all_backend
551 enable_elastic_ep: bool = ParallelConfig.enable_elastic_ep
552 elastic_ep_max_dp_size: int = ParallelConfig.elastic_ep_max_dp_size
553 enable_dbo: bool = ParallelConfig.enable_dbo
554 ubatch_size: int = ParallelConfig.ubatch_size
555 dbo_decode_token_threshold: int = ParallelConfig.dbo_decode_token_threshold
556 dp_sync_interval: int = ParallelConfig.dp_sync_interval
557 dbo_prefill_token_threshold: int = ParallelConfig.dbo_prefill_token_threshold
558 disable_nccl_for_dp_synchronization: bool | None = (
559 ParallelConfig.disable_nccl_for_dp_synchronization
560 )
561 eplb_config: EPLBConfig = get_field(ParallelConfig, "eplb_config")
562 enable_eplb: bool = ParallelConfig.enable_eplb
563 expert_placement_strategy: ExpertPlacementStrategy = (
564 ParallelConfig.expert_placement_strategy
565 )
566 _api_process_count: int = ParallelConfig._api_process_count
567 _api_process_rank: int = ParallelConfig._api_process_rank
568 max_parallel_loading_workers: int | None = (
569 ParallelConfig.max_parallel_loading_workers
570 )
571 block_size: int | None = None
572 enable_prefix_caching: bool | None = None
573 prefix_caching_hash_algo: PrefixCachingHashAlgo = (
574 CacheConfig.prefix_caching_hash_algo
575 )
576 prefix_cache_retention_interval: int | None = get_field(
577 CacheConfig, "prefix_cache_retention_interval"
578 )
579 disable_sliding_window: bool = ModelConfig.disable_sliding_window
580 disable_cascade_attn: bool = ModelConfig.disable_cascade_attn
581 offload_backend: str = OffloadConfig.offload_backend
582 cpu_offload_gb: float = UVAOffloadConfig.cpu_offload_gb
583 cpu_offload_params: set[str] = get_field(UVAOffloadConfig, "cpu_offload_params")
584 offload_group_size: int = PrefetchOffloadConfig.offload_group_size
585 offload_num_in_group: int = PrefetchOffloadConfig.offload_num_in_group
586 offload_prefetch_step: int = PrefetchOffloadConfig.offload_prefetch_step
587 offload_params: set[str] = get_field(PrefetchOffloadConfig, "offload_params")
588 gpu_memory_utilization: float = CacheConfig.gpu_memory_utilization
589 kv_cache_memory_bytes: int | None = CacheConfig.kv_cache_memory_bytes
590 max_num_batched_tokens: int | None = None
591 max_num_scheduled_tokens: int | None = None
592 long_prefill_token_threshold: int = SchedulerConfig.long_prefill_token_threshold
593 long_prefill_token_threshold_adaptive: bool = (
594 SchedulerConfig.long_prefill_token_threshold_adaptive
595 )
596 max_num_seqs: int | None = None
597 max_num_active_seqs: int | None = SchedulerConfig.max_num_active_seqs
598 max_num_queued_reqs: int | None = None
599 max_num_queued_tokens: int | None = None
600 max_logprobs: int = ModelConfig.max_logprobs
601 logprobs_mode: LogprobsMode = ModelConfig.logprobs_mode
602 use_fp64_gumbel: bool = ModelConfig.use_fp64_gumbel
603 enable_trace_replay: bool = ModelConfig.enable_trace_replay
604 disable_log_stats: bool = False
605 aggregate_engine_logging: bool = False
606 revision: str | None = ModelConfig.revision
607 code_revision: str | None = ModelConfig.code_revision
608 hf_token: bool | str | None = ModelConfig.hf_token
609 hf_overrides: HfOverrides = get_field(ModelConfig, "hf_overrides")
610 model_class_overrides: dict[str, str] = get_field(
611 ModelConfig, "model_class_overrides"
612 )
613 tokenizer_revision: str | None = ModelConfig.tokenizer_revision
614 quantization: QuantizationMethods | str | None = ModelConfig.quantization
615 quantization_config: "dict[str, Any] | QuantizationConfigArgs | None" = None
616 """User-facing quantization configuration. Carries per-layer-kind
617 QuantSpecs (linear, moe) and ignore patterns; see
618 :class:`QuantizationConfigArgs`. Auto-populated from the matching online
619 shorthand when `quantization` is one of the values in
620 `ONLINE_QUANT_SHORTHAND_NAMES`."""
621 allow_deprecated_quantization: bool = ModelConfig.allow_deprecated_quantization
622 enforce_eager: bool = ModelConfig.enforce_eager
623 disable_custom_all_reduce: bool = ParallelConfig.disable_custom_all_reduce
624 language_model_only: bool = MultiModalConfig.language_model_only
625 limit_mm_per_prompt: dict[str, int | dict[str, int]] = get_field(
626 MultiModalConfig, "limit_per_prompt"
627 )
628 enable_mm_embeds: bool = MultiModalConfig.enable_mm_embeds
629 interleave_mm_strings: bool = MultiModalConfig.interleave_mm_strings
630 media_io_kwargs: dict[str, dict[str, Any]] = get_field(
631 MultiModalConfig, "media_io_kwargs"
632 )
633 mm_processor_kwargs: dict[str, Any] | None = MultiModalConfig.mm_processor_kwargs
634 mm_processor_cache_gb: float = MultiModalConfig.mm_processor_cache_gb
635 mm_processor_cache_type: MMCacheType | None = (
636 MultiModalConfig.mm_processor_cache_type
637 )
638 mm_hasher_algorithm: MMHasherAlgorithm = get_field(
639 MultiModalConfig, "mm_hasher_algorithm"
640 )
641 mm_shm_cache_max_object_size_mb: int = (
642 MultiModalConfig.mm_shm_cache_max_object_size_mb
643 )
644 mm_encoder_only: bool = MultiModalConfig.mm_encoder_only
645 mm_encoder_tp_mode: MMEncoderTPMode = MultiModalConfig.mm_encoder_tp_mode
646 mm_encoder_attn_backend: AttentionBackendEnum | str | None = (
647 MultiModalConfig.mm_encoder_attn_backend
648 )
649 mm_encoder_attn_dtype: str | None = MultiModalConfig.mm_encoder_attn_dtype
650 mm_encoder_fp8_scale_path: str | None = MultiModalConfig.mm_encoder_fp8_scale_path
651 mm_encoder_fp8_scale_save_path: str | None = (
652 MultiModalConfig.mm_encoder_fp8_scale_save_path
653 )
654 mm_encoder_fp8_scale_save_margin: float = (
655 MultiModalConfig.mm_encoder_fp8_scale_save_margin
656 )
657 io_processor_plugin: str | None = None
658 renderer_num_workers: int = 1
659 skip_mm_profiling: bool = MultiModalConfig.skip_mm_profiling
660 video_pruning_rate: float | None = MultiModalConfig.video_pruning_rate
661 video_pruning_method: str = MultiModalConfig.video_pruning_method
662 mm_tensor_ipc: MMTensorIPC = MultiModalConfig.mm_tensor_ipc
663 mm_processor_device: MMProcessorDevice = "auto"
664 mm_ipc_gpu_memory_gb: float = MultiModalConfig.mm_ipc_gpu_memory_gb
665 mm_device_do_normalize: bool | None = MultiModalConfig.mm_device_do_normalize
666 # LoRA fields
667 enable_lora: bool = False
668 max_loras: int = LoRAConfig.max_loras
669 max_lora_rank: MaxLoRARanks = LoRAConfig.max_lora_rank
670 default_mm_loras: dict[str, str] | None = LoRAConfig.default_mm_loras
671 fully_sharded_loras: bool = LoRAConfig.fully_sharded_loras
672 max_cpu_loras: int | None = LoRAConfig.max_cpu_loras
673 lora_dtype: str | torch.dtype | None = LoRAConfig.lora_dtype
674 lora_target_modules: list[str] | None = LoRAConfig.target_modules
675 enable_tower_connector_lora: bool = LoRAConfig.enable_tower_connector_lora
676 specialize_active_lora: bool = LoRAConfig.specialize_active_lora
677 enable_mixed_moe_lora_format: bool = LoRAConfig.enable_mixed_moe_lora_format
678 enable_moe_shared_loras: bool = LoRAConfig.enable_moe_shared_loras
679 max_lora_cls_labels: int | None = LoRAConfig.max_lora_cls_labels
680
681 ray_workers_use_nsight: bool = ParallelConfig.ray_workers_use_nsight
682 num_gpu_blocks_override: int | None = CacheConfig.num_gpu_blocks_override
683 model_loader_extra_config: dict = get_field(LoadConfig, "model_loader_extra_config")
684 ignore_patterns: str | list[str] = get_field(LoadConfig, "ignore_patterns")
685
686 enable_chunked_prefill: bool | None = None
687 disable_chunked_mm_input: bool = SchedulerConfig.disable_chunked_mm_input
688
689 scheduler_reserve_full_isl: bool = SchedulerConfig.scheduler_reserve_full_isl
690 prefill_schedule_interval: int = SchedulerConfig.prefill_schedule_interval
691
692 watermark: float = SchedulerConfig.watermark
693
694 disable_hybrid_kv_cache_manager: bool | None = (
695 SchedulerConfig.disable_hybrid_kv_cache_manager
696 )
697
698 structured_outputs_config: StructuredOutputsConfig = get_field(
699 VllmConfig, "structured_outputs_config"
700 )
701 aux_output_config: AuxOutputConfig = get_field(VllmConfig, "aux_output_config")
702 reasoning_parser: str = StructuredOutputsConfig.reasoning_parser
703 reasoning_parser_plugin: str | None = None
704
705 speculative_config: dict[str, Any] | None = None
706 spec_method: str | None = None
707 spec_model: str | None = None
708 spec_tokens: int | None = None
709 watermark_config: dict[str, Any] | None = None
710 diffusion_config: dict[str, Any] | None = None
711
712 show_hidden_metrics_for_version: str | None = (
713 ObservabilityConfig.show_hidden_metrics_for_version
714 )
715 otlp_traces_endpoint: str | None = ObservabilityConfig.otlp_traces_endpoint
716 collect_detailed_traces: list[DetailedTraceModules] | None = (
717 ObservabilityConfig.collect_detailed_traces
718 )
719 per_request_spec_decode_metrics: Literal["none", "summary", "detailed"] = (
720 ObservabilityConfig.per_request_spec_decode_metrics
721 )
722 kv_cache_metrics: bool = ObservabilityConfig.kv_cache_metrics
723 kv_cache_metrics_sample: float = get_field(
724 ObservabilityConfig, "kv_cache_metrics_sample"
725 )
726 custom_histogram_buckets: dict[str, list[float]] | None = (
727 ObservabilityConfig.custom_histogram_buckets
728 )
729 cudagraph_metrics: bool = ObservabilityConfig.cudagraph_metrics
730 enable_layerwise_nvtx_tracing: bool = (
731 ObservabilityConfig.enable_layerwise_nvtx_tracing
732 )
733 enable_mfu_metrics: bool = ObservabilityConfig.enable_mfu_metrics
734 enable_logging_iteration_details: bool = (
735 ObservabilityConfig.enable_logging_iteration_details
736 )
737 jit_monitor_mode: Literal["warn", "error"] = ObservabilityConfig.jit_monitor_mode
738 jit_monitor_verbose: bool = ObservabilityConfig.jit_monitor_verbose
739 enable_mm_processor_stats: bool = ObservabilityConfig.enable_mm_processor_stats
740 scheduling_policy: SchedulerPolicy = SchedulerConfig.policy
741 scheduler_cls: str | type[object] | None = SchedulerConfig.scheduler_cls
742
743 pooler_config: PoolerConfig | None = ModelConfig.pooler_config
744 compilation_config: CompilationConfig = get_field(VllmConfig, "compilation_config")
745 attention_config: AttentionConfig = get_field(VllmConfig, "attention_config")
746 engram_config: EngramConfig | None = VllmConfig.engram_config
747 mamba_config: MambaConfig = get_field(VllmConfig, "mamba_config")
748 kernel_config: KernelConfig = get_field(VllmConfig, "kernel_config")
749 enable_flashinfer_autotune: bool = get_field(
750 KernelConfig, "enable_flashinfer_autotune"
751 )
752 worker_cls: str = ParallelConfig.worker_cls
753 worker_extension_cls: str = ParallelConfig.worker_extension_cls
754
755 profiler_config: ProfilerConfig = get_field(VllmConfig, "profiler_config")
756
757 logging_config: LoggingConfig | None = None
758 log_level: LogLevel | None = None
759 log_config_file: str | None = None
760
761 kv_transfer_config: KVTransferConfig | None = None
762 kv_events_config: KVEventsConfig | None = None
763
764 ec_transfer_config: ECTransferConfig | None = None
765 ec_manager_config: EncoderCacheManagerConfig = get_field(
766 VllmConfig, "ec_manager_config"
767 )
768 reasoning_config: ReasoningConfig = get_field(VllmConfig, "reasoning_config")
769
770 generation_config: str = ModelConfig.generation_config
771 enable_sleep_mode: bool = ModelConfig.enable_sleep_mode
772 sleep_preserve_parameter_names: list[str] = get_field(
773 ModelConfig, "sleep_preserve_parameter_names"
774 )
775 enable_cumem_allocator: bool = ModelConfig.enable_cumem_allocator
776 enable_nccl_comm_suspend: bool = ModelConfig.enable_nccl_comm_suspend
777 override_generation_config: dict[str, Any] = get_field(
778 ModelConfig, "override_generation_config"
779 )
780 model_impl: str = ModelConfig.model_impl
781 attention_backend: AttentionBackendEnum | None = AttentionConfig.backend
782
783 kv_cache_dtype_skip_layers: list[str] = get_field(
784 CacheConfig, "kv_cache_dtype_skip_layers"
785 )
786 mamba_cache_dtype: MambaDType = CacheConfig.mamba_cache_dtype
787 mamba_ssm_cache_dtype: MambaDType = CacheConfig.mamba_ssm_cache_dtype
788 mamba_block_size: int | None = get_field(CacheConfig, "mamba_block_size")
789 prefix_match_unit: int | None = get_field(CacheConfig, "prefix_match_unit")
790 mamba_cache_mode: MambaCacheMode = CacheConfig.mamba_cache_mode
791 enable_mamba_shared_prefix_checkpoint: bool = (
792 CacheConfig.enable_mamba_shared_prefix_checkpoint
793 )
794 replayssm_buffer_len: int = CacheConfig.replayssm_buffer_len
795 use_replayssm: bool = CacheConfig.use_replayssm
796
797 mamba_backend: MambaBackendEnum = MambaBackendEnum.TRITON
798 mamba_ssu_algorithm: MambaSSUAlgorithm | None = None
799 enable_mamba_cache_stochastic_rounding: bool = (
800 MambaConfig.enable_stochastic_rounding
801 )
802 mamba_cache_philox_rounds: int = MambaConfig.stochastic_rounding_philox_rounds
803
804 additional_config: dict[str, Any] = get_field(VllmConfig, "additional_config")
805
806 use_tqdm_on_load: bool = LoadConfig.use_tqdm_on_load
807 pt_load_map_location: str | dict[str, str] = LoadConfig.pt_load_map_location
808
809 logits_processors: list[str | type[LogitsProcessor]] | None = (
810 ModelConfig.logits_processors
811 )
812 """Custom logitproc types"""
813
814 async_scheduling: bool | None = SchedulerConfig.async_scheduling
815
816 stream_interval: int = SchedulerConfig.stream_interval
817
818 kv_sharing_fast_prefill: bool = CacheConfig.kv_sharing_fast_prefill
819 swa_bounded_replay: bool = CacheConfig.swa_bounded_replay
820 optimization_level: OptimizationLevel = VllmConfig.optimization_level
821 performance_mode: PerformanceMode = VllmConfig.performance_mode
822
823 fault_tolerance_config: FaultToleranceConfig = get_field(
824 ParallelConfig, "fault_tolerance_config"
825 )
826 enable_fault_tolerance: bool = ParallelConfig.enable_fault_tolerance
827
828 kv_offloading_size: float | None = CacheConfig.kv_offloading_size
829 kv_offloading_backend: KVOffloadingBackend = CacheConfig.kv_offloading_backend
830 tokens_only: bool = False
831
832 shutdown_timeout: int = 0
833
834 weight_transfer_config: WeightTransferConfig | None = get_field(
835 VllmConfig,
836 "weight_transfer_config",
837 )
838
839 fail_on_environ_validation: bool = False
840 gdn_prefill_backend: Literal["flashinfer", "triton", "cutedsl"] | None = None
841 kda_prefill_backend: (
842 Literal["auto", "triton", "flashkda", "flashinfer", "fused"] | None
843 ) = None
844 kda_decode_backend: Literal["auto", "native", "flashinfer", "triton"] | None = None
845
846 def __post_init__(self):
847 # support `EngineArgs(compilation_config={...})`
848 # without having to manually construct a
849 # CompilationConfig object
850 if isinstance(self.compilation_config, dict):
851 self.compilation_config = CompilationConfig(**self.compilation_config)
852 if isinstance(self.attention_config, dict):
853 self.attention_config = AttentionConfig(**self.attention_config)
854 if isinstance(self.aux_output_config, dict):
855 self.aux_output_config = AuxOutputConfig(**self.aux_output_config)
856 if self.enable_return_routed_experts:
857 self.aux_output_config.enable_return_routed_experts = True
858 if isinstance(self.engram_config, dict):
859 self.engram_config = EngramConfig(**self.engram_config)
860 if isinstance(self.mamba_config, dict):
861 self.mamba_config = MambaConfig(**self.mamba_config)
862 if isinstance(self.kernel_config, dict):
863 self.kernel_config = KernelConfig(**self.kernel_config)
864 if isinstance(self.ec_manager_config, dict):
865 self.ec_manager_config = EncoderCacheManagerConfig(**self.ec_manager_config)
866 if isinstance(self.eplb_config, dict):
867 self.eplb_config = EPLBConfig(**self.eplb_config)
868 if isinstance(self.weight_transfer_config, dict):
869 self.weight_transfer_config = WeightTransferConfig(
870 **self.weight_transfer_config
871 )
872 if isinstance(self.fault_tolerance_config, dict):
873 if not self.enable_fault_tolerance:
874 logger.warning(
875 "--fault-tolerance-config was passed. Fault tolerance is being "
876 "automatically enabled."
877 )
878 self.enable_fault_tolerance = True
879 self.fault_tolerance_config = FaultToleranceConfig(
880 **self.fault_tolerance_config
881 )
882 if isinstance(self.ir_op_priority, dict):
883 self.ir_op_priority = IrOpPriorityConfig(**self.ir_op_priority)
884
885 from vllm.config.quantization import resolve_quantization_config
886
887 self.quantization_config = resolve_quantization_config(
888 self.quantization, self.quantization_config
889 )
890
891 # Setup plugins
892 from vllm.plugins import load_general_plugins
893
894 load_general_plugins()
895 # when use hf offline,replace model and tokenizer id to local model path
896 if huggingface_hub.constants.HF_HUB_OFFLINE:
897 # Skip cloud storage URIs (s3://, gs://, az://) — they are not
898 # HF repo IDs and will be resolved later by
899 # ModelConfig.maybe_pull_model_tokenizer_for_runai().
900 if not is_cloud_storage(self.model):
901 model_id = self.model
902 self.model = get_model_path(self.model, self.revision)
903 if model_id is not self.model:
904 logger.info(
905 "HF_HUB_OFFLINE is True, replace model_id "
906 "[%s] to model_path [%s]",
907 model_id,
908 self.model,
909 )
910 if self.tokenizer is not None and not is_cloud_storage(self.tokenizer):
911 tokenizer_id = self.tokenizer
912 self.tokenizer = get_model_path(self.tokenizer, self.tokenizer_revision)
913 if tokenizer_id is not self.tokenizer:
914 logger.info(
915 "HF_HUB_OFFLINE is True, replace tokenizer_id [%s] "
916 "to tokenizer_path [%s]",
917 tokenizer_id,
918 self.tokenizer,
919 )
920
921 @staticmethod
922 def add_cli_args(parser: FlexibleArgumentParser) -> FlexibleArgumentParser:
923 """Shared CLI arguments for vLLM engine."""
924 # Model arguments
925 model_kwargs = get_kwargs(ModelConfig)
926 aux_output_kwargs = get_kwargs(AuxOutputConfig)
927 model_group = parser.add_argument_group(
928 title="ModelConfig",
929 description=ModelConfig.__doc__,
930 )
931 if not ("serve" in sys.argv[1:] and "--help" in sys.argv[1:]):
932 model_group.add_argument("--model", **model_kwargs["model"])
933 model_group.add_argument("--runner", **model_kwargs["runner"])
934 model_group.add_argument("--convert", **model_kwargs["convert"])
935 model_group.add_argument("--tokenizer", **model_kwargs["tokenizer"])
936 model_group.add_argument("--tokenizer-mode", **model_kwargs["tokenizer_mode"])
937 model_group.add_argument(
938 "--trust-remote-code", **model_kwargs["trust_remote_code"]
939 )
940 model_group.add_argument("--dtype", **model_kwargs["dtype"])
941 model_group.add_argument("--seed", **model_kwargs["seed"])
942 model_group.add_argument("--hf-config-path", **model_kwargs["hf_config_path"])
943 model_group.add_argument(
944 "--allowed-local-media-path", **model_kwargs["allowed_local_media_path"]
945 )
946 model_group.add_argument(
947 "--allowed-media-domains", **model_kwargs["allowed_media_domains"]
948 )
949 model_group.add_argument("--revision", **model_kwargs["revision"])
950 model_group.add_argument("--code-revision", **model_kwargs["code_revision"])
951 model_group.add_argument(
952 "--tokenizer-revision", **model_kwargs["tokenizer_revision"]
953 )
954 model_group.add_argument("--max-model-len", **model_kwargs["max_model_len"])
955 model_group.add_argument("--quantization", "-q", **model_kwargs["quantization"])
956 model_group.add_argument(
957 "--quantization-config", **model_kwargs["quantization_config"]
958 )
959 model_group.add_argument(
960 "--allow-deprecated-quantization",
961 **model_kwargs["allow_deprecated_quantization"],
962 )
963 model_group.add_argument("--enforce-eager", **model_kwargs["enforce_eager"])
964 model_group.add_argument(
965 "--enable-return-routed-experts",
966 **aux_output_kwargs["enable_return_routed_experts"],
967 )
968 model_group.add_argument(
969 "--return-sampling-mask",
970 **model_kwargs["return_sampling_mask"],
971 )
972 model_group.add_argument("--max-logprobs", **model_kwargs["max_logprobs"])
973 model_group.add_argument("--logprobs-mode", **model_kwargs["logprobs_mode"])
974 model_group.add_argument("--use-fp64-gumbel", **model_kwargs["use_fp64_gumbel"])
975 model_group.add_argument(
976 "--enable-trace-replay", **model_kwargs["enable_trace_replay"]
977 )
978 model_group.add_argument(
979 "--disable-sliding-window", **model_kwargs["disable_sliding_window"]
980 )
981 model_group.add_argument(
982 "--disable-cascade-attn", **model_kwargs["disable_cascade_attn"]
983 )
984 model_group.add_argument(
985 "--skip-tokenizer-init", **model_kwargs["skip_tokenizer_init"]
986 )
987 model_group.add_argument(
988 "--enable-prompt-embeds", **model_kwargs["enable_prompt_embeds"]
989 )
990 model_group.add_argument(
991 "--served-model-name", **model_kwargs["served_model_name"]
992 )
993 model_group.add_argument("--config-format", **model_kwargs["config_format"])
994 model_group.add_argument("--hf-token", **model_kwargs["hf_token"])
995 model_group.add_argument("--hf-overrides", **model_kwargs["hf_overrides"])
996 model_group.add_argument(
997 "--model-class-overrides", **model_kwargs["model_class_overrides"]
998 )
999 model_group.add_argument("--pooler-config", **model_kwargs["pooler_config"])
1000 model_group.add_argument(
1001 "--generation-config", **model_kwargs["generation_config"]
1002 )
1003 model_group.add_argument(
1004 "--override-generation-config", **model_kwargs["override_generation_config"]
1005 )
1006 model_group.add_argument(
1007 "--enable-sleep-mode", **model_kwargs["enable_sleep_mode"]
1008 )
1009 model_group.add_argument(
1010 "--sleep-preserve-parameter-names",
1011 **model_kwargs["sleep_preserve_parameter_names"],
1012 )
1013 model_group.add_argument(
1014 "--enable-cumem-allocator", **model_kwargs["enable_cumem_allocator"]
1015 )
1016 model_group.add_argument(
1017 "--enable-nccl-comm-suspend",
1018 **model_kwargs["enable_nccl_comm_suspend"],
1019 )
1020 model_group.add_argument("--model-impl", **model_kwargs["model_impl"])
1021 model_group.add_argument(
1022 "--logits-processors", **model_kwargs["logits_processors"]
1023 )
1024 model_group.add_argument(
1025 "--io-processor-plugin", **model_kwargs["io_processor_plugin"]
1026 )
1027 model_group.add_argument(
1028 "--renderer-num-workers",
1029 **model_kwargs["renderer_num_workers"],
1030 )
1031
1032 # Model loading arguments
1033 load_kwargs = get_kwargs(LoadConfig)
1034 load_group = parser.add_argument_group(
1035 title="LoadConfig",
1036 description=LoadConfig.__doc__,
1037 )
1038 load_group.add_argument("--load-format", **load_kwargs["load_format"])
1039 load_group.add_argument("--download-dir", **load_kwargs["download_dir"])
1040 load_group.add_argument(
1041 "--safetensors-load-strategy", **load_kwargs["safetensors_load_strategy"]
1042 )
1043 load_group.add_argument(
1044 "--safetensors-prefetch-num-threads",
1045 **load_kwargs["safetensors_prefetch_num_threads"],
1046 )
1047 load_group.add_argument(
1048 "--safetensors-prefetch-block-size",
1049 **load_kwargs["safetensors_prefetch_block_size"],
1050 )
1051 load_group.add_argument(
1052 "--model-loader-extra-config", **load_kwargs["model_loader_extra_config"]
1053 )
1054 load_group.add_argument("--ignore-patterns", **load_kwargs["ignore_patterns"])
1055 load_group.add_argument("--use-tqdm-on-load", **load_kwargs["use_tqdm_on_load"])
1056 load_group.add_argument(
1057 "--pt-load-map-location", **load_kwargs["pt_load_map_location"]
1058 )
1059
1060 # Attention arguments
1061 attention_kwargs = get_kwargs(AttentionConfig)
1062 attention_group = parser.add_argument_group(
1063 title="AttentionConfig",
1064 description=AttentionConfig.__doc__,
1065 )
1066 attention_group.add_argument(
1067 "--attention-backend", **attention_kwargs["backend"]
1068 )
1069
1070 # Mamba arguments
1071 mamba_kwargs = get_kwargs(MambaConfig)
1072 mamba_group = parser.add_argument_group(
1073 title="MambaConfig",
1074 description=MambaConfig.__doc__,
1075 )
1076 mamba_group.add_argument("--mamba-backend", **mamba_kwargs["backend"])
1077 mamba_group.add_argument(
1078 "--mamba-ssu-algorithm", **mamba_kwargs["ssu_algorithm"]
1079 )
1080 mamba_group.add_argument(
1081 "--enable-mamba-cache-stochastic-rounding",
1082 **mamba_kwargs["enable_stochastic_rounding"],
1083 )
1084 mamba_group.add_argument(
1085 "--mamba-cache-philox-rounds",
1086 **mamba_kwargs["stochastic_rounding_philox_rounds"],
1087 )
1088
1089 # Structured outputs arguments
1090 structured_outputs_kwargs = get_kwargs(StructuredOutputsConfig)
1091 structured_outputs_group = parser.add_argument_group(
1092 title="StructuredOutputsConfig",
1093 description=StructuredOutputsConfig.__doc__,
1094 )
1095 structured_outputs_group.add_argument(
1096 "--reasoning-parser",
1097 # Choices need to be validated after parsing to include plugins
1098 **structured_outputs_kwargs["reasoning_parser"],
1099 )
1100 structured_outputs_group.add_argument(
1101 "--reasoning-parser-plugin",
1102 **structured_outputs_kwargs["reasoning_parser_plugin"],
1103 )
1104
1105 # Parallel arguments
1106 parallel_kwargs = get_kwargs(ParallelConfig)
1107 parallel_group = parser.add_argument_group(
1108 title="ParallelConfig",
1109 description=ParallelConfig.__doc__,
1110 )
1111 parallel_group.add_argument(
1112 "--distributed-executor-backend",
1113 **parallel_kwargs["distributed_executor_backend"],
1114 )
1115 parallel_group.add_argument(
1116 "--pipeline-parallel-size",
1117 "-pp",
1118 **parallel_kwargs["pipeline_parallel_size"],
1119 )
1120 parallel_group.add_argument("--master-addr", **parallel_kwargs["master_addr"])
1121 parallel_group.add_argument("--master-port", **parallel_kwargs["master_port"])
1122 parallel_group.add_argument("--nnodes", "-n", **parallel_kwargs["nnodes"])
1123 parallel_group.add_argument("--node-rank", "-r", **parallel_kwargs["node_rank"])
1124 parallel_group.add_argument(
1125 "--distributed-timeout-seconds",
1126 **parallel_kwargs["distributed_timeout_seconds"],
1127 )
1128 parallel_group.add_argument(
1129 "--cpu-distributed-timeout-seconds",
1130 **parallel_kwargs["cpu_distributed_timeout_seconds"],
1131 )
1132 parallel_group.add_argument("--numa-bind", **parallel_kwargs["numa_bind"])
1133 parallel_group.add_argument(
1134 "--numa-bind-nodes", **parallel_kwargs["numa_bind_nodes"]
1135 )
1136 parallel_group.add_argument(
1137 "--numa-bind-cpus", **parallel_kwargs["numa_bind_cpus"]
1138 )
1139 parallel_group.add_argument(
1140 "--device-ids",
1141 type=lambda s: [
1142 int(device_id) if device_id.isdigit() else device_id
1143 for device_id in (part.strip() for part in s.split(","))
1144 ],
1145 default=None,
1146 help="Comma-separated physical GPU device IDs or UUIDs to use "
1147 '(e.g. --device-ids "2,3,5,7"). Avoids setting '
1148 "CUDA_VISIBLE_DEVICES, preserving full GPU topology "
1149 "visibility for GPU-NIC affinity and DeepGEMM. "
1150 "Note: has no effect with Ray executors; use Ray "
1151 "placement groups for GPU selection instead.",
1152 )
1153 parallel_group.add_argument(
1154 "--tensor-parallel-size", "-tp", **parallel_kwargs["tensor_parallel_size"]
1155 )
1156 parallel_group.add_argument(
1157 "--decode-context-parallel-size",
1158 "-dcp",
1159 **parallel_kwargs["decode_context_parallel_size"],
1160 )
1161 parallel_group.add_argument(
1162 "--dcp-comm-backend",
1163 **parallel_kwargs["dcp_comm_backend"],
1164 )
1165 parallel_group.add_argument(
1166 "--dcp-q-replicate",
1167 **parallel_kwargs["dcp_q_replicate"],
1168 )
1169 parallel_group.add_argument(
1170 "--dcp-kv-cache-interleave-size",
1171 **parallel_kwargs["dcp_kv_cache_interleave_size"],
1172 )
1173 parallel_group.add_argument(
1174 "--cp-kv-cache-interleave-size",
1175 **{
1176 **parallel_kwargs["cp_kv_cache_interleave_size"],
1177 "default": None,
1178 },
1179 )
1180 parallel_group.add_argument(
1181 "--prefill-context-parallel-size",
1182 "-pcp",
1183 **parallel_kwargs["prefill_context_parallel_size"],
1184 )
1185 parallel_group.add_argument(
1186 "--data-parallel-size", "-dp", **parallel_kwargs["data_parallel_size"]
1187 )
1188 parallel_group.add_argument(
1189 "--data-parallel-rank",
1190 "-dpn",
1191 type=int,
1192 help="Data parallel rank of this instance. "
1193 "When set, enables external load balancer mode for MoE "
1194 "data-parallel deployments. Unsupported for non-MoE models; "
1195 "launch independent vLLM instances instead.",
1196 )
1197 parallel_group.add_argument(
1198 "--data-parallel-start-rank",
1199 "-dpr",
1200 type=int,
1201 help="Starting data parallel rank for secondary nodes.",
1202 )
1203 parallel_group.add_argument(
1204 "--data-parallel-size-local",
1205 "-dpl",
1206 type=int,
1207 help="Number of data parallel replicas to run on this node.",
1208 )
1209 parallel_group.add_argument(
1210 "--data-parallel-address",
1211 "-dpa",
1212 type=str,
1213 help="Address of data parallel cluster head-node.",
1214 )
1215 parallel_group.add_argument(
1216 "--data-parallel-rpc-port",
1217 "-dpp",
1218 type=int,
1219 help="Fixed port for data parallel RPC communication. All nodes "
1220 "must use the same port.",
1221 )
1222 parallel_group.add_argument(
1223 "--data-parallel-backend",
1224 "-dpb",
1225 type=str,
1226 default="mp",
1227 help='Backend for data parallel, either "mp" or "ray".',
1228 )
1229 parallel_group.add_argument(
1230 "--data-parallel-hybrid-lb",
1231 "-dph",
1232 **parallel_kwargs["data_parallel_hybrid_lb"],
1233 )
1234 parallel_group.add_argument(
1235 "--data-parallel-external-lb",
1236 "-dpe",
1237 **parallel_kwargs["data_parallel_external_lb"],
1238 )
1239 parallel_group.add_argument(
1240 "--data-parallel-multi-port-external-lb",
1241 "-dpm",
1242 action="store_true",
1243 default=False,
1244 help="Run a node-local supervisor that launches one external-LB API "
1245 "server per local data parallel rank and exposes aggregated health on "
1246 "a supervisor port.",
1247 )
1248 parallel_group.add_argument(
1249 "--enable-expert-parallel",
1250 "-ep",
1251 **parallel_kwargs["enable_expert_parallel"],
1252 )
1253 parallel_group.add_argument(
1254 "--enable-batch-sharded-sampling",
1255 **parallel_kwargs["enable_batch_sharded_sampling"],
1256 )
1257 parallel_group.add_argument(
1258 "--enable-ep-weight-filter",
1259 **parallel_kwargs["enable_ep_weight_filter"],
1260 )
1261 parallel_group.add_argument(
1262 "--all2all-backend", **parallel_kwargs["all2all_backend"]
1263 )
1264 parallel_group.add_argument("--enable-dbo", **parallel_kwargs["enable_dbo"])
1265 parallel_group.add_argument(
1266 "--ubatch-size",
1267 **parallel_kwargs["ubatch_size"],
1268 )
1269 parallel_group.add_argument(
1270 "--enable-elastic-ep", **parallel_kwargs["enable_elastic_ep"]
1271 )
1272 parallel_group.add_argument(
1273 "--elastic-ep-max-dp-size",
1274 **parallel_kwargs["elastic_ep_max_dp_size"],
1275 )
1276 parallel_group.add_argument(
1277 "--dbo-decode-token-threshold",
1278 **parallel_kwargs["dbo_decode_token_threshold"],
1279 )
1280 parallel_group.add_argument(
1281 "--dp-sync-interval",
1282 **parallel_kwargs["dp_sync_interval"],
1283 )
1284 parallel_group.add_argument(
1285 "--dbo-prefill-token-threshold",
1286 **parallel_kwargs["dbo_prefill_token_threshold"],
1287 )
1288 parallel_group.add_argument(
1289 "--disable-nccl-for-dp-synchronization",
1290 **parallel_kwargs["disable_nccl_for_dp_synchronization"],
1291 )
1292 parallel_group.add_argument("--enable-eplb", **parallel_kwargs["enable_eplb"])
1293 parallel_group.add_argument("--eplb-config", **parallel_kwargs["eplb_config"])
1294 parallel_group.add_argument(
1295 "--expert-placement-strategy",
1296 **parallel_kwargs["expert_placement_strategy"],
1297 )
1298
1299 parallel_group.add_argument(
1300 "--max-parallel-loading-workers",
1301 **parallel_kwargs["max_parallel_loading_workers"],
1302 )
1303 parallel_group.add_argument(
1304 "--ray-workers-use-nsight", **parallel_kwargs["ray_workers_use_nsight"]
1305 )
1306 parallel_group.add_argument(
1307 "--disable-custom-all-reduce",
1308 **parallel_kwargs["disable_custom_all_reduce"],
1309 )
1310 parallel_group.add_argument("--worker-cls", **parallel_kwargs["worker_cls"])
1311 parallel_group.add_argument(
1312 "--worker-extension-cls", **parallel_kwargs["worker_extension_cls"]
1313 )
1314 parallel_group.add_argument(
1315 "--enable-fault-tolerance", **parallel_kwargs["enable_fault_tolerance"]
1316 )
1317 parallel_group.add_argument(
1318 "--fault-tolerance-config", **parallel_kwargs["fault_tolerance_config"]
1319 )
1320
1321 # KV cache arguments
1322 cache_kwargs = get_kwargs(CacheConfig)
1323 cache_group = parser.add_argument_group(
1324 title="CacheConfig",
1325 description=CacheConfig.__doc__,
1326 )
1327 cache_group.add_argument("--block-size", **cache_kwargs["block_size"])
1328 cache_group.add_argument(
1329 "--gpu-memory-utilization",
1330 "--device-memory-utilization",
1331 dest="gpu_memory_utilization",
1332 **cache_kwargs["gpu_memory_utilization"],
1333 )
1334 cache_group.add_argument(
1335 "--kv-cache-memory-bytes", **cache_kwargs["kv_cache_memory_bytes"]
1336 )
1337 cache_group.add_argument("--kv-cache-dtype", **cache_kwargs["cache_dtype"])
1338 cache_group.add_argument(
1339 "--num-gpu-blocks-override", **cache_kwargs["num_gpu_blocks_override"]
1340 )
1341 cache_group.add_argument(
1342 "--enable-prefix-caching",
1343 **{
1344 **cache_kwargs["enable_prefix_caching"],
1345 "default": None,
1346 },
1347 )
1348 cache_group.add_argument(
1349 "--prefix-caching-hash-algo", **cache_kwargs["prefix_caching_hash_algo"]
1350 )
1351 cache_group.add_argument(
1352 "--prefix-cache-retention-interval",
1353 **cache_kwargs["prefix_cache_retention_interval"],
1354 )
1355 cache_group.add_argument(
1356 "--kv-cache-dtype-skip-layers", **cache_kwargs["kv_cache_dtype_skip_layers"]
1357 )
1358 cache_group.add_argument(
1359 "--kv-sharing-fast-prefill", **cache_kwargs["kv_sharing_fast_prefill"]
1360 )
1361 cache_group.add_argument(
1362 "--swa-bounded-replay", **cache_kwargs["swa_bounded_replay"]
1363 )
1364 cache_group.add_argument(
1365 "--mamba-cache-dtype", **cache_kwargs["mamba_cache_dtype"]
1366 )
1367 cache_group.add_argument(
1368 "--mamba-ssm-cache-dtype", **cache_kwargs["mamba_ssm_cache_dtype"]
1369 )
1370 cache_group.add_argument(
1371 "--mamba-block-size", **cache_kwargs["mamba_block_size"]
1372 )
1373 cache_group.add_argument(
1374 "--prefix-match-unit", **cache_kwargs["prefix_match_unit"]
1375 )
1376 cache_group.add_argument(
1377 "--mamba-cache-mode", **cache_kwargs["mamba_cache_mode"]
1378 )
1379 cache_group.add_argument(
1380 "--enable-mamba-shared-prefix-checkpoint",
1381 **cache_kwargs["enable_mamba_shared_prefix_checkpoint"],
1382 )
1383 cache_group.add_argument(
1384 "--replayssm-buffer-len", **cache_kwargs["replayssm_buffer_len"]
1385 )
1386 cache_group.add_argument("--use-replayssm", **cache_kwargs["use_replayssm"])
1387 cache_group.add_argument(
1388 "--kv-offloading-size", **cache_kwargs["kv_offloading_size"]
1389 )
1390 cache_group.add_argument(
1391 "--kv-offloading-backend", **cache_kwargs["kv_offloading_backend"]
1392 )
1393
1394 # Model weight offload related configs
1395 offload_kwargs = get_kwargs(OffloadConfig)
1396 uva_kwargs = get_kwargs(UVAOffloadConfig)
1397 prefetch_kwargs = get_kwargs(PrefetchOffloadConfig)
1398 offload_group = parser.add_argument_group(
1399 title="OffloadConfig",
1400 description=OffloadConfig.__doc__,
1401 )
1402 offload_group.add_argument(
1403 "--offload-backend", **offload_kwargs["offload_backend"]
1404 )
1405 offload_group.add_argument("--cpu-offload-gb", **uva_kwargs["cpu_offload_gb"])
1406 offload_group.add_argument(
1407 "--cpu-offload-params", **uva_kwargs["cpu_offload_params"]
1408 )
1409 offload_group.add_argument(
1410 "--offload-group-size",
1411 **prefetch_kwargs["offload_group_size"],
1412 )
1413 offload_group.add_argument(
1414 "--offload-num-in-group",
1415 **prefetch_kwargs["offload_num_in_group"],
1416 )
1417 offload_group.add_argument(
1418 "--offload-prefetch-step",
1419 **prefetch_kwargs["offload_prefetch_step"],
1420 )
1421 offload_group.add_argument(
1422 "--offload-params", **prefetch_kwargs["offload_params"]
1423 )
1424
1425 # Multimodal related configs
1426 multimodal_kwargs = get_kwargs(MultiModalConfig)
1427 multimodal_group = parser.add_argument_group(
1428 title="MultiModalConfig",
1429 description=MultiModalConfig.__doc__,
1430 )
1431 multimodal_group.add_argument(
1432 "--language-model-only", **multimodal_kwargs["language_model_only"]
1433 )
1434 multimodal_group.add_argument(
1435 "--limit-mm-per-prompt", **multimodal_kwargs["limit_per_prompt"]
1436 )
1437 multimodal_group.add_argument(
1438 "--enable-mm-embeds", **multimodal_kwargs["enable_mm_embeds"]
1439 )
1440 multimodal_group.add_argument(
1441 "--media-io-kwargs", **multimodal_kwargs["media_io_kwargs"]
1442 )
1443 multimodal_group.add_argument(
1444 "--mm-processor-kwargs", **multimodal_kwargs["mm_processor_kwargs"]
1445 )
1446 multimodal_group.add_argument(
1447 "--mm-processor-cache-gb", **multimodal_kwargs["mm_processor_cache_gb"]
1448 )
1449 multimodal_group.add_argument(
1450 "--mm-processor-cache-type", **multimodal_kwargs["mm_processor_cache_type"]
1451 )
1452 multimodal_group.add_argument(
1453 "--mm-hasher-algorithm", **multimodal_kwargs["mm_hasher_algorithm"]
1454 )
1455 multimodal_group.add_argument(
1456 "--mm-shm-cache-max-object-size-mb",
1457 **multimodal_kwargs["mm_shm_cache_max_object_size_mb"],
1458 )
1459 multimodal_group.add_argument(
1460 "--mm-encoder-only", **multimodal_kwargs["mm_encoder_only"]
1461 )
1462 multimodal_group.add_argument(
1463 "--mm-encoder-tp-mode", **multimodal_kwargs["mm_encoder_tp_mode"]
1464 )
1465 multimodal_group.add_argument(
1466 "--mm-encoder-attn-backend",
1467 **multimodal_kwargs["mm_encoder_attn_backend"],
1468 )
1469 multimodal_group.add_argument(
1470 "--mm-encoder-attn-dtype",
1471 **multimodal_kwargs["mm_encoder_attn_dtype"],
1472 )
1473 multimodal_group.add_argument(
1474 "--mm-encoder-fp8-scale-path",
1475 **multimodal_kwargs["mm_encoder_fp8_scale_path"],
1476 )
1477 multimodal_group.add_argument(
1478 "--mm-encoder-fp8-scale-save-path",
1479 **multimodal_kwargs["mm_encoder_fp8_scale_save_path"],
1480 )
1481 multimodal_group.add_argument(
1482 "--mm-encoder-fp8-scale-save-margin",
1483 **multimodal_kwargs["mm_encoder_fp8_scale_save_margin"],
1484 )
1485 multimodal_group.add_argument(
1486 "--interleave-mm-strings", **multimodal_kwargs["interleave_mm_strings"]
1487 )
1488 multimodal_group.add_argument(
1489 "--skip-mm-profiling", **multimodal_kwargs["skip_mm_profiling"]
1490 )
1491
1492 multimodal_group.add_argument(
1493 "--video-pruning-rate", **multimodal_kwargs["video_pruning_rate"]
1494 )
1495 multimodal_group.add_argument(
1496 "--video-pruning-method",
1497 **multimodal_kwargs["video_pruning_method"],
1498 )
1499 multimodal_group.add_argument(
1500 "--mm-tensor-ipc", **multimodal_kwargs["mm_tensor_ipc"]
1501 )
1502 multimodal_group.add_argument(
1503 "--mm-processor-device",
1504 choices=["auto", "cpu"]
1505 + (
1506 [current_platform.device_type]
1507 if current_platform.device_type not in ("", "cpu")
1508 else []
1509 ),
1510 default="auto",
1511 help="Device the HF multi-modal processor runs the image/video "
1512 "transform on. Convenience for `--mm-processor-kwargs "
1513 "'{\"device\": ...}'`: the value is resolved here and stored there, "
1514 "it is not kept as separate state. Only takes effect for HF "
1515 '"fast" (torchvision-backed) processors, which accept a `device` '
1516 "argument; the others ignore it and stay on CPU.\n\n"
1517 '"auto" uses the accelerator on encoder instances of an '
1518 "encode/prefill/decode deployment -- an EC producer that is not "
1519 "also a consumer allocates no KV cache, so its accelerator is not "
1520 "contended by the language model -- and then only when "
1521 "`--mm-tensor-ipc=torch_shm` can carry device tensors, since every "
1522 "other transport would copy the result back to the host and that "
1523 'copy costs more than it saves. "auto" resolves to "cpu" '
1524 "everywhere else.",
1525 )
1526 multimodal_group.add_argument(
1527 "--mm-ipc-gpu-memory-gb",
1528 **multimodal_kwargs["mm_ipc_gpu_memory_gb"],
1529 )
1530 multimodal_group.add_argument(
1531 "--mm-device-do-normalize",
1532 **{
1533 **multimodal_kwargs["mm_device_do_normalize"],
1534 "default": None,
1535 },
1536 )
1537
1538 # LoRA related configs
1539 lora_kwargs = get_kwargs(LoRAConfig)
1540 lora_group = parser.add_argument_group(
1541 title="LoRAConfig",
1542 description=LoRAConfig.__doc__,
1543 )
1544 lora_group.add_argument(
1545 "--enable-lora",
1546 action=argparse.BooleanOptionalAction,
1547 help="If True, enable handling of LoRA adapters.",
1548 )
1549 lora_group.add_argument("--max-loras", **lora_kwargs["max_loras"])
1550 lora_group.add_argument("--max-lora-rank", **lora_kwargs["max_lora_rank"])
1551 lora_group.add_argument(
1552 "--lora-dtype",
1553 **lora_kwargs["lora_dtype"],
1554 )
1555 lora_group.add_argument(
1556 "--enable-tower-connector-lora",
1557 **lora_kwargs["enable_tower_connector_lora"],
1558 )
1559 lora_group.add_argument("--max-cpu-loras", **lora_kwargs["max_cpu_loras"])
1560 lora_group.add_argument(
1561 "--fully-sharded-loras", **lora_kwargs["fully_sharded_loras"]
1562 )
1563 lora_group.add_argument(
1564 "--lora-target-modules", **lora_kwargs["target_modules"]
1565 )
1566 lora_group.add_argument("--default-mm-loras", **lora_kwargs["default_mm_loras"])
1567 lora_group.add_argument(
1568 "--specialize-active-lora", **lora_kwargs["specialize_active_lora"]
1569 )
1570 lora_group.add_argument(
1571 "--enable-mixed-moe-lora-format",
1572 **lora_kwargs["enable_mixed_moe_lora_format"],
1573 )
1574 lora_group.add_argument(
1575 "--enable-moe-shared-loras",
1576 **lora_kwargs["enable_moe_shared_loras"],
1577 )
1578 lora_group.add_argument(
1579 "--max-lora-cls-labels",
1580 **lora_kwargs["max_lora_cls_labels"],
1581 )
1582
1583 # Logging arguments
1584 logging_group = parser.add_argument_group(
1585 title="LoggingConfig",
1586 description=LoggingConfig.__doc__,
1587 )
1588 logging_config_kwargs = get_kwargs(VllmConfig)["logging_config"]
1589 logging_config_kwargs["default"] = argparse.SUPPRESS
1590 logging_group.add_argument("--logging-config", **logging_config_kwargs)
1591 logging_group.add_argument(
1592 "--log-level",
1593 choices=get_args(LogLevel),
1594 default=argparse.SUPPRESS,
1595 help=(
1596 "Shortcut for --logging-config.log_level. "
1597 "Overrides that field if both are specified."
1598 ),
1599 )
1600 logging_group.add_argument(
1601 "--log-config-file",
1602 dest="log_config_file",
1603 default=argparse.SUPPRESS,
1604 metavar="PYLOGGING_CONFIG_FILE",
1605 action=DeprecatedLogConfigFileAction,
1606 help=_LOG_CONFIG_FILE_DEPRECATION_MESSAGE,
1607 )
1608 # Retain the warning in v0.31.0 and v0.32.0. Remove this option and its
1609 # compatibility mapping in create_logging_config() in v0.33.0.
1610
1611 # Observability arguments
1612 observability_kwargs = get_kwargs(ObservabilityConfig)
1613 observability_group = parser.add_argument_group(
1614 title="ObservabilityConfig",
1615 description=ObservabilityConfig.__doc__,
1616 )
1617 observability_group.add_argument(
1618 "--show-hidden-metrics-for-version",
1619 **observability_kwargs["show_hidden_metrics_for_version"],
1620 )
1621 observability_group.add_argument(
1622 "--otlp-traces-endpoint", **observability_kwargs["otlp_traces_endpoint"]
1623 )
1624 observability_group.add_argument(
1625 "--collect-detailed-traces",
1626 **observability_kwargs["collect_detailed_traces"],
1627 )
1628 observability_group.add_argument(
1629 "--per-request-spec-decode-metrics",
1630 **observability_kwargs["per_request_spec_decode_metrics"],
1631 )
1632 observability_group.add_argument(
1633 "--kv-cache-metrics", **observability_kwargs["kv_cache_metrics"]
1634 )
1635 observability_group.add_argument(
1636 "--kv-cache-metrics-sample",
1637 **observability_kwargs["kv_cache_metrics_sample"],
1638 )
1639 observability_group.add_argument(
1640 "--custom-histogram-buckets",
1641 **observability_kwargs["custom_histogram_buckets"],
1642 )
1643 observability_group.add_argument(
1644 "--cudagraph-metrics",
1645 **observability_kwargs["cudagraph_metrics"],
1646 )
1647 observability_group.add_argument(
1648 "--enable-layerwise-nvtx-tracing",
1649 **observability_kwargs["enable_layerwise_nvtx_tracing"],
1650 )
1651 observability_group.add_argument(
1652 "--enable-mfu-metrics",
1653 **observability_kwargs["enable_mfu_metrics"],
1654 )
1655 observability_group.add_argument(
1656 "--enable-logging-iteration-details",
1657 **observability_kwargs["enable_logging_iteration_details"],
1658 )
1659 observability_group.add_argument(
1660 "--jit-monitor-mode",
1661 **observability_kwargs["jit_monitor_mode"],
1662 )
1663 observability_group.add_argument(
1664 "--jit-monitor-verbose",
1665 **observability_kwargs["jit_monitor_verbose"],
1666 )
1667
1668 # Scheduler arguments
1669 scheduler_kwargs = get_kwargs(SchedulerConfig)
1670 scheduler_group = parser.add_argument_group(
1671 title="SchedulerConfig",
1672 description=SchedulerConfig.__doc__,
1673 )
1674 scheduler_group.add_argument(
1675 "--max-num-batched-tokens",
1676 **{
1677 **scheduler_kwargs["max_num_batched_tokens"],
1678 "default": None,
1679 },
1680 )
1681 scheduler_group.add_argument(
1682 "--max-num-scheduled-tokens",
1683 **{
1684 **scheduler_kwargs["max_num_scheduled_tokens"],
1685 "default": None,
1686 },
1687 )
1688 scheduler_group.add_argument(
1689 "--max-num-seqs",
1690 **{
1691 **scheduler_kwargs["max_num_seqs"],
1692 "default": None,
1693 },
1694 )
1695 scheduler_group.add_argument(
1696 "--max-num-active-seqs",
1697 **scheduler_kwargs["max_num_active_seqs"],
1698 )
1699 scheduler_group.add_argument(
1700 "--max-num-queued-reqs", **scheduler_kwargs["max_num_queued_reqs"]
1701 )
1702 scheduler_group.add_argument(
1703 "--max-num-queued-tokens",
1704 **scheduler_kwargs["max_num_queued_tokens"],
1705 )
1706 scheduler_group.add_argument(
1707 "--long-prefill-token-threshold",
1708 **scheduler_kwargs["long_prefill_token_threshold"],
1709 )
1710 scheduler_group.add_argument(
1711 "--long-prefill-token-threshold-adaptive",
1712 **scheduler_kwargs["long_prefill_token_threshold_adaptive"],
1713 )
1714 # multi-step scheduling has been removed; corresponding arguments
1715 # are no longer supported.
1716 scheduler_group.add_argument(
1717 "--scheduling-policy", **scheduler_kwargs["policy"]
1718 )
1719 scheduler_group.add_argument(
1720 "--enable-chunked-prefill",
1721 **{
1722 **scheduler_kwargs["enable_chunked_prefill"],
1723 "default": None,
1724 },
1725 )
1726 scheduler_group.add_argument(
1727 "--disable-chunked-mm-input", **scheduler_kwargs["disable_chunked_mm_input"]
1728 )
1729 scheduler_group.add_argument(
1730 "--scheduler-cls", **scheduler_kwargs["scheduler_cls"]
1731 )
1732 scheduler_group.add_argument(
1733 "--scheduler-reserve-full-isl",
1734 **scheduler_kwargs["scheduler_reserve_full_isl"],
1735 )
1736 scheduler_group.add_argument("--watermark", **scheduler_kwargs["watermark"])
1737 scheduler_group.add_argument(
1738 "--prefill-schedule-interval",
1739 **scheduler_kwargs["prefill_schedule_interval"],
1740 )
1741 scheduler_group.add_argument(
1742 "--disable-hybrid-kv-cache-manager",
1743 **scheduler_kwargs["disable_hybrid_kv_cache_manager"],
1744 )
1745 scheduler_group.add_argument(
1746 "--async-scheduling", **scheduler_kwargs["async_scheduling"]
1747 )
1748 scheduler_group.add_argument(
1749 "--stream-interval", **scheduler_kwargs["stream_interval"]
1750 )
1751
1752 # Compilation arguments
1753 compilation_kwargs = get_kwargs(CompilationConfig)
1754 compilation_group = parser.add_argument_group(
1755 title="CompilationConfig",
1756 description=CompilationConfig.__doc__,
1757 )
1758 compilation_group.add_argument(
1759 "--cudagraph-capture-sizes", **compilation_kwargs["cudagraph_capture_sizes"]
1760 )
1761 compilation_group.add_argument(
1762 "--max-cudagraph-capture-size",
1763 **compilation_kwargs["max_cudagraph_capture_size"],
1764 )
1765
1766 # Kernel arguments
1767 kernel_kwargs = get_kwargs(KernelConfig)
1768 kernel_group = parser.add_argument_group(
1769 title="KernelConfig",
1770 description=KernelConfig.__doc__,
1771 )
1772 kernel_group.add_argument("--ir-op-priority", **kernel_kwargs["ir_op_priority"])
1773 kernel_group.add_argument(
1774 "--enable-flashinfer-autotune",
1775 **kernel_kwargs["enable_flashinfer_autotune"],
1776 )
1777 moe_backend_kwargs = kernel_kwargs["moe_backend"]
1778 moe_backend_kwargs["type"] = lambda s: s.lower().replace("-", "_")
1779 kernel_group.add_argument("--moe-backend", **moe_backend_kwargs)
1780 linear_backend_kwargs = kernel_kwargs["linear_backend"]
1781 linear_backend_kwargs["type"] = lambda s: s.lower().replace("-", "_")
1782 kernel_group.add_argument("--linear-backend", **linear_backend_kwargs)
1783 sparse_indexer_topk_kwargs = kernel_kwargs["sparse_indexer_topk_backend"]
1784 sparse_indexer_topk_kwargs["type"] = lambda s: s.lower().replace("-", "_")
1785 kernel_group.add_argument(
1786 "--sparse-indexer-topk-backend", **sparse_indexer_topk_kwargs
1787 )
1788
1789 # vLLM arguments
1790 vllm_kwargs = get_kwargs(VllmConfig)
1791 vllm_group = parser.add_argument_group(
1792 title="VllmConfig",
1793 description=VllmConfig.__doc__,
1794 )
1795 # We construct SpeculativeConfig using fields from other configs in
1796 # create_engine_config. So we set the type to a JSON string here to
1797 # delay the Pydantic validation that comes with SpeculativeConfig.
1798 vllm_kwargs["speculative_config"]["type"] = optional_type(json.loads)
1799 vllm_group.add_argument(
1800 "--speculative-config", "-sc", **vllm_kwargs["speculative_config"]
1801 )
1802 speculative_kwargs = get_kwargs(SpeculativeConfig)
1803 vllm_group.add_argument("--spec-method", **speculative_kwargs["method"])
1804 vllm_group.add_argument("--spec-model", **speculative_kwargs["model"])
1805 vllm_group.add_argument(
1806 "--spec-tokens", **speculative_kwargs["num_speculative_tokens"]
1807 )
1808 vllm_kwargs["watermark_config"]["type"] = optional_type(json.loads)
1809 vllm_group.add_argument("--watermark-config", **vllm_kwargs["watermark_config"])
1810 vllm_kwargs["diffusion_config"]["type"] = optional_type(json.loads)
1811 vllm_group.add_argument(
1812 "--diffusion-config", "-dc", **vllm_kwargs["diffusion_config"]
1813 )
1814 vllm_group.add_argument(
1815 "--kv-transfer-config", **vllm_kwargs["kv_transfer_config"]
1816 )
1817 vllm_group.add_argument("--kv-events-config", **vllm_kwargs["kv_events_config"])
1818 vllm_group.add_argument(
1819 "--ec-transfer-config", **vllm_kwargs["ec_transfer_config"]
1820 )
1821 vllm_group.add_argument(
1822 "--ec-manager-config", **vllm_kwargs["ec_manager_config"]
1823 )
1824 vllm_group.add_argument(
1825 "--compilation-config", "-cc", **vllm_kwargs["compilation_config"]
1826 )
1827 vllm_group.add_argument(
1828 "--attention-config", "-ac", **vllm_kwargs["attention_config"]
1829 )
1830 vllm_group.add_argument("--engram-config", **vllm_kwargs["engram_config"])
1831 vllm_group.add_argument("--reasoning-config", **vllm_kwargs["reasoning_config"])
1832 vllm_group.add_argument("--kernel-config", **vllm_kwargs["kernel_config"])
1833 vllm_group.add_argument(
1834 "--additional-config", **vllm_kwargs["additional_config"]
1835 )
1836 vllm_group.add_argument(
1837 "--structured-outputs-config", **vllm_kwargs["structured_outputs_config"]
1838 )
1839 vllm_group.add_argument(
1840 "--aux-output-config", **vllm_kwargs["aux_output_config"]
1841 )
1842 vllm_group.add_argument("--profiler-config", **vllm_kwargs["profiler_config"])
1843 vllm_group.add_argument(
1844 "--optimization-level", **vllm_kwargs["optimization_level"]
1845 )
1846 vllm_group.add_argument("--performance-mode", **vllm_kwargs["performance_mode"])
1847 vllm_group.add_argument(
1848 "--weight-transfer-config", **vllm_kwargs["weight_transfer_config"]
1849 )
1850
1851 # Other arguments
1852 parser.add_argument(
1853 "--disable-log-stats",
1854 action="store_true",
1855 help="Disable logging statistics.",
1856 )
1857
1858 parser.add_argument(
1859 "--aggregate-engine-logging",
1860 action="store_true",
1861 help="Log aggregate rather than per-engine statistics "
1862 "when using data parallelism.",
1863 )
1864
1865 parser.add_argument(
1866 "--fail-on-environ-validation",
1867 help="If set, the engine will raise an error if "
1868 "environment validation fails.",
1869 default=False,
1870 action=argparse.BooleanOptionalAction,
1871 )
1872
1873 parser.add_argument(
1874 "--shutdown-timeout",
1875 type=int,
1876 default=0,
1877 help="Shutdown timeout in seconds. 0 = abort, >0 = wait.",
1878 )
1879
1880 parser.add_argument(
1881 "--gdn-prefill-backend",
1882 dest="gdn_prefill_backend",
1883 choices=["flashinfer", "triton", "cutedsl"],
1884 default=None,
1885 help="Select GDN prefill backend.",
1886 )
1887 parser.add_argument(
1888 "--kda-prefill-backend",
1889 dest="kda_prefill_backend",
1890 choices=["auto", "triton", "flashkda", "flashinfer", "fused"],
1891 default=None,
1892 help="Select KDA prefill backend. 'flashkda' is CUDA-only and "
1893 "'fused' is ROCm-only; 'auto' picks a supported backend.",
1894 )
1895 parser.add_argument(
1896 "--kda-decode-backend",
1897 dest="kda_decode_backend",
1898 choices=["auto", "native", "flashinfer", "triton"],
1899 default=None,
1900 help="Select KDA decode backend.",
1901 )
1902 return parser
1903
1904 @classmethod
1905 def from_cli_args(cls, args: argparse.Namespace):
1906 # Get the list of attributes of this dataclass.
1907 attrs = [attr.name for attr in dataclasses.fields(cls)]
1908
1909 # Set the attributes from the parsed arguments.
1910 engine_args = cls(
1911 **{attr: getattr(args, attr) for attr in attrs if hasattr(args, attr)}
1912 )
1913 return engine_args
1914
1915 def create_model_config(self) -> ModelConfig:
1916 if not envs.VLLM_ENABLE_V1_MULTIPROCESSING:
1917 logger.warning(
1918 "The global random seed is set to %d. Since "
1919 "VLLM_ENABLE_V1_MULTIPROCESSING is set to False, this may "
1920 "affect the random state of the Python process that "
1921 "launched vLLM.",
1922 self.seed,
1923 )
1924
1925 return ModelConfig(
1926 model=self.model,
1927 model_weights=self.model_weights,
1928 hf_config_path=self.hf_config_path,
1929 runner=self.runner,
1930 convert=self.convert,
1931 tokenizer=self.tokenizer, # type: ignore[arg-type]
1932 tokenizer_mode=self.tokenizer_mode,
1933 trust_remote_code=self.trust_remote_code,
1934 allowed_local_media_path=self.allowed_local_media_path,
1935 allowed_media_domains=self.allowed_media_domains,
1936 dtype=self.dtype,
1937 seed=self.seed,
1938 revision=self.revision,
1939 code_revision=self.code_revision,
1940 hf_token=self.hf_token,
1941 hf_overrides=self.hf_overrides,
1942 model_class_overrides=self.model_class_overrides,
1943 tokenizer_revision=self.tokenizer_revision,
1944 max_model_len=self.max_model_len,
1945 quantization=self.quantization,
1946 quantization_config=self.quantization_config,
1947 allow_deprecated_quantization=self.allow_deprecated_quantization,
1948 enforce_eager=self.enforce_eager,
1949 return_sampling_mask=self.return_sampling_mask,
1950 max_logprobs=self.max_logprobs,
1951 logprobs_mode=self.logprobs_mode,
1952 use_fp64_gumbel=self.use_fp64_gumbel,
1953 enable_trace_replay=self.enable_trace_replay,
1954 disable_sliding_window=self.disable_sliding_window,
1955 disable_cascade_attn=self.disable_cascade_attn,
1956 skip_tokenizer_init=self.skip_tokenizer_init,
1957 enable_prompt_embeds=self.enable_prompt_embeds,
1958 served_model_name=self.served_model_name,
1959 language_model_only=self.language_model_only,
1960 limit_mm_per_prompt=self.limit_mm_per_prompt,
1961 enable_mm_embeds=self.enable_mm_embeds,
1962 interleave_mm_strings=self.interleave_mm_strings,
1963 media_io_kwargs=self.media_io_kwargs,
1964 skip_mm_profiling=self.skip_mm_profiling,
1965 config_format=self.config_format,
1966 mm_processor_kwargs=self.mm_processor_kwargs,
1967 mm_processor_cache_gb=self.mm_processor_cache_gb,
1968 mm_processor_cache_type=self.mm_processor_cache_type,
1969 mm_shm_cache_max_object_size_mb=self.mm_shm_cache_max_object_size_mb,
1970 mm_hasher_algorithm=self.mm_hasher_algorithm,
1971 mm_encoder_only=self.mm_encoder_only,
1972 mm_encoder_tp_mode=self.mm_encoder_tp_mode,
1973 mm_encoder_attn_backend=self.mm_encoder_attn_backend,
1974 mm_encoder_attn_dtype=self.mm_encoder_attn_dtype,
1975 mm_encoder_fp8_scale_path=self.mm_encoder_fp8_scale_path,
1976 mm_encoder_fp8_scale_save_path=self.mm_encoder_fp8_scale_save_path,
1977 mm_encoder_fp8_scale_save_margin=self.mm_encoder_fp8_scale_save_margin,
1978 pooler_config=self.pooler_config,
1979 generation_config=self.generation_config,
1980 override_generation_config=self.override_generation_config,
1981 enable_sleep_mode=self.enable_sleep_mode,
1982 sleep_preserve_parameter_names=self.sleep_preserve_parameter_names,
1983 enable_cumem_allocator=self.enable_cumem_allocator,
1984 enable_nccl_comm_suspend=self.enable_nccl_comm_suspend,
1985 model_impl=self.model_impl,
1986 logits_processors=self.logits_processors,
1987 video_pruning_rate=self.video_pruning_rate,
1988 video_pruning_method=self.video_pruning_method,
1989 mm_tensor_ipc=self.mm_tensor_ipc,
1990 mm_ipc_gpu_memory_gb=self.mm_ipc_gpu_memory_gb,
1991 mm_device_do_normalize=self.mm_device_do_normalize,
1992 mm_processor_device=self.mm_processor_device,
1993 io_processor_plugin=self.io_processor_plugin,
1994 renderer_num_workers=self.renderer_num_workers,
1995 )
1996
1997 def validate_tensorizer_args(self):
1998 from vllm.model_executor.model_loader.tensorizer import TensorizerConfig
1999
2000 for key in self.model_loader_extra_config:
2001 if key in TensorizerConfig._fields:
2002 self.model_loader_extra_config["tensorizer_config"][key] = (
2003 self.model_loader_extra_config[key]
2004 )
2005
2006 def create_load_config(self) -> LoadConfig:
2007 if self.load_format == "tensorizer":
2008 if hasattr(self.model_loader_extra_config, "to_serializable"):
2009 self.model_loader_extra_config = (
2010 self.model_loader_extra_config.to_serializable()
2011 )
2012 self.model_loader_extra_config["tensorizer_config"] = {}
2013 self.model_loader_extra_config["tensorizer_config"]["tensorizer_dir"] = (
2014 self.model
2015 )
2016 self.validate_tensorizer_args()
2017
2018 return LoadConfig(
2019 load_format=self.load_format,
2020 download_dir=self.download_dir,
2021 safetensors_load_strategy=self.safetensors_load_strategy,
2022 safetensors_prefetch_num_threads=self.safetensors_prefetch_num_threads,
2023 safetensors_prefetch_block_size=self.safetensors_prefetch_block_size,
2024 model_loader_extra_config=self.model_loader_extra_config,
2025 ignore_patterns=self.ignore_patterns,
2026 use_tqdm_on_load=self.use_tqdm_on_load,
2027 pt_load_map_location=self.pt_load_map_location,
2028 )
2029
2030 def create_speculative_config(
2031 self,
2032 target_model_config: ModelConfig,
2033 target_parallel_config: ParallelConfig,
2034 ) -> SpeculativeConfig | None:
2035 """Initializes and returns a SpeculativeConfig object based on
2036 `speculative_config`.
2037 """
2038 for flag, key, value in (
2039 ("--spec-method", "method", self.spec_method),
2040 ("--spec-model", "model", self.spec_model),
2041 ("--spec-tokens", "num_speculative_tokens", self.spec_tokens),
2042 ):
2043 if value is None:
2044 continue
2045 if self.speculative_config is None:
2046 self.speculative_config = {}
2047 if key in self.speculative_config:
2048 raise ValueError(
2049 f"{flag} and --speculative-config['{key}'] are mutually exclusive"
2050 )
2051 self.speculative_config[key] = value
2052
2053 if self.speculative_config is None:
2054 return None
2055
2056 self.speculative_config = {
2057 k.replace("-", "_"): v for k, v in self.speculative_config.items()
2058 }
2059
2060 # Note(Shangming): These parameters are not obtained from the cli arg
2061 # '--speculative-config' and must be passed in when creating the engine
2062 # config.
2063 self.speculative_config.update(
2064 {
2065 "target_model_config": target_model_config,
2066 "target_parallel_config": target_parallel_config,
2067 }
2068 )
2069 return SpeculativeConfig(**self.speculative_config)
2070
2071 def _resolve_device_ids(self) -> list[int] | None:
2072 if not self.device_ids:
2073 return None
2074 if self.distributed_executor_backend == "ray":
2075 logger.warning(
2076 "--device-ids has no effect when using the Ray executor. "
2077 "Use Ray placement groups for GPU selection instead."
2078 )
2079 ids = self.device_ids
2080 if len(set(ids)) != len(ids):
2081 raise ValueError(f"--device-ids must not contain duplicates: {ids}")
2082 if all(isinstance(i, str) for i in ids):
2083 return [
2084 current_platform.device_control_id_to_physical_device_id(i)
2085 for i in cast(list[str], ids)
2086 ]
2087 if any(isinstance(i, str) for i in ids):
2088 raise ValueError("--device-ids must not mix integer IDs and UUIDs")
2089 int_ids = cast(list[int], ids)
2090 # Compose with CUDA_VISIBLE_DEVICES: if CVD is set, treat
2091 # --device-ids values as indices into the CVD-visible set.
2092 cvd = getattr(
2093 envs,
2094 current_platform.device_control_env_var,
2095 os.environ.get(current_platform.device_control_env_var),
2096 )
2097 if cvd:
2098 cvd_ids = [
2099 current_platform.device_control_id_to_physical_device_id(x)
2100 for x in cvd.split(",")
2101 ]
2102 for i in int_ids:
2103 if i >= len(cvd_ids):
2104 raise ValueError(
2105 f"--device-ids index {i} is out of range for "
2106 f"{current_platform.device_control_env_var}"
2107 f"={cvd} ({len(cvd_ids)} devices visible)"
2108 )
2109 return [cvd_ids[i] for i in int_ids]
2110 return int_ids
2111
2112 def create_diffusion_config(self) -> DiffusionConfig | None:
2113 if self.diffusion_config is None:
2114 return None
2115 cfg = self.diffusion_config
2116 if isinstance(cfg, str):
2117 cfg = json.loads(cfg)
2118 return DiffusionConfig(**cfg)
2119
2120 def create_watermark_config(self) -> WatermarkConfig | None:
2121 if self.watermark_config is None:
2122 return None
2123 cfg = self.watermark_config
2124 if isinstance(cfg, str):
2125 cfg = json.loads(cfg)
2126 return WatermarkConfig(**cfg)
2127
2128 def create_observability_config(self) -> ObservabilityConfig:
2129 return ObservabilityConfig(
2130 show_hidden_metrics_for_version=self.show_hidden_metrics_for_version,
2131 otlp_traces_endpoint=self.otlp_traces_endpoint,
2132 collect_detailed_traces=self.collect_detailed_traces,
2133 per_request_spec_decode_metrics=self.per_request_spec_decode_metrics,
2134 kv_cache_metrics=self.kv_cache_metrics,
2135 kv_cache_metrics_sample=self.kv_cache_metrics_sample,
2136 custom_histogram_buckets=self.custom_histogram_buckets,
2137 cudagraph_metrics=self.cudagraph_metrics,
2138 enable_layerwise_nvtx_tracing=self.enable_layerwise_nvtx_tracing,
2139 enable_mfu_metrics=self.enable_mfu_metrics,
2140 enable_mm_processor_stats=self.enable_mm_processor_stats,
2141 enable_logging_iteration_details=self.enable_logging_iteration_details,
2142 jit_monitor_mode=self.jit_monitor_mode,
2143 jit_monitor_verbose=self.jit_monitor_verbose,
2144 )
2145
2146 def create_logging_config(self) -> LoggingConfig:
2147 config = self.logging_config or LoggingConfig()
2148 if self.log_level is not None:
2149 config = dataclasses.replace(config, log_level=self.log_level)
2150 if self.log_config_file is not None:
2151 config = dataclasses.replace(
2152 config, pylogging_config_file=self.log_config_file
2153 )
2154 return config
2155
2156 def create_engine_config(
2157 self,
2158 usage_context: UsageContext | None = None,
2159 headless: bool = False,
2160 ) -> VllmConfig:
2161 """Create the VllmConfig.
2162
2163 NOTE: If VllmConfig is incompatible, we raise an error.
2164 """
2165 logging_config = self.create_logging_config()
2166 configure_logging_if_needed(logging_config)
2167
2168 current_platform.pre_register_and_update()
2169
2170 device_config = DeviceConfig(device=cast(Device, current_platform.device_type))
2171
2172 current_platform.validate_environ(self.fail_on_environ_validation)
2173
2174 # Check if the model is a speculator and override model/tokenizer/config
2175 # BEFORE creating ModelConfig, so the config is created with the target model
2176 # Skip speculator detection for cloud storage models (eg: S3, GCS) since
2177 # HuggingFace cannot load configs directly from S3 URLs. S3 models can still
2178 # use speculators with explicit --speculative-config.
2179 if not is_cloud_storage(self.model):
2180 (self.model, self.tokenizer, self.speculative_config) = (
2181 maybe_override_with_speculators(
2182 model=self.model,
2183 tokenizer=self.tokenizer,
2184 revision=self.revision,
2185 trust_remote_code=self.trust_remote_code,
2186 vllm_speculative_config=self.speculative_config,
2187 hf_token=self.hf_token,
2188 )
2189 )
2190
2191 model_config = self.create_model_config()
2192 self.model = model_config.model
2193 self.model_weights = model_config.model_weights
2194 self.tokenizer = model_config.tokenizer
2195
2196 self._check_feature_supported()
2197 self._set_default_chunked_prefill_and_prefix_caching_args(model_config)
2198 self._set_default_reasoning_config_args()
2199 sliding_window: int | None = None
2200 layer_types = getattr(model_config.hf_text_config, "layer_types", None)
2201 if layer_types is None or all(lt == "sliding_attention" for lt in layer_types):
2202 # Only set CacheConfig.sliding_window if the model is all sliding
2203 # window. Otherwise CacheConfig.sliding_window will override the
2204 # global layers in interleaved sliding window models.
2205 sliding_window = model_config.get_sliding_window()
2206
2207 # Resolve "auto" kv_cache_dtype to actual value from model config
2208 resolved_cache_dtype = resolve_kv_cache_dtype_string(
2209 self.kv_cache_dtype, model_config
2210 )
2211
2212 assert self.enable_prefix_caching is not None, (
2213 "enable_prefix_caching must be set by this point"
2214 )
2215
2216 cache_config = CacheConfig(
2217 block_size=self.block_size, # type: ignore[arg-type]
2218 gpu_memory_utilization=self.gpu_memory_utilization,
2219 kv_cache_memory_bytes=self.kv_cache_memory_bytes,
2220 cache_dtype=resolved_cache_dtype, # type: ignore[arg-type]
2221 is_attention_free=model_config.is_attention_free,
2222 num_gpu_blocks_override=self.num_gpu_blocks_override,
2223 sliding_window=sliding_window,
2224 enable_prefix_caching=self.enable_prefix_caching,
2225 prefix_caching_hash_algo=self.prefix_caching_hash_algo,
2226 prefix_cache_retention_interval=self.prefix_cache_retention_interval,
2227 kv_cache_dtype_skip_layers=self.kv_cache_dtype_skip_layers,
2228 kv_sharing_fast_prefill=self.kv_sharing_fast_prefill,
2229 swa_bounded_replay=self.swa_bounded_replay,
2230 mamba_cache_dtype=self.mamba_cache_dtype,
2231 mamba_ssm_cache_dtype=self.mamba_ssm_cache_dtype,
2232 mamba_block_size=self.mamba_block_size,
2233 prefix_match_unit=self.prefix_match_unit,
2234 mamba_cache_mode=self.mamba_cache_mode,
2235 enable_mamba_shared_prefix_checkpoint=(
2236 self.enable_mamba_shared_prefix_checkpoint
2237 ),
2238 replayssm_buffer_len=self.replayssm_buffer_len,
2239 use_replayssm=self.use_replayssm,
2240 kv_offloading_size=self.kv_offloading_size,
2241 kv_offloading_backend=self.kv_offloading_backend,
2242 )
2243
2244 if resolved_cache_dtype.startswith("turboquant_"):
2245 from vllm.model_executor.layers.quantization.turboquant.config import (
2246 TurboQuantConfig,
2247 )
2248
2249 boundary = TurboQuantConfig.get_boundary_skip_layers(model_config)
2250 existing = set(cache_config.kv_cache_dtype_skip_layers)
2251 cache_config.kv_cache_dtype_skip_layers = sorted(
2252 existing | set(boundary), key=int
2253 )
2254
2255 ray_runtime_env = None
2256 if is_ray_initialized():
2257 # Ray Serve LLM calls `create_engine_config` in the context
2258 # of a Ray task, therefore we check is_ray_initialized()
2259 # as opposed to is_in_ray_actor().
2260 import ray
2261
2262 ray_runtime_env = ray.get_runtime_context().runtime_env
2263 # Avoid logging sensitive environment variables
2264 sanitized_env = ray_runtime_env.to_dict() if ray_runtime_env else {}
2265 if "env_vars" in sanitized_env:
2266 sanitized_env["env_vars"] = {
2267 k: "***" for k in sanitized_env["env_vars"]
2268 }
2269 logger.info("Using ray runtime env (env vars redacted): %s", sanitized_env)
2270
2271 # Get the current placement group if Ray is initialized and
2272 # we are in a Ray actor. If so, then the placement group will be
2273 # passed to spawned processes.
2274 placement_group = None
2275 if is_in_ray_actor():
2276 import ray
2277
2278 # This call initializes Ray automatically if it is not initialized,
2279 # but we should not do this here.
2280 placement_group = ray.util.get_current_placement_group()
2281
2282 assert not headless or not self.data_parallel_hybrid_lb, (
2283 "data_parallel_hybrid_lb is not applicable in headless mode"
2284 )
2285 if self.data_parallel_hybrid_lb and self.data_parallel_external_lb:
2286 raise ValueError(
2287 "Invalid data-parallel launch options: "
2288 "`--data-parallel-hybrid-lb` and "
2289 "`--data-parallel-external-lb` cannot be enabled together. "
2290 "Enable only one load-balancing mode."
2291 )
2292 if self.nnodes > 1 and self.data_parallel_backend != "mp":
2293 raise ValueError(
2294 "Invalid data-parallel launch options: "
2295 f"`--nnodes {self.nnodes}` requires "
2296 "`--data-parallel-backend mp`; got "
2297 f"`--data-parallel-backend {self.data_parallel_backend}`. "
2298 "Use the MP backend or set `--nnodes 1`."
2299 )
2300 inferred_data_parallel_rank = 0
2301 if self.nnodes > 1:
2302 world_size_within_dp = (
2303 self.pipeline_parallel_size
2304 * self.tensor_parallel_size
2305 * self.prefill_context_parallel_size
2306 )
2307 world_size = self.data_parallel_size * world_size_within_dp
2308 if world_size % self.nnodes != 0:
2309 raise ValueError(
2310 "Invalid data-parallel launch options: "
2311 f"`--nnodes {self.nnodes}` must evenly divide the total "
2312 f"world size ({world_size}). Adjust `--nnodes`, "
2313 "`--data-parallel-size`, `--pipeline-parallel-size`, "
2314 "`--tensor-parallel-size`, or `--prefill-context-parallel-size`."
2315 )
2316 if not 0 <= self.node_rank < self.nnodes:
2317 raise ValueError(
2318 "Invalid data-parallel launch options: `--node-rank` must "
2319 f"be between 0 and {self.nnodes - 1}; got "
2320 f"`--node-rank {self.node_rank}`. Set it to this node's "
2321 "zero-based index."
2322 )
2323 local_world_size = world_size // self.nnodes
2324 inferred_data_parallel_rank = (
2325 self.node_rank * local_world_size
2326 ) // world_size_within_dp
2327 if self.data_parallel_size > 1 and self.data_parallel_external_lb:
2328 if self.data_parallel_rank is None:
2329 if self.nnodes % self.data_parallel_size != 0:
2330 raise ValueError(
2331 "Invalid data-parallel launch options: "
2332 "`--node-rank` cannot unambiguously identify external "
2333 "data-parallel ranks when `--nnodes` is not divisible "
2334 "by `--data-parallel-size`. Set a unique "
2335 "`--data-parallel-rank` for each external-LB process."
2336 )
2337 self.data_parallel_rank = inferred_data_parallel_rank
2338 logger.info(
2339 "Inferred data_parallel_rank %d from node_rank %d "
2340 "for external lb",
2341 self.data_parallel_rank,
2342 self.node_rank,
2343 )
2344 elif self.data_parallel_size_local is None:
2345 # Infer data parallel size local for internal dplb:
2346 self.data_parallel_size_local = max(
2347 local_world_size // world_size_within_dp, 1
2348 )
2349 data_parallel_external_lb = (
2350 self.data_parallel_external_lb or self.data_parallel_rank is not None
2351 )
2352 if self.enable_fault_tolerance and not data_parallel_external_lb:
2353 raise ValueError(
2354 "Fault tolerance requires external load balancer mode "
2355 "(--data-parallel-external-lb or --data-parallel-rank). "
2356 "Internal LB mode is not supported."
2357 )
2358 if (
2359 self.data_parallel_size > 1
2360 and data_parallel_external_lb
2361 and not model_config.is_moe
2362 ):
2363 raise ValueError(
2364 "Non-MoE models do not support external data parallel mode. "
2365 "For external load balancing, launch independent vLLM "
2366 "instances without --data-parallel-* arguments."
2367 )
2368 # Local DP rank = 1, use pure-external LB.
2369 if data_parallel_external_lb:
2370 if self.data_parallel_rank is None:
2371 raise ValueError(
2372 "Invalid data-parallel launch options: "
2373 "`--data-parallel-external-lb` requires a data-parallel "
2374 "rank. Set `--data-parallel-rank`, or set "
2375 "`--data-parallel-size` greater than 1 and use `--nnodes` "
2376 "with `--node-rank` so the rank can be inferred."
2377 )
2378 if self.data_parallel_size_local not in (1, None):
2379 raise ValueError(
2380 "Invalid data-parallel launch options: an external "
2381 "data-parallel rank requires `--data-parallel-size-local "
2382 f"1`; got {self.data_parallel_size_local}. Set it to 1 or "
2383 "omit it."
2384 )
2385 data_parallel_size_local = 1
2386 # Use full external lb if we have local_size of 1.
2387 self.data_parallel_hybrid_lb = False
2388 elif self.data_parallel_size_local is not None:
2389 data_parallel_size_local = self.data_parallel_size_local
2390
2391 if self.data_parallel_start_rank is not None and not headless:
2392 # Infer hybrid LB mode.
2393 self.data_parallel_hybrid_lb = True
2394
2395 if self.data_parallel_hybrid_lb and data_parallel_size_local == 1:
2396 # Use full external lb if we have local_size of 1.
2397 logger.warning(
2398 "data_parallel_hybrid_lb is not eligible when "
2399 "data_parallel_size_local = 1, autoswitch to "
2400 "data_parallel_external_lb."
2401 )
2402 data_parallel_external_lb = True
2403 self.data_parallel_hybrid_lb = False
2404
2405 if data_parallel_size_local == self.data_parallel_size:
2406 # Disable hybrid LB mode if set for a single node
2407 self.data_parallel_hybrid_lb = False
2408
2409 self.data_parallel_rank = (
2410 self.data_parallel_start_rank
2411 if self.data_parallel_start_rank is not None
2412 else inferred_data_parallel_rank
2413 )
2414 if self.nnodes > 1:
2415 logger.info(
2416 "Inferred data_parallel_rank %d from node_rank %d",
2417 self.data_parallel_rank,
2418 self.node_rank,
2419 )
2420 else:
2421 if self.data_parallel_hybrid_lb:
2422 raise ValueError(
2423 "Invalid data-parallel launch options: "
2424 "`--data-parallel-hybrid-lb` requires "
2425 "`--data-parallel-size-local`. Set it to the number of "
2426 "data-parallel ranks on this node."
2427 )
2428
2429 if self.data_parallel_backend == "ray" and (
2430 envs.VLLM_RAY_DP_PACK_STRATEGY == "span"
2431 ):
2432 # Data parallel size defaults to 1 if DP ranks are spanning
2433 # multiple nodes
2434 data_parallel_size_local = 1
2435 else:
2436 # Otherwise local DP size defaults to global DP size if not set
2437 data_parallel_size_local = self.data_parallel_size
2438
2439 # DP address, used in multi-node case for torch distributed group
2440 # and ZMQ sockets.
2441 if self.data_parallel_address is None:
2442 if self.data_parallel_backend == "ray":
2443 host_ip = get_ip()
2444 logger.info(
2445 "Using host IP %s as ray-based data parallel address", host_ip
2446 )
2447 data_parallel_address = host_ip
2448 else:
2449 assert self.data_parallel_backend == "mp", (
2450 "data_parallel_backend can only be ray or mp, got %s",
2451 self.data_parallel_backend,
2452 )
2453 data_parallel_address = (
2454 self.master_addr or ParallelConfig.data_parallel_master_ip
2455 )
2456 else:
2457 data_parallel_address = self.data_parallel_address
2458
2459 # This port is only used when there are remote data parallel engines,
2460 # otherwise the local IPC transport is used.
2461 data_parallel_rpc_port = (
2462 self.data_parallel_rpc_port
2463 if (self.data_parallel_rpc_port is not None)
2464 else ParallelConfig.data_parallel_rpc_port
2465 )
2466
2467 if self.tokens_only and not model_config.skip_tokenizer_init:
2468 model_config.skip_tokenizer_init = True
2469 logger.info("Skipping tokenizer initialization for tokens-only mode.")
2470
2471 parallel_config = ParallelConfig(
2472 pipeline_parallel_size=self.pipeline_parallel_size,
2473 tensor_parallel_size=self.tensor_parallel_size,
2474 prefill_context_parallel_size=self.prefill_context_parallel_size,
2475 data_parallel_size=self.data_parallel_size,
2476 data_parallel_rank=self.data_parallel_rank or 0,
2477 data_parallel_external_lb=data_parallel_external_lb,
2478 data_parallel_size_local=data_parallel_size_local,
2479 master_addr=self.master_addr,
2480 master_port=self.master_port,
2481 nnodes=self.nnodes,
2482 node_rank=self.node_rank,
2483 distributed_timeout_seconds=self.distributed_timeout_seconds,
2484 cpu_distributed_timeout_seconds=self.cpu_distributed_timeout_seconds,
2485 data_parallel_master_ip=data_parallel_address,
2486 data_parallel_rpc_port=data_parallel_rpc_port,
2487 data_parallel_backend=self.data_parallel_backend,
2488 data_parallel_hybrid_lb=self.data_parallel_hybrid_lb,
2489 is_moe_model=model_config.is_moe,
2490 enable_expert_parallel=self.enable_expert_parallel,
2491 enable_batch_sharded_sampling=self.enable_batch_sharded_sampling,
2492 enable_ep_weight_filter=self.enable_ep_weight_filter,
2493 all2all_backend=self.all2all_backend,
2494 enable_elastic_ep=self.enable_elastic_ep,
2495 elastic_ep_max_dp_size=self.elastic_ep_max_dp_size,
2496 enable_dbo=self.enable_dbo,
2497 ubatch_size=self.ubatch_size,
2498 dbo_decode_token_threshold=self.dbo_decode_token_threshold,
2499 dp_sync_interval=self.dp_sync_interval,
2500 dbo_prefill_token_threshold=self.dbo_prefill_token_threshold,
2501 disable_nccl_for_dp_synchronization=self.disable_nccl_for_dp_synchronization,
2502 enable_eplb=self.enable_eplb,
2503 eplb_config=self.eplb_config,
2504 expert_placement_strategy=self.expert_placement_strategy,
2505 max_parallel_loading_workers=self.max_parallel_loading_workers,
2506 disable_custom_all_reduce=self.disable_custom_all_reduce,
2507 ray_workers_use_nsight=self.ray_workers_use_nsight,
2508 ray_runtime_env=ray_runtime_env,
2509 placement_group=placement_group,
2510 distributed_executor_backend=self.distributed_executor_backend,
2511 worker_cls=self.worker_cls,
2512 worker_extension_cls=self.worker_extension_cls,
2513 decode_context_parallel_size=self.decode_context_parallel_size,
2514 dcp_comm_backend=self.dcp_comm_backend,
2515 dcp_q_replicate=self.dcp_q_replicate,
2516 dcp_kv_cache_interleave_size=self.dcp_kv_cache_interleave_size,
2517 cp_kv_cache_interleave_size=(
2518 self.cp_kv_cache_interleave_size
2519 if self.cp_kv_cache_interleave_size is not None
2520 else ParallelConfig.cp_kv_cache_interleave_size
2521 ),
2522 _allow_auto_resolve_cp_interleave_size=(
2523 self.cp_kv_cache_interleave_size is None
2524 ),
2525 _api_process_count=self._api_process_count,
2526 _api_process_rank=self._api_process_rank,
2527 assigned_physical_gpu_ids=self._resolve_device_ids(),
2528 enable_fault_tolerance=self.enable_fault_tolerance,
2529 fault_tolerance_config=self.fault_tolerance_config,
2530 numa_bind=self.numa_bind,
2531 numa_bind_nodes=self.numa_bind_nodes,
2532 numa_bind_cpus=self.numa_bind_cpus,
2533 )
2534
2535 speculative_config = self.create_speculative_config(
2536 target_model_config=model_config,
2537 target_parallel_config=parallel_config,
2538 )
2539 diffusion_config = self.create_diffusion_config()
2540 watermark_config = self.create_watermark_config()
2541
2542 self._set_default_max_num_seqs_and_batched_tokens_args(
2543 usage_context,
2544 model_config,
2545 parallel_config,
2546 )
2547
2548 assert self.max_num_batched_tokens is not None, (
2549 "max_num_batched_tokens must be set by this point"
2550 )
2551 assert self.max_num_seqs is not None, "max_num_seqs must be set by this point"
2552 assert self.enable_chunked_prefill is not None, (
2553 "enable_chunked_prefill must be set by this point"
2554 )
2555 assert model_config.max_model_len is not None, (
2556 "max_model_len must be set by this point"
2557 )
2558 scheduler_config = SchedulerConfig(
2559 runner_type=model_config.runner_type,
2560 max_num_batched_tokens=self.max_num_batched_tokens,
2561 max_num_scheduled_tokens=self.max_num_scheduled_tokens,
2562 max_num_seqs=self.max_num_seqs,
2563 max_num_active_seqs=self.max_num_active_seqs,
2564 max_num_queued_reqs=self.max_num_queued_reqs,
2565 max_num_queued_tokens=self.max_num_queued_tokens,
2566 max_model_len=model_config.max_model_len,
2567 enable_chunked_prefill=self.enable_chunked_prefill,
2568 disable_chunked_mm_input=self.disable_chunked_mm_input,
2569 is_multimodal_model=model_config.is_multimodal_model,
2570 is_encoder_decoder=model_config.is_encoder_decoder,
2571 policy=self.scheduling_policy,
2572 scheduler_cls=self.scheduler_cls,
2573 long_prefill_token_threshold=self.long_prefill_token_threshold,
2574 long_prefill_token_threshold_adaptive=(
2575 self.long_prefill_token_threshold_adaptive
2576 ),
2577 scheduler_reserve_full_isl=self.scheduler_reserve_full_isl,
2578 watermark=self.watermark,
2579 prefill_schedule_interval=self.prefill_schedule_interval,
2580 disable_hybrid_kv_cache_manager=self.disable_hybrid_kv_cache_manager,
2581 async_scheduling=self.async_scheduling,
2582 stream_interval=self.stream_interval,
2583 )
2584
2585 if not model_config.is_multimodal_model and self.default_mm_loras:
2586 raise ValueError(
2587 "Default modality-specific LoRA(s) were provided for a "
2588 "non multimodal model"
2589 )
2590
2591 lora_config = (
2592 LoRAConfig(
2593 max_lora_rank=self.max_lora_rank,
2594 max_loras=self.max_loras,
2595 default_mm_loras=self.default_mm_loras,
2596 fully_sharded_loras=self.fully_sharded_loras,
2597 lora_dtype=self.lora_dtype,
2598 target_modules=self.lora_target_modules,
2599 enable_tower_connector_lora=self.enable_tower_connector_lora,
2600 specialize_active_lora=self.specialize_active_lora,
2601 enable_mixed_moe_lora_format=self.enable_mixed_moe_lora_format,
2602 enable_moe_shared_loras=self.enable_moe_shared_loras,
2603 max_lora_cls_labels=self.max_lora_cls_labels,
2604 max_cpu_loras=self.max_cpu_loras
2605 if self.max_cpu_loras and self.max_cpu_loras > 0
2606 else None,
2607 )
2608 if self.enable_lora
2609 else None
2610 )
2611
2612 if (
2613 lora_config is not None
2614 and speculative_config is not None
2615 and scheduler_config.max_num_batched_tokens
2616 < (
2617 scheduler_config.max_num_seqs
2618 * (speculative_config.num_speculative_tokens + 1)
2619 )
2620 ):
2621 raise ValueError(
2622 "Consider increasing max_num_batched_tokens or "
2623 "decreasing num_speculative_tokens"
2624 )
2625
2626 # Attention config overrides
2627 attention_config = copy.deepcopy(self.attention_config)
2628 if self.attention_backend is not None:
2629 if attention_config.backend is not None:
2630 raise ValueError(
2631 "attention_backend and attention_config.backend "
2632 "are mutually exclusive"
2633 )
2634 # Reuse the validator to handle "auto" and string-to-enum conversion
2635 attention_config.backend = AttentionConfig.validate_backend_before(
2636 self.attention_backend
2637 )
2638
2639 # Batch-invariant mode requires deterministic attention behavior.
2640 # If no backend is explicitly requested, prefer Triton Attention.
2641 if (
2642 envs.VLLM_BATCH_INVARIANT
2643 and attention_config.backend is None
2644 and current_platform.is_xpu()
2645 ):
2646 attention_config.backend = AttentionBackendEnum.TRITON_ATTN
2647 logger.info(
2648 "VLLM_BATCH_INVARIANT is enabled and no attention backend was "
2649 "specified; defaulting to TRITON_ATTN."
2650 )
2651
2652 # TurboQuant requires FlashAttention 2 — FA3 boundary layers assert
2653 # FlashAttentionImpl which fails with TurboQuantAttentionImpl.
2654 if resolved_cache_dtype.startswith("turboquant_") and (
2655 attention_config.flash_attn_version is None
2656 or attention_config.flash_attn_version >= 3
2657 ):
2658 logger.warning(
2659 "TurboQuant is not yet compatible with FlashAttention >= 3. "
2660 "Overriding flash_attn_version to 2. To silence this "
2661 "warning, pass --attention-config.flash_attn_version=2"
2662 )
2663 attention_config.flash_attn_version = 2
2664
2665 # Mamba config overrides
2666 mamba_config = copy.deepcopy(self.mamba_config)
2667 # Convert string to enum if needed (CLI parsing returns a string)
2668 if isinstance(self.mamba_backend, str):
2669 mamba_config.backend = MambaBackendEnum[self.mamba_backend.upper()]
2670 else:
2671 mamba_config.backend = self.mamba_backend
2672 if self.mamba_ssu_algorithm is not None:
2673 mamba_config.ssu_algorithm = self.mamba_ssu_algorithm
2674 if self.enable_mamba_cache_stochastic_rounding:
2675 mamba_config.enable_stochastic_rounding = (
2676 self.enable_mamba_cache_stochastic_rounding
2677 )
2678 if self.mamba_cache_philox_rounds:
2679 mamba_config.stochastic_rounding_philox_rounds = (
2680 self.mamba_cache_philox_rounds
2681 )
2682 mamba_config.validate_ssu_algorithm()
2683
2684 # Kernel config overrides
2685 kernel_config = copy.deepcopy(self.kernel_config)
2686 if self.enable_flashinfer_autotune is not None:
2687 if kernel_config.enable_flashinfer_autotune is not None:
2688 raise ValueError(
2689 "enable_flashinfer_autotune and "
2690 "kernel_config.enable_flashinfer_autotune "
2691 "are mutually exclusive"
2692 )
2693 kernel_config.enable_flashinfer_autotune = self.enable_flashinfer_autotune
2694 if self.moe_backend != "auto":
2695 kernel_config.moe_backend = self.moe_backend
2696 if self.linear_backend != "auto":
2697 kernel_config.linear_backend = self.linear_backend
2698 if self.sparse_indexer_topk_backend != "auto":
2699 kernel_config.sparse_indexer_topk_backend = self.sparse_indexer_topk_backend
2700
2701 # Transfer top-level ir_op_priority into KernelConfig.ir_op_priority
2702 for op_name, op_priority in asdict(self.ir_op_priority).items():
2703 # Empty means unset
2704 if not op_priority:
2705 continue
2706
2707 # Priority cannot be set 2x for the same op
2708 if getattr(kernel_config.ir_op_priority, op_name):
2709 raise ValueError(
2710 f"Op priority for {op_name} specified via both ir_op_priority "
2711 f"and KernelConfig.ir_op_priority, only one allowed at a time."
2712 )
2713
2714 # Set the attribute
2715 setattr(kernel_config.ir_op_priority, op_name, op_priority)
2716
2717 load_config = self.create_load_config()
2718
2719 # Pass reasoning_parser into StructuredOutputsConfig
2720 if self.reasoning_parser:
2721 self.structured_outputs_config.reasoning_parser = self.reasoning_parser
2722
2723 if self.reasoning_parser_plugin:
2724 self.structured_outputs_config.reasoning_parser_plugin = (
2725 self.reasoning_parser_plugin
2726 )
2727
2728 observability_config = self.create_observability_config()
2729
2730 # Compilation config overrides
2731 compilation_config = copy.deepcopy(self.compilation_config)
2732 if self.cudagraph_capture_sizes is not None:
2733 if compilation_config.cudagraph_capture_sizes is not None:
2734 raise ValueError(
2735 "cudagraph_capture_sizes and compilation_config."
2736 "cudagraph_capture_sizes are mutually exclusive"
2737 )
2738 compilation_config.cudagraph_capture_sizes = self.cudagraph_capture_sizes
2739 if self.max_cudagraph_capture_size is not None:
2740 if compilation_config.max_cudagraph_capture_size is not None:
2741 raise ValueError(
2742 "max_cudagraph_capture_size and compilation_config."
2743 "max_cudagraph_capture_size are mutually exclusive"
2744 )
2745 compilation_config.max_cudagraph_capture_size = (
2746 self.max_cudagraph_capture_size
2747 )
2748
2749 offload_config = OffloadConfig(
2750 offload_backend=self.offload_backend,
2751 uva=UVAOffloadConfig(
2752 cpu_offload_gb=self.cpu_offload_gb,
2753 cpu_offload_params=self.cpu_offload_params,
2754 ),
2755 prefetch=PrefetchOffloadConfig(
2756 offload_group_size=self.offload_group_size,
2757 offload_num_in_group=self.offload_num_in_group,
2758 offload_prefetch_step=self.offload_prefetch_step,
2759 offload_params=self.offload_params,
2760 ),
2761 )
2762
2763 if self.gdn_prefill_backend is not None:
2764 self.additional_config["gdn_prefill_backend"] = self.gdn_prefill_backend
2765 if self.kda_prefill_backend is not None:
2766 if (
2767 self.kda_prefill_backend == "flashkda"
2768 and not current_platform.is_cuda()
2769 ):
2770 raise ValueError(
2771 "--kda-prefill-backend=flashkda is only available on CUDA."
2772 )
2773 if self.kda_prefill_backend == "fused" and not current_platform.is_rocm():
2774 raise ValueError(
2775 "--kda-prefill-backend=fused is only available on ROCm."
2776 )
2777 self.additional_config["kda_prefill_backend"] = self.kda_prefill_backend
2778 if self.kda_decode_backend is not None:
2779 self.additional_config["kda_decode_backend"] = self.kda_decode_backend
2780
2781 config = VllmConfig(
2782 model_config=model_config,
2783 cache_config=cache_config,
2784 parallel_config=parallel_config,
2785 scheduler_config=scheduler_config,
2786 device_config=device_config,
2787 load_config=load_config,
2788 offload_config=offload_config,
2789 attention_config=attention_config,
2790 aux_output_config=self.aux_output_config,
2791 engram_config=self.engram_config,
2792 mamba_config=mamba_config,
2793 kernel_config=kernel_config,
2794 lora_config=lora_config,
2795 speculative_config=speculative_config,
2796 watermark_config=watermark_config,
2797 diffusion_config=diffusion_config,
2798 structured_outputs_config=self.structured_outputs_config,
2799 observability_config=observability_config,
2800 logging_config=logging_config,
2801 compilation_config=compilation_config,
2802 kv_transfer_config=self.kv_transfer_config,
2803 kv_events_config=self.kv_events_config,
2804 ec_transfer_config=self.ec_transfer_config,
2805 ec_manager_config=self.ec_manager_config,
2806 reasoning_config=self.reasoning_config,
2807 profiler_config=self.profiler_config,
2808 additional_config=self.additional_config,
2809 optimization_level=self.optimization_level,
2810 performance_mode=self.performance_mode,
2811 weight_transfer_config=self.weight_transfer_config,
2812 shutdown_timeout=self.shutdown_timeout,
2813 )
2814
2815 return config
2816
2817 def _check_feature_supported(self):
2818 """Raise an error if the feature is not supported."""
2819 if self.pipeline_parallel_size > 1:
2820 supports_pp = getattr(
2821 self.distributed_executor_backend, "supports_pp", False
2822 )
2823 if not supports_pp and self.distributed_executor_backend not in (
2824 ParallelConfig.distributed_executor_backend,
2825 "ray",
2826 "mp",
2827 "external_launcher",
2828 ):
2829 name = (
2830 "Pipeline Parallelism without Ray distributed "
2831 "executor or multiprocessing executor or external "
2832 "launcher"
2833 )
2834 _raise_unsupported_error(feature_name=name)
2835
2836 @classmethod
2837 def get_batch_defaults(
2838 cls,
2839 world_size: int,
2840 ) -> tuple[dict[UsageContext | None, int], dict[UsageContext | None, int]]:
2841 from vllm.usage.usage_lib import UsageContext
2842
2843 default_max_num_batched_tokens: dict[UsageContext | None, int]
2844 default_max_num_seqs: dict[UsageContext | None, int]
2845
2846 # When no user override, set the default values based on the usage
2847 # context.
2848 # Use different default values for different hardware.
2849
2850 # Try to query the device name on the current platform. If it fails,
2851 # it may be because the platform that imports vLLM is not the same
2852 # as the platform that vLLM is running on (e.g. the case of scaling
2853 # vLLM with Ray) and has no GPUs. In this case we use the default
2854 # values for non-H100/H200 GPUs.
2855 try:
2856 device_memory = current_platform.get_device_total_memory()
2857 device_name = current_platform.get_device_name().lower()
2858 except Exception:
2859 # This is only used to set default_max_num_batched_tokens
2860 device_memory = 0
2861 device_name = ""
2862
2863 # NOTE(Kuntai): Setting large `max_num_batched_tokens` for A100 reduces
2864 # throughput, see PR #17885 for more details.
2865 # So here we do an extra device name check to prevent such regression.
2866 if device_memory >= 160 * GiB_bytes:
2867 # for GPUs like B200/B300 with >= 160GB memory, use the largest defaults
2868 default_max_num_batched_tokens = {
2869 UsageContext.LLM_CLASS: 16384,
2870 UsageContext.OPENAI_API_SERVER: 16384,
2871 }
2872 default_max_num_seqs = {
2873 UsageContext.LLM_CLASS: 1024,
2874 UsageContext.OPENAI_API_SERVER: 1024,
2875 }
2876 elif device_memory >= 70 * GiB_bytes and "a100" not in device_name:
2877 # For GPUs like H100 and H200, use larger offline defaults.
2878 default_max_num_batched_tokens = {
2879 UsageContext.LLM_CLASS: 16384,
2880 UsageContext.OPENAI_API_SERVER: 8192,
2881 }
2882 default_max_num_seqs = {
2883 UsageContext.LLM_CLASS: 1024,
2884 UsageContext.OPENAI_API_SERVER: 1024,
2885 }
2886 else:
2887 # TODO(woosuk): Tune the default values for other hardware.
2888 default_max_num_batched_tokens = {
2889 UsageContext.LLM_CLASS: 8192,
2890 UsageContext.OPENAI_API_SERVER: 2048,
2891 }
2892 default_max_num_seqs = {
2893 UsageContext.LLM_CLASS: 256,
2894 UsageContext.OPENAI_API_SERVER: 256,
2895 }
2896
2897 # tpu specific default values.
2898 if current_platform.is_tpu():
2899 chip_name = current_platform.get_device_name()
2900
2901 if chip_name == "V6E":
2902 default_max_num_batched_tokens = {
2903 UsageContext.LLM_CLASS: 2048,
2904 UsageContext.OPENAI_API_SERVER: 1024,
2905 }
2906 elif chip_name == "V5E":
2907 default_max_num_batched_tokens = {
2908 UsageContext.LLM_CLASS: 1024,
2909 UsageContext.OPENAI_API_SERVER: 512,
2910 }
2911 elif chip_name == "V5P":
2912 default_max_num_batched_tokens = {
2913 UsageContext.LLM_CLASS: 512,
2914 UsageContext.OPENAI_API_SERVER: 256,
2915 }
2916
2917 # cpu specific default values.
2918 if current_platform.is_cpu():
2919 default_max_num_batched_tokens = {
2920 UsageContext.LLM_CLASS: 4096 * world_size,
2921 UsageContext.OPENAI_API_SERVER: 2048 * world_size,
2922 }
2923 default_max_num_seqs = {
2924 UsageContext.LLM_CLASS: 256 * world_size,
2925 UsageContext.OPENAI_API_SERVER: 128 * world_size,
2926 }
2927
2928 return default_max_num_batched_tokens, default_max_num_seqs
2929
2930 def _set_default_chunked_prefill_and_prefix_caching_args(
2931 self, model_config: ModelConfig
2932 ) -> None:
2933 default_chunked_prefill = model_config.is_chunked_prefill_supported
2934 default_prefix_caching = model_config.is_prefix_caching_supported
2935
2936 if self.enable_chunked_prefill is None:
2937 self.enable_chunked_prefill = default_chunked_prefill
2938
2939 logger.debug(
2940 "%s chunked prefill by default",
2941 "Enabling" if default_chunked_prefill else "Disabling",
2942 )
2943 elif (
2944 model_config.runner_type == "generate"
2945 and not self.enable_chunked_prefill
2946 and default_chunked_prefill
2947 ):
2948 logger.warning_once(
2949 "This model does not officially support disabling chunked prefill. "
2950 "Disabling this manually may cause the engine to crash "
2951 "or produce incorrect outputs.",
2952 )
2953 elif (
2954 model_config.runner_type == "pooling"
2955 and self.enable_chunked_prefill
2956 and not default_chunked_prefill
2957 ):
2958 logger.warning_once(
2959 "This model does not officially support chunked prefill. "
2960 "Enabling this manually may cause the engine to crash "
2961 "or produce incorrect outputs.",
2962 )
2963
2964 if self.enable_prefix_caching is None:
2965 self.enable_prefix_caching = default_prefix_caching
2966
2967 logger.debug(
2968 "%s prefix caching by default",
2969 "Enabling" if default_prefix_caching else "Disabling",
2970 )
2971 elif (
2972 model_config.runner_type == "pooling"
2973 and self.enable_prefix_caching
2974 and not default_prefix_caching
2975 ):
2976 logger.warning_once(
2977 "This model does not officially support prefix caching. "
2978 "Enabling this manually may cause the engine to crash "
2979 "or produce incorrect outputs.",
2980 )
2981
2982 # Disable chunked prefill and prefix caching for:
2983 # RISCV CPUs in V1
2984 if current_platform.is_cpu() and current_platform.get_cpu_architecture() in (
2985 CpuArchEnum.RISCV,
2986 ):
2987 logger.info(
2988 "Chunked prefill is not supported for"
2989 "RISC-V CPUs; "
2990 "disabling it for V1 backend."
2991 )
2992 self.enable_chunked_prefill = False
2993 logger.info(
2994 "Prefix caching is not supported for "
2995 "RISC-V CPUs; "
2996 "disabling it for V1 backend."
2997 )
2998 self.enable_prefix_caching = False
2999
3000 def _set_default_reasoning_config_args(self):
3001 if not self.reasoning_parser:
3002 return
3003 if self.reasoning_config is None:
3004 self.reasoning_config = ReasoningConfig()
3005 self.reasoning_config.reasoning_parser = self.reasoning_parser
3006
3007 @staticmethod
3008 def _get_min_mm_batched_tokens(
3009 model_config: ModelConfig,
3010 ) -> tuple[int, str] | None:
3011 """Get the minimum max_num_batched_tokens needed for a multimodal
3012 prefix-LM model to process at least one item of any supported modality.
3013
3014 Returns (token_count, modality_name) for the most expensive modality,
3015 or None if the value cannot be determined at this stage.
3016 """
3017 try:
3018 from vllm.multimodal import MULTIMODAL_REGISTRY
3019
3020 # get_processing_info returns the model's multimodal processing
3021 # metadata (supported modalities, token limits) without loading
3022 # model weights or generating dummy data.
3023 info = MULTIMODAL_REGISTRY.get_processing_info(model_config)
3024 mm_counts = {modality: 1 for modality in info.supported_mm_limits}
3025 # get_mm_max_tokens_per_item returns pre-computed per-item token
3026 # ceilings for models that override it (e.g., Gemma4), or None
3027 # for models that rely on dummy-input profiling. When None is
3028 # returned we bail out — no dummy generation is triggered here.
3029 max_tokens = info.get_mm_max_tokens_per_item(
3030 seq_len=model_config.max_model_len,
3031 mm_counts=mm_counts,
3032 )
3033 if max_tokens is not None:
3034 modality = max(max_tokens, key=max_tokens.__getitem__)
3035 return (max_tokens[modality], modality)
3036 except Exception as e:
3037 logger.warning("Failed to determine min multimodal batched tokens: %s", e)
3038 return None
3039
3040 def _set_default_max_num_seqs_and_batched_tokens_args(
3041 self,
3042 usage_context: UsageContext | None,
3043 model_config: ModelConfig,
3044 parallel_config: ParallelConfig,
3045 ):
3046 world_size = self.pipeline_parallel_size * self.tensor_parallel_size
3047 (
3048 default_max_num_batched_tokens,
3049 default_max_num_seqs,
3050 ) = self.get_batch_defaults(world_size)
3051
3052 orig_max_num_batched_tokens = self.max_num_batched_tokens
3053 orig_max_num_seqs = self.max_num_seqs
3054
3055 if self.max_num_batched_tokens is None:
3056 if parallel_config.use_batched_dp_moe:
3057 self.max_num_batched_tokens = (
3058 SchedulerConfig.DEFAULT_MAX_NUM_BATCHED_TOKENS_FOR_BATCHED_DP
3059 )
3060 else:
3061 self.max_num_batched_tokens = default_max_num_batched_tokens.get(
3062 usage_context,
3063 SchedulerConfig.DEFAULT_MAX_NUM_BATCHED_TOKENS,
3064 )
3065
3066 if self.max_num_seqs is None:
3067 self.max_num_seqs = default_max_num_seqs.get(
3068 usage_context,
3069 SchedulerConfig.DEFAULT_MAX_NUM_SEQS,
3070 )
3071
3072 # If throughput mode is set, double max_num_batched_tokens and max_num_seqs.
3073 if self.performance_mode == "throughput":
3074 if orig_max_num_batched_tokens is None:
3075 self.max_num_batched_tokens *= 2
3076 if orig_max_num_seqs is None:
3077 self.max_num_seqs *= 2
3078
3079 if orig_max_num_batched_tokens is None:
3080 assert model_config.max_model_len is not None, (
3081 "max_model_len must be set by this point"
3082 )
3083 if not self.enable_chunked_prefill:
3084 # If max_model_len is too short, use the default for higher throughput.
3085 self.max_num_batched_tokens = max(
3086 model_config.max_model_len,
3087 self.max_num_batched_tokens,
3088 )
3089
3090 # For multimodal prefix-LM models (e.g., Gemma 4) that disable
3091 # chunked MM input, a single multimodal item must fit in one batch.
3092 # Raise the floor to accommodate the largest per-item token count.
3093 if model_config.is_multimodal_model and model_config.is_mm_prefix_lm:
3094 result = self._get_min_mm_batched_tokens(model_config)
3095 if result is not None and result[0] > self.max_num_batched_tokens:
3096 mm_min, modality = result
3097 logger.info(
3098 "Raising max_num_batched_tokens from %d to %d to "
3099 "accommodate '%s' input for prefix-LM model %s.",
3100 self.max_num_batched_tokens,
3101 mm_min,
3102 modality,
3103 model_config.model,
3104 )
3105 self.max_num_batched_tokens = mm_min
3106
3107 # When using default settings,
3108 # Ensure max_num_batched_tokens does not exceed model limit.
3109 # Some models (e.g., Whisper) have embeddings tied to max length.
3110 self.max_num_batched_tokens = min(
3111 self.max_num_seqs * model_config.max_model_len,
3112 self.max_num_batched_tokens,
3113 )
3114
3115 logger.debug(
3116 "Defaulting max_num_batched_tokens to %d for %s usage context.",
3117 self.max_num_batched_tokens,
3118 usage_context.value if usage_context else None,
3119 )
3120
3121 if orig_max_num_seqs is None:
3122 assert self.max_num_batched_tokens is not None # For type checking
3123 self.max_num_seqs = min(self.max_num_seqs, self.max_num_batched_tokens)
3124
3125 logger.debug(
3126 "Defaulting max_num_seqs to %d for %s usage context.",
3127 self.max_num_seqs,
3128 usage_context.value if usage_context else None,
3129 )
3130
3131
3132 @dataclass
3133 class AsyncEngineArgs(EngineArgs):
3134 """Arguments for asynchronous vLLM engine."""
3135
3136 enable_log_requests: bool = False
3137
3138 @staticmethod
3139 def add_cli_args(
3140 parser: FlexibleArgumentParser, async_args_only: bool = False
3141 ) -> FlexibleArgumentParser:
3142 # Initialize plugin to update the parser, for example, The plugin may
3143 # add a new kind of quantization method to --quantization argument or
3144 # a new device to --device argument.
3145 load_general_plugins()
3146 if not async_args_only:
3147 parser = EngineArgs.add_cli_args(parser)
3148 parser.add_argument(
3149 "--enable-log-requests",
3150 action=argparse.BooleanOptionalAction,
3151 default=AsyncEngineArgs.enable_log_requests,
3152 help="Enable logging request information, dependent on log level:\n"
3153 "- INFO: Request ID, parameters and LoRA request.\n"
3154 "- DEBUG: Prompt inputs (e.g: text, token IDs).\n"
3155 "You can set the minimum log level via `VLLM_LOGGING_LEVEL`.",
3156 )
3157 current_platform.pre_register_and_update(parser)
3158 return parser
3159
3160
3161 def _raise_unsupported_error(feature_name: str):
3162 msg = (
3163 f"{feature_name} is not supported. We recommend to "
3164 f"remove {feature_name} from your config."
3165 )
3166 raise NotImplementedError(msg)