feat: Add limit-mm-data-per-request argument to server arguments (#15418)

Signed-off-by: Xinyuan Tong <xinyuantong.cs@gmail.com>
This commit is contained in:
Xinyuan Tong
2025-12-20 18:44:47 +00:00
committed by GitHub
parent bc18cb8631
commit 0a346d3bd9
3 changed files with 50 additions and 7 deletions

View File

@@ -31,7 +31,6 @@ from http import HTTPStatus
from typing import Any, Awaitable, Dict, List, Optional, Tuple, Union
import fastapi
import orjson
import uvloop
import zmq
import zmq.asyncio
@@ -184,11 +183,7 @@ class TokenizerManager(TokenizerCommunicatorMixin, TokenizerManagerMultiItemMixi
self.enable_metrics = server_args.enable_metrics
self.log_requests = server_args.log_requests
self.log_requests_level = server_args.log_requests_level
self.preferred_sampling_params = (
orjson.loads(server_args.preferred_sampling_params)
if server_args.preferred_sampling_params
else None
)
self.preferred_sampling_params = server_args.preferred_sampling_params
self.crash_dump_folder = server_args.crash_dump_folder
self.enable_trace = server_args.enable_trace
@@ -628,6 +623,7 @@ class TokenizerManager(TokenizerCommunicatorMixin, TokenizerManagerMultiItemMixi
obj.image_data = [obj.image_data]
if obj.audio_data is not None and not isinstance(obj.audio_data, list):
obj.audio_data = [obj.audio_data]
self._validate_mm_limits(obj)
mm_inputs = None
@@ -748,6 +744,21 @@ class TokenizerManager(TokenizerCommunicatorMixin, TokenizerManagerMultiItemMixi
"Please set `--enable-custom-logit-processor` to enable this feature."
)
def _validate_mm_limits(
self, obj: Union[GenerateReqInput, EmbeddingReqInput]
) -> None:
if not self.server_args.limit_mm_data_per_request:
return
for modality, limit in self.server_args.limit_mm_data_per_request.items():
data = getattr(obj, f"{modality}_data", None)
if data:
count = len(data) if isinstance(data, list) else 1
if count > limit:
raise ValueError(
f"{modality.capitalize()} count {count} exceeds limit {limit} per request."
)
def _validate_for_matryoshka_dim(self, obj: EmbeddingReqInput) -> None:
"""Validate the request for Matryoshka dim if it has the field set."""
if obj.dimensions is None:

View File

@@ -264,6 +264,7 @@ class ServerArgs:
context_length: Optional[int] = None
is_embedding: bool = False
enable_multimodal: Optional[bool] = None
limit_mm_data_per_request: Optional[Union[str, Dict[str, int]]] = None
revision: Optional[str] = None
model_impl: str = "auto"
@@ -2367,6 +2368,29 @@ class ServerArgs:
self.disable_cuda_graph = True
self.skip_server_warmup = True
# Validate limit_mm_per_prompt modalities
if self.limit_mm_data_per_request:
if isinstance(self.limit_mm_data_per_request, str):
self.limit_mm_data_per_request = json.loads(
self.limit_mm_data_per_request
)
if isinstance(self.limit_mm_data_per_request, dict):
allowed_modalities = {"image", "video", "audio"}
for modality in self.limit_mm_data_per_request.keys():
if modality not in allowed_modalities:
raise ValueError(
f"Invalid modality '{modality}' in --limit-mm-data-per-request."
f"Allowed modalities are: {list(allowed_modalities)}"
)
# Validate preferred_sampling_params
if self.preferred_sampling_params:
if isinstance(self.preferred_sampling_params, str):
self.preferred_sampling_params = json.loads(
self.preferred_sampling_params
)
@staticmethod
def add_cli_args(parser: argparse.ArgumentParser):
@@ -2455,6 +2479,13 @@ class ServerArgs:
action="store_true",
help="Enable the multimodal functionality for the served model. If the model being served is not multimodal, nothing will happen",
)
parser.add_argument(
"--limit-mm-data-per-request",
type=json.loads,
default=ServerArgs.limit_mm_data_per_request,
help="Limit the number of multimodal inputs per request. "
'e.g. \'{"image": 1, "video": 1, "audio": 1}\'',
)
parser.add_argument(
"--revision",
type=str,
@@ -3135,7 +3166,7 @@ class ServerArgs:
)
parser.add_argument(
"--preferred-sampling-params",
type=str,
type=json.loads,
help="json-formatted sampling settings that will be returned in /get_model_info",
)