Bufor KV na kartach GPU 16 GB: jak realnie pomieścić długi kontekst

Dlaczego kontekst 128K zawodzi na 16 GB

Page content

Model może reklamować okno kontekstu o rozmiarze 128K i nadal zawodzić przy 40K tokenach na GPU o pamięci 16 GB. Architektoniczny limit nigdy nie gwarantował, że wagom, pamięci podręcznej KV, buforom obliczeniowym i kompozytorowi pulpitu zmieści się jednocześnie na karcie graficznej.

Pamięć podręczna KV to zwykle miejsce, w którym plany dotyczące długiego kontekstu zderzają się z tym fizycznym ograniczeniem. Wzrasta wraz z każdym aktywnym tokenem i sekwencją, dlatego konfiguracja, która na starcie wydaje się komfortowa, może drastycznie spowolnić pracę, wylać dane do pamięci systemowej lub zawieść podczas dużego prefillu.

Budżet pamięci pamięci podręcznej KV na GPU 16 GB

Ten poradnik zamienia ten problem w budżet VRAM. Omawia on wzór na pamięć podręczną, odtwarzalne tabele rozmiaru od 32K do 128K oraz działające konfiguracje dla llama.cpp --cache-type-k i --cache-type-v, pamięci paged i przedrostkowej w vLLM oraz kontroli kontekstu w Ollama — a także eksperymentalne rozgałęzienia adaptive-cache, które zasługują na zainteresowanie, ale nie na ślepe zaufanie. W celu szerszego kontekstu dotyczącego przepustowości, opóźnień i wyników testów wydajności stojących za tymi liczbami, zacznij od Centrum wydajności LLM.

Krótka odpowiedź dla GPU 16 GB

Zacznij od jednej sekwencji, realistycznego maksymalnego kontekstu, Flash Attention i 8-bitowej pamięci podręcznej KV. Zmierz tę konfigurację, zanim spróbujesz pamięci podręcznej 4-bitowej, odciążenia na CPU, wielu równoległych slotów lub eksperymentalnego rozgałęzienia.

Cel Słuszna pierwsza próba na 16 GB Główne ryzyko
32K Wagi Q4 lub Q5, KV Q8, jedna sekwencja Wagi modelu zostawiają zbyt mało miejsca na bufory
64K Mniejszy model lub agresywna kwantyzacja wag, KV Q8 Opóźnienie prefillu i przepustowość pamięci podręcznej
128K Mały model GQA, KV Q8 lub przetestowane KV Q4, jedna sekwencja Sama pamięć podręczna może zająć większość VRAM
Dwie równoległe sesje 64K Traktuj to jako budżet pamięci podręcznej ok. 128K Pojemność równoległa jest mylona z darmową przepustowością

Moja opinia jest prosta: stabilna konfiguracja 64K jest zwykle bardziej użyteczna niż nominalna konfiguracja 128K działająca na granicy błędu braku pamięci (OOM). Pojemność kontekstu to nie trofeum; to decyzja dotycząca opóźnień, jakości i współbieżności.

Co przechowuje pamięć podręczna KV

Podczas generowania autoregresyjnego warstwa uwagi tworzy tensory kluczy (key) i wartości (value) dla każdego przetworzonego tokenu. Runtime zachowuje te tensory, aby następny token mógł uwzględniać wcześniejsze tokeny bez ponownego obliczania całego prefiksu.

Pamięć podręczna oszczędza ogromne zasoby obliczeniowe, ale zużywa pamięć proporcjonalnie do liczby zachowanych tokenów. Dla konwencjonalnego transformera z grupowaną uwagą zapytań (GQA) przydatną bazą jest:

KV baje = sekwencje * tokeny * warstwy * 2 * głowy KV * wymiar głowy * bajty na wartość

Czynnik dwa reprezentuje klucze i wartości. Uwaga wielogłowa (Multi-head attention) wykorzystuje tyle samo głów KV co głów zapytań, uwaga grupowa zapytań (GQA) używa mniej głów KV, a uwaga wielogłowa latentna (MLA) lub hybrydowe architektury rekurencyjne wymagają innych obliczeń.

Dlaczego liczba parametrów nie jest wystarczająca

Dwa modele 8B mogą mieć bardzo różne koszty pamięci podręcznej KV. Jeden może używać 32 warstw i ośmiu głów KV, podczas gdy inny może używać mniej głów KV, współdzielonych warstw KV, uwagi ze śladowym oknem (sliding-window) lub skompresowanych stanów latentnych.

Liczba parametrów w głównej mierze przewiduje pamięć na wagi. Geometria KV pochodzi z architektury uwagi, więc czytaj metadane modelu, a nie zgaduj na podstawie 8B, 27B lub rozmiaru pliku GGUF. Najjaśniejszą ilustracją tego jest to, jak daleko projektowanie uwagi odeszło od zwykłej uwagi wielogłowej (MHA):

  • Uwaga wielozapytaniowa (MQA) dzieli jedną głowę K/V między wszystkie głowy zapytań — maksymalna oszczędność pamięci, ale jest to najbardziej agresywny kompromis jakościowy i rzadko stosowany samodzielnie w obecnych modelach frontier.
  • Uwaga grupowa zapytań (GQA) grupuje głowy zapytań w klastry, z których każdy dzieli jedną głowę K/V — jest to główny kompromis stosowany przez większość otwartych modeli gęstych i geometria zakładana we wzorze powyżej.
  • Uwaga wielogłowa latentna (MLA), wprowadzona w DeepSeek-V2 i rozwinięta w DeepSeek-V3 oraz Kimi K2, podejmuje zupełnie inne podejście: zamiast dzielić K/V między głowami, projekuje klucze i wartości do skompresowanego, niskorangiowego wektora latentnego i odtwarza K/V pełnej rozdzielczości na żądanie w momencie uwagi. DeepSeek zgłosił około 93% redukcji pamięci KV w porównaniu z modelem gęstym MHA o równoważnym rozmiarze, zachowując przy tym jakość konkurencyjną — a czasem przewyższającą — GQA przy tym samym budżecie pamięci.

W praktyce oznacza to, że „model 27B GQA” i „model 27B MLA” mogą mieć ślad pamięci KV różniący się rzędem wielkości dla tej samej długości kontekstu. Nie zakładaj, że wzór powyżej dotyczy modelu, który dokumentuje się jako używający uwagi latentnej, stanu w stylu DeltaNet lub warstw ze śladowym oknem — najpierw sprawdź sekcję architektury w karcie modelu.

W Ollama, ollama show MODEL --verbose ujawnia metadane modelu, w tym liczbę warstw, głów uwagi, głowy KV i długość kontekstu, jeśli format na to pozwala. W llama.cpp, wyjście ładowarki modelu wyświetlane przy starcie zwykle zawiera równoważne metadane GGUF i faktyczną alokację pamięci podręcznej runtime.

Limit modelu, zaalokowany kontekst i użyty kontekst

To trzy różne liczby. Limit modelu to maksimum wspierane przez jego trening i kodowanie pozycyjne, zaalokowany kontekst to to, co runtime rezerwuje lub pozwala, a użyty kontekst to tokeny aktualnie zachowywane dla sekwencji.

Podniesienie flagi silnika nie może bezpiecznie przedłużyć modelu poza jego wspierany schemat pozycji. Skalowanie RoPE może przedłużyć niektóre architektury, ale jest to eksperyment z jakością modelu, a nie optymalizacja pamięci KV.

Tabela rozmiaru pamięci KV: budżety kontekstu 32K, 64K i 128K

Rozważmy reprezentatywny model GQA z 32 warstwami, ośmioma głowami KV i wymiarem głowy 128. Te wymiary generują 65 536 elementów kluczy i wartości na token przed pomnożeniem przez rozmiar przechowywania każdego elementu.

Tabela używa binarnych GiB i fizycznych rozmiarów bloków powszechnie związanych z llama.cpp f16, q8_0 i q4_0. Jest to obliczenie bazowe, a nie obietnica dotycząca całkowitej pamięci procesu; wyrównanie, metadane, warstwy hybrydowe i przestrzenie robocze backendu dodają narzut.

Typ pamięci Przybliżone bajty na zachowaną wartość Kontekst 32K Kontekst 64K Kontekst 128K
F16 2.0000 4.00 GiB 8.00 GiB 16.00 GiB
Q8_0 1.0625 2.13 GiB 4.25 GiB 8.50 GiB
Q4_0 0.5625 1.13 GiB 2.25 GiB 4.50 GiB
Q8_0 K plus Q4_0 V Mieszany 1.63 GiB 3.25 GiB 6.50 GiB

Podwojmy teraz liczbę warstw do 64, pozostawiając inne wymiary bez zmian. Pamięć FP16 wynosi 8 GiB przy 32K, 16 GiB przy 64K i 32 GiB przy 128K, co wykazuje, dlaczego jedna rekomendacja kontekstu nie może pokryć każdego modelu.

Równanie dla faktycznych 16 GB

Praktyczny budżet jest szerszy niż wzór na KV:

dostępny VRAM = całkowity VRAM - rezerwa pulpitu i sterownika

budżet KV = dostępny VRAM
          - wagi modelu rezydentne na GPU
          - bufory grafu i aktywacji
          - przestrzeń robocza runtime
          - stan spekulatywnego dekodowania
          - margines bezpieczeństwa

Na karcie 16 GB podłączonym do wyświetlacza nie planuj tak, jakby całe 16 GiB było dostępne. Zrezerwuj co najmniej kilkaset MiB dla pulpitu i sterownika, a następnie zostaw dodatkowy margines na bufory zależne od obciążenia; 1.0 do 1.5 GiB całkowitej rezerwy jest rozsądnym założeniem startowym, ale to Twoje logi są autorytetem.

Załóżmy, że model GGUF zajmuje 10.8 GiB na GPU, a narzut runtime sięga 1.2 GiB. Po odjęciu 1 GiB marginesu bezpieczeństwa na KV zostaje tylko około 3 GiB, więc model reprezentatywny mieści około 45K tokenów z Q8_0 lub 87K z Q4_0, przed uwzględnieniem narzutu specyficznego dla silnika.

To nie oznacza automatycznie, że Q4_0 jest właściwym wyborem. Jeśli dokładność długiego kontekstu spada przy Twoim obciążeniu, mniejszy model lub model z bardziej agresywną kwantyzacją wag z pamięcią Q8_0 może być lepszy niż większe wagi połączone z kruchą pamięcią. Zmierzone punkty odniesienia dla dokładnie tej arytmetyki znajdują się w Tabelach wyników testów wydajności llama.cpp dla VRAM 16 GB, gdzie VRAM dla każdego modelu jest rejestrowany przy kontekście 19K, 32K i 64K. W celu szerszego przeglądu, które rozmiary modeli i poziomy kwantyzacji dobrze zachowują się w Ollama na tej samej klasie karty, zobacz Porównanie wydajności LLM w Ollama na GPU z VRAM 16GB.

Oblicz budżet pamięci KV dla swojego modelu

Poniższy fragment kodu Pythona szacuje konwencjonalną pamięć pełnej uwagi GQA. Zamień geometrię na wartości z konfiguracji modelu lub metadanych GGUF.

def kv_gib(tokens, layers, kv_heads, head_dim, bytes_per_value, sequences=1):
    total = (
        sequences
        * tokens
        * layers
        * 2
        * kv_heads
        * head_dim
        * bytes_per_value
    )
    return total / (1024 ** 3)


model = {
    "layers": 32,
    "kv_heads": 8,
    "head_dim": 128,
}

types = {
    "f16": 2.0,
    "q8_0": 34 / 32,
    "q4_0": 18 / 32,
}

for tokens in (32768, 65536, 131072):
    row = {
        name: round(kv_gib(tokens=tokens, bytes_per_value=size, **model), 2)
        for name, size in types.items()
    }
    print(tokens, row)

Proporcje Q8_0 i Q4_0 zawierają proste metadane bloków, dlatego są nieco większe niż dokładnie jeden bajt i połowa bajta na wartość. Raport uruchomieniowy runtime pozostaje bardziej dokładny, ponieważ zna specyficzne dla modelu układy pamięci.

Kiedy ten wzór jest błędny: Architektury hybrydowe i ze śladowym oknem

Nie wymuszaj architektur hybrydowych na konwencjonalnym równaniu GQA. Warstwy ze śladowym oknem (sliding-window) zachowują tylko ostatnie okno, współdzielone warstwy KV zmniejszają duplikację, warstwy rekurencyjne mogą przenosić stan o stałym rozmiarze, a uwaga wielogłowa latentna przechowuje skompresowaną reprezentację zamiast tensory K/V dla każdej głowy — przypadek MLA powyżej jest najbardziej dramatycznym przykładem.

Nowoczesne silniki coraz częściej zarządzają tymi mieszanymi układami w sposób jawny. Użyj wzoru, aby wyjaśnić dominujące terminy, a następnie potwierdź alokację zgłaszaną przez dokładną wersję silnika i backend, który planujesz wdrożyć.

llama.cpp: Bezpośrednia kontrola precyzji K i V

llama.cpp udostępnia osobne opcje --cache-type-k i --cache-type-v w swoim bieżącym parserze argumentów. To najbardziej użyteczny interfejs lokalnego inferencji, gdy trzeba wymienić precyzję pamięci na pojemność kontekstu, zamiast akceptować jeden globalny preset. Jeśli potrzebujesz najpierw otaczającej konfiguracji instalacji i serwowania, poradnik llama.cpp obejmuje llama-cli, llama-server i kluczowe flagi VRAM.

Konservatywna konfiguracja 64K dla jednego użytkownika wygląda następująco:

./llama-server \
  --model /models/model.gguf \
  --n-gpu-layers 999 \
  --ctx-size 65536 \
  --parallel 1 \
  --flash-attn on \
  --cache-type-k q8_0 \
  --cache-type-v q8_0 \
  --batch-size 1024 \
  --ubatch-size 256

Sytaksa flag i wsparcie backendów zmieniają się szybko, więc uruchom llama-server --help dla zainstalowanej wersji. Co ważniejsze, sprawdź log uruchomienia: powinien pokazywać zamierzony kontekst, typy pamięci, odciążenie GPU oraz zaalokowane bufory K i V.

Które typy pamięci llama.cpp wypróbować

Zacznij od Q8_0 dla obu K i V. Przybliżenie połowy pamięci KV w stosunku do F16, a niezależne testy perplexity na modelach 20B i większych (Qwen3.6-27B, Nemotron-30B) pokazują, że kumulatywna różnica jakości względem F16 mieści się w szumie pomiarowym — to znacznie mniejsze ryzyko niż przejście bezpośrednio do Q4_0, które te same testy wykazały jako powodujące załamanie prędkości dekodowania i dokładności przy długim kontekście na mniejszych modelach.

Jeśli Q8_0 nie mieści się w pamięci, przetestuj klucze Q8_0 z wartościami Q4_0 przed skwantyzowaniem obu stron do Q4_0. Ta kolejność ma poparcie badawcze, a nie tylko folklor: kontrolowane badania alokacji bitów na checkpointach Llama, Phi-4, Qwen3 i Mistral wykazały, że tensory kluczy są konsekwentnie od dwóch do dziesięciu razy bardziej wrażliwe na błąd kwantyzacji niż tensory wartości, a przyznanie kluczyom większego budżetu bitów (na przykład 4-bity dla kluczy i 2-bity dla wartości) odzyskuje od 94 do 98% dokładności pełnej precyzji — podczas gdy odwrócona proporcja (2-bity dla kluczy, 4-bity dla wartości) może stracić 30 punktów procentowych w zadaniach takich jak GSM8K. Klucze określają, które wcześniejsze tokeny uwaga faktycznie dopasowuje, więc ich ochrona w pierwszej kolejności jest architektonicznie trafnym wyborem, a nie tylko bezpieczniejszym brzmieniem.

Konfiguracja Pamięć Ryzyko jakościowe Rekomendacja
F16 K i V Najwyższa Najniższe Bazowo, gdy się mieści
Q8_0 K i V O połowę mniej niż F16 Niskie, ale nie zerowe Punkt startowy dla 16 GB
Q8_0 K, Q4_0 V Między Q8 a Q4 Umiarkowane Przydatny drugi krok
Q4_0 K i V O jedną czwartą mniej niż F16 Najwyższe Zweryfikuj przy docelowej głębokości

Jedna uwaga warta zapamiętania: „niskie ryzyko jakościowe” na kumulatywnych testach nie oznacza zerowego ryzyka na poziomie tokena. Kontrolowany test, który utrzymywał Flash Attention stałego i zmieniał tylko precyzję KV przy dekodowaniu żądlowym (deterministycznym), wykazał, że pamięć Q8_0 zmieniała dokładny wygenerowany tekst na dużej większości promptów, a Q4_0 zmieniała go praktycznie w każdym — gdy tylko jeden token się odwróci, reszta dalszego ciągu może się rozjechać. Punkty perplexity i wyniki zadań dalszych mogą wyglądać dobrze na średniej, podczas gdy pojedyncze wyjścia nadal różnią się od bazy F16. Jeśli Twoja aplikacja potrzebuje reprodukcji bajt-po-bajcie (testy regresji, buforowane odpowiedzi, agenci deterministyczne), traktuj każdą kwantyzację KV jako zmianę behawioralną, a nie tylko optymalizację pamięci, i zweryfikuj to na swoim stałym zestawie promptów.

Skwantyzowana pamięć V może wymagać Flash Attention lub kompatybilnej ścieżki backendu. Serwer, który cicho cofa się do innego typu, unieważnia eksperyment, dlatego logi uruchomienia są ważniejsze niż skopiowane linie poleceń.

Kontekst, sloty równoległe i ujednolicona pamięć

--ctx-size opisuje pojemność silnika, a nie gwarancję, że każdy slot równoległy otrzyma niezależnie tyle tokenów. Zarządzanie pamięcią ewoluowało w llama.cpp, w tym zachowanie ujednoliconej pamięci, więc testuj dokładną wersję, zamiast polegać na starszej regule, która po prostu dzieli kontekst przez liczbę slotów.

Równanie pojemności nadal przetrwa zmiany implementacyjne: jednoczesne unikalne tokeny potrzebują gdzieś przechowywania. Jeśli dwie sesje agenta mogą osiągnąć każde 48K, załóż budżet bliski 96K aktywnych tokenów, chyba że obciążenie współdzieli prefiksy lub toleruje wyrzucanie i ponowne obliczanie.

Rozmiar partii (Batch Size) nie zmniejsza przechowywanego KV

--batch-size i --ubatch-size wpływają na przetwarzanie promptu i pamięć tymczasową. Obniżenie ich może uratować duży prefill przed szczytem pamięci aktywacji, ale nie zmienia trwałych bajtów wymaganych dla każdego zachowanego tokenu.

Ta rozróżnienie wyjaśnia powszechny wzorzec awarii: model startuje i pusty request działa, ale prompt 60K zawodzi podczas ingestii. Zmniejsz mikropartię, aby zdiagnozować tymczasowy szczyt; zmniejsz kontekst, precyzję pamięci, równoległość lub rezydencję wag, aby zmienić trwałą pojemność.

vLLM: Pojemność paged to nadal pojemność

vLLM podchodzi do problemu jako silnik serwisowy. Profiluje dostępną pamięć, rezerwuje pulę pamięci KV i alokuje pamięć w blokach, aby równoległe sekwencje nie wymagały każdej po jednym dużym ciągłym regionie. Jeśli decydujesz, czy w ogóle przejść na vLLM, poradnik migracji z Ollama na vLLM obejmuje sygnały obciążenia; tutaj pytanie jest czysto o to, ile pamięci może utrzymać pula, a szybki start vLLM obejmuje instalację i ogólne flagi serwisowania poza dźwigniami pojemności poniżej.

PagedAttention redukuje fragmentację i marnotrawstwo wokół zmiennej długości sekwencji — alokacja paged eliminuje fragmentację, ale nie koszt przechowywania na token, więc jeden unikalny request 128K nadal potrzebuje wystarczająco dużo bloków dla jego stanu KV.

Oficjalny przewodnik vLLM po oszczędzaniu pamięci zaleca limitowanie max_model_len i max_num_seqs, gdy pamięć jest ograniczona, i zauważa, że grafy CUDA zużywają dodatkową pamięć GPU. Na karcie 16 GB obie te ustawienia powinny być zamierzone, a nie odziedziczone z maksymalnej konfiguracji modelu.

Sklarowany serwer jednowątkowy może zacząć tutaj:

vllm serve MODEL_ID \
  --max-model-len 65536 \
  --max-num-seqs 1 \
  --gpu-memory-utilization 0.90 \
  --kv-cache-dtype fp8 \
  --enable-prefix-caching

Nie każde GPU 16 GB, model, metoda kwantyzacji lub backend uwagi obsługuje tę dokładną kombinację. Traktuj to jako kształt konfiguracji: ogranicz długość i współbieżność, zarezerwuj zapas, wybierz wspierany typ danych pamięci i zweryfikuj raport inicjalizacji.

Pamięć KV FP8 w vLLM

Bieżąca dokumentacja vLLM dotycząca skwantyzowanej pamięci KV wspiera formaty pamięci FP8 na kompatybilnych ścieżkach CUDA i ROCm. FP8 przybliża połowę surowego przechowywania pamięci względem BF16 lub FP16 i może zatem zwiększyć pojemność tokenów lub współbieżność.

Skalowanie ma znaczenie. Dokumentacja rozróżnia domyślne skale, wyliczanie warm-upu i kalibrację zbioru danych i zaleca kalibrację opartą na zbiorze danych dla najwyższej dokładności; po prostu ustawienie FP8 ze skalą 1.0 jest wygodne, ale nie jest automatycznie najbardziej wiarygodnym wyborem jakościowym.

Pamięć przedrostkowa to optymalizacja ponownego użycia

Automatyczna pamięć przedrostkowa pozwala nowemu żądaniu ponownie wykorzystać bloki KV dla identycznego zachowanego prefiksu. Jest doskonała dla powtarzających się zapytań do tego samego długiego dokumentu, współdzielonych promptów systemowych i wielorundowych rozmów, ponieważ unika ponownego obliczania dopasowanego prefillu.

Nie sprawia, że unikalne długie żądanie staje się mniejsze i nie przyspiesza generowania nowych tokenów. Dokumentacja vLLM dotycząca pamięci przedrostkowej wyraźnie ogranicza korzyść do pracy prefill dla współdzielonych prefiksów.

Wykorzystanie pamięci GPU to nie darmowa pamięć

Podnoszenie --gpu-memory-utilization daje vLLM większy cel rezerwacji, ale nie tworzy VRAM. Pchaniu go zbyt blisko 1.0 może pozostawić niewystarczającą przestrzeń dla wyświetlacza, innego procesu, zmieniających się szczytów aktywacji lub alokacji innych niż PyTorch.

Zacznij w okolicach 0.88 do 0.92 na dedykowanym GPU 16 GB, sprawdź profil i zwiększaj tylko wtedy, gdy obciążenie pozostaje stabilne. Jeśli inicjalizacja się powiedzie, ale rzeczywiste prompty zawiodą, zmniejsz partycjonowane tokeny, współbieżność sekwencji, przechwytywanie grafu CUDA lub maksymalny kontekst, zanim zakładasz, że alokator jest zepsuty.

Ollama: Łatwiejsze kontrole, mniej szczegółowa diagnostyka

Ollama świadomie oferuje mniejszą powierzchnię operacyjną. Jego bieżąca dokumentacja długości kontekstu domyślnie ustawia GPU poniżej 24 GiB na kontekst 4K, zaleca co najmniej 64K dla obciążeń agentowych i kodowania i ostrzega, że większy kontekst zużywa więcej pamięci.

Ustaw domyślną wartość dla serwera i potwierdź załadowany model w ten sposób:

OLLAMA_CONTEXT_LENGTH=65536 ollama serve

ollama ps

Możesz też ustawić num_ctx per żądanie lub model. ollama ps jest ważne, ponieważ jego kolumny PROCESSOR i CONTEXT ujawniają, czy model pozostał w pełni na GPU i czy zażądany kontekst został faktycznie zaalokowany. Pamiętaj, że zachowanie harmonogramowania za tymi liczbami zmieniło się między wersjami Ollama; moje porównanie alokacji pamięci w Ollama v0.12.1 pokazuje, że nowy harmonogram pcha niektóre modele dalej na CPU na karcie 16 GB, więc przypnij wersję, którą zmierzyłeś.

Skwantyzowana pamięć KV w Ollama

Ollama udostępnia OLLAMA_KV_CACHE_TYPE z opcjami f16, q8_0 i q4_0 w swoim bieżącym FAQ. Skwantyzowana KV wymaga Flash Attention, co Ollama używa automatycznie na wspieranych backendach lub można o to poprosić za pomocą OLLAMA_FLASH_ATTENTION=1.

Usługa o długim kontekście na 16 GB może więc zostać uruchomiona jako:

OLLAMA_CONTEXT_LENGTH=65536 \
OLLAMA_FLASH_ATTENTION=1 \
OLLAMA_KV_CACHE_TYPE=q8_0 \
OLLAMA_NUM_PARALLEL=1 \
ollama serve

Q8_0 jest zalecaną przez Ollama alternatywą dla F16. FAQ ostrzega, że Q4_0 może powodować bardziej odczuwalną utratę jakości, szczególnie przy wyższym kontekście, więc powinno być zmierzone zapasem, a nie automatycznym presetem dla 16 GB.

Równoległość Ollama mnoży budżet kontekstu

Ollama dokumentuje wyjątkowo jasną zasadę: wymagana pamięć skaluje się z OLLAMA_NUM_PARALLEL * OLLAMA_CONTEXT_LENGTH. Cztery równoległe żądania przy ustawieniu 32K mogą implikować alokację łącznego kontekstu 128K dla tego modelu.

Dla osobistego agenta na 16 GB, utrzymuj OLLAMA_NUM_PARALLEL=1, dopóki jedna długa sesja nie będzie stabilna. Kolejkowanie drugiego żądania jest zwykle preferowane nad pchaniem pierwszego modelu częściowo na CPU i spowalnianiem obu żądań. Mechanika kolejkowania, 503 i odładowywania modeli za tym wyborem jest udokumentowana w jak Ollama obsługuje równoległe żądania.

Odciążanie CPU: Wyzwalacz z ceną

Przeniesienie niektórych warstw modelu lub stanu KV do pamięci RAM systemowej może przekształcić błąd alokacji w działający proces. Umieszcza też przepustowość PCIe i opóźnienie pamięci hosta w ścieżce dekodowania, gdzie każdy wygenerowany token może płacić tę cenę. Dalsze informacje i dowody na to, kiedy PCIe faktycznie gryzie, znajdują się w Wydajność LLM i szyny PCIe.

Odciążanie może mieć sens dla okazjonalnej pracy partiami, ale rzadko jest najlepszym domyślnym wyborem dla interaktywnego agenta kodującego. Najpierw porównaj mniejszą kwantyzację wag, KV Q8, zmniejszoną współbieżność i realistyczny limit kontekstu; użyj odciążenia, gdy pojemność ma większe znaczenie niż opóźnienie.

Obserwuj klif, a nie średnią. Serwer może szybko dekodować przy 8K, a potem gwałtownie spowolnić po tym, jak część zbioru roboczego wyleje się, więc testuj wydajność przy 32K, 64K i zamierzonym maksimum, a nie zgłaszaj tylko prędkość tokenów przy pustym kontekście.

Pamięć KV ze śladowym oknem i adaptacyjna

Uwaga ze śladowym oknem zmienia budżet, zachowując tylko ostatnie okno dla wybranych warstw. Modele hybrydowe mogą łączyć te warstwy z okazjonalną uwagą globalną lub stanem rekurencyjnym, co sprawia, że płaska kalkulacja pełnego kontekstu znacznie przeszacowuje lub nieprawidłowo lokuje pamięć.

Ta optymalizacja jest częścią architektury modelu, a nie ogólnym przełącznikiem, który można zastosować bez konsekwencji. Silnik musi prawidłowo rozumieć wzorzec warstw, zasady wyrzucania, pozycje i wszelkie tokeny globalne.

Co adaptacyjna KV próbuje poprawić

Eksperymentalne rozgałęzienia idą dalej, wybierając precyzję lub układ pamięci per warstwa i głębokość kontekstu. Cel jest atrakcyjny: zachowaj wyższą precyzję tam, gdzie ma znaczenie, skompresuj mniej wrażliwe warstwy i zmień mieszankę, zanim presja VRAM spowoduje twarde wylanie — to samo odkrycie o wrażliwości kluczy ponad wrażliwość wartości opisane powyżej to dokładnie taki typ sygnału, który adaptacyjny alokator chciałby wykorzystać automatycznie, zamiast pozostawiać to ręcznemu strojeniu --cache-type-k/--cache-type-v.

Jeden projekt pochodny z sierpnia 2026, llama.cpp-adaptive-turboquant, zgłasza automatyczny selektor dla kilku trybów adaptacyjnych per warstwa i publikuje testy o dużej głębokości na RTX 5080 16 GB. Te liczby to wyniki zgłaszane przez autora ze specjalistycznego rozgałęzienia, a nie dowód, że górnopłynowe llama.cpp zachowuje się tak samo.

Dlaczego nadal jest eksperymentalne

Rozgałęzienie łączy niestandardowe typy pamięci, rdzenie CUDA, ścieżki specyficzne dla modelu i ograniczenia narzędzi. To znacznie więcej kodu do zaufania niż zmiana przechowywania pamięci w górnopłynie z F16 na Q8_0.

Używaj takiego rozgałęzienia tylko wtedy, gdy górnopłyn nie może spełnić rzeczywistego wymagania i możesz odtworzyć jakość, stabilność i szybkość na swoim modelu. Zanotuj commit i wersję CUDA, ponieważ wynik powiązany tylko z nazwą projektu nie jest odtwarzalny.

Sprawiedliwy test adaptacyjnej pamięci

Porównaj rozgałęzienie z bazowym Q8_0 górnopłynnym z tym samym GGUF, promptem, samplerem, głębokością kontekstu i długością wyjścia. Zmierz VRAM przy starcie, szczytowy VRAM prefill, prędkość przetwarzania promptu, prędkość dekodowania i zadanie jakościowe, które faktycznie wymaga dowodów z najstarszej części kontekstu.

Nie akceptuj udanej alokacji jako kompletnego wyniku. Pamięć może zmieścić 128K i nadal tracić wczesne fakty, korumpować wyjście późno w sekwencji lub dekodować zbyt wolno, aby być użytecznym.

Wykonana procedura strojenia 16 GB: Jedna zmienna naraz

Najszybsza droga do stabilnej konfiguracji to zmiana jednego wymiaru pamięci naraz. Losowe zmienianie typu pamięci, rozmiaru partii, odciążania warstw, równoległości i kontekstu jednocześnie produkuje działające polecenie bez wyjaśnienia.

flowchart TD A["Krok 1: załaduj przy kontekście 8K, jedna sekwencja, zanotuj VRAM po rozgrzaniu"] --> B{"Wagi + runtime poniżej ok. 14.5 GiB?"} B -- "nie" --> C["Wybierz mniejszą kwantyzację lub model, powtórz Krok 1"] C --> A B -- "tak" --> D["Krok 2: baza jakościowa KV F16/BF16, zapisz wyjścia zadań"] D --> E["Krok 3: przełącz na KV Q8_0 / FP8 z Flash Attention"] E --> F["Krok 4: zwiększaj kontekst etapami - 32K, 64K, 96K, 128K"] F --> G{"Awaria podczas prefillu?"} G -- "tak" --> H["Krok 5: zmniejsz rozmiar batch / ubatch"] H --> F G -- "nie" --> I{"Awaria tylko przy równoległych żądaniach?"} I -- "tak" --> J["Krok 5: zmniejsz sloty równoległe / max-num-seqs"] J --> F I -- "nie" --> K["Dopiero teraz: mieszany Q8/Q4, pełny Q4, odciążenie, adaptacyjne rozg."]

Krok 1: Ustal podłogę wag

Załaduj model przy kontekście 8K, jednej sekwencji i zamierzonym odciążeniu GPU. Zanotuj VRAM procesu po rozgrzaniu i sprawdź, czy żadne warstwy nie przeniosły się nieoczekiwanie na CPU.

Jeśli wagi i runtime zużywają już ponad około 14.5 do 15 GiB, długiemu kontekstowi nie ma zdrowego marginesu. Wybierz mniejszą kwantyzację wag lub model przed strojeniem pamięci.

Krok 2: Zmierz KV F16 lub BF16 jako bazę jakościową

Uruchom najmniejszy kontekst, który wspiera Twój test, i zachowaj domyślną pamięć wysokiej precyzji. Zapisz wyjścia z zadań odzyskiwania, edycji kodu, wyboru narzędzi i długich instrukcji.

Ta baza mówi Ci, czy późniejsze błędy pochodzą z kwantyzacji pamięci. Bez niego problem z szablonem czatu lub słaby model mogą łatwo zostać obwinione za KV Q4.

Krok 3: Przejdź na Q8 lub FP8

Włącz Flash Attention, jeśli jest wymagany, wybierz Q8_0 w llama.cpp lub Ollama, lub wspierany tryb FP8 w vLLM. Powtórz te same prompty przy tej samej głębokości tokenów i potwierdź, że log pokazuje zamierzony typ pamięci.

Dla wielu wdrożeń 16 GB to użyteczny punkt zatrzymania. Przybliżenie podwójnej surowej pojemności KV bez robienia kompresji pamięci najbardziej agresywną kwantyzacją w stosie.

Krok 4: Podwyższaj kontekst w etapach

Testuj 32K, 64K, 96K i 128K, zamiast skakać bezpośrednio do reklamowanego maksimum. Na każdym etapie zapisz tokeny na sekundę podczas przetwarzania promptu, tokeny na sekundę podczas dekodowania, szczytowy VRAM i czy dowody z początku wciąż mogą być odzyskane.

Dekodowanie długiego kontekstu często zwalnia, nawet po tym, jak pamięć się mieści, ponieważ uwaga czyta więcej zachowanego stanu. Pojemność i wydajność to osobne osie.

Krok 5: Dostroij pamięć tymczasową

Jeśli awaria występuje podczas prefill, a nie inicjalizacji, zmniejsz mikropartię lub maksymalne partycjonowane tokeny. Jeśli awaria występuje tylko przy jednoczesnych żądaniach, zmniejsz współbieżność sekwencji lub sloty równoległe.

Dopiero po zrozumieniu tych kontroli należy spróbować mieszanej pamięci Q8/Q4, pełnej pamięci Q4, odciążenia CPU lub adaptacyjnego rozgałęzienia. Zachowaj wykonanie Q8 górnopłynnego jako porównawczą bazę. Jeśli później dodasz spekulatywne dekodowanie lub MTP, pamiętaj, że bufory szkicowe to kolejna linia w równaniu budżetu, a nie darmowa prędkość — poradnik spekulatywnego dekodowania obejmuje mechanikę i jej koszt VRAM, a moje benchmarki Qwen 3.6 27B i 35B MTP vs Standard pokazują dokładnie, ile kontekstu może kosztować dodatkowy stan głowy MTP na karcie 16 GB.

Co zanotować w benchmarku długiego kontekstu

Pojedyncza liczba tokens/s ukrywa dokładny problem, który ten artykuł próbuje rozwiązać. Testowanie długiego kontekstu powinno zachować wystarczająco dużo szczegółów, aby inny operator mógł odtworzyć granicę pamięci.

Pole Dlaczego to ważne
GPU i dostępny VRAM Użycie wyświetlacza i inne procesy zmieniają budżet
Wersja silnika lub commit Zachowanie pamięci i flagi ewoluują szybko
Wersja sterownika, CUDA, ROCm lub Vulkan Określa zachowanie backendu i rdzeni
Dokładny model i kwantyzacja wag Określa rezydencję wag i architekturę
Typy pamięci K i V Określa rozmiar trwałej pamięci i ryzyko jakościowe
Pojemność kontekstu i głębokość promptu Alokacja nie jest taka sama jak faktyczna głębokość
Równoległe sekwencje Mnoży lub współdzieli zapotrzebowanie na pamięć
Batch i mikropartia Wpływa na szczyty prefill i szybkość
Szybkość przetwarzania promptu Ujawnia użyteczność długiego prefill
Szybkość dekodowania na każdej głębokości Ujawnia spowolnienie przepustowości pamięci
Szczytowy VRAM i odciążenie CPU Rozróżnia dopasowanie od wylania
Wynik jakościowy długiego kontekstu Wykrywa porażki kompresji lub pozycji

Używaj próbkowania nvidia-smi lub równoważnego narzędzia producenta zarówno podczas prefill, jak i dekodowania. Raport alokacji silnika jest konieczny, ale szczytowa pamięć urządzenia podczas rzeczywistego promptu to liczba, która decyduje o stabilności.

Powszechne błędy pamięci KV na GPU 16 GB

Traktowanie wsparcia 128K jako obietnicy sprzętowej

Pole kontekstu w konfiguracji modelu to architektoniczny sufit. Nie mówi nic o pamięci pozostałej po załadowaniu szczególnej kwantyzacji na szczególnym silniku.

Oblicz pamięć i zweryfikuj runtime. Reklamowana wielkość kontekstu bez budżetu VRAM to jedynie OOM opóźniony do pierwszego poważnego promptu.

Kwantyzowanie wag, ale zapomnienie o KV

GGUF 4-bity zmniejsza wagi modelu, a nie pamięć KV F16. Przy długim kontekście pamięć może wymazać całą oszczędność i ostatecznie przewyższyć ślad wag.

Zgłaszaj obie kwantyzacje. Model Q4_K_M, KV Q8_0 ma znaczenie; model 4-bity jest niekompletne.

Zakładanie, że uwaga paged kompresuje tokeny

Stronicowanie poprawia zachowanie alokacji i współdzielenia. Nie zmienia precyzji tensorów ani nie usuwa stanu KV wymaganego przez jedną unikalną sekwencję.

Używaj alokacji paged do wydajnego serwisowania zmiennych obciążeń. Używaj precyzji pamięci, architektury modelu, limitów kontekstu i limitów współbieżności, aby kontrolować pojemność.

Zakładanie, że pamięć przedrostkowa pomaga każdemu długiemu promptowi

Pamięć przedrostkowa oszczędza ponowne obliczanie prefill, gdy żądania współdzielą dokładny prefiks. Jednorazowy zrzut repozytorium 100K nie otrzymuje magicznego rabatu pamięciowego tylko dlatego, że pamięć przedrostkowa jest włączona.

To optymalizacja obciążenia, a nie zamiennik równania budżetu. Mierz wskaźnik trafień i presję zachowanej pamięci w serwisowaniu wieloużytkownikowym.

Używanie KV Q4 bez testu jakościowego

Pamięć o niskiej liczbie bitów może zawieść subtelnie. Model nadal pisze płynny tekst, ale uwaga nad odległymi dowodami, dokładnymi nazwami, argumentami narzędzi lub zależnościami kodu może się pogorszyć — a jak wykazuje powyższe badanie rozbieżności tokenów, nawet „bezpieczne” ustawienie Q8_0 nie gwarantuje odtworzenia dokładnego wyjścia F16 przy dekodowaniu deterministycznym, tylko zachowanie dokładności na agregacie.

Testuj docelowe zadanie na docelowej głębokości. Krótkie benchmarki czatu są niemal bezużyteczne do walidacji pamięci długiego kontekstu.

Pozostawianie równoległości na auto

Silnik może wybrać współbieżność sensowną dla przepustowości, ale niemożliwą dla Twojego celu długiego kontekstu. Na 16 GB jedna głęboka sekwencja i kilka krótkich sekwencji to fundamentalnie różne obciążenia.

Ustaw limit jawnie, a następnie podnosz go z mierzonego ruchu. W przeciwnym razie drugie żądanie może przekształcić stabilną konfigurację 64K w niespodziankę alokacji lub opóźnienia.

Zalecane profile 16 GB

Te profile to punkty startowe, a nie uniwersalne presety. Model z nietypową geometrią KV — w szczególności projekt MLA lub hybrydowy ze śladowym oknem — może być znacznie tańszy lub droższy niż konwencjonalny przykład GQA.

Interaktywny agent kodujący

Użyj jednej sekwencji, kontekstu 48K do 64K, pamięci Q8, Flash Attention i pełnej rezydencji wag na GPU, jeśli to możliwe. Ten profil faworyzuje przewidywalne opóźnienia i dobrą precyzję pamięci ponad imponujące, ale rzadko użyteczne maksimum.

Włącz ponowne użycie przedrostka, jeśli silnik to wspiera, ponieważ tury kodowania często współdzielą duży prefiks repozytorium lub rozmowy. Nadal skompresuj wyjścia narzędzi i stare transkrypcje; inżynieria pamięci nie sprawia, że nierelewantne tokeny stają się cenne.

Analiza długich dokumentów

Użyj mniejszego modelu z pojemnością 64K do 128K, pamięci Q8 lub skalibrowanej FP8 i pamięci przedrostka przy powtarzających się prefiksach, gdy kilka pytań dotyczy tego samego dokumentu. Mierz czas do pierwszego tokenu, ponieważ prefill może dominować, nawet jeśli dekodowanie pozostaje akceptowalne.

Jeśli zostanie zadane tylko jedno pytanie, odzyskiwanie lub skompresowane podsumowanie w kawałkach może być szybsze i bardziej wiarygodne niż pchanie całego korpusu przez kartę 16 GB. Długi kontekst to narzędzie, a nie zamiennik architektury informacji.

Mały serwer wieloużytkownikowy

Limituj kontekst per żądanie i całkowitą liczbę aktywnych sekwencji, zamiast reklamować maksimum modelu każdemu klientowi. Paged allocation w vLLM jest tu przydatne, podczas gdy Ollama i llama.cpp również wymagają jawnej uwagi do łącznych aktywnych tokenów.

Preferuj kolejkowanie przed niekontrolowanym wylaniem. Wolniejsza polityka przyjęcia jest mniej szkodliwa niż nagłe przekroczenie PCIe przez wszystkie żądania podczas dekodowania.

Końcowa rekomendacja dla długiego kontekstu 16 GB

Dla długiego kontekstu na 16 GB, KV Q8 i jedna aktywna sekwencja to właściwa baza. Ujawniają rzeczywisty limit, nie powodując jednocześnie awarii jakości niskobitowej pamięci, alokacji równoległej i opóźnień odciążenia.

Obliczaj od geometrii uwagi, odejmij wagi i narzut runtime, a następnie potwierdź wynik w logach silnika i pomiarach szczytowej pamięci. Jeśli 128K nadal się nie mieści, mniejszy model jest często najsłodsza optymalizacją; jeśli się mieści, ale pełza, zmniejszenie kontekstu jest często uczciwym wyborem.

Uwaga paged, pamięć przedrostkowa, śladowe okna i adaptacyjna precyzja rozwiązują użyteczne, ale różne problemy. Wygrywająca konfiguracja to ta, która pozostaje na GPU, prawidłowo odzyskuje stare dowody i utrzymuje akceptowalną prędkość dekodowania na głębokości kontekstu, którą faktycznie używasz.

Referencje

Subskrybuj

Otrzymuj nowe wpisy o systemach, infrastrukturze i inżynierii AI.