Skip to content

[Bug]: sometimes tool calling is not correctly parsed but remains in the plain content for qwen3 coder #22975

Closed as not planned

Description

@Co1lin

Your current environment

The output of python collect_env.py
==============================
        System Info
==============================
OS                           : Ubuntu 22.04.5 LTS (x86_64)
GCC version                  : (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
Clang version                : Could not collect
CMake version                : version 4.0.3
Libc version                 : glibc-2.35

==============================
       PyTorch Info
==============================
PyTorch version              : 2.7.1+cu128
Is debug build               : False
CUDA used to build PyTorch   : 12.8
ROCM used to build PyTorch   : N/A

==============================
      Python Environment
==============================
Python version               : 3.12.11 (main, Jun  4 2025, 08:56:18) [GCC 11.4.0] (64-bit runtime)
Python platform              : Linux-6.8.0-1031-aws-x86_64-with-glibc2.35

==============================
       CUDA / GPU Info
==============================
Is CUDA available            : True
CUDA runtime version         : 12.8.93
CUDA_MODULE_LOADING set to   : LAZY
GPU models and configuration :
GPU 0: NVIDIA B200
GPU 1: NVIDIA B200
GPU 2: NVIDIA B200
GPU 3: NVIDIA B200
GPU 4: NVIDIA B200
GPU 5: NVIDIA B200
GPU 6: NVIDIA B200
GPU 7: NVIDIA B200

Nvidia driver version        : 570.172.08
cuDNN version                : Could not collect
HIP runtime version          : N/A
MIOpen runtime version       : N/A
Is XNNPACK available         : True

==============================
          CPU Info
==============================
Architecture:                         x86_64
CPU op-mode(s):                       32-bit, 64-bit
Address sizes:                        46 bits physical, 48 bits virtual
Byte Order:                           Little Endian
CPU(s):                               192
On-line CPU(s) list:                  0-191
Vendor ID:                            GenuineIntel
Model name:                           Intel(R) Xeon(R) Platinum 8559C
CPU family:                           6
Model:                                207
Thread(s) per core:                   2
Core(s) per socket:                   48
Socket(s):                            2
Stepping:                             2
BogoMIPS:                             4800.00
Flags:                                fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq monitor ssse3 fma cx16 pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch ssbd ibrs ibpb stibp ibrs_enhanced fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves avx_vnni avx512_bf16 wbnoinvd ida arat avx512vbmi umip pku ospke waitpkg avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg tme avx512_vpopcntdq rdpid cldemote movdiri movdir64b md_clear serialize amx_bf16 avx512_fp16 amx_tile amx_int8 flush_l1d arch_capabilities
Hypervisor vendor:                    KVM
Virtualization type:                  full
L1d cache:                            4.5 MiB (96 instances)
L1i cache:                            3 MiB (96 instances)
L2 cache:                             192 MiB (96 instances)
L3 cache:                             640 MiB (2 instances)
NUMA node(s):                         2
NUMA node0 CPU(s):                    0-47,96-143
NUMA node1 CPU(s):                    48-95,144-191
Vulnerability Gather data sampling:   Not affected
Vulnerability Itlb multihit:          Not affected
Vulnerability L1tf:                   Not affected
Vulnerability Mds:                    Not affected
Vulnerability Meltdown:               Not affected
Vulnerability Mmio stale data:        Not affected
Vulnerability Reg file data sampling: Not affected
Vulnerability Retbleed:               Not affected
Vulnerability Spec rstack overflow:   Not affected
Vulnerability Spec store bypass:      Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:             Mitigation; usercopy/swapgs barriers and __user pointer sanitization
Vulnerability Spectre v2:             Mitigation; Enhanced / Automatic IBRS; IBPB conditional; RSB filling; PBRSB-eIBRS SW sequence; BHI BHI_DIS_S
Vulnerability Srbds:                  Not affected
Vulnerability Tsx async abort:        Not affected

==============================
Versions of relevant libraries
==============================
[pip3] numpy==2.2.6
[pip3] nvidia-cublas-cu12==12.8.3.14
[pip3] nvidia-cuda-cupti-cu12==12.8.57
[pip3] nvidia-cuda-nvrtc-cu12==12.8.61
[pip3] nvidia-cuda-runtime-cu12==12.8.57
[pip3] nvidia-cudnn-cu12==9.7.1.26
[pip3] nvidia-cufft-cu12==11.3.3.41
[pip3] nvidia-cufile-cu12==1.13.0.11
[pip3] nvidia-curand-cu12==10.3.9.55
[pip3] nvidia-cusolver-cu12==11.7.2.55
[pip3] nvidia-cusparse-cu12==12.5.7.53
[pip3] nvidia-cusparselt-cu12==0.6.3
[pip3] nvidia-ml-py==12.575.51
[pip3] nvidia-nccl-cu12==2.26.2
[pip3] nvidia-nvjitlink-cu12==12.8.61
[pip3] nvidia-nvshmem-cu12==3.3.9
[pip3] nvidia-nvtx-cu12==12.8.55
[pip3] pynvml==12.0.0
[pip3] pyzmq==27.0.0
[pip3] torch==2.7.1+cu128
[pip3] torchaudio==2.7.1+cu128
[pip3] torchvision==0.22.1+cu128
[pip3] transformers==4.54.1
[pip3] triton==3.3.1
[conda] Could not collect

==============================
         vLLM Info
==============================
ROCM Version                 : Could not collect
Neuron SDK Version           : N/A
vLLM Version                 : 0.10.1.dev1+gbcc0a3cbe (git sha: bcc0a3cbe)
vLLM Build Flags:
  CUDA Archs: Not Set; ROCm: Disabled; Neuron: Disabled
GPU Topology:
        GPU0    GPU1    GPU2    GPU3    GPU4    GPU5    GPU6    GPU7    CPU Affinity    NUMA Affinity   GPU NUMA ID
GPU0     X      NV18    NV18    NV18    NV18    NV18    NV18    NV18    0-47,96-143     0               N/A
GPU1    NV18     X      NV18    NV18    NV18    NV18    NV18    NV18    0-47,96-143     0               N/A
GPU2    NV18    NV18     X      NV18    NV18    NV18    NV18    NV18    0-47,96-143     0               N/A
GPU3    NV18    NV18    NV18     X      NV18    NV18    NV18    NV18    0-47,96-143     0               N/A
GPU4    NV18    NV18    NV18    NV18     X      NV18    NV18    NV18    48-95,144-191   1               N/A
GPU5    NV18    NV18    NV18    NV18    NV18     X      NV18    NV18    48-95,144-191   1               N/A
GPU6    NV18    NV18    NV18    NV18    NV18    NV18     X      NV18    48-95,144-191   1               N/A
GPU7    NV18    NV18    NV18    NV18    NV18    NV18    NV18     X      48-95,144-191   1               N/A

Legend:

  X    = Self
  SYS  = Connection traversing PCIe as well as the SMP interconnect between NUMA nodes (e.g., QPI/UPI)
  NODE = Connection traversing PCIe as well as the interconnect between PCIe Host Bridges within a NUMA node
  PHB  = Connection traversing PCIe as well as a PCIe Host Bridge (typically the CPU)
  PXB  = Connection traversing multiple PCIe bridges (without traversing the PCIe Host Bridge)
  PIX  = Connection traversing at most a single PCIe bridge
  NV#  = Connection traversing a bonded set of # NVLinks

==============================
     Environment Variables
==============================
NVIDIA_VISIBLE_DEVICES=all
NVIDIA_REQUIRE_CUDA=cuda>=12.8 brand=unknown,driver>=470,driver<471 brand=grid,driver>=470,driver<471 brand=tesla,driver>=470,driver<471 brand=nvidia,driver>=470,driver<471 brand=quadro,driver>=470,driver<471 brand=quadrortx,driver>=470,driver<471 brand=nvidiartx,driver>=470,driver<471 brand=vapps,driver>=470,driver<471 brand=vpc,driver>=470,driver<471 brand=vcs,driver>=470,driver<471 brand=vws,driver>=470,driver<471 brand=cloudgaming,driver>=470,driver<471 brand=unknown,driver>=535,driver<536 brand=grid,driver>=535,driver<536 brand=tesla,driver>=535,driver<536 brand=nvidia,driver>=535,driver<536 brand=quadro,driver>=535,driver<536 brand=quadrortx,driver>=535,driver<536 brand=nvidiartx,driver>=535,driver<536 brand=vapps,driver>=535,driver<536 brand=vpc,driver>=535,driver<536 brand=vcs,driver>=535,driver<536 brand=vws,driver>=535,driver<536 brand=cloudgaming,driver>=535,driver<536 brand=unknown,driver>=550,driver<551 brand=grid,driver>=550,driver<551 brand=tesla,driver>=550,driver<551 brand=nvidia,driver>=550,driver<551 brand=quadro,driver>=550,driver<551 brand=quadrortx,driver>=550,driver<551 brand=nvidiartx,driver>=550,driver<551 brand=vapps,driver>=550,driver<551 brand=vpc,driver>=550,driver<551 brand=vcs,driver>=550,driver<551 brand=vws,driver>=550,driver<551 brand=cloudgaming,driver>=550,driver<551 brand=unknown,driver>=560,driver<561 brand=grid,driver>=560,driver<561 brand=tesla,driver>=560,driver<561 brand=nvidia,driver>=560,driver<561 brand=quadro,driver>=560,driver<561 brand=quadrortx,driver>=560,driver<561 brand=nvidiartx,driver>=560,driver<561 brand=vapps,driver>=560,driver<561 brand=vpc,driver>=560,driver<561 brand=vcs,driver>=560,driver<561 brand=vws,driver>=560,driver<561 brand=cloudgaming,driver>=560,driver<561 brand=unknown,driver>=565,driver<566 brand=grid,driver>=565,driver<566 brand=tesla,driver>=565,driver<566 brand=nvidia,driver>=565,driver<566 brand=quadro,driver>=565,driver<566 brand=quadrortx,driver>=565,driver<566 brand=nvidiartx,driver>=565,driver<566 brand=vapps,driver>=565,driver<566 brand=vpc,driver>=565,driver<566 brand=vcs,driver>=565,driver<566 brand=vws,driver>=565,driver<566 brand=cloudgaming,driver>=565,driver<566
NCCL_VERSION=2.25.1-1
NVIDIA_DRIVER_CAPABILITIES=compute,utility
NVIDIA_PRODUCT_NAME=CUDA
VLLM_USAGE_SOURCE=production-docker-image
CUDA_VERSION=12.8.1
LD_LIBRARY_PATH=/usr/local/cuda/lib64
NCCL_CUMEM_ENABLE=0
PYTORCH_NVML_BASED_CUDA_CHECK=1
TORCHINDUCTOR_COMPILE_THREADS=1
CUDA_MODULE_LOADING=LAZY

🐛 Describe the bug

For some requests to qwen3 coder, I can get responses like this, where the tool calling is not correctly parsed as tool calls:

vllm/vllm-openai   latest      4d3b60090244   2 weeks ago   21.2GB

docker run --runtime nvidia --gpus all --shm-size 32g -it --rm \
    --network=host \
    --ipc=host \
    -v /ssd/share/huggingface:/root/.cache/huggingface \
    --name vllm_qwen3 \
    vllm/vllm-openai:latest \
    --model Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8 \
    --trust-remote-code \
    --host 0.0.0.0 --port 30008 \
    --tensor-parallel-size 4 --data-parallel-size 2 \
    --enable-auto-tool-choice \
    --tool-call-parser qwen3_coder \
    --enable-expert-parallel


ModelResponse(id='chatcmpl-66e83c6c9b2047519d4815483d85dbda', created=1755245218, model='Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8', object='chat.completion', system_fingerprint=None, choices=[Choices(finish_reason='stop', index=0, message=Message(content="Let me check if there might be a base.py file that's not showing up. Since we know it's being imported, let me try to grep for the implementation of BaseService.\n\n<tool_call>\n<function=GrepTool>\n<parameter=pattern>\nclass BaseService\\(\n</parameter>\n<parameter=path>\n.\n</parameter>\n</function>\n</tool_call>", role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}), provider_specific_fields={'stop_reason': None})], usage=Usage(completion_tokens=69, prompt_tokens=9894, total_tokens=9963, completion_tokens_details=None, prompt_tokens_details=None), service_tier=None, prompt_logprobs=None, kv_transfer_params=None)

Before submitting a new issue...

  • Make sure you already searched for relevant issues, and asked the chatbot living at the bottom right corner of the documentation page, which can answer lots of frequently asked questions.

Activity

  1. VivekMalipatel commented on Aug 18, 2025

    @VivekMalipatel

    I have the same issue.

    I am runnign Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8 on vLLM with

        vllm serve Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8 \
          --host 0.0.0.0 \
          --port 8001 \
          --served-model-name o3 \
          --dtype float16 \
          --enable-auto-tool-choice \
          --tool-call-parser qwen3_coder \
          --enable-expert-parallel \
          --enable-chunked-prefill \
          --enable-prefix-caching \
          --max-model-len 65536 \
          --trust-remote-code \
          --pipeline-parallel-size 2 \
          --gpu-memory-utilization 0.90 \
          --api-key test-key
    

    But when I use it for a tool call, it outputs

    I will use the knowledge_search_agent tool to retrieve a list of all documents in your knowledge base.
    <function=knowledge_search_agent>
    <parameter=prompt>
    List all the documents in the user's knowledge base.
    </parameter>
    </function>
    </tool_call>
    

    Its calling the tool but vLLM is not able to pick parse that.

    any fix for this?

  2. avi-nference commented on Aug 19, 2025

    @avi-nference

    I'm facing the same issue when using gptoss-20B model.

  3. Co1lin commented on Aug 19, 2025

    @Co1lin
    Author

    I think I also met with the issue for Qwen3-8B (not coder). It outputs the following content in the "content" field of a message. I think it is a valid tool calling.

    <tool_call>\n{"name": "GrepTool", "arguments": {"pattern": "Plot\\\\.add\\\\(", "path": "seaborn/_core"}}\n</tool_call>
    
  4. killershrimp commented on Aug 19, 2025

    @killershrimp
    Contributor

    could you show some of the prompts + tool descriptions being passed into the engine?

  5. Co1lin commented on Aug 19, 2025

    @Co1lin
    Author

    Sorry I am not able to share the prompts at this time... In my understanding, given the ModelResponse, someone should be able to debug the parser.

  6. sempervictus commented on Aug 21, 2025

    @sempervictus

    This seems to be a problem with all Qwen3 MoE models themselves and its not specific to VLLM - Ollama and Candle-VLLM are experiencing similar things. From what i've gathered so far, because these models use markup language tags internally, they have been trained for specialized processing around <tag>/</tag> markers with the latter sometimes coming back as </tag} breaking whatever parser is receiving that. Probably some fun to be had around injections there but its a bloody mess for standardized tools and even the Qwen3-Coder agent users are experiencing similar things.

    I've a gory MiTM patch for candle-vllm in testing right now which can correct some of this in the stream/response objects but the structural part of making the model aware of tool calls in its schema might take a little bit more work than that since even machinations with chat templates dont quite seem to get this thing resolved.

    Curious to know if you folks come up with a reasonable solution as there's a bit more attention/momentum on this side of the house than in Rust. Will post a link to the PR if testing proves this in any way worth-while.

  7. mondaylord commented on Aug 21, 2025

    @mondaylord
    Contributor

    Same error. The test is fine as below
    {"id":"chatcmpl-37f36888418342ee9a32fb6b0620bb04","object":"chat.completion","created":1755764628,"model":"qwen/qwen3-coder","choices":[{"index":0,"message":{"role":"assistant","content":null,"refusal":null,"annotations":null,"audio":null,"function_call":null,"tool_calls":[{"id":"chatcmpl-tool-692e2aabebb14e658fe48f2c4dba5887","type":"function","function":{"name":"math_calculator","arguments":"{\"operation\": \"add\", \"operand1\": 15, \"operand2\": 27}"}}],"reasoning_content":null},"logprobs":null,"finish_reason":"tool_calls","stop_reason":null}],"service_tier":null,"system_fingerprint":null,"usage":{"prompt_tokens":354,"total_tokens":402,"completion_tokens":48,"prompt_tokens_details":null},"prompt_logprobs":null,"kv_transfer_params":null}

    But sometimes it just returns
    <tool_call> <function=get_current_weather> <parameter=location> Boston </parameter> <parameter=unit> fahrenheit </parameter> </function> </tool_call>
    Seems the parser is not suitable for some outputs?

  8. mondaylord commented on Aug 22, 2025

    @mondaylord
    Contributor

    I think this is related to streaming output, if the stream is false, then tool-call is fine, but it returns <tool_call> tag when streaming is true

  9. bbartels commented on Aug 22, 2025

    @bbartels
    Contributor
  10. Ithanil commented on Aug 22, 2025

    @Ithanil
    Contributor

    I did just see that the tool call parser got updated in the qwen3 repo, might come with some fixes? https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct/commit/9d90cf8fca1bf7b7acca42d3fc9ae694a2194069

    parser + chat template

    Definitely works, exactly how much better I can't say.

  11. mondaylord commented on Aug 27, 2025

    @mondaylord
    Contributor

    I did just see that the tool call parser got updated in the qwen3 repo, might come with some fixes? https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct/commit/9d90cf8fca1bf7b7acca42d3fc9ae694a2194069

    parser + chat template

    Definitely works, exactly how much better I can't say.

    Still failed for streaming case, here is the content and result

    {
        "model": "qwen3-coder",
        "stream": true,
        "stream_options": {
          "include_usage": true
        },
        "messages": [
          {
            "role": "user",
            "content": "What is the weather like in Boston in fahrenheit?"
          }
        ],
        "tools": [
          {
            "type": "function",
            "function": {
              "name": "get_current_weather",
              "description": "Get the current weather in a given location",
              "strict": true,
              "parameters": {
                "type": "object",
                "properties": {
                  "location": {
                    "type": "string",
                    "description": "The city and state, e.g. San Francisco, CA"
                  },
                  "unit": {
                    "type": "string",
                    "enum": [
                      "celsius",
                      "fahrenheit"
                    ]
                  }
                },
                "additionalProperties": false,
                "required": [
                  "location",
                  "unit"
                ]
              }
            }
          }
        ],
        "max_tokens": 235808,
        "temperature": 1,
        "top_p": 1,
        "frequency_penalty": 0,
        "presence_penalty": 0,
        "seed": null,
        "min_p": 0,
        "repetition_penalty": 1
      }
    

    Result:

    <tool_call>
    <function=get_current_weather>
    <parameter=location>
    Boston
    </parameter>
    <parameter=unit>
    fahrenheit
    </parameter>
    </function>
    </tool_call>
    
  12. mondaylord commented on Aug 28, 2025

    @mondaylord
    Contributor

    I did just see that the tool call parser got updated in the qwen3 repo, might come with some fixes? https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct/commit/9d90cf8fca1bf7b7acca42d3fc9ae694a2194069

    parser + chat template
    Definitely works, exactly how much better I can't say.

    Still failed for streaming case, here is the content and result

    {
        "model": "qwen3-coder",
        "stream": true,
        "stream_options": {
          "include_usage": true
        },
        "messages": [
          {
            "role": "user",
            "content": "What is the weather like in Boston in fahrenheit?"
          }
        ],
        "tools": [
          {
            "type": "function",
            "function": {
              "name": "get_current_weather",
              "description": "Get the current weather in a given location",
              "strict": true,
              "parameters": {
                "type": "object",
                "properties": {
                  "location": {
                    "type": "string",
                    "description": "The city and state, e.g. San Francisco, CA"
                  },
                  "unit": {
                    "type": "string",
                    "enum": [
                      "celsius",
                      "fahrenheit"
                    ]
                  }
                },
                "additionalProperties": false,
                "required": [
                  "location",
                  "unit"
                ]
              }
            }
          }
        ],
        "max_tokens": 235808,
        "temperature": 1,
        "top_p": 1,
        "frequency_penalty": 0,
        "presence_penalty": 0,
        "seed": null,
        "min_p": 0,
        "repetition_penalty": 1
      }
    

    Result:

    <tool_call>
    <function=get_current_weather>
    <parameter=location>
    Boston
    </parameter>
    <parameter=unit>
    fahrenheit
    </parameter>
    </function>
    </tool_call>
    

    Found the reason, no reasoning-parser in deployment stage, then everything works fine

  13. dotmobo commented on Sep 5, 2025

    @dotmobo

    same bug for me

  14. mdierolf commented on Sep 17, 2025

    @mdierolf

    If there is a way to make it work fine, please explain.

    Found the reason, no reasoning-parser in deployment stage, then everything works fine

  15. andrea-tomassi commented on Sep 18, 2025

    @andrea-tomassi

    If there is a way to make it work fine, please explain.

    Found the reason, no reasoning-parser in deployment stage, then everything works fine

    --model Intel/Qwen3-Coder-30B-A3B-Instruct-int4-AutoRound \
    --trust-remote-code \
    --enable-chunked-prefill \
    --max-model-len 24576 \
    --max-num-batched-tokens 8192 \
    --gpu-memory-utilization 0.9 \
    --enable-auto-tool-choice \
    --tool-call-parser qwen3_coder \
    --max-num-seqs 2 \
    

    this seems to be is working for me

  16. chaunceyjiang commented on Sep 19, 2025

    @chaunceyjiang
    Contributor
  17. github-actions commented on Dec 19, 2025

    @github-actions

    This issue has been automatically marked as stale because it has not had any activity within 90 days. It will be automatically closed if no further activity occurs within 30 days. Leave a comment if you feel this issue should remain open. Thank you!

  18. github-actions commented on Jan 19, 2026

    @github-actions

    This issue has been automatically closed due to inactivity. Please feel free to reopen if you feel it is still relevant. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingstaleOver 90 days of inactivitytool-calling

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions