Мощный блог

Инференс LLM: KV-кэш, квантизация, LoRA и эмбеддинги

29 августа 2026 · Собесы

Темы 51–55: prefill и decode, KV-кэш, квантизация, LoRA и QLoRA, длинный контекст, эмбеддинги и реранкеры.

51. KV-кэш и как устроен инференс

Важность на собеседовании: 9/10 █████████░

🔥🔥🔥 Критично для 2026. «Почему инференс LLM дорогой» и «что такое KV-кэш» — вопросы почти обязательные. Копают глубоко: фазы prefill/decode, формула размера кэша, continuous batching.

Разбивка по подтемам:

Подтема Балл
Prefill vs decode, compute- vs memory-bound 10/10
Что такое KV-кэш и зачем 10/10
Формула размера кэша 9/10
Continuous batching 8/10
Prefix caching 8/10
PagedAttention 7/10
Speculative decoding 7/10

Две фазы генерации — надо знать разницу назубок:

Prefill Decode
Что делает Обрабатывает весь промпт целиком Генерирует ответ по одному токену
Параллелизуется? Да, все токены сразу Нет, каждый токен зависит от предыдущего
Упирается в Вычисления (compute-bound) Скорость памяти (memory-bound)
Метрика TTFT — время до первого токена TPOT — время на каждый следующий токен

Почему decode упирается в память, а не в вычисления. На каждый новый токен нужно прочитать все веса модели из памяти видеокарты, но полезной работы при этом делается всего на один токен. Считать нечего, а читать надо много — ядра простаивают. Именно поэтому батчинг так важен: при большом батче те же прочитанные веса используются сразу для многих запросов.

Prefill, decode и KV-кэш

KV-кэш. При генерации токена N внимание считается по всем предыдущим токенам. Их ключи (K) и значения (V) не меняются — зачем считать их заново на каждом шаге? Сохраняем и переиспользуем. Без кэша генерация была бы квадратично дороже.

Размер кэша:

память ≈ 2 × батч × длина × число_слоёв × число_KV_голов × размер_головы × байт_на_число

Двойка — потому что храним и K, и V. Главное следствие: кэш растёт линейно с длиной контекста и с размером батча. Именно он, а не веса, обычно ограничивает, сколько запросов вы поместите на карту. Отсюда мотивация GQA (уменьшает число KV-голов) и квантизации кэша.

PagedAttention (vLLM). Проблема: под каждый запрос выделяли кэш «с запасом» на максимальную длину — память фрагментировалась и тратилась впустую. Решение подсмотрено у операционных систем: кэш бьётся на страницы фиксированного размера, физические блоки выделяются по мере надобности, логически запрос видит непрерывное пространство. Результат — кратный рост числа одновременных запросов.

Continuous batching. Обычный батчинг: собрали пачку запросов, прогнали, вернули. Плохо, потому что короткие запросы ждут длинных, а видеокарта простаивает. Continuous batching работает на уровне отдельных шагов генерации: закончившийся запрос сразу убирается из батча, на его место тут же встаёт новый. Это главный источник роста пропускной способности в vLLM и подобных движках.

Prefix caching. Если у всех запросов общее начало (длинный системный промпт, few-shot примеры), его KV-кэш считается один раз и переиспользуется. Резко снижает TTFT и стоимость. Отсюда правило: стабильную часть промпта держите в начале, изменяющуюся — в конце.

Speculative decoding. Маленькая быстрая модель («драфт») генерирует несколько токенов вперёд, большая модель проверяет их все за один проход. Совпавший префикс принимается целиком. Даёт ускорение в 2–3 раза, если модели достаточно согласованы. Качество не страдает — процедура проверки построена так, что итоговое распределение совпадает с распределением большой модели.

Вопрос: Чат-бот отвечает медленно. Что смотреть? — Разделить TTFT и TPOT. Большой TTFT — проблема в prefill: слишком длинный промпт, нет prefix caching, очередь на входе. Большой TPOT — проблема в decode: модель слишком большая для этого железа, батч плохо собирается, кэш не помещается и вытесняется. Плюс: включён ли стриминг — он не ускоряет, но воспринимаемая задержка падает радикально.

52. Квантизация

Важность на собеседовании: 8/10 ████████░░

🔥🔥 Часто. Практический вопрос «сколько нужно видеопамяти» задают регулярно, и умение посчитать в уме сильно поднимает оценку. Форматы (GPTQ/AWQ/GGUF/FP8) — знать названия и когда что.

Идея. Хранить веса не в 16 битах, а в 8 или 4. Память падает кратно, скорость обычно растёт, качество немного проседает.

Как считать память (это и просят на собесе):

память на веса ≈ число параметров × байт на параметр
  • FP16/BF16 — 2 байта: модель 7B ≈ 14 ГБ
  • INT8 — 1 байт: 7B ≈ 7 ГБ
  • INT4 — 0.5 байта: 7B ≈ 3.5 ГБ

Плюс сверху 20–30% на KV-кэш, активации и накладные расходы. То есть 7B в 4 битах комфортно живёт на карте с 8 ГБ, а 70B в 4 битах — около 35–40 ГБ, то есть влезает в одну A100/H100 80 ГБ вместе с кэшем.

Форматы:

  • GPTQ — послойная квантизация с калибровкой на небольшом наборе данных. Ветеран, широко поддержан.
  • AWQ — умнее: определяет по активациям, какие веса важны для качества, и оставляет их точнее. Обычно лучше GPTQ на том же размере. Предпочтительный INT4 для серверных карт.
  • GGUF (llama.cpp, Ollama) — для локального запуска, умеет делить модель между GPU и CPU. Уровни от Q2 до Q8; практическая рекомендация — Q5_K_M или Q6_K дают качество, близкое к исходному, а Q2 уже заметно деградирует.
  • FP8 — 8-битный плавающий формат, поддержан аппаратно на H100 и новее. Качество почти как FP16 при вдвое меньшей памяти. Хороший дефолт на современных серверах.
  • Bitsandbytes NF4 — используется в QLoRA (тема 53).

Что можно квантовать: только веса (weight-only — самый популярный и безопасный вариант, активации остаются в fp16), веса и активации (сложнее, нужна калибровка), и отдельно KV-кэш (даёт больше места под контекст и батч).

Важная оговорка. Снижение точности не всегда ускоряет. Скорость зависит от того, поддерживает ли конкретная видеокарта арифметику в этом формате аппаратно и есть ли под него оптимизированные ядра. Экономия памяти будет всегда, а вот ускорение — не гарантировано. Проговорить это — признак практического опыта.

Вопрос: Влезет ли LLaMA-70B на одну карту 24 ГБ? — В FP16 нет (нужно ~140 ГБ). В INT4 веса займут ~35 ГБ — тоже нет. Варианты: взять модель поменьше (лучший выбор), разложить на несколько карт, использовать GGUF с выгрузкой части слоёв в оперативную память (будет медленно), либо арендовать карту побольше. Честный ответ «на 24 ГБ 70B нормально не поедет» лучше попытки натянуть.

53. LoRA и QLoRA

Важность на собеседовании: 9/10 █████████░

🔥🔥🔥 Критично. Один из самых частых практических вопросов на LLM-собесе. Ждут не только «что это», но и суждение: когда файнтюнить не надо. Копают глубоко: rank, alpha, целевые модули.

Разбивка по подтемам:

Подтема Балл
Когда файнтюн НЕ нужен (RAG вместо него) 10/10
Механика LoRA: ΔW = B·A 9/10
Параметры r, alpha, target_modules 8/10
QLoRA и 4-битная база 8/10
Катастрофическое забывание 7/10
Много адаптеров поверх одной базы 6/10

Проблема. Полный файнтюн модели 7B требует памяти не только под веса (14 ГБ), но и под градиенты (ещё 14) и состояния оптимизатора Adam (ещё ~56 ГБ в fp32). Итого под сотню гигабайт ради одной задачи.

LoRA и полный файнтюн

LoRA (Low-Rank Adaptation). Замораживаем всю модель. Рядом с выбранными слоями добавляем две маленькие матрицы: ΔW = B·A, где A имеет размер r×d, а B — d×r, и r очень маленькое (8, 16, 32). Обучаем только их. Обучаемых параметров становится меньше 1% от исходных.

Почему это работает: гипотеза в том, что адаптация модели к новой задаче — «низкоранговая», то есть требует изменений в небольшом числе направлений, а не переписывания всей матрицы.

Ключевые параметры:

  • r (rank) — «ёмкость» адаптера. 8–16 хватает для стиля и формата; 32–64 нужны, если задача действительно новая и сложная. Больше — не всегда лучше, начинается переобучение.
  • alpha — масштаб вклада адаптера, эффективная сила равна alpha/r. Практика: alpha = 2r (например, r=16, alpha=32).
  • target_modules — к каким слоям цеплять. Раньше только к q_proj и v_proj; сейчас практика показывает, что лучше ко всем линейным слоям, включая FFN.
  • dropout — 0.05–0.1 для регуляризации.

Плюсы, которые стоит назвать: обучение на одной потребительской карте; адаптер весит десятки мегабайт вместо десятков гигабайт; можно держать много адаптеров под разные задачи и переключать их на лету поверх одной базовой модели; при желании адаптер вливается в базовые веса (merge), и тогда на инференсе нет никакого замедления.

QLoRA — то же самое, но базовая модель хранится в 4 битах (формат NF4), а адаптеры обучаются в более высокой точности. Плюс два трюка: двойная квантизация (квантуются даже константы квантизации) и paged optimizers (выгрузка состояний оптимизатора в оперативную память при пиках). Итог: файнтюн модели 70B помещается на одну карту 48 ГБ.

Когда файнтюнить, а когда нет — это и есть главный вопрос:

Нужно Решение
Модель должна знать свежие/внутренние факты RAG, не файнтюн
Нужен свой стиль, тон, формат ответа LoRA
Нужен строго определённый формат вывода Structured output, не файнтюн
Нужна специфичная терминология домена RAG + few-shot; LoRA если не хватило
Нужно поведение/логика принятия решений LoRA/SFT
Нужно сделать модель дешевле и быстрее Дистилляция в маленькую модель

Формула для запоминания: RAG даёт модели что знать, файнтюн — как отвечать.

Катастрофическое забывание. Дообучаясь на узкой задаче, модель теряет общие способности. Лечится малым learning rate, малым числом эпох (1–3), подмешиванием общих данных и — собственно — самим LoRA, потому что базовые веса заморожены.

Вопрос: Бизнес хочет, чтобы бот отвечал по свежей внутренней документации. Файнтюнить? — Нет. Документация меняется, а файнтюн — это фиксация знаний в весах на момент обучения: при каждом обновлении придётся переобучать, и всё равно нет гарантии, что модель воспроизведёт факт точно, и нельзя дать ссылку на источник. Правильно — RAG. Файнтюн уместен рядом с ним, если нужно приучить модель к корпоративному стилю ответа или к строгому следованию регламенту.

54. Длинный контекст

Важность на собеседовании: 7/10 ███████░░░

🔥🔥 Часто, и заметно вырос в 2026. Любимый вопрос: «зачем RAG, если контекст миллион токенов». Хороший ответ требует знать про деградацию качества на длине.

Почему длинный контекст дорог. Внимание квадратично: удвоение длины даёт четырёхкратный рост вычислений. Плюс KV-кэш растёт линейно и съедает память.

Как его получают:

  • Эффективные реализации внимания (FlashAttention) — снимают память, но не квадратичность вычислений.
  • Разреженное/оконное внимание (Longformer, BigBird) — каждый токен смотрит не на всех, а на окно плюс несколько «глобальных» токенов.
  • Расширение RoPE после обучения (position interpolation, NTK-aware, YaRN) — самый ходовой путь.
  • Альтернативные архитектуры (Mamba и state-space модели) — линейная сложность, но пока проигрывают на задачах точного извлечения.

Главный факт 2026 года — «context rot». Заявленная длина контекста и полезная длина — разные вещи. Модель может проходить синтетический тест «найди иголку в стоге сена» с точностью выше 99%, но на реальных многошаговых задачах качество заметно падает уже к 32k, а между 200k и 1M у большинства моделей просадка на десятки процентных пунктов. Плюс известный эффект «lost in the middle»: факты в середине длинного контекста находятся хуже, чем в начале и в конце.

Практический вывод, который и хотят услышать: длинный контекст не отменил RAG. Он полезен, когда база знаний маленькая и помещается целиком (тогда плюс кэширование промпта — и это дешевле и проще RAG). Но когда документов много, RAG выигрывает по всем статьям: дешевле (не платим за 500k токенов на каждый запрос), быстрее, точнее (модель получает 5 релевантных кусков вместо стога сена), даёт ссылки на источники и позволяет разграничить права доступа. Замеры на моделях среднего размера показывают преимущество RAG над «закинуть всё в контекст» даже при окне 128k.

Вопрос: Как проверить, что модель реально держит заявленный контекст? — Не синтетическим «needle in a haystack» — он слишком лёгкий и завышает оценку. Нужны многошаговые задачи с несколькими «иголками», разбросанными по разным позициям, и замер качества как функции от длины входа и позиции факта. И обязательно на своих данных, а не на публичном бенчмарке.

55. Эмбеддинги и реранкеры

Важность на собеседовании: 10/10 ██████████

🔥🔥🔥 Критично для LLM-приложений. Это фундамент RAG, спрашивают всегда. Обязателен вопрос про bi-encoder vs cross-encoder — он проверяет, понимаете ли вы, почему нельзя просто «взять модель поточнее».

Разбивка по подтемам:

Подтема Балл
Bi-encoder vs cross-encoder 10/10
Двухступенчатая схема поиска 10/10
Как выбирать модель эмбеддингов 9/10
Контрастивное обучение и hard negatives 7/10
Косинус vs скалярное произведение 7/10
Переиндексация при смене модели 7/10

Эмбеддинг — вектор фиксированной длины, представляющий смысл текста. Похожие по смыслу тексты дают близкие векторы.

Как их обучают. Контрастивно: берут пары «похожие» (вопрос и правильный ответ) и «непохожие», и учат модель сближать первые и разводить вторые. Отрицательные примеры берут двумя способами: in-batch negatives (все остальные примеры в батче) и hard negatives — специально подобранные тексты, которые похожи, но не подходят. Именно hard negatives дают основной прирост качества. Тонкость: часть «отрицательных» на самом деле релевантна, просто не размечена — это шумит обучение.

Bi-encoder против cross-encoder — ключевое различие:

Bi-encoder Cross-encoder
Как считает Кодирует запрос и документ отдельно, сравнивает векторы Подаёт запрос и документ вместе в модель, выдаёт оценку
Скорость Очень быстро: документы закодированы заранее Очень медленно: нужен прогон на каждую пару
Качество Хорошее Заметно лучше
Можно индексировать? Да Нет

Bi-encoder и cross-encoder

Отсюда стандартная двухступенчатая схема: bi-encoder быстро достаёт 50–100 кандидатов из миллионов документов, cross-encoder (реранкер) аккуратно переупорядочивает эти 50–100. Прирост точности от реранкинга измеряют в десятках процентов — это одна из самых окупаемых оптимизаций RAG.

Что использовать в 2026:

  • Открытые многоязычные: BGE-M3 (умеет и плотные, и разреженные представления, длинный контекст), multilingual-E5, Qwen3-Embedding, для русского — модели вроде FRIDA и ru-адаптации E5.
  • Через API: OpenAI text-embedding-3, Voyage, Cohere Embed (сильны на многоязычии).
  • Реранкеры: bge-reranker-v2-m3, Qwen3-Reranker, Cohere Rerank.

Как выбирать (не «по верхушке MTEB»):

  1. Смотреть не общий средний балл MTEB, а подраздел Retrieval и, если есть, русскоязычный ruMTEB.
  2. Проверять на своих данных — доменная специфика решает больше, чем позиция в лидерборде.
  3. Учитывать размерность вектора (влияет на стоимость хранения и скорость поиска) и максимальную длину входа.
  4. Помнить: смена модели эмбеддингов требует переиндексации всей базы. Это дорогая операция, выбирайте один раз и осознанно.

Matryoshka-эмбеддинги — модель обучена так, что первые k координат вектора уже сами по себе осмысленны. Можно хранить укороченные векторы и экономить память почти без потери качества. Приятный факт для собеседования.

Вопрос: Поиск по эмбеддингам находит тематически похожее, но не то, что нужно. Что делать? — Сначала проверить, не лексическая ли это задача (артикулы, коды, имена) — тогда нужен гибрид с BM25. Потом добавить реранкер. Потом посмотреть на чанкинг — возможно, куски слишком большие и смысл размывается. И только потом думать о дообучении эмбеддера на своём домене контрастивно.


Часть 11 из 17 конспекта для подготовки к собеседованиям на NLP/LLM-разработчика. Остальные части — в разделе «Собесы».

0,0
0 оценок
5★
0
4★
0
3★
0
2★
0
1★
0

Оставить отзыв

Нажмите на звезду для оценки от 1 до 5
Необязательно. Используется только для связи
0/2000

Комментарии

Все С ответами Проверенные Только 4-5★