[Chore] Consolidate reasoning/tool parser attributes into unified Parser in chat serving (#45548)
Signed-off-by: sfeng33 <4florafeng@gmail.com>
This commit is contained in:
@@ -1350,6 +1350,21 @@ class TestServingChatWithHarmony:
|
||||
else serving_chat.chat_completion_full_generator
|
||||
)
|
||||
|
||||
chat_template_kwargs = serving_chat._effective_chat_template_kwargs(req)
|
||||
if stream:
|
||||
extra_kwargs: dict[str, Any] = {
|
||||
"chat_template_kwargs": chat_template_kwargs,
|
||||
}
|
||||
else:
|
||||
parser = None
|
||||
if serving_chat.parser_cls is not None:
|
||||
parser = serving_chat.parser_cls(
|
||||
tokenizer,
|
||||
req.tools,
|
||||
chat_template_kwargs=chat_template_kwargs,
|
||||
)
|
||||
extra_kwargs = {"parser": parser}
|
||||
|
||||
result = generator_func(
|
||||
request=req,
|
||||
result_generator=result_generator(),
|
||||
@@ -1361,7 +1376,7 @@ class TestServingChatWithHarmony:
|
||||
request_id=req.request_id,
|
||||
model_name=req.model,
|
||||
),
|
||||
chat_template_kwargs=serving_chat._effective_chat_template_kwargs(req),
|
||||
**extra_kwargs,
|
||||
)
|
||||
|
||||
if stream:
|
||||
|
||||
@@ -25,7 +25,7 @@ from vllm.entrypoints.serve.utils.api_utils import get_max_tokens
|
||||
from vllm.inputs import EngineInput
|
||||
from vllm.logger import init_logger
|
||||
from vllm.outputs import RequestOutput
|
||||
from vllm.reasoning import ReasoningParser
|
||||
from vllm.parser.abstract_parser import Parser
|
||||
from vllm.tokenizers import TokenizerLike
|
||||
from vllm.utils.async_utils import merge_async_iterators
|
||||
from vllm.utils.collection_utils import as_list
|
||||
@@ -119,14 +119,15 @@ class OpenAIServingChatBatch(OpenAIServingChat):
|
||||
for messages in request.messages
|
||||
]
|
||||
|
||||
reasoning_parser: ReasoningParser | None = None
|
||||
if self.reasoning_parser_cls:
|
||||
parser: Parser | None = None
|
||||
if self.parser_cls is not None:
|
||||
chat_template_kwargs = self._effective_chat_template_kwargs(
|
||||
single_requests[0]
|
||||
)
|
||||
reasoning_parser = self.reasoning_parser_cls(
|
||||
parser = self.parser_cls(
|
||||
tokenizer,
|
||||
chat_template_kwargs=chat_template_kwargs, # type: ignore[call-arg]
|
||||
None, # tools
|
||||
chat_template_kwargs=chat_template_kwargs,
|
||||
)
|
||||
|
||||
render_result = await self.render_batch_chat_request(request)
|
||||
@@ -194,7 +195,7 @@ class OpenAIServingChatBatch(OpenAIServingChat):
|
||||
all_conversations,
|
||||
tokenizer,
|
||||
request_metadata,
|
||||
reasoning_parser,
|
||||
parser,
|
||||
)
|
||||
|
||||
async def chat_completion_full_generator_batch(
|
||||
@@ -206,7 +207,7 @@ class OpenAIServingChatBatch(OpenAIServingChat):
|
||||
all_conversations: list[list[ConversationMessage]],
|
||||
tokenizer: TokenizerLike,
|
||||
request_metadata: RequestResponseMetadata,
|
||||
reasoning_parser: ReasoningParser | None = None,
|
||||
parser: Parser | None = None,
|
||||
) -> ErrorResponse | ChatCompletionResponse:
|
||||
"""Handle batched (non-streaming) chat completions.
|
||||
|
||||
@@ -262,12 +263,12 @@ class OpenAIServingChatBatch(OpenAIServingChat):
|
||||
else:
|
||||
logprobs = None
|
||||
|
||||
if reasoning_parser:
|
||||
reasoning, content = reasoning_parser.extract_reasoning(
|
||||
if parser is not None:
|
||||
reasoning, content, _ = parser.parse(
|
||||
output.text,
|
||||
request=request, # type: ignore[arg-type]
|
||||
)
|
||||
if not getattr(request, "include_reasoning", True):
|
||||
if not request.include_reasoning:
|
||||
reasoning = None
|
||||
else:
|
||||
reasoning = None
|
||||
|
||||
@@ -955,6 +955,8 @@ class BatchChatCompletionRequest(OpenAIBaseModel):
|
||||
temperature: float | None = 0.7
|
||||
top_p: float | None = 1.0
|
||||
user: str | None = None
|
||||
tool_choice: Literal["none"] | None = "none"
|
||||
include_reasoning: bool = True
|
||||
|
||||
# vLLM extensions
|
||||
best_of: int | None = None
|
||||
|
||||
@@ -60,7 +60,6 @@ from vllm.logprobs import Logprob
|
||||
from vllm.outputs import RequestOutput
|
||||
from vllm.parser import ParserManager
|
||||
from vllm.parser.abstract_parser import Parser
|
||||
from vllm.reasoning import ReasoningParser
|
||||
from vllm.renderers import ChatParams
|
||||
from vllm.sampling_params import BeamSearchParams, SamplingParams
|
||||
from vllm.tokenizers import TokenizerLike
|
||||
@@ -145,17 +144,7 @@ class OpenAIServingChat(OpenAIServing):
|
||||
self.enable_log_outputs = enable_log_outputs
|
||||
self.enable_log_deltas = enable_log_deltas
|
||||
|
||||
# set up reasoning parser
|
||||
self.reasoning_parser_cls = ParserManager.get_reasoning_parser(
|
||||
reasoning_parser_name=reasoning_parser
|
||||
)
|
||||
# set up tool use
|
||||
self.enable_auto_tools: bool = enable_auto_tools
|
||||
self.tool_parser = ParserManager.get_tool_parser(
|
||||
tool_parser_name=tool_parser,
|
||||
enable_auto_tools=enable_auto_tools,
|
||||
model_name=self.model_config.model,
|
||||
)
|
||||
self.parser_cls = ParserManager.get_parser(
|
||||
tool_parser_name=tool_parser,
|
||||
reasoning_parser_name=reasoning_parser,
|
||||
@@ -164,8 +153,9 @@ class OpenAIServingChat(OpenAIServing):
|
||||
is_harmony=self.model_config.hf_config.model_type == "gpt_oss",
|
||||
)
|
||||
if (
|
||||
is_mistral_tool_parser(self.tool_parser)
|
||||
and self.reasoning_parser_cls is not None
|
||||
self.parser_cls is not None
|
||||
and is_mistral_tool_parser(self.parser_cls.tool_parser_cls)
|
||||
and self.parser_cls.reasoning_parser_cls is not None
|
||||
):
|
||||
from vllm.tool_parsers.mistral_tool_parser import MistralToolParser
|
||||
|
||||
@@ -267,11 +257,12 @@ class OpenAIServingChat(OpenAIServing):
|
||||
tokenizer = self.renderer.tokenizer
|
||||
assert tokenizer is not None
|
||||
chat_template_kwargs = self._effective_chat_template_kwargs(request)
|
||||
reasoning_parser: ReasoningParser | None = None
|
||||
if self.reasoning_parser_cls:
|
||||
reasoning_parser = self.reasoning_parser_cls(
|
||||
parser: Parser | None = None
|
||||
if self.parser_cls is not None:
|
||||
parser = self.parser_cls(
|
||||
tokenizer,
|
||||
chat_template_kwargs=chat_template_kwargs, # type: ignore[call-arg]
|
||||
request.tools,
|
||||
chat_template_kwargs=chat_template_kwargs,
|
||||
)
|
||||
result = await self.render_chat_request(request)
|
||||
if isinstance(result, ErrorResponse):
|
||||
@@ -359,10 +350,8 @@ class OpenAIServingChat(OpenAIServing):
|
||||
# `think?` rule that handles both reasoning and
|
||||
# non-reasoning outputs.
|
||||
reasoning_ended = True
|
||||
elif reasoning_parser:
|
||||
reasoning_ended = reasoning_parser.is_reasoning_end(
|
||||
prompt_token_ids or []
|
||||
)
|
||||
elif parser is not None and parser.reasoning_parser is not None:
|
||||
reasoning_ended = parser.is_reasoning_end(prompt_token_ids or [])
|
||||
else:
|
||||
reasoning_ended = None
|
||||
|
||||
@@ -378,7 +367,7 @@ class OpenAIServingChat(OpenAIServing):
|
||||
reasoning_parser_kwargs={
|
||||
"chat_template_kwargs": chat_template_kwargs,
|
||||
}
|
||||
if reasoning_parser
|
||||
if parser is not None and parser.reasoning_parser is not None
|
||||
else None,
|
||||
)
|
||||
|
||||
@@ -408,7 +397,7 @@ class OpenAIServingChat(OpenAIServing):
|
||||
conversation,
|
||||
tokenizer,
|
||||
request_metadata,
|
||||
chat_template_kwargs=chat_template_kwargs,
|
||||
parser=parser,
|
||||
mm_token_counts=mm_token_counts,
|
||||
)
|
||||
|
||||
@@ -835,7 +824,7 @@ class OpenAIServingChat(OpenAIServing):
|
||||
conversation: list[ConversationMessage],
|
||||
tokenizer: TokenizerLike,
|
||||
request_metadata: RequestResponseMetadata,
|
||||
chat_template_kwargs: dict[str, Any] | None = None,
|
||||
parser: Parser | None = None,
|
||||
mm_token_counts: dict[str, int] | None = None,
|
||||
) -> ErrorResponse | ChatCompletionResponse:
|
||||
created_time = int(time.time())
|
||||
@@ -861,6 +850,9 @@ class OpenAIServingChat(OpenAIServing):
|
||||
history_tool_call_cnt = 0
|
||||
|
||||
role = self.get_chat_request_role(request)
|
||||
tool_parser_cls = (
|
||||
self.parser_cls.tool_parser_cls if self.parser_cls is not None else None
|
||||
)
|
||||
for output in final_res.outputs:
|
||||
# check for error finish reason and raise GenerationError
|
||||
# finish_reason='error' indicates a retryable request-level internal error
|
||||
@@ -880,14 +872,6 @@ class OpenAIServingChat(OpenAIServing):
|
||||
else:
|
||||
logprobs = None
|
||||
|
||||
parser: Parser | None = None
|
||||
if self.parser_cls is not None:
|
||||
parser = self.parser_cls(
|
||||
tokenizer,
|
||||
request.tools,
|
||||
chat_template_kwargs=chat_template_kwargs,
|
||||
)
|
||||
|
||||
if parser is not None:
|
||||
reasoning, content, tool_calls = parser.parse(
|
||||
output.text,
|
||||
@@ -904,7 +888,7 @@ class OpenAIServingChat(OpenAIServing):
|
||||
|
||||
auto_tools_called = False
|
||||
|
||||
if (not self.enable_auto_tools or not self.tool_parser) and (
|
||||
if (not self.enable_auto_tools or not tool_parser_cls) and (
|
||||
not isinstance(request.tool_choice, ChatCompletionNamedToolChoiceParam)
|
||||
and request.tool_choice != "required"
|
||||
):
|
||||
@@ -963,7 +947,7 @@ class OpenAIServingChat(OpenAIServing):
|
||||
request.tools
|
||||
and (request.tool_choice == "auto" or request.tool_choice is None)
|
||||
and self.enable_auto_tools
|
||||
and self.tool_parser
|
||||
and tool_parser_cls
|
||||
):
|
||||
auto_tools_called = tool_calls is not None and len(tool_calls) > 0
|
||||
if tool_calls:
|
||||
|
||||
Reference in New Issue
Block a user