Conversation
Qwen3.5 emits tool calls in the XML style shared with Qwen3-Coder rather than the JSON-in-<tool_call> style of Qwen3, so QwenFCHandler cannot decode its output. This adds Qwen35FCHandler and registers Qwen3.5-2B and Qwen3.5-4B as self-hosted FC models. The handler renders prompts with the model's own chat template through the tokenizer OSSHandler already loads, so the prompt matches what the model was trained on. Parameter values in the XML format are untyped text, so it re-types each one from the function spec of the current test entry (the index is thread-local, since the handler instance is shared by the generation pool), then stores the typed Qwen3-style JSON form as the model response. QwenFCHandler's decode_ast and decode_execute and the AST checker are reused unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
The new handler’s dtype parameter is currently silently ignored due to base-class initialization behavior, which can lead to incorrect local server dtype selection.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds first-class support for Qwen3.5 self-hosted function-calling models by introducing a dedicated handler that can parse Qwen3.5’s XML-ish tool-call output and convert it into the existing Qwen3 JSON <tool_call>{...}</tool_call> form reused by current decoders/checkers.
Changes:
- Introduces
Qwen35FCHandlerto render prompts via the model’schat_templateand parse/coerce XML tool-call parameters into typed JSON tool calls. - Registers
Qwen/Qwen3.5-2B-FCandQwen/Qwen3.5-4B-FCin the model registry/config. - Documents the new self-hosted Qwen3.5 FC entries in
SUPPORTED_MODELS.md.
File summaries
| File | Description |
|---|---|
| berkeley-function-call-leaderboard/SUPPORTED_MODELS.md | Adds documentation row for Qwen3.5 FC self-hosted entries. |
| berkeley-function-call-leaderboard/bfcl_eval/model_handler/local_inference/qwen3_5_fc.py | New handler for Qwen3.5 XML tool-call parsing + prompt rendering via chat_template. |
| berkeley-function-call-leaderboard/bfcl_eval/constants/supported_models.py | Adds Qwen3.5 FC model IDs to supported model list. |
| berkeley-function-call-leaderboard/bfcl_eval/constants/model_config.py | Wires new model IDs to Qwen35FCHandler and model metadata. |
Review details
Suppressed comments (1)
berkeley-function-call-leaderboard/bfcl_eval/model_handler/local_inference/qwen3_5_fc.py:87
- The string-type check is redundant (
"any"is included in the tuple and also checked again witht == "any"). This doesn't change behavior, but simplifying reduces cognitive overhead.
if t in ("string", "str", "any", "") or t == "any":
- Files reviewed: 4/4 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| super().__init__(model_name, temperature, registry_name, is_fc_model, dtype, **kwargs) | ||
| self.model_name_huggingface = model_name |
| _INT_TYPES = {"integer", "int", "long", "short", "byte"} | ||
| _FLOAT_TYPES = {"float", "number", "double"} | ||
| _BOOL_TYPES = {"boolean", "bool"} | ||
| _LIST_TYPES = {"array", "tuple", "list", "arraylist", "array"} |
QwenFCHandler takes a dtype argument but does not pass it to OSSHandler, where self.dtype is what the local vLLM/SGLang server is launched with, so a non-default dtype was silently dropped. Set it in this handler. Also removes a duplicate "array" from _LIST_TYPES and a redundant "any" check in the string branch of _coerce. Both were noise rather than behaviour. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Thanks for the review. All three points are addressed in the latest commit. dtype is silently ignored — confirmed, and it is worth flagging where it comes from. I have set The same latent bug affects the existing Duplicate |
|
@HuanzhiMao gentle ping whenever you have a moment. This adds Qwen3.5 support, which isn't on main yet. Qwen3.5 emits tool calls in an XML format, so the existing Qwen handler parses nothing and the model scores near zero for reasons unrelated to its ability. The Copilot review findings, including the dtype one, are addressed. It would also unblock #1319, a Qwen3.5-0.8B fine-tune that currently has results but no handler to produce them. Happy to rebase or change anything you'd like. |
What this adds
Qwen35FCHandler, plus registry entries forQwen/Qwen3.5-2B-FCandQwen/Qwen3.5-4B-FCas self-hosted function-calling models.Why
Qwen3.5 changed the tool-call wire format. Qwen3 emits JSON inside
<tool_call>tags, whichQwenFCHandlerparses. Qwen3.5 uses the XML style shared with Qwen3-Coder:Running a Qwen3.5 model through
QwenFCHandleryields no parsed calls, so the model scores near zero for a reason that has nothing to do with its ability.How it works
chat_template, through the tokenizerOSSHandleralready loads, with tools converted byconvert_to_toolto OpenAI style. The prompt is byte-identical to what the model was trained on.10must become an int when the schema says integer,["a","b"]a list, and a ZIP code must stay a string). The spec index is thread-local because the handler instance is shared by the generation thread pool.<tool_call>form, soQwenFCHandler.decode_ast,decode_executeand the AST checker are reused unchanged rather than duplicated.Thinking is left at the template default, so the generation prompt ends with an empty
<think></think>block, which is how these checkpoints are meant to be served for tool use.Verification
Both entries resolve to the new handler:
Scores for
Qwen/Qwen3.5-2B-FCfrom a local run with this handler (vLLM, bf16, temperature 0.001, 128k serving context; the 32k default rejects about fortymulti_turn_long_contextentries):Run with:
Note that vLLM 0.17 or newer is needed for the Qwen3.5 architecture.
Happy to adjust naming or split this differently if you would prefer.
🤖 Generated with Claude Code