VLLM chat template / tool calling issue
#18
by skyqu - opened
I was having trouble with tool calling in VLLM 0.19 - "no tool calling output detected".
When serving via vLLM's OpenAI-compatible endpoint, tool role messages have their content field passed as a list of content blocks (e.g. [{"type": "text", "text": "..."}]) rather than a plain string.
This falls through to the branch that re-renders tool schemas via tool_to_json(), so the model sees signatures instead of the actual tool output.
Also, visible_text() doesn't guard against None content, which can show as the literal string "None" in the final prompt.
This patch fixes it for me, not sure if it will be helpful to others:
--- <unnamed>
+++ <unnamed>
@@ -32,7 +32,8 @@
For each function call, output the function name and arguments within the following XML format:
<tool_call>{function-name}<arg_key>{arg-key-1}</arg_key><arg_value>{arg-value-1}</arg_value><arg_key>{arg-key-2}</arg_key><arg_value>{arg-value-2}</arg_value>...</tool_call>{%- endif -%}
{%- macro visible_text(content) -%}
- {%- if content is string -%}
+ {%- if content is none -%}
+ {%- elif content is string -%}
{{- content }}
{%- elif content is iterable and content is not mapping -%}
{%- for item in content -%}
@@ -94,20 +95,32 @@
{%- endif %}
{%- if m.content is string -%}
{{- '<tool_response>' + m.content + '</tool_response>' -}}
+{%- elif m.content is iterable and m.content is not mapping -%}
+ {%- set ns_tool_content = namespace(text='') -%}
+ {%- for part in m.content -%}
+ {%- if part is mapping and part.type == 'text' -%}
+ {%- set ns_tool_content.text = ns_tool_content.text + part.text -%}
+ {%- endif -%}
+ {%- endfor -%}
+ {%- if ns_tool_content.text -%}
+ {{- '<tool_response>' + ns_tool_content.text + '</tool_response>' -}}
+ {%- else -%}
+ {{- '<tool_response><tools>\n' -}}
+ {%- for tr in m.content -%}
+ {%- for tool in tools -%}
+ {%- if 'function' in tool -%}
+ {%- set tool = tool['function'] -%}
+ {%- endif -%}
+ {%- if tool.name == tr.name -%}
+ {{- tool_to_json(tool) + '\n' -}}
+ {%- endif -%}
+ {%- endfor -%}
+ {%- endfor -%}
+ {{- '</tools></tool_response>' -}}
+ {%- endif -%}
{%- else -%}
- {{- '<tool_response><tools>\n' -}}
- {% for tr in m.content %}
- {%- for tool in tools -%}
- {%- if 'function' in tool -%}
- {%- set tool = tool['function'] -%}
- {%- endif -%}
- {%- if tool.name == tr.name -%}
- {{- tool_to_json(tool) + '\n' -}}
- {%- endif -%}
- {%- endfor -%}
- {%- endfor -%}
- {{- '</tools></tool_response>' -}}
-{% endif -%}
+ {{- '<tool_response>' + m.content | string + '</tool_response>' -}}
+{%- endif -%}
{%- elif m.role == 'system' -%}
<|system|>{{ visible_text(m.content) }}
{%- endif -%}
skyqu changed discussion title from VLLM chat template issue to VLLM chat template / tool calling issue