Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tests/v1/entrypoints/llm/test_struct_output_generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from vllm.entrypoints.llm import LLM
from vllm.outputs import RequestOutput
from vllm.platforms import current_platform
from vllm.reasoning.abs_reasoning_parsers import ReasoningParserManager
from vllm.reasoning import ReasoningParserManager
from vllm.sampling_params import (
GuidedDecodingParams,
SamplingParams,
Expand Down
17 changes: 17 additions & 0 deletions vllm/config/structured_outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from typing_extensions import Self

from vllm.config.utils import config
from vllm.reasoning import ReasoningParserManager

StructuredOutputsBackend = Literal[
"auto", "xgrammar", "guidance", "outlines", "lm-format-enforcer"
Expand Down Expand Up @@ -37,6 +38,9 @@ class StructuredOutputsConfig:
reasoning_parser: str = ""
"""Select the reasoning parser depending on the model that you're using.
This is used to parse the reasoning content into OpenAI API format."""
reasoning_parser_plugin: str = ""
"""Path to a dynamically reasoning parser plugin that can be dynamically
loaded and registered."""
enable_in_reasoning: bool = False
"""Whether to use structured input for reasoning."""

Expand All @@ -60,6 +64,19 @@ def compute_hash(self) -> str:

@model_validator(mode="after")
def _validate_structured_output_config(self) -> Self:
if self.reasoning_parser_plugin and len(self.reasoning_parser_plugin) > 3:
ReasoningParserManager.import_reasoning_parser(self.reasoning_parser_plugin)

valid_reasoning_parses = ReasoningParserManager.reasoning_parsers.keys()
if (
self.reasoning_parser != ""
and self.reasoning_parser not in valid_reasoning_parses
):
raise ValueError(
f"invalid reasoning parser: {self.reasoning_parser} "
f"(chose from {{ {','.join(valid_reasoning_parses)} }})"
)

if self.disable_any_whitespace and self.backend not in ("xgrammar", "guidance"):
raise ValueError(
"disable_any_whitespace is only supported for "
Expand Down
15 changes: 11 additions & 4 deletions vllm/engine/arg_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@
from vllm.platforms import CpuArchEnum, current_platform
from vllm.plugins import load_general_plugins
from vllm.ray.lazy_utils import is_in_ray_actor, is_ray_initialized
from vllm.reasoning import ReasoningParserManager
from vllm.transformers_utils.config import (
get_model_path,
is_interleaved,
Expand Down Expand Up @@ -495,7 +494,7 @@ class EngineArgs:
VllmConfig, "structured_outputs_config"
)
reasoning_parser: str = StructuredOutputsConfig.reasoning_parser

reasoning_parser_plugin: str | None = None
# Deprecated guided decoding fields
guided_decoding_backend: str | None = None
guided_decoding_disable_fallback: bool | None = None
Expand Down Expand Up @@ -707,10 +706,13 @@ def add_cli_args(parser: FlexibleArgumentParser) -> FlexibleArgumentParser:
)
structured_outputs_group.add_argument(
"--reasoning-parser",
# This choice is a special case because it's not static
choices=list(ReasoningParserManager.reasoning_parsers),
# Choices are dynamic to include plugins so they are validated later
**structured_outputs_kwargs["reasoning_parser"],
)
structured_outputs_group.add_argument(
"--reasoning-parser-plugin",
**structured_outputs_kwargs["reasoning_parser_plugin"],
)
# Deprecated guided decoding arguments
for arg, type in [
("--guided-decoding-backend", str),
Expand Down Expand Up @@ -1629,6 +1631,11 @@ def create_engine_config(
if self.reasoning_parser:
self.structured_outputs_config.reasoning_parser = self.reasoning_parser

if self.reasoning_parser_plugin:
self.structured_outputs_config.reasoning_parser_plugin = (
self.reasoning_parser_plugin
)

# Forward the deprecated CLI args to the StructuredOutputsConfig
so_config = self.structured_outputs_config
if self.guided_decoding_backend is not None:
Expand Down
6 changes: 6 additions & 0 deletions vllm/entrypoints/openai/api_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -1970,6 +1970,9 @@ def setup_server(args):
if args.tool_parser_plugin and len(args.tool_parser_plugin) > 3:
ToolParserManager.import_tool_parser(args.tool_parser_plugin)

if args.reasoning_parser_plugin and len(args.reasoning_parser_plugin) > 3:
ReasoningParserManager.import_reasoning_parser(args.reasoning_parser_plugin)

validate_api_server_args(args)

# workaround to make sure that we bind the port before the engine is set up.
Expand Down Expand Up @@ -2019,6 +2022,9 @@ async def run_server_worker(
if args.tool_parser_plugin and len(args.tool_parser_plugin) > 3:
ToolParserManager.import_tool_parser(args.tool_parser_plugin)

if args.reasoning_parser_plugin and len(args.reasoning_parser_plugin) > 3:
ReasoningParserManager.import_reasoning_parser(args.reasoning_parser_plugin)

# Load logging config for uvicorn if specified
log_config = load_log_config(args.log_config_file)
if log_config is not None:
Expand Down
2 changes: 1 addition & 1 deletion vllm/reasoning/deepseek_r1_reasoning_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from collections.abc import Sequence

from vllm.entrypoints.openai.protocol import DeltaMessage
from vllm.reasoning.abs_reasoning_parsers import ReasoningParserManager
from vllm.reasoning import ReasoningParserManager
from vllm.reasoning.basic_parsers import BaseThinkingReasoningParser


Expand Down
2 changes: 1 addition & 1 deletion vllm/reasoning/qwen3_reasoning_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


from vllm.entrypoints.openai.protocol import ChatCompletionRequest, ResponsesRequest
from vllm.reasoning.abs_reasoning_parsers import ReasoningParserManager
from vllm.reasoning import ReasoningParserManager
from vllm.reasoning.basic_parsers import BaseThinkingReasoningParser


Expand Down
2 changes: 1 addition & 1 deletion vllm/reasoning/seedoss_reasoning_parser.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project

from vllm.reasoning.abs_reasoning_parsers import ReasoningParserManager
from vllm.reasoning import ReasoningParserManager
from vllm.reasoning.basic_parsers import BaseThinkingReasoningParser


Expand Down
9 changes: 9 additions & 0 deletions vllm/v1/structured_output/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@ def __init__(self, vllm_config: VllmConfig):
self.tokenizer = init_tokenizer_from_configs(
model_config=self.vllm_config.model_config
)
reasoning_parser = (
self.vllm_config.structured_outputs_config.reasoning_parser
)
reasoning_parser_plugin = (
self.vllm_config.structured_outputs_config.reasoning_parser_plugin
)
if reasoning_parser_plugin and len(reasoning_parser_plugin) > 3:
ReasoningParserManager.import_reasoning_parser(reasoning_parser_plugin)

reasoning_parser = (
self.vllm_config.structured_outputs_config.reasoning_parser
)
Expand Down