Когда код молчит, а консоль кричит: что не так с вашим Qwen3.5?
Вы только что загрузили свежую квантованную версию Qwen3.5-Coder через Unsloth, запускаете модель в llama.cpp и... бац. Вместо приветствия - красная ошибка:
error: unknown filter items: [{"id": "...", "object": "..."}]
Модель отказывается стартовать. В логах - непонятные JSON-структуры, которые llama.cpp категорически не хочет переваривать. Знакомо? Добро пожаловать в клуб.
Важно: Эта ошибка появилась в последних версиях llama.cpp (на февраль 2026) и связана с изменениями в обработке системных промптов для моделей семейства Qwen. Особенно часто встречается при использовании Unsloth для экспорта моделей в GGUF.
Корень зла: почему llama.cpp не понимает ваш шаблон
Проблема не в вашей модели. Не в железе. И даже не в кривых руках (хотя последнее всегда под вопросом). Всё дело в том, как современные LLM-инфраструктуры общаются между собой.
Unsloth (на февраль 2026 - версия 0.4.8+) при экспорте моделей в GGUF формат добавляет метаданные о фильтрах и системных промптах. Эти метаданные используют новый формат, который старые версии llama.cpp просто не распознают. Получается классический конфликт версий: инструмент для экспорта бежит впереди паровоза, а движок для инференса отстаёт.
Особенно страдают модели Qwen3.5-Coder и Qwen3.5-Math - те, где активно используются tool calling и системные инструкции. Обычный Qwen3.5-Instruct тоже может попасть под раздачу, если в шаблоне есть сложные JSON-структуры.
Что на самом деле происходит в коде
Заглянем под капот. Когда llama.cpp загружает GGUF файл, он парсит метаданные в разделе general.instruction_template. Для Qwen моделей ожидается простой строковый шаблон вроде qwen или qwen2. Но Unsloth кладёт туда вот такое:
{
"template_name": "qwen",
"system_prompt": "You are a helpful assistant",
"filters": [
{
"id": "system_filter",
"object": "conversation.system"
}
]
}
Именно этот filters массив и вызывает ошибку unknown filter items. Llama.cpp версий до 2025 года просто не знал о таком формате. Даже в 2026 году не все сборки поддерживают этот функционал.
Быстрое решение: патчим GGUF на лету
Не нужно пересобирать llama.cpp. Не нужно катить модель обратно в Unsloth. Всё решается одной утилитой и парой команд.
1 Устанавливаем GGUF-редактор
Для работы с GGUF файлами понадобится gguf - Python библиотека от создателей llama.cpp. Ставим через pip:
pip install gguf
Если не работает (бывает), качаем напрямую из репозитория:
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
pip install -e .
2 Смотрим, что сломалось
Сначала проверим, что именно не так с вашим файлом. Запускаем скрипт диагностики:
import gguf
gguf_file = "your-model.Q4_K_M.gguf"
reader = gguf.GGUFReader(gguf_file, "r")
# Ищем проблемный параметр
for field in reader.fields:
if field.name == "general.instruction_template":
print(f"Found instruction_template: {field.parts[field.data[0]]}")
break
Если выводит JSON вместо простой строки - вот он, корень проблемы.
3 Чиним шаблон в три строки
Создаём файл fix_gguf.py со следующим содержимым:
#!/usr/bin/env python3
import gguf
import json
import sys
if len(sys.argv) != 3:
print(f"Usage: {sys.argv[0]} ")
sys.exit(1)
input_file = sys.argv[1]
output_file = sys.argv[2]
print(f"Reading {input_file}...")
reader = gguf.GGUFReader(input_file, "r")
writer = gguf.GGUFWriter(output_file, "auto")
# Копируем все поля, кроме проблемного
for field in reader.fields:
if field.name == "general.instruction_template":
# Вместо JSON оставляем просто 'qwen'
print("Fixing instruction_template...")
writer.add_string("general.instruction_template", "qwen")
else:
# Копируем остальные поля как есть
writer.add_field(field)
print(f"Writing fixed model to {output_file}...")
writer.write_header_to_file()
writer.write_kv_data_to_file()
writer.write_tensors_to_file()
print("Done! Model fixed successfully.")
Запускаем:
python fix_gguf.py qwen3.5-coder-q4.gguf qwen3.5-coder-q4-fixed.gguf
Готово. Новая модель будет работать в любой версии llama.cpp. Потеряете ли вы что-то? Теоретически - расширенные системные промпты. Практически - 99% пользователей их не используют.
Альтернативный путь: правим llama.cpp
Если вы фанат собирать всё из исходников (или просто хотите поддержать новые фичи Unsloth), вот как обновить llama.cpp:
- Клонируем свежую версию:
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
- Переключаемся на ветку с поддержкой новых шаблонов:
git fetch origin
# На февраль 2026 актуальная ветка - 'experimental/templates'
git checkout experimental/templates
- Собираем с поддержкой CUDA/Metal (в зависимости от железа):
# Для NVIDIA
make -j LLAMA_CUDA=1
# Для Apple Silicon
make -j LLAMA_METAL=1
# Для CPU
make -j
Обновлённая версия понимает JSON в instruction_template и корректно обрабатывает фильтры. Но будьте готовы к тому, что экспериментальная ветка может содержать другие баги. Не для продакшена.
Глубокое погружение: что такое эти фильтры и зачем они нужны
Чтобы не просто чинить ошибку, а понимать, что чините, давайте разберёмся с архитектурой.
Фильтры в контексте Unsloth и llama.cpp - это механизм для управления системными сообщениями. В традиционном подходе системный промпт был простой строкой: "You are a helpful assistant". Но современные модели (особенно те, что обучены на tool calling) требуют более сложной логики.
| Тип фильтра | Назначение | Пример |
|---|---|---|
| system_filter | Обработка системных сообщений | {"id": "system", "object": "conversation.system"} |
| tool_filter | Управление tool calls | {"id": "tools", "object": "conversation.tools"} |
| context_filter | Контроль длины контекста | {"id": "context", "object": "conversation.context"} |
Проблема в том, что эта система родилась в экосистеме Unsloth и пока не стандартизирована. Llama.cpp её не знает - отсюда и ошибка. Похожие проблемы уже всплывали с JSON-парсером в llama.cpp, когда сломалась поддержка Qwen3 Next Coder.
Частые ошибки и как их избежать
Даже после фикса шаблона могут остаться подводные камни. Вот самые частые:
1. "Модель работает, но tool calling сломан"
Если после фикса модель запускается, но не отвечает на запросы с инструментами - проблема в шаблоне диалога. Для Qwen3.5-Coder нужен специальный формат:
# НЕПРАВИЛЬНО
messages = [
{"role": "user", "content": "Напиши код на Python"}
]
# ПРАВИЛЬНО для Qwen3.5-Coder
messages = [
{"role": "system", "content": "You are a coding assistant"},
{"role": "user", "content": "Напиши функцию на Python"}
]
2. "Контекст обрезается раньше времени"
Особенно актуально для больших моделей вроде Qwen3.5-397B. Проверьте параметры контекста при конвертации в GGUF. В Unsloth используйте флаг:
--context-length 8192 # или больше
3. "Разные квантования ведут себя по-разному"
Q4_K_M может работать, а Q8_0 - падать. Это известная проблема с некоторыми версиями llama.cpp. Решение: использовать проверенные квантования или обновить llama.cpp до последней стабильной версии. Подробнее о выборе квантований читайте в нашем гайде по Qwen3-Coder.
Профилактика: как не попадать в эту ловушку снова
- Используйте проверенные конвейеры: Если работаете с Unsloth, сразу экспортируйте модели с флагом
--simple-template, если он доступен - Держите llama.cpp в актуальном состоянии: Регулярно обновляйтесь, особенно если используете новые модели
- Тестируйте перед долгими вычислениями: Запустите модель на простом промпте сразу после конвертации
- Сохраняйте оригинальные веса: Всегда оставляйте оригинальную модель в формате PyTorch/Safetensors - на случай, если понадобится переконвертировать
Совет от бывалого: Создайте себе скрипт-чекер, который автоматически проверяет GGUF файлы на проблемные метаданные. 10 минут на написание сэкономят часы отладки в будущем.
Будущее шаблонов в llama.cpp: что нас ждёт
Ситуация с шаблонами напоминает историю с расчётом key_gdiff - сначала баг, потом фича, потом стандарт. К февралю 2026 года в основной ветке llama.cpp уже есть поддержка расширенных шаблонов, но она пока экспериментальная.
Что изменится в ближайшие месяцы:
- Стандартизация формата: JSON-шаблоны станут официальной частью GGUF спецификации
- Обратная совместимость: Llama.cpp научится игнорировать неизвестные фильтры вместо падения
- Универсальные конвертеры: Появятся инструменты для миграции между разными форматами шаблонов
Пока этого не произошло, наш фикс-скрипт - ваш лучший друг. Сохраните его где-нибудь, потому что с выходом Qwen4.0 история наверняка повторится.
А если хотите глубоко разобраться в оптимизации локальных моделей, посмотрите гайд по настройке долгой памяти для LLM - там много полезного про работу с контекстом и шаблонами.
Теперь вы знаете не только как чинить ошибку Unknown filter items, но и почему она возникает. И главное - как сделать так, чтобы она больше никогда не мешала вашим экспериментам с локальными моделями. Код вышел - модель заработала. Что может быть лучше?