Skip to content

vllm.parser.qwen3

Qwen3 parser for tool calls and reasoning.

Qwen3 XML tool call format::

<tool_call>
<function=func_name>
<parameter=key>value</parameter>
</function>
</tool_call>

The argument body consists of <parameter=NAME>VALUE</parameter> tags. The _qwen3_arg_converter parses these into a JSON object.

Classes:

  • Qwen3Parser

    Qwen3 parser: <think>/</think> reasoning +

Qwen3Parser

Bases: ParserEngine

Qwen3 parser: <think>/</think> reasoning + <tool_call> XML tool calls in a single engine.

  • <tool_call> as implicit reasoning end
  • Unpaired <tool_call> token ID detection for is_reasoning_end
Source code in vllm/parser/qwen3.py
class Qwen3Parser(ParserEngine):
    """Qwen3 parser: ``<think>``/``</think>`` reasoning +
    ``<tool_call>`` XML tool calls in a single engine.

    - ``<tool_call>`` as implicit reasoning end
    - Unpaired ``<tool_call>`` token ID detection for ``is_reasoning_end``
    """

    def __init__(
        self,
        tokenizer: TokenizerLike,
        tools: list[Tool] | None = None,
        **kwargs,
    ) -> None:
        chat_kwargs = kwargs.get("chat_template_kwargs", {}) or {}
        self.thinking_enabled = chat_kwargs.get("enable_thinking", True)
        kwargs.setdefault(
            "parser_engine_config",
            qwen3_config(thinking=self.thinking_enabled),
        )
        super().__init__(
            tokenizer,
            tools,
            **kwargs,
        )
        vocab = self.vocab
        self._tool_call_token_id: int | None = vocab.get("<tool_call>")
        self._tool_call_end_token_id: int | None = vocab.get("</tool_call>")

    def extract_reasoning(
        self,
        model_output: str,
        request: ChatCompletionRequest | ResponsesRequest,
    ) -> tuple[str | None, str | None]:
        if not self.thinking_enabled:
            return None, model_output
        return super().extract_reasoning(model_output, request)

    def is_reasoning_end(self, input_ids: list[int]) -> bool:
        if super().is_reasoning_end(input_ids):
            return True
        tool_call_id = self._tool_call_token_id
        tool_call_end_id = self._tool_call_end_token_id
        if tool_call_id is not None:
            for i in range(len(input_ids) - 1, -1, -1):
                if input_ids[i] == tool_call_id:
                    if tool_call_end_id is not None and any(
                        input_ids[j] == tool_call_end_id
                        for j in range(i + 1, len(input_ids))
                    ):
                        continue
                    return True
        return False