From 2ddde19e8e0ba1b9d06a3f9b6201f7fc915d27ab Mon Sep 17 00:00:00 2001 From: sungbin1015 Date: Fri, 9 Oct 2026 05:38:17 +0900 Subject: [PATCH] [Frontend] Support min_p in the Responses API (#48084) Signed-off-by: sungbin1015 Co-authored-by: Flora Feng <4florafeng@gmail.com> --- .../online_serving/openai_compatible_server.md | 6 ++++++ tests/benchmarks/test_responses_request_func.py | 4 +--- .../openai/responses/test_sampling_params.py | 13 +++++++++++++ vllm/benchmarks/serve.py | 5 ----- vllm/entrypoints/openai/responses/protocol.py | 7 +++++++ 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/docs/serving/online_serving/openai_compatible_server.md b/docs/serving/online_serving/openai_compatible_server.md index c50910040d..7b4e84a17f 100644 --- a/docs/serving/online_serving/openai_compatible_server.md +++ b/docs/serving/online_serving/openai_compatible_server.md @@ -204,6 +204,12 @@ To get prompt token IDs before generation, use a self-contained Responses request without inference and returns the prompt token IDs, so a separate `/tokenize` call is not needed. +#### Sampling parameters + +In addition to the OpenAI request fields, the Responses API forwards vLLM +[sampling parameters](../../api/README.md#inference-parameters) such as `top_k`, +`min_p`, `repetition_penalty`, `seed`, `stop`, and `ignore_eos` to the engine. + #### Extra parameters The following extra parameters in the request object are supported: diff --git a/tests/benchmarks/test_responses_request_func.py b/tests/benchmarks/test_responses_request_func.py index 38f1bdc507..1ecf6115ff 100644 --- a/tests/benchmarks/test_responses_request_func.py +++ b/tests/benchmarks/test_responses_request_func.py @@ -183,6 +183,7 @@ def test_request_payload_is_accepted_by_the_server_schema(): "temperature": 0.7, "top_p": 0.9, "top_k": 20, + "min_p": 0.05, "frequency_penalty": 0.2, "presence_penalty": 0.1, "repetition_penalty": 1.05, @@ -217,9 +218,6 @@ def test_request_payload_is_accepted_by_the_server_schema(): assert set(seen["payload"]) <= set(ResponsesRequest.model_fields) ResponsesRequest.model_validate(seen["payload"]) - # `vllm bench serve` rejects --min-p for this backend for the same reason. - assert "min_p" not in ResponsesRequest.model_fields - def test_latency_accounting_matches_the_other_endpoints(): """`latency - ttft` must equal `sum(itl)`. diff --git a/tests/entrypoints/openai/responses/test_sampling_params.py b/tests/entrypoints/openai/responses/test_sampling_params.py index 01fdfa4594..24d54b8960 100644 --- a/tests/entrypoints/openai/responses/test_sampling_params.py +++ b/tests/entrypoints/openai/responses/test_sampling_params.py @@ -29,6 +29,7 @@ class TestResponsesRequestSamplingParams: temperature=0.8, top_p=0.95, top_k=50, + min_p=0.1, max_output_tokens=100, ) @@ -37,8 +38,20 @@ class TestResponsesRequestSamplingParams: assert sampling_params.temperature == 0.8 assert sampling_params.top_p == 0.95 assert sampling_params.top_k == 50 + assert sampling_params.min_p == 0.1 assert sampling_params.max_tokens == 100 + def test_min_p_default(self): + """Test that min_p defaults to 0.0 when unset (parity with top_k).""" + request = ResponsesRequest( + model="test-model", + input="test input", + ) + + sampling_params = request.to_sampling_params(default_max_tokens=1000) + + assert sampling_params.min_p == 0.0 + def test_extra_sampling_params(self): """Test extra sampling parameters are correctly mapped.""" request = ResponsesRequest( diff --git a/vllm/benchmarks/serve.py b/vllm/benchmarks/serve.py index 895e5c6c18..01a0f62aee 100644 --- a/vllm/benchmarks/serve.py +++ b/vllm/benchmarks/serve.py @@ -2196,11 +2196,6 @@ async def main_async(args: argparse.Namespace) -> dict[str, Any]: "Sampling parameters are only supported by openai-compatible backends." ) - # The Responses API accepts every sampling parameter above except - # min_p, which it would silently drop as an unknown field. - if args.backend == "openai-responses" and "min_p" in sampling_params: - raise ValueError("--min-p is not supported by the Responses API.") - if "temperature" not in sampling_params: print( "WARNING: vllm bench serve no longer sets temperature==0 (greedy) " diff --git a/vllm/entrypoints/openai/responses/protocol.py b/vllm/entrypoints/openai/responses/protocol.py index 12e40e98a8..d1a4ea4f6c 100644 --- a/vllm/entrypoints/openai/responses/protocol.py +++ b/vllm/entrypoints/openai/responses/protocol.py @@ -259,6 +259,7 @@ class ResponsesRequest(OpenAIBaseModel): top_logprobs: TopLogprobsParam = 0 top_p: float | None = None top_k: int | None = None + min_p: float | None = None truncation: Literal["auto", "disabled"] | None = "disabled" user: str | None = None skip_special_tokens: bool = True @@ -444,6 +445,7 @@ class ResponsesRequest(OpenAIBaseModel): "temperature": 1.0, "top_p": 1.0, "top_k": 0, + "min_p": 0.0, } def extract_structured_outputs(self) -> StructuredOutputsParams | None: @@ -494,6 +496,10 @@ class ResponsesRequest(OpenAIBaseModel): top_k = default_sampling_params.get( "top_k", self._DEFAULT_SAMPLING_PARAMS["top_k"] ) + if (min_p := self.min_p) is None: + min_p = default_sampling_params.get( + "min_p", self._DEFAULT_SAMPLING_PARAMS["min_p"] + ) if (repetition_penalty := self.repetition_penalty) is None: repetition_penalty = default_sampling_params.get("repetition_penalty", 1.0) @@ -519,6 +525,7 @@ class ResponsesRequest(OpenAIBaseModel): watermarking=self.watermarking, top_p=top_p, top_k=top_k, + min_p=min_p, max_tokens=max_tokens, logprobs=self.top_logprobs if self.is_include_output_logprobs() else None, stop=stop,