Ollama num_ctx: як збільшити контекст prompt
Ollama непомітно обрізає довгі prompt через мале вікно контексту. Дізнайтеся, як задати num_ctx для запиту або сервера й оцінити RAM для KV cache.
Що робить num_ctx і чому ваш довгий prompt було обрізано
Контекстна довжина Ollama — це кількість токенів, які завантажена модель може одночасно зберігати в пам’яті, а num_ctx — параметр, який її встановлює. Ollama вибирає значення за замовчуванням, що значно менше за максимальний контекст, заявлений для моделі, тому довший prompt обрізається ще до того, як модель його прочитає. У відповіді немає жодної ознаки, що це сталося.
Для Llama 3.1 8B у бібліотеці моделей Ollama вказано контекстне вікно 128k. Стандартний сервер не надає такий контекст. У власній документації Ollama на різних сторінках наведено різні значення за замовчуванням: у FAQ зазначено 4096 токенів, у довідці Modelfile сказано, що num_ctx за замовчуванням дорівнює 2048, а на сторінці про довжину контексту зазначено, що значення за замовчуванням визначається доступною VRAM (відеопам’яттю): 4k для обсягу менше 24 GiB, 32k для діапазону від 24 до 48 GiB і 256k для обсягу понад 48 GiB. Кожне з цих значень було актуальним для певної збірки. Корисний висновок полягає в іншому: перевіряйте значення на власному запущеному сервері, а не покладайтеся на будь-яку сторінку, зокрема на цю.
Обрізання непомітне, оскільки модель усе одно відповідає, і відповідь залишається змістовною. Вона була сформована на основі кінцевої частини вашого input. Резюме, у якому пропущено першу половину документа, виглядає як результат роботи слабкої моделі. Зазвичай причина полягає в малій контекстній довжині.
Перевірте фактичну довжину контексту Ollama, яку застосував сервер
Перевірка, що працює в будь-якій збірці, — це prompt_eval_count, тобто кількість токенів промпту, оброблених сервером. Надішліть більше токенів, ніж може вмістити контекст, і це число зупиниться на граничному значенні.
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}'Цей промпт містить приблизно 18,000 слів, тобто значно більше за 4096 токенів. prompt_eval_count повертає значення близько 4096, а не фактичну кількість токенів, оскільки сервер відкинув решту. Запустіть команду ще раз із "num_ctx":16384 — кількість зросте. Якщо ваша збірка повертає помилку замість обрізання, це той самий результат, але з чіткішим сигналом.
ollama psУ збірках, де цей стовпець виводиться, стовпець CONTEXT містить довжину контексту, з якою завантажена модель працює зараз. Сусідній стовпець PROCESSOR показує, де розміщена модель. 100% CPU — нормальне значення для VPS без GPU. Розподіл на кшталт 30%/70% CPU/GPU на сервері з GPU означає, що ваги моделі разом із кешем більше не вміщуються у VRAM. Зазвичай причиною є збільшене значення num_ctx.
journalctl -u ollama --no-pager | grep -i n_ctx | tail -n 5Inference runner виводить розмір контексту в рядку, що містить n_ctx. Точне формулювання змінюється між релізами, тому відсутній рядок слід сприймати як перейменування, а не як доказ будь-якого факту.
Чотири місця для налаштування num_ctx
У запиті. Передайте "options": {"num_ctx": 16384} до /api/generate або /api/chat. Це налаштування має найвищий пріоритет і діє лише для цього запиту. Якщо значення відрізняється від того, з яким запущена завантажена модель, сервер спочатку повторно завантажує модель. Це видно за load_duration у відповіді: значення зростає майже з нуля до кількох повних секунд. Така сама затримка виникає, коли модель достатньо довго простоює і вивантажується. Тому після вибору розміру контексту варто залишати модель завантаженою за допомогою keep_alive.
В інтерактивному сеансі. У ollama run введіть /set parameter num_ctx 16384. Це налаштування діє протягом поточного сеансу.
У Modelfile. Так значення вбудовується в іменовану модель, і кожен клієнт отримує його без змін на стороні клієнта.
FROM llama3.1:8b
PARAMETER num_ctx 16384ollama create llama3.1-16k -f ./Modelfile
ollama run llama3.1-16kНа сервері. OLLAMA_CONTEXT_LENGTH задає значення за замовчуванням для кожного запиту, який не містить власного num_ctx. У systemd додайте drop-in, а не редагуйте файл unit.
sudo systemctl edit ollama.service[Service]
Environment="OLLAMA_CONTEXT_LENGTH=16384"sudo systemctl daemon-reload
sudo systemctl restart ollama
ollama psПріоритет налаштувань особливо важливий під час налагодження чужого клієнта. Запит із num_ctx має вищий пріоритет за значення сервера за замовчуванням. Тому chat front end або агент, який сам надсилає невелике значення, непомітно скасовує вашу зміну в systemd. Коли ви підключаєте coding agent до свого Ollama server, перевірте, що саме надсилає клієнт, перш ніж звинувачувати сервер.
Чому не можна просто встановити num_ctx на максимальне значення моделі
Механізм attention змушує кожен токен звертатися до всіх попередніх токенів. Обчислені для попередніх токенів keys і values зберігаються, щоб не обчислювати їх повторно для кожного нового токена. Це сховище називається KV cache (key/value cache). Воно виділяється для всього num_ctx під час завантаження моделі, а не в міру зростання діалогу. Тому великий контекст споживає цю пам’ять навіть для однорядкового запиту.
У посібнику DigitalOcean про вартість inference наведено розрахунок в одному рядку:
kv_bytes_per_token = 2 * layers * kv_heads * head_dim * bytes_per_valueЧисло 2 означає, що keys і values рахуються окремо. Інші значення візьміть із параметрів власної моделі.
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 вказано 32 layers і 8 key/value heads. Розмір head дорівнює embed, поділеному на heads, тобто тут 4096 / 32 = 128. Деякі моделі публікують це значення безпосередньо як llama.attention.key_length. Кеш за замовчуванням зберігає значення у форматі f16, тому bytes_per_value дорівнює 2. Розрахунок 2 32 8 128 2 дає 131,072 bytes. Отже, кожен токен контексту потребує 128 KiB кешу. Помножте це значення на довжину контексту, і витрати стають очевидними.
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
}
]Значення 6 у рядках отримано розрахунком за наведеною вище формулою, а не вимірюваннями. У стовпці total враховано 4.9 GB для завантаження, яке бібліотека Ollama вказала для llama3.1:8b у August 2026. Це 4.6 GiB. Буфери обчислень і сам серверний процес не враховано. Вважайте це мінімальною оцінкою.
Важливий масштаб витрат. За контексту 8k кеш потребує 1 GiB. Порівняно з вагами моделі це незначний обсяг. За максимального для моделі контексту 128k кеш потребує 16 GiB. Це більш ніж утричі більше за обсяг ваг. Загальне споживання становить приблизно 20.6 GiB. Тому VPS із 4 GB не може завантажити цю модель із придатною для роботи довжиною контексту. VPS із 8 GB має достатньо пам’яті для 8k. VPS із 16 GB підтримує 32k, залишаючи пам’ять для інших компонентів системи. Із зростанням обсягу ваг кожен із цих порогів також зростає. Якщо ви порівнюєте більшу модель із цією 8B, ті самі розрахунки для тега Qwen 27B на VPS лише з CPU показують, як мало пам’яті залишається для контексту на системах із 8–64 GB.
Що відбувається, коли KV cache не вміщується
На VPS лише з CPU процес просто збільшується за обсягом. Спостерігайте за ним під час завантаження моделі та виконання тривалого запиту.
free -m
ps -eo rss,comm --sort=-rss | head -n 5RSS (resident set size) виводиться в кілобайтах. Якщо використання swap у free -m починає зростати, зменште розмір контексту. KV cache у swap спричиняє зупинки генерації на кілька секунд для кожного токена, оскільки кожен новий токен читає весь cache.
Якщо на сервері повністю закінчується пам’ять, kernel вибирає найбільший процес і завершує його.
sudo dmesg | grep -i "killed process"Рядок із Out of memory: Killed process 1234 (ollama) означає, що запитаний розмір контексту не вмістився. Ollama часто відмовляє ще до цього моменту, і тоді запит завершується помилкою, у якій зазначено потрібний обсяг пам’яті та обсяг вільної пам’яті.
На сервері з GPU збій менш очевидний. Частина шарів переміщується в системну RAM, ollama ps показує розподіл між CPU і GPU, а пропускна здатність різко знижується. Наскільки різко — залежить від обладнання, тому вимірюйте кількість токенів за секунду на власному сервері для кожного значення контексту, а не покладайтеся на показник з іншої системи.
Підготовка prompt зростає швидше, ніж сам prompt
Prefill — це обробка вашого вводу до появи першого токена відповіді. Кожен токен prompt обробляється з урахуванням усіх попередніх токенів, тому загальний обсяг роботи зростає пропорційно квадрату довжини вводу. Якщо подвоїти prompt, час очікування першого токена зросте більш ніж удвічі.
Відповідь містить вимірювання, тому вам не потрібно приймати це без перевірки.
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)}'Запустіть це з коротким і довгим промптом, а потім у кожному випадку поділіть кількість токенів на кількість секунд. На VPS лише з CPU prefill зазвичай є найповільнішою частиною запиту з довгим контекстом, тому показник токенів за секунду, отриманий для короткого промпту, не прогнозує час його обробки. Якщо prefill триває довше, ніж дозволяє встановлений перед ним timeout, довгий промпт зазвичай завершується повідомленням перевищено граничний час контексту, а не відповіддю. Тому спочатку з’ясуйте, який саме рівень перервав операцію, і лише потім скорочуйте контекст.
Найбільше це впливає на одночасну обробку запитів. Кожен запит, який обслуговується, потребує власного кешу. Тому обсяг пам’яті на наведеній вище діаграмі вказано для одного запиту, а не для всього сервера. Один довгий запит може зайняти весь сервер, поки короткі запити стоятимуть у черзі. Установлюйте OLLAMA_NUM_PARALLEL обдумано та перегляньте скільки одночасних користувачів може обслуговувати self-hosted LLM, перш ніж одночасно збільшувати обидва значення.
Поверніть контекст, зменшивши кеш
bytes_per_value у формулі — це параметр, яким ви керуєте. У FAQ Ollama описано OLLAMA_KV_CACHE_TYPE, де f16 є типовим значенням — 2 байти, а q8_0 використовує 1 байт, тоді як q4_0 має ще менше значення. Перехід на q8_0 удвічі зменшує кеш, тому рядок на 32k потребує 2 GiB замість 4 GiB. Квантування ваг вивільняє пам’ять з іншої частини того самого бюджету, а тег GLM, який фактично вміщується на VPS розглядається з варіантами квантування, якщо ви віддаєте перевагу такому компромісу. У тому самому FAQ описано OLLAMA_FLASH_ATTENTION=1, який деякі збірки потребують перед застосуванням квантизованого кешу.
[Service]
Environment="OLLAMA_FLASH_ATTENTION=1"
Environment="OLLAMA_KV_CACHE_TYPE=q8_0"Не робіть припущень, а перевірте результат: перезапустіть сервіс, завантажте модель із тим самим num_ctx, що й раніше, і порівняйте RSS. Підтримка залежить від моделі та бекенду, тому параметр, який нічого не змінює, означає, що ваша комбінація не підтримується. У документації ці параметри наведено без гарантії якості результату, тому перевірте q4_0 на власних запитах, перш ніж покладатися на нього. Якщо ви звернулися до цього матеріалу через ці параметри, Ollama і llama.cpp реалізують їх по-різному.
Рекомендації щодо вибору num_ctx
- Зчитайте максимальний контекст моделі, кількість її шарів і кількість голів key/value з
/api/show. - Обчисліть кількість байтів на токен за формулою, а потім помножте її на потрібний розмір контексту.
- Додайте розмір ваг, порівняйте результат із вільною RAM і залиште щонайменше 1 GiB для інших процесів сервера.
- Установіть значення, завантажте модель, а потім перевірте застосовані параметри за допомогою
ollama psіprompt_eval_count. - Запустіть реальне робоче навантаження, стежачи за
free -m, і зменште контекст удвічі, якщо swap почне використовуватися.
Для більшості завдань потрібен менший контекст, ніж зазвичай указують. Резюме довгого звіту вміщується в 16k. Front end для retrieval, який додає п’ять фрагментів документів, рідко перевищує 8k. Coding agent, який читає цілі файли, є випадком, коли справді потрібен контекст 64k або більше. У такому разі машину слід підбирати за розміром контексту, а не навпаки. Якщо сервер ще не налаштований, почніть із робочої інсталяції Ollama на VPS і налаштуйте контекст після того, як моделі почнуть завантажуватися без помилок.
FAQ
Яка довжина контексту встановлена в Ollama за замовчуванням?
Це залежить від збірки та обладнання, тому перевіряйте значення, а не припускайте його. У FAQ Ollama зазначено 4096 токенів, у довідці щодо Modelfile — значення num_ctx за замовчуванням, яке дорівнює 2048, а на сторінці про довжину контексту — значення за замовчуванням, вибране за доступним VRAM: 4k для обсягу менше ніж 24 GiB, 32k для 24–48 GiB і 256k для понад 48 GiB. VPS лише з CPU використовує нижнє значення. ollama ps виводить застосовану довжину контексту в збірках, де є відповідний стовпець, а prompt_eval_count у відповіді API підтверджує її в будь-якій збірці.
Чому Ollama ігнорує початок мого довгого промпту?
Тому що промпт був довшим за контекстне вікно. Сервер обрізав його до того, як модель отримала запит, і не повернув помилку. Надішліть той самий промпт ще раз із більшим значенням num_ctx і перевірте, чи збільшується prompt_eval_count у відповіді. Якщо це число не змінюється, щось між вами та сервером самостійно встановлює num_ctx. Це часто трапляється з chat front end і agent framework.
Скільки додаткової RAM потребує більший num_ctx?
Помножте довжину контексту на вартість кешу на один токен: це 2 * layers * kv_heads * head_dim * bytes_per_value. Для Llama 3.1 8B у режимі f16 це 128 KiB на токен. Тому 32k токенів потребують 4 GiB, а повні 128k — 16 GiB додатково до пам’яті під ваги моделі. Кеш виділяється під час завантаження моделі, тому велике значення num_ctx споживає цю пам’ять, навіть якщо ваші промпти залишаються короткими.
Чи робить більше контекстне вікно Ollama повільнішою?
Так, з двох причин. Обсяг роботи на етапі prefill зростає пропорційно квадрату довжини промпту, тому довгий вхідний текст затримує появу першого токена сильніше, ніж можна припустити лише за його довжиною. Більший кеш також конкурує за пам’ять: на GPU-сервері він переміщує частину шарів у системну RAM, а на CPU-сервері наближає систему до використання swap. Велике значення num_ctx, яке ви ніколи не заповнюєте, усе одно споживає пам’ять, хоча й не збільшує час prefill.
Чи можна назавжди встановити num_ctx для однієї моделі?
Так. Створіть Modelfile, що містить FROM llama3.1:8b і PARAMETER num_ctx 16384, а потім виконайте ollama create llama3.1-16k -f ./Modelfile. Кожен клієнт, який запитує llama3.1-16k, отримує цей контекст без передавання додаткових параметрів. Запит із власним значенням num_ctx має вищий пріоритет, тому це встановлює значення за замовчуванням, а не верхню межу.