Skip to content

[model-gateway]: add qwen coder tool parser support xml format for qwen3 coder and microthinker - #12909

Merged
slin1237 merged 1 commit into
sgl-project:mainfrom
whybeyoung:qwen-coder-router-parser
Jan 12, 2026
Merged

slin1237 merged 1 commit into
sgl-project:mainfrom
whybeyoung:qwen-coder-router-parser

Conversation

@whybeyoung

@whybeyoung whybeyoung commented Nov 9, 2025 •

Copy link
Copy Markdown
Collaborator

Summary

Add a new Qwen Coder XML format tool parser for the Rust Router (sgl-model-gateway).

Qwen Coder models use a distinct XML-based tool call format that differs from the standard Qwen JSON format:

<tool_call>
<function=execute_bash>
<parameter=command>pwd && ls</parameter>
</function>
</tool_call>

This PR implements full support for parsing this format in both complete and streaming modes.

Motivation

  • Qwen Coder models (Qwen3-Coder, Qwen2.5-Coder) use XML format for tool calls
  • The existing qwen parser only handles JSON format inside <tool_call> tags
  • Users needed to use Python-side parsing, losing Rust Router performance benefits

Reference: https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8?chat_template=default

Changes

New Parser: QwenCoderParser

  • Location: src/tool_parser/parsers/qwen_coder.rs
  • Format: <tool_call><function=name><parameter=key>value</tool_call>
  • Features:
    • HTML entity decoding (& → &, < → <, etc.)
    • Python literal support (True, False, None)
    • Streaming support with complete parameter emission
    • Unicode support in function names and parameters

Model Auto-Detection

Added model mappings in factory.rs:
registry.map_model("Qwen/Qwen3-Coder*", "qwen_coder");
registry.map_model("Qwen3-Coder*", "qwen_coder");
registry.map_model("qwen3-coder*", "qwen_coder");
registry.map_model("Qwen/Qwen2.5-Coder*", "qwen_coder");
registry.map_model("Qwen2.5-Coder*", "qwen_coder");
registry.map_model("qwen2.5-coder*", "qwen_coder");

Users can also explicitly use --tool-call-parser qwen_coder.

Test Coverage

Test categories:

  • Basic parsing (single/multiple tools)
  • Streaming (chunked input, partial tags)
  • Type conversion (JSON, Python literals)
  • HTML entity decoding
  • Unicode support
  • Edge cases (malformed XML, large values, nested JSON)

Test Plan

  • All 49 unit and integration tests pass
  • Clippy passes with no warnings
  • Code follows existing parser patterns
  • E2E test with actual Qwen Coder model (requires model availability)

@github-actions github-actions Bot added the router label Nov 9, 2025
@sglang-bot sglang-bot added the run-ci CI: run the baseline test suite on this PR label Nov 9, 2025
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @whybeyoung, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the Qwen tool parser within the Rust Router by introducing comprehensive support for XML-formatted tool calls. This update ensures that the router can correctly interpret and process tool calls from Qwen models that utilize an XML structure, providing parity with existing Python implementations and improving the overall compatibility and robustness of the system.

Highlights

  • XML Format Support: The Qwen tool parser now supports parsing tool calls in XML format, in addition to the existing JSON format. This aligns the Rust Router's capabilities with the Python-side Qwen3CoderDetector.
  • Streaming XML Parsing: New internal state fields and a dedicated parse_xml_incremental method have been added to handle the streaming parsing of XML-formatted tool calls, allowing for real-time extraction of function names and parameters.
  • Automatic Format Detection: The parser can now automatically detect whether a tool call content is in JSON or XML format and dispatches to the appropriate parsing logic, ensuring flexibility in handling different Qwen model outputs.
  • Robust Parameter Parsing: The XML parser attempts to parse parameter values as JSON first, falling back to treating them as strings if JSON parsing fails, providing robust handling of various data types within XML parameters.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for parsing XML-formatted tool calls from Qwen models, which is a great feature enhancement. The implementation covers both complete and incremental (streaming) parsing, and includes logic to detect the format (JSON vs. XML) automatically. The changes are well-structured, but I've identified a few critical performance and correctness issues. Specifically, regular expressions are being recompiled on every function call, which will degrade performance, and the logic for building JSON strings during streaming is brittle and can produce invalid output. I've also included some suggestions to improve code maintainability by reducing duplication and adhering to standard Rust conventions.

Comment thread sgl-router/src/tool_parser/parsers/qwen.rs Outdated
Comment thread sgl-router/src/tool_parser/parsers/qwen.rs Outdated
Comment thread sgl-router/src/tool_parser/parsers/qwen.rs Outdated
Comment thread sgl-router/src/tool_parser/parsers/qwen.rs Outdated
@CatherineSue

Copy link
Copy Markdown
Collaborator

Why don't we have a qwen3_coder_parser.rs separately?

@whybeyoung

Copy link
Copy Markdown
Collaborator Author

Why don't we have a qwen3_coder_parser.rs separately?

It seems overly simplistic to assume that all of Qwen's tools should be implemented here. If we implement them separately, wouldn't we have to designate Qwen3-Coder specifically for the parser? There appears to be a significant amount of redundancy in this approach, so implementing them within Qwen itself shouldn't pose major issues, right?
I need your opinion. I can fix this.

@CatherineSue CatherineSue left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand there might be a lot duplications between qwen.rs and qwen-coder. However, the current architecture is a big if-else to me at the moment.

The logic that parses xml in complete or incremental style looks good to me. But my biggest concern is the fall back logic or how do we manage the is_xml_format or is_json_format state thru incremental parsing. I am concerned with future debug and maintenance.

From what we know, qwen3-coder or qwen3-xml-format is specific to qwen3-coder models. The other qwen family models use the json format. It might be clear if we separate qwen-xml.rs from qwen.rs. And in the tool parser registry, we simply add a qwen3-coder match for qwen-xml.

Let me know what you think @whybeyoung @slin1237

If we want to keep them in the same file, then let's add through tests, as detailed as possible. We should add tests nevertheless. But if we are gonna keep them in the same file, more test cases should be covered.

Comment thread sgl-router/src/tool_parser/parsers/qwen.rs
Comment thread sgl-router/src/tool_parser/parsers/qwen.rs Outdated
Comment thread sgl-router/src/tool_parser/parsers/qwen.rs Outdated
Comment thread sgl-router/src/tool_parser/parsers/qwen.rs Outdated
@whybeyoung

Copy link
Copy Markdown
Collaborator Author

I understand there might be a lot duplications between qwen.rs and qwen-coder. However, the current architecture is a big if-else to me at the moment.

The logic that parses xml in complete or incremental style looks good to me. But my biggest concern is the fall back logic or how do we manage the is_xml_format or is_json_format state thru incremental parsing. I am concerned with future debug and maintenance.

From what we know, qwen3-coder or qwen3-xml-format is specific to qwen3-coder models. The other qwen family models use the json format. It might be clear if we separate qwen-xml.rs from qwen.rs. And in the tool parser registry, we simply add a qwen3-coder match for qwen-xml.

Let me know what you think @whybeyoung @slin1237

If we want to keep them in the same file, then let's add through tests, as detailed as possible. We should add tests nevertheless. But if we are gonna keep them in the same file, more test cases should be covered.

make sense. I agree with the approach of separating them into individual files, and I will fix this following the separation pattern. @CatherineSue

Comment thread sgl-router/src/tool_parser/parsers/qwen_coder.rs Outdated
Comment thread sgl-router/src/tool_parser/parsers/qwen_coder.rs Outdated
Comment thread sgl-router/src/tool_parser/parsers/qwen_coder.rs Outdated
Comment thread sgl-model-gateway/src/tool_parser/parsers/qwen_coder.rs Outdated
Comment thread sgl-router/src/tool_parser/parsers/qwen_coder.rs Outdated
Comment thread sgl-model-gateway/src/tool_parser/parsers/qwen_coder.rs Outdated
Comment thread sgl-router/src/tool_parser/parsers/qwen_coder.rs Outdated
@slin1237
slin1237 force-pushed the qwen-coder-router-parser branch from e778a6f to 9e8b528 Compare January 9, 2026 19:41
@slin1237

slin1237 commented Jan 9, 2026

Copy link
Copy Markdown
Collaborator

/gemini review

@slin1237
slin1237 force-pushed the qwen-coder-router-parser branch from 9e8b528 to bc6941c Compare January 9, 2026 19:42

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new QwenCoderParser to handle XML-based tool calls, analogous to the Python implementation. The changes include adding the parser, integrating it into the factory, and providing comprehensive tests. The implementation is robust, covering both complete and incremental parsing, including various edge cases. I've identified a couple of areas for improvement, mainly related to code duplication and a potential bug in JSON fragment construction during streaming. Overall, this is a solid contribution that extends the gateway's capabilities.

Comment thread sgl-model-gateway/src/tool_parser/parsers/qwen_coder.rs Outdated
Comment thread sgl-model-gateway/src/tool_parser/parsers/qwen_coder.rs Outdated
Comment thread sgl-model-gateway/src/tool_parser/parsers/qwen_coder.rs Outdated
Comment on lines +613 to +615
println!("Chunk {}: {:?}", i, chunk);
println!(" Calls: {:?}", result.calls);
println!(" Normal text: {:?}", result.normal_text);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The println! statements are useful for debugging during development but should be removed from the final test code to keep the test output clean. Test output should ideally only show failures, not verbose logging for successful runs.

@slin1237
slin1237 force-pushed the qwen-coder-router-parser branch from bc6941c to ab911e8 Compare January 9, 2026 19:58
@slin1237 slin1237 changed the title feat: qwen coder tool parser support xml format [model-gateway]: add qwen coder tool parser support xml format for qwen3 coder and microthinker Jan 9, 2026
@slin1237

slin1237 commented Jan 9, 2026

Copy link
Copy Markdown
Collaborator

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new QwenCoderParser to handle XML-based tool calls from Qwen Coder models, which is a great addition. The changes include the parser implementation, factory registration, model mappings, and an extensive suite of unit and integration tests. The implementation is thorough and the test coverage is excellent. I've identified a high-severity correctness issue in the html_unescape helper function that could lead to data corruption, and a medium-severity issue with an unused parameter. With these fixes, this will be a very solid contribution.

Comment thread sgl-model-gateway/src/tool_parser/parsers/qwen_coder.rs
Comment thread sgl-model-gateway/src/tool_parser/parsers/qwen_coder.rs Outdated
@slin1237
slin1237 force-pushed the qwen-coder-router-parser branch 2 times, most recently from 3aff23d to 53b1b46 Compare January 9, 2026 21:16
@slin1237

slin1237 commented Jan 9, 2026

Copy link
Copy Markdown
Collaborator

/gemini reviewww

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@slin1237 slin1237 self-assigned this Jan 9, 2026
@slin1237
slin1237 force-pushed the qwen-coder-router-parser branch 3 times, most recently from 010480a to 50a3058 Compare January 11, 2026 02:48
@slin1237
slin1237 force-pushed the qwen-coder-router-parser branch from 50a3058 to 278a63c Compare January 11, 2026 02:49

@CatherineSue CatherineSue left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

}
}

#[cfg(test)]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we move the tests here to tool_parser_qwen_coder.rs?

@slin1237
slin1237 merged commit 503c3d9 into sgl-project:main Jan 12, 2026
62 checks passed
0826joyce pushed a commit to 0826joyce/sglang-perf-opt that referenced this pull request May 19, 2026
Chronostasys pushed a commit to MindLab-Research/sglang that referenced this pull request Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

high priority model-gateway router run-ci CI: run the baseline test suite on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants