[Tool Call][DSV32] Streamline function call parameters (#14750)

Signed-off-by: Muqi Li <muqi1029@gmail.com>
This commit is contained in:
Muqi Li
2025-12-27 03:35:30 +08:00
committed by GitHub
parent 43e1bbc0d5
commit 01bd0d3e8b
2 changed files with 60 additions and 29 deletions

View File

@@ -1159,6 +1159,10 @@ class TestDeepSeekV32Detector(unittest.TestCase):
),
]
self.detector = DeepSeekV32Detector()
from transformers import AutoTokenizer
self.tokenizer = AutoTokenizer.from_pretrained("deepseek-ai/DeepSeek-V3.2")
self.interval = 1
def test_detect_and_parse_xml_format(self):
"""Test parsing standard XML format (DSML)"""
@@ -1236,12 +1240,19 @@ class TestDeepSeekV32Detector(unittest.TestCase):
text = """<DSMLfunction_calls>
<DSMLinvoke name="get_favorite_tourist_spot">
<DSMLparameter name="city" string="true">San Francisco</DSMLparameter>
<DSMLparameter name="another_city" string="true">London</DSMLparameter>
<DSMLparameter name="topn" string="false">10</DSMLparameter>
<DSMLparameter name="obj" string="false">{"name": "John", "age": 30}</DSMLparameter>
</DSMLinvoke>
</DSMLfunction_calls>"""
chunks = [text[i : i + 5] for i in range(0, len(text), 5)]
input_ids = self.tokenizer.encode(text, add_special_tokens=False)
chunk_ids = [
input_ids[i : i + self.interval]
for i in range(0, len(input_ids), self.interval)
]
chunks = [self.tokenizer.decode(chunk_id) for chunk_id in chunk_ids]
accumulated_calls = []
tool_calls_by_index = {}
for chunk in chunks:
@@ -1263,15 +1274,12 @@ class TestDeepSeekV32Detector(unittest.TestCase):
self.assertEqual(len(tool_calls_by_index), 1)
self.assertEqual(tool_calls_by_index[0]["name"], "get_favorite_tourist_spot")
# Note: The detector might accumulate partial JSON string which is valid,
# but for XML format it constructs JSON at the end.
# Let's check if the final parameters parse correctly.
try:
params = json.loads(tool_calls_by_index[0]["parameters"])
self.assertEqual(params["city"], "San Francisco")
except json.JSONDecodeError:
# In streaming XML, parameters might be constructed differently or incrementally
pass
params = json.loads(tool_calls_by_index[0]["parameters"])
self.assertEqual(params["city"], "San Francisco")
self.assertEqual(params["another_city"], "London")
self.assertEqual(params["topn"], 10)
self.assertEqual(params["obj"]["name"], "John")
self.assertEqual(params["obj"]["age"], 30)
def test_streaming_json_format(self):
"""Test streaming parsing of JSON format"""
@@ -1283,7 +1291,12 @@ class TestDeepSeekV32Detector(unittest.TestCase):
</DSMLinvoke>
</DSMLfunction_calls>"""
chunks = [text[i : i + 5] for i in range(0, len(text), 5)]
input_ids = self.tokenizer.encode(text, add_special_tokens=False)
chunk_ids = [
input_ids[i : i + self.interval]
for i in range(0, len(input_ids), self.interval)
]
chunks = [self.tokenizer.decode(chunk_id) for chunk_id in chunk_ids]
tool_calls_by_index = {}
@@ -1370,7 +1383,12 @@ class TestDeepSeekV32Detector(unittest.TestCase):
self.detector = DeepSeekV32Detector()
# Simulate streaming by splitting into small chunks
chunks = [text[i : i + 5] for i in range(0, len(text), 5)]
input_ids = self.tokenizer.encode(text, add_special_tokens=False)
chunk_ids = [
input_ids[i : i + self.interval]
for i in range(0, len(input_ids), self.interval)
]
chunks = [self.tokenizer.decode(chunk_id) for chunk_id in chunk_ids]
tool_calls_by_index = {}
@@ -1425,7 +1443,12 @@ class TestDeepSeekV32Detector(unittest.TestCase):
# Reset detector state
self.detector = DeepSeekV32Detector()
chunks = [text[i : i + 5] for i in range(0, len(text), 5)]
input_ids = self.tokenizer.encode(text, add_special_tokens=False)
chunk_ids = [
input_ids[i : i + self.interval]
for i in range(0, len(input_ids), self.interval)
]
chunks = [self.tokenizer.decode(chunk_id) for chunk_id in chunk_ids]
tool_calls_by_index = {}