vllm-tool-calling-guide / chat_templates /hermes3_tool_calling.j2
Joshua Odmark
Initial release: VLLM tool calling guide for open source models
634c038
{# ============================================================================ #}
{# Hermes-3 Tool Calling Chat Template (ChatML + XML) #}
{# ============================================================================ #}
{# #}
{# Use this template with VLLM when you need custom tool call handling. #}
{# For most use cases, VLLM's built-in templates work fine. #}
{# #}
{# Usage with VLLM: #}
{# --chat-template chat_templates/hermes3_tool_calling.j2 #}
{# #}
{# Format: #}
{# <|im_start|>system ... <|im_end|> (ChatML system message) #}
{# <|im_start|>assistant #}
{# <tool_call>{"name": "...", "arguments": {...}}</tool_call> #}
{# <|im_end|> #}
{# <|im_start|>tool #}
{# <tool_response>...result...</tool_response> #}
{# <|im_end|> #}
{# ============================================================================ #}
{# ---- Safe defaults: use default(..., true) so None -> fallback ---- #}
{% set _messages = messages | default([], true) %}
{% set _tools = tools | default([], true) %}
{% set _add_gen = add_generation_prompt | default(true, true) %}
<|im_start|>system
You are a function-calling AI model. If tools are provided in <tools></tools>, you may call them to help the user.
Return tool calls inside <tool_call></tool_call> blocks. Return tool outputs inside <tool_response></tool_response> blocks.
{# ---- Tools inventory (only if non-empty) ---- #}
{% if (_tools | length) > 0 %}
Here are the available tools:
<tools>
{{ _tools | tojson }}
</tools>
{% endif %}
<|im_end|>
{# ---- Prior turns ---- #}
{% for m in _messages %}
{% set role = (m.role | default('user', true)) %}
{# User/system turns, or assistant turns WITHOUT tool_calls #}
{% if role in ['system','user'] or (role == 'assistant' and not (m.tool_calls is defined and m.tool_calls)) %}
<|im_start|>{{ role }}
{{ m.content | default('', true) }}<|im_end|>
{# Assistant turn WITH tool_calls: re-emit as Hermes <tool_call> blocks #}
{% elif role == 'assistant' and (m.tool_calls is defined and m.tool_calls) %}
<|im_start|>assistant
{% for tc in m.tool_calls %}
<tool_call>
{% set call = (tc.function if tc.function is defined else tc) %}
{"name":"{{ call.name }}"{% if call.arguments is defined %}, "arguments": {% if call.arguments is string %}{{ call.arguments }}{% else %}{{ call.arguments | tojson }}{% endif %}{% endif %}}
</tool_call>
{% endfor %}
<|im_end|>
{# Tool responses #}
{% elif role == 'tool' %}
<|im_start|>tool
<tool_response>
{{ m.content | default('', true) }}
</tool_response>
<|im_end|>
{% endif %}
{% endfor %}
{# ---- Generation prompt for assistant ---- #}
{% if _add_gen %}
<|im_start|>assistant
{% endif %}