Ollama: jak zwiększyć limit num_ctx dla długich promptów
Dowiedz się jak poprawnie skonfigurować parametr num_ctx w Ollama, aby uniknąć ucinania długich promptów. Sprawdź jak obliczyć zapotrzebowanie na pamięć VRAM przed zmianą ustawień.
Czym jest num_ctx i dlaczego długi prompt został ucięty
Długość kontekstu w Ollama to liczba tokenów, które załadowany model może jednocześnie przechowywać w pamięci, a num_ctx jest opcją służącą do jej ustawienia. Ollama wybiera wartość domyślną znacznie niższą od maksymalnej deklarowanej przez model, dlatego zbyt długi prompt jest ucinany, zanim model zdąży go odczytać. Żaden element odpowiedzi nie informuje o wystąpieniu tego zdarzenia.
Model Llama 3.1 8B jest wymieniony w bibliotece modeli Ollama z oknem kontekstowym 128k. Standardowy serwer nie zapewni takiej wartości. Dokumentacja Ollama podaje różne wartości domyślne na różnych stronach: FAQ wskazuje na 4096 tokenów, dokumentacja Modelfile podaje, że num_ctx domyślnie wynosi 2048, a strona dotycząca długości kontekstu informuje, że wartość domyślna jest dobierana na podstawie dostępnej pamięci VRAM (video RAM): 4k poniżej 24 GiB, 32k dla zakresu od 24 do 48 GiB oraz 256k powyżej tej wartości. Każde z tych stwierdzeń było prawdziwe dla określonej wersji kompilacji. Rozbieżność ta stanowi istotną lekcję: należy odczytać wartość z własnego, uruchomionego serwera, zamiast polegać na jakiejkolwiek stronie, w tym na niniejszej.
Ucinanie danych odbywa się w sposób cichy, ponieważ model nadal generuje odpowiedź, która brzmi poprawnie. Została ona napisana na podstawie końcowej części danych wejściowych. Podsumowanie, które pomija pierwszą połowę dokumentu, sprawia wrażenie słabego modelu. Zazwyczaj przyczyną jest zbyt małe okno kontekstowe.
Weryfikacja długości kontekstu Ollama faktycznie zastosowanej przez serwer
Weryfikacja działająca w każdej kompilacji to prompt_eval_count, czyli liczba tokenów promptu, którą serwer raportuje jako przetworzoną. Wyślij więcej danych, niż mieści kontekst, a liczba ta zatrzyma się na limicie.
sudo apt update && sudo apt install -y jq
LONG=$(python3 -c "print('the quick brown fox jumps over the lazy dog. ' * 2000)")
jq -n --arg p "$LONG" '{model:"llama3.1:8b", prompt:$p, stream:false, options:{num_ctx:4096}}' |
curl -s http://localhost:11434/api/generate -d @- |
jq '{prompt_eval_count, prompt_eval_duration}'Ten prompt zawiera około 18 000 słów, czyli znacznie więcej niż 4096 tokenów. prompt_eval_count zwraca wartość bliską 4096, a nie rzeczywistą liczbę tokenów, ponieważ serwer odrzucił resztę. Uruchom to ponownie z "num_ctx":16384, a liczba wzrośnie. Jeśli kompilacja zwraca błąd zamiast ucinania danych, oznacza to ten sam wynik, ale z wyraźniejszym sygnałem.
ollama psKolumna CONTEXT, w kompilacjach które ją wyświetlają, zawiera długość kontekstu, z jaką aktualnie działa załadowany model. Kolumna PROCESSOR obok niej wskazuje, gdzie znajduje się model. 100% CPU jest wartością normalną na VPS bez GPU. Podział taki jak 30%/70% CPU/GPU na maszynie z GPU oznacza, że wagi wraz z pamięcią podręczną nie mieszczą się już w VRAM, a najczęstszą przyczyną jest podniesiona wartość num_ctx.
journalctl -u ollama --no-pager | grep -i n_ctx | tail -n 5Moduł wnioskowania (inference runner) drukuje rozmiar swojego kontekstu w linii zawierającej n_ctx. Dokładne brzmienie komunikatu zmienia się między wydaniami, więc brak tej linii należy traktować jako zmianę nazwy, a nie jako dowód czegokolwiek.
Cztery miejsca konfiguracji num_ctx
W żądaniu. Prześlij "options": {"num_ctx": 16384} do /api/generate lub /api/chat. To ustawienie ma najwyższy priorytet i dotyczy tylko tego jednego wywołania. Jeśli wartość różni się od tej, z którą uruchomiono załadowany model, serwer najpierw przeładuje model, co można zaobserwować w load_duration w odpowiedzi: czas wzrośnie z wartości bliskich zeru do pełnych sekund.
W sesji interaktywnej. Wewnątrz ollama run wpisz /set parameter num_ctx 16384. Ustawienie obowiązuje przez czas trwania tej sesji.
W pliku Modelfile. Ta metoda trwale przypisuje wartość do nazwanego modelu, dzięki czemu każdy klient korzysta z niej bez konieczności wprowadzania zmian po swojej stronie.
FROM llama3.1:8b
PARAMETER num_ctx 16384ollama create llama3.1-16k -f ./Modelfile
ollama run llama3.1-16kNa serwerze. OLLAMA_CONTEXT_LENGTH definiuje wartość domyślną dla każdego żądania, które nie zawiera własnego parametru num_ctx. W systemd należy dodać plik typu drop-in zamiast edytować główny plik jednostki.
sudo systemctl edit ollama.service[Service]
Environment="OLLAMA_CONTEXT_LENGTH=16384"sudo systemctl daemon-reload
sudo systemctl restart ollama
ollama psKolejność pierwszeństwa ma kluczowe znaczenie podczas debugowania klienta innej osoby. Żądanie zawierające num_ctx nadpisuje ustawienie domyślne serwera, więc interfejs czatu lub agent przesyłający własną, niską wartość, może nieświadomie unieważnić zmiany wprowadzone w systemd. Gdy konfigurujesz agenta programistycznego do pracy z serwerem Ollama, sprawdź, co wysyła klient, zanim przypiszesz winę serwerowi.
Dlaczego nie można po prostu ustawić num_ctx na wartość maksymalną modelu
Mechanizm atencji sprawia, że każdy token analizuje wszystkie poprzednie tokeny. Klucze i wartości obliczone dla wcześniejszych tokenów są przechowywane, aby nie trzeba było ich przeliczać dla każdego nowego tokenu; ten magazyn to KV cache (pamięć podręczna kluczy/wartości). Jest ona alokowana dla całego num_ctx w momencie ładowania modelu, a nie w miarę rozwoju konwersacji, więc duży kontekst zajmuje pamięć nawet przy zapytaniu składającym się z jednej linii.
Samouczek DigitalOcean dotyczący kosztów wnioskowania przedstawia obliczenia w jednej linii:
kv_bytes_per_token = 2 * layers * kv_heads * head_dim * bytes_per_valueCyfra 2 oznacza oddzielne zliczanie kluczy i wartości. Pozostałe liczby należy odczytać z parametrów własnego modelu.
curl -s http://localhost:11434/api/show -d '{"model":"llama3.1:8b"}' |
jq '.model_info | {ctx: ."llama.context_length", layers: ."llama.block_count", heads: ."llama.attention.head_count", kv_heads: ."llama.attention.head_count_kv", embed: ."llama.embedding_length"}'Llama 3.1 8B posiada 32 warstwy i 8 głowic kluczy/wartości. Wymiar głowicy to embed podzielone przez heads, czyli w tym przypadku 4096 / 32 = 128, a niektóre modele podają tę wartość bezpośrednio jako llama.attention.key_length. Domyślna pamięć podręczna przechowuje wartości f16, więc bytes_per_value wynosi 2, a działanie 2 32 8 128 2 daje 131 072 bajty. Jest to 128 KiB pamięci podręcznej na każdy pojedynczy token kontekstu. Po pomnożeniu przez długość kontekstu koszt przestaje być abstrakcyjny.
The data behind this chart
[
{
"label": "4k",
"kv_cache_gib": 0.5,
"total_ram_gib": 5.1
},
{
"label": "8k",
"kv_cache_gib": 1,
"total_ram_gib": 5.6
},
{
"label": "16k",
"kv_cache_gib": 2,
"total_ram_gib": 6.6
},
{
"label": "32k",
"kv_cache_gib": 4,
"total_ram_gib": 8.6
},
{
"label": "64k",
"kv_cache_gib": 8,
"total_ram_gib": 12.6
},
{
"label": "128k",
"kv_cache_gib": 16,
"total_ram_gib": 20.6
}
]Wiersze 6 wynikają z powyższego wzoru, a nie z pomiarów. Kolumna sumy uwzględnia pobranie 4,9 GB, które biblioteka Ollama wskazała dla llama3.1:8b w sierpniu 2026 roku, co daje 4,6 GiB, i pomija bufory obliczeniowe oraz sam proces serwera. Należy traktować to jako wartość minimalną.
Kluczowe znaczenie ma skala. Przy 8k pamięć podręczna kosztuje 1 GiB, co jest wartością pomijalną w porównaniu z wagami modelu. Przy pełnych 128k modelu kosztuje ona 16 GiB, czyli ponad trzy razy więcej niż same wagi, co daje łącznie blisko 20.6 GiB. Zatem serwer VPS o pojemności 4 GB nie załaduje tego modelu z żadnym użytecznym kontekstem. Serwer VPS o pojemności 8 GB pozwala na komfortową pracę przy 8k. Serwer VPS o pojemności 16 GB osiąga 32k, pozostawiając zapas pamięci dla reszty systemu. Każdy z tych progów przesuwa się wraz z wagami, więc przy porównywaniu większego modelu z tym 8B, te same obliczenia wykonane dla tagu Qwen 27B na VPS tylko z CPU pokazują, jak niewiele miejsca wagi pozostawiają na kontekst w przedziale od 8 do 64 GB.
Co się dzieje, gdy pamięć podręczna KV nie mieści się w pamięci
Na serwerze VPS korzystającym wyłącznie z procesora (CPU) proces po prostu zwiększa swoje zapotrzebowanie na pamięć. Należy monitorować ten proces podczas ładowania modelu oraz w trakcie przetwarzania długiego zapytania.
free -m
ps -eo rss,comm --sort=-rss | head -n 5Wartość RSS (resident set size) jest wyświetlana w kilobajtach. Jeśli użycie partycji wymiany (swap) w free -m zaczyna rosnąć, należy zmniejszyć rozmiar kontekstu. Pamięć podręczna KV znajdująca się w swapie powoduje, że generowanie tokenów zatrzymuje się na sekundy, ponieważ każdy nowy token wymaga odczytania całej pamięci podręcznej.
Jeśli w systemie całkowicie zabraknie pamięci, jądro wybierze proces o największym zapotrzebowaniu i zakończy go (OOM Killer).
sudo dmesg | grep -i "killed process"Wiersz zawierający Out of memory: Killed process 1234 (ollama) oznacza, że żądany kontekst nie zmieścił się w pamięci. Ollama często odrzuca zapytanie, zanim do tego dojdzie, a żądanie kończy się niepowodzeniem z komunikatem wskazującym ilość wymaganej pamięci w odniesieniu do dostępnych zasobów.
Na serwerze z procesorem graficznym (GPU) awaria przebiega mniej gwałtownie. Warstwy modelu są przenoszone do pamięci RAM systemu, ollama ps pokazuje podział obciążenia między CPU a GPU, a przepustowość drastycznie spada. Skala spadku zależy od używanego sprzętu, dlatego należy zmierzyć liczbę tokenów na sekundę na własnym serwerze dla każdego ustawienia kontekstu, zamiast polegać na wynikach uzyskanych na innej maszynie.
Czas prefill rośnie szybciej niż długość promptu
Prefill to operacja wykonywana na danych wejściowych przed wygenerowaniem pierwszego tokena wyjściowego. Każdy token promptu odnosi się do wszystkich poprzedzających go tokenów, dlatego całkowity nakład pracy rośnie kwadratowo względem długości danych wejściowych. Podwojenie długości promptu powoduje ponad dwukrotny wzrost czasu oczekiwania na pierwszy token.
Odpowiedź zawiera pomiar, więc nie trzeba polegać na szacunkach.
jq -n --arg p "$LONG" '{model:"llama3.1:8b", prompt:$p, stream:false, options:{num_ctx:16384}}' |
curl -s http://localhost:11434/api/generate -d @- |
jq '{tokens: .prompt_eval_count, prefill_seconds: (.prompt_eval_duration/1000000000)}'Należy uruchomić to z krótkim promptem, a następnie z długim, dzieląc liczbę tokenów przez liczbę sekund w każdym przypadku. Na serwerach VPS korzystających wyłącznie z CPU, faza prefill jest zazwyczaj najwolniejszym elementem żądania z długim kontekstem, a wskaźnik tokenów na sekundę uzyskany z krótkiego promptu nie pozwoli jej przewidzieć.
Współbieżność jest obszarem, w którym odczuwa się to najbardziej. Każde obsługiwane żądanie wymaga własnej pamięci podręcznej, więc zużycie pamięci przedstawione na wykresie powyżej dotyczy pojedynczego żądania, a nie całego serwera. Jedno długie żądanie może zablokować zasoby, podczas gdy krótkie żądania będą czekać w kolejce. Wartość OLLAMA_NUM_PARALLEL należy ustawiać świadomie i zapoznać się z artykułem ilu użytkowników jednocześnie może obsłużyć samodzielnie hostowany LLM przed jednoczesnym zwiększeniem obu tych parametrów.
Odzyskiwanie pamięci podręcznej przy użyciu mniejszego cache
bytes_per_value we wzorze to ustawienie, którym można sterować. FAQ Ollama dokumentuje OLLAMA_KV_CACHE_TYPE, gdzie f16 jest wartością domyślną wynoszącą 2 bajty, a q8_0 wynosi 1 bajt, przy czym q4_0 oznacza wartości niższe. Przejście na q8_0 zmniejsza cache o połowę, więc wiersz 32k zajmuje 2 GiB zamiast 4 GiB. To samo FAQ dokumentuje OLLAMA_FLASH_ATTENTION=1, którego niektóre kompilacje wymagają przed aktywacją skwantowanego cache.
[Service]
Environment="OLLAMA_FLASH_ATTENTION=1"
Environment="OLLAMA_KV_CACHE_TYPE=q8_0"Należy potwierdzić, zamiast zakładać: zrestartuj usługę, załaduj model z tym samym num_ctx co poprzednio i porównaj wartość RSS. Obsługa zależy od modelu oraz backendu, więc jeśli ustawienie nie przynosi zmian, oznacza to, że dana kombinacja nie jest wspierana. Dokumentacja wymienia te opcje bez gwarancji jakości wyników, dlatego przetestuj q4_0 na własnych promptach, zanim zaczniesz na nich polegać. Jeśli te parametry są powodem wizyty w tym miejscu, Ollama i llama.cpp udostępniają je w różny sposób.
Przepis na dobór num_ctx
- Odczytaj maksymalny kontekst modelu, liczbę warstw oraz liczbę głowic klucza/wartości z
/api/show. - Oblicz liczbę bajtów na token za pomocą wzoru, a następnie pomnóż ją przez pożądaną wielkość kontekstu.
- Dodaj rozmiar wag, porównaj wynik z dostępną pamięcią RAM i zachowaj co najmniej 1 GiB zapasu dla pozostałych procesów systemowych.
- Ustaw wartość, załaduj model, a następnie potwierdź zastosowane parametry za pomocą
ollama psorazprompt_eval_count. - Uruchom właściwe zadania, monitorując
free -m, i zmniejsz kontekst o połowę, jeśli zacznie być używana przestrzeń wymiany (swap).
Większość zadań wymaga mniejszego kontekstu, niż zazwyczaj się zakłada. Podsumowanie długiego raportu mieści się w 16k. Interfejs wyszukiwania, który wkleja pięć fragmentów dokumentów, rzadko przekracza 8k. Agent programistyczny czytający całe pliki to przypadek, który faktycznie wymaga 64k lub więcej; jest to również sytuacja, w której należy dobrać parametry maszyny pod kątem kontekstu, a nie odwrotnie. Jeśli serwer jest nowy, zacznij od działającej instalacji Ollama na VPS i dostosuj kontekst, gdy modele będą się poprawnie ładować.
FAQ
Jaka jest domyślna długość kontekstu w Ollama?
Zależy to od kompilacji oraz sprzętu, dlatego należy to sprawdzić, zamiast zakładać wartość. FAQ Ollama podaje 4096 tokenów, dokumentacja Modelfile wskazuje na num_ctx domyślnie 2048, a strona dotycząca długości kontekstu opisuje wartość dobieraną na podstawie dostępnej pamięci VRAM: 4k poniżej 24 GiB, 32k od 24 do 48 GiB oraz 256k powyżej. VPS działający wyłącznie na CPU otrzymuje najniższą wartość. ollama ps wyświetla zastosowany kontekst w kompilacjach zawierających tę kolumnę, a prompt_eval_count w odpowiedzi API potwierdza go w każdej kompilacji.
Dlaczego Ollama ignoruje początek mojego długiego promptu?
Ponieważ prompt był dłuższy niż okno kontekstowe, więc serwer uciął go, zanim model go przetworzył, nie zwracając przy tym błędu. Wyślij ten sam prompt ponownie z większym num_ctx i obserwuj, jak rośnie prompt_eval_count w odpowiedzi. Jeśli ta liczba się nie zmienia, oznacza to, że coś pomiędzy Tobą a serwerem narzuca własne num_ctx, co jest częstym zjawiskiem w interfejsach czatowych i frameworkach agentowych.
Ile dodatkowej pamięci RAM wymaga większe num_ctx?
Pomnóż długość kontekstu przez koszt pamięci podręcznej na token, który wynosi 2 * layers * kv_heads * head_dim * bytes_per_value. Dla Llama 3.1 8B w formacie f16 jest to 128 KiB na token, więc 32k tokenów kosztuje 4 GiB, a pełne 128k kosztuje 16 GiB ponad wagę modelu. Pamięć podręczna jest przydzielana w momencie ładowania modelu, więc duże num_ctx zajmuje tę pamięć nawet wtedy, gdy Twoje prompty pozostają krótkie.
Czy większe okno kontekstowe spowalnia Ollama?
Tak, na dwa sposoby. Czas przetwarzania wstępnego (prefill) rośnie kwadratowo wraz z długością promptu, więc długie dane wejściowe opóźniają pierwszy token bardziej, niż sugerowałaby sama długość. Większa pamięć podręczna konkuruje również o zasoby pamięci: na serwerze z GPU wypycha warstwy do pamięci RAM systemu, a na serwerze z samym CPU zbliża maszynę do użycia swapu. Duże num_ctx, którego nigdy nie zapełnisz, nadal zajmuje pamięć, choć nie wpływa na czas przetwarzania wstępnego.
Czy mogę ustawić num_ctx na stałe dla jednego modelu?
Tak. Utwórz plik Modelfile zawierający FROM llama3.1:8b oraz PARAMETER num_ctx 16384, a następnie uruchom ollama create llama3.1-16k -f ./Modelfile. Każdy klient, który wywoła llama3.1-16k, otrzyma ten kontekst bez konieczności przesyłania dodatkowych opcji. Żądanie zawierające własne num_ctx nadal ma pierwszeństwo, więc ustawienie to pełni rolę wartości domyślnej, a nie limitu górnego.