Диагностика: симптом → причина → решение
Локальный инференс падает паттернами. Одни и те же дюжины симптомов объясняют почти каждый запрос о помощи, и у каждого скучная причина и двухминутный фикс. Просканируйте таблицу, примените фикс, затем прочитайте числа, чтобы подтвердить, что вы реально починены.
Диагностическая таблица
| Симптом | Вероятная причина | Фикс |
|---|---|---|
Вывод содержит токены ролей (user:, `< |
im_start | >`) |
| Мгновенный пустой ответ | Шаблон рендерит «законченный» чат или неверный токен EOS | Почините шаблон; проверьте EOS: промптинг |
| Повторяет ваш вопрос вместо ответа | Базовая модель, а не instruct | Используйте instruct/чат-GGUF |
| Не хватает памяти при загрузке | Веса + квант превышают VRAM | Квант поменьше или модель поменьше: математика VRAM |
| Не хватает памяти посреди генерации | KV-кэш вырастает за запас | Короче контекст, KV-кэш q8_0: KV-кэш |
| 1–3 tok/s при наличии GPU | Слои всё ещё на CPU | Полный оффлоад (n_gpu_layers): параметры движка |
| Медленный первый токен, быстрый стрим после | Ограничено префиллом: очень длинные промпты | Короче промпты, батч, быстрее префилл: скорость |
| Бесконечные повторы, циклы фраз | Сэмплер слишком мягкий, штрафы выключены | temp ≤ 0.8, repeat_penalty 1.05–1.1: сэмплирование |
| Вывод на корейском — бред или коряво | Модель слаба в корейском | Мультиязычные семейства (Qwen, Gemma): семейства моделей |
| Вывод обрезан посреди предложения | Окно контекста заполнено или max_tokens мал | Подрежьте контекст или поднимите лимит вывода |
| Невалидный JSON от хорошей модели | Свободное сэмплирование | Ограниченное декодирование: структурированный вывод |
| Модель игнорирует ваши инструкции | Потерянные в середине на длинных промптах | Цель первой, полезная нагрузка последней, повторите просьбу: промптинг |
| Краш или coredump при загрузке | Повреждённая загрузка | Проверьте контрольную сумму, скачайте заново |
Читайте по симптомам, а не по причинам: сопоставьте то, что видите, примените фикс, измерьте снова. Большинство репортов «моя модель сломана» заканчиваются на строках 1, 2 или 6.
Пятиминутный pre-flight
Перед любой глубокой отладкой соберите факты:
nvidia-smi --query-gpu=name,memory.total,memory.used --format=csv # GPU + VRAM
ls -lh model.gguf # размер против VRAM
llama-server --version # сборка движка
Если файл модели больше свободного VRAM, строка 4 — ваш ответ, и никакой флаг вас не спасёт. Если memory.used стабильно лезет вверх во время генерации, это KV-кэш, а не утечка.
Как выглядит норма
Прежде чем дебажить производительность, знайте порядок величин. Скорость декодирования модели 7–8B Q4_K_M, батч 1:
| Железо | Декодирование tok/s |
|---|---|
| Средняя GPU (класс RTX 3060/4060) | 30–60 |
| Высшая GPU (класс RTX 3090/4090) | 100–150 |
| Apple M-серии (единая память) | 20–40 |
| Только CPU (современные 8 ядер) | 3–8 |
Две формулы объясняют большую часть этого:
decode tok/s ≈ пропускная способность памяти (GB/s) ÷ размер модели (GB)
нужно VRAM ≈ веса + KV-кэш + 1–2 GB накладных
Квант 7B на 4.5 GB на карте 288 GB/s теоретически упирается около 64 tok/s; ждите ~45–55 реальных. Если вы в пределах 2× от таблицы, ваше железо — не баг.
Время до первого токена (TTFT) должно быть сильно меньше секунды для коротких промптов; оно растёт с длиной промпта, делённой на пропускную способность префилла (которая бежит в 10–100× скорости декодирования). Промпт на 10k токенов, занимающий 20 с до первого токена, ограничен префиллом, а не сломан.
Бухгалтерия VRAM: если веса загрузились нормально, но OOM приходит позже, это KV-кэш или длина контекста, а не квант — KV-кэш.
Воркфлоу: меняйте одну переменную
Баги прячутся, когда вы меняете две вещи сразу. Изолируйте по цепочке — модель → движок → конфиг → промпт:
- Базовая линия. Известно-хорошая модель, известно-хороший движок, дефолтные флаги. Чат работает? Значит, стек в порядке.
- Смените модель (тот же движок, те же флаги). Сломалось? Это файл или его шаблон.
- Смените движок (та же модель). Сломалось? Баг движка или перевод флагов.
- Бисекция флагов. Верните дефолты, добавляйте флаги по одному, пока не сломается.
- Дампните отрендеренный промпт. Когда вывод странный-но-работающий, отрендеренный шаблон — где живёт истина.
Ведите заметки по ходу — «работает при temp 0.8, ломается с min_p 0.2» — это диагноз; «пробовал разное, всё плохо» — нет.
Как просить о помощи хорошо
Хороший пост о помощи — лабораторный отчёт. Включите:
- Файл модели: точное имя, квант и источник (
qwen2.5-7b-instruct-q4_k_m.gguf, какой репозиторий). - Движок и версия: дата сборки llama.cpp, версия Ollama, релиз vLLM — движки меняются еженедельно.
- Точные флаги или API-вызов: вся командная строка или тело запроса, а не пересказ.
- Железо: GPU + VRAM (или Mac + RAM), CPU, если он несёт слои.
- Наблюдаемые числа: tok/s, TTFT, использованный VRAM и точный текст ошибки, если есть.
- Что вы уже пробовали и что изменилось в результате.
Скелет для копипасты:
Модель: qwen2.5-7b-instruct-q4_k_m.gguf (репозиторий bartowski)
Движок: llama.cpp b4321 (llama-server)
Флаги: -ngl 99 -c 8192 --temp 0.7
Железо: RTX 4060 8GB / Ryzen 7 / 32GB RAM
Наблюдал: загрузка 21с, ~35 tok/s, TTFT ~1.2с, затем OOM при ~6k ctx
Пробовал: -c 4096 → без краша; q8_0 KV → без краша
С этими шестью фактами большинство проблем ложится на строку таблицы выше в один ответ. Этот форум существует ровно для таких постов — принесите лабораторный отчёт, и вы получите фикс.
Связанные разделы: параметры движка · математика VRAM · kv cache · сэмплирование