Проблема: модель внезапно обрывается на полуслове
Если вы запускаете GLM-4.5-Air на MacBook с Apple Silicon (M1/M2/M3) через llama.cpp или mlx_lm, вы могли столкнуться с раздражающим багом: модель внезапно прекращает генерацию, выдавая токен EOS (End of Sequence) в совершенно неподходящий момент. Вы задаёте сложный вопрос, модель начинает отвечать, но через 2-3 предложения... обрыв.
Это НЕ проблема с памятью, температурой или контекстом. Это специфический баг в обработке EOS-токена GLM-4.5-Air на Apple Silicon, который проявляется в популярных фреймворках.
Проблема особенно досадна, если вы используете GLM-4.5-Air для серьёзных задач — например, для обработки длинных PDF или сложных вычислений. Вместо полного ответа вы получаете обрывки.
Причины бага: что происходит под капотом
GLM-4.5-Air использует нестандартный формат токенизации, и его EOS-токен (идентификатор 151643) иногда интерпретируется системами инференса на Apple Silicon некорректно. Особенно это проявляется при:
- Использовании 2-3 битных квантований (подробнее в нашем гайде по квантованиям)
- Запуске через llama.cpp с Metal backend
- Использовании mlx_lm с float16 precision
- Попытках генерации длинных ответов (более 512 токенов)
Решение 1: патч для llama.cpp (самый надёжный способ)
Если вы используете llama.cpp, самый эффективный способ — внести небольшое изменение в код, которое заставит игнорировать проблемный EOS-токен в определённых контекстах.
1Скачиваем и собираем llama.cpp с патчем
Сначала убедитесь, что у вас установлены необходимые зависимости:
brew install cmake ninja
cd ~
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
mkdir build && cd build2Применяем патч к common.cpp
Найдите файл common.cpp в директории ~/llama.cpp и добавьте следующую проверку в функцию, обрабатывающую EOS:
// Примерное место для патча в common.cpp
// Ищем функцию bool has_eos(const llama_token * tokens, int n_tokens)
// Или аналогичную логику обработки EOS
// Добавляем проверку для GLM-4.5-Air
if (model_path.find("glm-4.5-air") != std::string::npos) {
// Игнорируем EOS в середине генерации если контекст меньше 200 токенов
if (n_tokens_generated < 200) {
return false; // Не считать это за EOS
}
}Важно: точное место патча зависит от версии llama.cpp. Проверьте актуальный код на GitHub перед внесением изменений.
3Собираем с поддержкой Metal
cmake -DLLAMA_METAL=ON ..
cmake --build . --config ReleaseРешение 2: обходной манёвр в mlx_lm
Если вы предпочитаете mlx_lm (нативный фреймворк для Apple Silicon), решение проще. Нужно просто переопределить EOS-токен в настройках генерации:
import mlx_lm
from mlx_lm.utils import generate
# Загружаем модель
model, tokenizer = mlx_lm.load("glm-4.5-air-q4_0")
# Промпт
prompt = "Объясни квантовую механику простыми словами:"
# Генерируем с кастомным eos_token_id
# Используем токен, который НЕ 151643
response = generate(
model,
tokenizer,
prompt=prompt,
max_tokens=1024,
temp=0.7,
eos_token_id=2, # Используем стандартный eos_token
verbose=True
)
print(response)tokenizer.eos_token_id.Решение 3: временный workaround через бэктики
Если вы не хотите трогать код, есть несколько обходных путей:
Вариант A: Использовать более стабильную модель
Попробуйте GLM-4-9B или другие версии. У них меньше проблем с EOS на Apple Silicon. Хотя GLM-4.5-Air мощнее, иногда стабильность важнее.
Вариант B: Разбивать запросы на части
Если вам нужен длинный ответ, разбейте задачу:
# Вместо одного длинного запроса
# "Напиши подробное руководство по Python на 5000 слов"
# Разбиваем на части
запросы = [
"Напиши введение в Python",
"Расскажи про основные типы данных",
"Объясни функции и классы",
"..."
]Таблица сравнения методов
| Метод | Сложность | Эффективность | Рекомендация |
|---|---|---|---|
| Патч llama.cpp | Высокая | 95% | Для продвинутых пользователей |
| Обход в mlx_lm | Средняя | 85% | Для пользователей mlx_lm |
| Workaround с бэктиками | Низкая | 70% | Быстрое временное решение |
| Смена модели | Очень низкая | 100% | Если сроки горят |
Частые ошибки и как их избежать
Ошибка 1: "Патч сломал сборку" — убедитесь, что вы редактируете правильную версию файла. Лучше сделать бэкап.
Ошибка 2: "Модель теперь генерирует бесконечно" — вы слишком агрессивно отключили EOS. Добавьте ограничение по max_tokens.
Ошибка 3: "Не работает с квантованными версиями" — некоторые квантования усугубляют проблему. Попробуйте разные уровни (q4_0, q5_0, q8_0).
Если у вас возникают другие проблемы с локальными LLM, рекомендую наш практический гайд по избеганию основных ошибок.
FAQ: ответы на частые вопросы
В: Этот баг есть только на MacBook?
О: Нет, но на Apple Silicon он проявляется чаще из-за особенностей Metal backend и оптимизаций для нейронного движка. На Linux с CUDA проблема тоже есть, но реже.
В: Zephyr и другие модели тоже страдают?
О: Нет, это специфично для GLM-4.5-Air и иногда для GLM-4-9B. Другие модели обычно используют стандартные EOS-токены.
В: Когда будет официальный фикс?
О: Сообщество llama.cpp уже в курсе проблемы. Скорее всего, в следующих версиях добавят workaround. Следите за обновлениями репозитория.
В: А если использовать Vulkan вместо Metal?
О: Интересная мысль! Производительность Vulkan на macOS может отличаться. У нас есть отдельная статья про Vulkan против CUDA, но для Metal/Vulkan сравнение ещё предстоит сделать.
Профилактика на будущее
Чтобы избежать подобных проблем с другими моделями:
- Всегда проверяйте EOS-токен модели после загрузки
- Тестируйте генерацию на коротких и длинных промптах
- Используйте последние версии llama.cpp/mlx_lm
- Читайте Issues на GitHub репозиториях моделей
Помните, что проблемы с преждевременным завершением — не редкость в мире LLM. Например, у SOTA-моделей вроде GLM 4.7 и Kimi K2 тоже есть свои особенности.
Заключение
Баг с преждевременным EOS в GLM-4.5-Air на MacBook — досадная, но решаемая проблема. В зависимости от вашего уровня комфорта с кодом, вы можете выбрать патч, workaround или временное решение со сменой модели.
Главное — не отчаиваться. Локальные LLM на Apple Silicon — мощный инструмент, и такие временные трудности — цена за возможность работать с передовыми моделями на своём ноутбуке. Удачи в экспериментах!