Почему ваш Qwen 3.5 отказывается звонить?
Вы настраиваете агента, пишете красивый системный промпт, описываете инструменты — а модель молчит. Или, что хуже, начинает галлюцинировать, выдавая XML-мусор вместо четкого вызова функции. Знакомая история? На 11 апреля 2026 года эта проблема живее всех живых, даже несмотря на выход Qwen 4.0. Многие команды остаются на Qwen 3.5 из-за проверенной стабильности и отлаженных пайплайнов, но с tool calling тут настоящая лотерея.
Корень зла — в чат-шаблоне. Том самом Jinja-файле, который превращает ваш диалог в последовательность токенов. Официальный шаблон от Hugging Face содержит тонкую ошибку, которая ломает логику нативных тегов модели. А без понимания этих тегов любая настройка превращается в стрельбу из пушки по воробьям.
1
Тег : нераскрытая карта модели
Qwen 3.5 — не глупая модель. У нее есть внутренний механизм рассуждений, который она обозначает специальными тегами
Вот как это выглядит в сыром выводе токенизатора:
Пользователь просит узнать погоду. У меня есть инструмент get_weather.
Нужно вызвать его с параметром location: "Москва".
{"name": "get_weather", "arguments": {"location": "Москва"}}
Проблема в том, что большинство фреймворков и клиентов (взгляните на баги парсера LM Studio) считают все, что между
Важно: На 11.04.2026 некоторые квантования Qwen 3.5 (особенно созданные старыми скриптами) могут вообще игнорировать теги
2 Сломанный шаблон vs исправленный: где собака порылась
Официальный шаблон для Qwen 3.5 делает грубейшую ошибку: он обрабатывает теги
{# Старый, сломанный подход #}
{% for message in messages %}
{% if message['role'] == 'system' %}
{{ '<|im_start|>system\n' + message['content'] + '<|im_end|>\n' }}
{% else %}
{{ '<|im_start|>' + message['role'] + '\n' + message['content'] + '<|im_end|>\n' }}
{% endif %}
{% endfor %}
Видите? Нет никакого разделения. Модель генерирует
3 Jinja-шаблон, который работает. Берите и пользуйтесь
Вот исправленная версия. Она делает одну простую вещь: отделяет reasoning-блок от финального ответа модели, используя те же нативные теги, которые понимает Qwen 3.5.
{# Исправленный шаблон для Qwen 3.5 Tool Calling (актуален на 11.04.2026) #}
{% for message in messages %}
{% if message['role'] == 'system' %}
{{ '<|im_start|>system\n' + message['content'] | trim + '<|im_end|>\n' }}
{% elif message['role'] == 'user' %}
{{ '<|im_start|>user\n' + message['content'] | trim + '<|im_end|>\n' }}
{% elif message['role'] == 'assistant' %}
{% set content = message['content'] | trim %}
{% if '' in content and ' ' in content %}
{# Разделяем reasoning и финальный ответ/action #}
{% set think_end = content.find('') + 9 %}
{{ '<|im_start|>assistant\n' + content[:think_end] + '<|im_end|>\n' }}
{{ '<|im_start|>assistant\n' + content[think_end:] | trim + '<|im_end|>\n' }}
{% else %}
{{ '<|im_start|>assistant\n' + content + '<|im_end|>\n' }}
{% endif %}
{% elif message['role'] == 'tool' %}
{{ '<|im_start|>tool\n' + message['content'] | trim + '<|im_end|>\n' }}
{% endif %}
{% endfor %}
{% if add_generation_prompt %}
{{ '<|im_start|>assistant\n' }}
{% endif %}
Что изменилось? Когда шаблон видит сообщение от assistant, он проверяет, содержит ли оно теги
Этот шаблон решает не только проблему tool calling. Он также фиксит баги с повторной обработкой промптов, которые убивают производительность в llama.cpp и подобных бэкендах. Один файл — и десятки часов отладки.
4 Как встроить этот шаблон в ваш проект
Не нужно пересобирать мир. Если вы используете Hugging Face Transformers (актуальная версия на 11.04.2026 — 4.45.0), просто установите этот шаблон для токенизатора:
from transformers import AutoTokenizer
# Загружаем модель и токенизатор
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3.5-7B-Instruct", trust_remote_code=True)
# Ваш исправленный шаблон в виде строки
correct_chat_template = """
{# Вставьте сюда Jinja-шаблон из шага 3 #}
"""
# Устанавливаем его
tokenizer.chat_template = correct_chat_template
# Теперь tokenizer.apply_chat_template будет работать правильно
messages = [
{"role": "system", "content": "Ты полезный ассистент с инструментами."},
{"role": "user", "content": "Какая погода в Берлине?"}
]
input_ids = tokenizer.apply_chat_template(messages, return_tensors="pt")
Для Ollama, llama.cpp или LM Studio процесс сложнее — нужно править конфигурационные файлы модели. Но принцип тот же: заменить стандартный шаблон на исправленный. В гайде по LM Studio есть детали.
А другие модели? Они тоже так больны?
Qwen 3.5 — не уникальна в своих проблемах. Механизм reasoning-тегов есть у многих современных моделей. Например, Minimax M2.1 использует похожий подход, но с другими тегами. Близкий родственник, Qwen 2.5 27B, страдает от похожих симптомов. Даже быстрые модели вроде Step 3.5 Flash могут галлюцинировать tool calls без правильного шаблона.
Альтернатива? Можно перейти на модели с нативным support tool calling API, как GPT-4o или Claude 3.7. Но это значит платить за API, терять контроль над данными и зависеть от чужой инфраструктуры. Наш исправленный шаблон дает бесплатный и полный контроль.
Кому стоит заморачиваться с этим шаблоном?
Это решение — для инженеров, которые уже увязли в Qwen 3.5 по уши. У вас есть прод-окружение, агенты на продакшене, и переезд на другую модель стоит как минимум месяц работы. Вы готовы потратить час на настройку, чтобы получить стабильный tool calling.
Не тратьте время, если:
- Вы только начинаете проект и можете выбрать любую модель. Возьмите что-то с менее кривым чат-шаблоном.
- Вам не нужны инструменты. Тогда баг с
вас не заденет. - Вы работаете исключительно через официальный API от Alibaba Cloud. Там шаблон уже исправлен (надеюсь).
Всем остальным — сохраняйте статью в закладки. Этот шаблон сэкономит вам недели нервов. И помните: в мире opensource-моделей стабильность — это не данность, а результат точечных исправлений. Иногда одно изменение в 20 строк кода оживляет целый стек технологий.