mirror of
https://git.datalinker.icu/vllm-project/vllm.git
synced 2025-12-25 18:01:50 +08:00
[Bugfix] Fix DeepSeekV31ToolParser to correctly parse multiple tools in non-streaming output (#25405)
Signed-off-by: taohui <taohui3@gmail.com> Signed-off-by: yewentao256 <zhyanwentao@126.com>
This commit is contained in:
parent
88d8c72d5f
commit
71566e8afc
54
tests/tool_use/test_deepseekv31_tool_parser.py
Normal file
54
tests/tool_use/test_deepseekv31_tool_parser.py
Normal file
@ -0,0 +1,54 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
|
||||
import pytest
|
||||
|
||||
from vllm.entrypoints.openai.tool_parsers import DeepSeekV31ToolParser
|
||||
from vllm.transformers_utils.tokenizer import get_tokenizer
|
||||
|
||||
MODEL = "deepseek-ai/DeepSeek-V3.1"
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def deepseekv31_tokenizer():
|
||||
return get_tokenizer(tokenizer_name=MODEL)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def parser(deepseekv31_tokenizer):
|
||||
return DeepSeekV31ToolParser(deepseekv31_tokenizer)
|
||||
|
||||
|
||||
def test_extract_tool_calls_with_tool(parser):
|
||||
model_output = (
|
||||
"normal text" + "<|tool▁calls▁begin|>" +
|
||||
"<|tool▁call▁begin|>foo<|tool▁sep|>{\"x\":1}<|tool▁call▁end|>" +
|
||||
"<|tool▁calls▁end|>")
|
||||
result = parser.extract_tool_calls(model_output, None)
|
||||
assert result.tools_called
|
||||
assert len(result.tool_calls) == 1
|
||||
assert result.tool_calls[0].function.name == "foo"
|
||||
assert result.tool_calls[0].function.arguments == "{\"x\":1}"
|
||||
assert result.content == "normal text"
|
||||
|
||||
|
||||
def test_extract_tool_calls_with_multiple_tools(parser):
|
||||
model_output = (
|
||||
"some prefix text" + "<|tool▁calls▁begin|>" +
|
||||
"<|tool▁call▁begin|>foo<|tool▁sep|>{\"x\":1}<|tool▁call▁end|>" +
|
||||
"<|tool▁call▁begin|>bar<|tool▁sep|>{\"y\":2}<|tool▁call▁end|>" +
|
||||
"<|tool▁calls▁end|>" + " some suffix text")
|
||||
|
||||
result = parser.extract_tool_calls(model_output, None)
|
||||
|
||||
assert result.tools_called
|
||||
assert len(result.tool_calls) == 2
|
||||
|
||||
assert result.tool_calls[0].function.name == "foo"
|
||||
assert result.tool_calls[0].function.arguments == "{\"x\":1}"
|
||||
|
||||
assert result.tool_calls[1].function.name == "bar"
|
||||
assert result.tool_calls[1].function.arguments == "{\"y\":2}"
|
||||
|
||||
# prefix is content
|
||||
assert result.content == "some prefix text"
|
||||
@ -39,7 +39,7 @@ class DeepSeekV31ToolParser(ToolParser):
|
||||
self.tool_call_end_token: str = "<|tool▁call▁end|>"
|
||||
|
||||
self.tool_call_regex = re.compile(
|
||||
r"<|tool▁call▁begin|>(?P<function_name>.*)<|tool▁sep|>(?P<function_arguments>.*)<|tool▁call▁end|>"
|
||||
r"<|tool▁call▁begin|>(?P<function_name>.*?)<|tool▁sep|>(?P<function_arguments>.*?)<|tool▁call▁end|>"
|
||||
)
|
||||
|
||||
self.stream_tool_call_portion_regex = re.compile(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user