SSD Nodes Learn Hosting plans →
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-09-06

Ollama: как увеличить контекст через num_ctx

Ollama обрезает длинный prompt из-за небольшого окна по умолчанию. Настройте num_ctx для запроса или сервера и заранее оцените RAM для KV cache.

Что делает num_ctx и почему длинный prompt был обрезан

Длина контекста Ollama — это количество токенов, которое загруженная модель может одновременно хранить в памяти, а num_ctx — параметр, который её задаёт. Ollama выбирает значение по умолчанию, значительно меньше максимального значения, заявленного для модели, поэтому длинный prompt обрезается ещё до того, как модель его прочитает. В ответе нет признака того, что это произошло.

В библиотеке моделей Ollama для Llama 3.1 8B указано окно контекста 128k. Стандартная конфигурация сервера не предоставит вам этот объём. В собственной документации Ollama на разных страницах указаны разные значения по умолчанию: в FAQ указано 4096 токенов, в справочнике Modelfile для num_ctx указано значение по умолчанию 2048, а на странице о длине контекста сказано, что значение по умолчанию выбирается по доступной VRAM (видеопамяти): 4k при объёме менее 24 GiB, 32k при объёме от 24 до 48 GiB и 256k при объёме более 48 GiB. Каждое из этих утверждений соответствовало некоторой сборке. Полезный вывод из этого расхождения: проверяйте значение на собственном запущенном сервере, а не доверяйте ни одной странице, включая эту.

Обрезание происходит незаметно, потому что модель по-прежнему отвечает, и ответ по-прежнему выглядит связным. Но он сформирован по хвосту входных данных. Резюме, в котором пропущена первая половина документа, выглядит как результат работы слабой модели. Обычно причина в небольшом размере контекста.

Проверьте фактический размер контекста, применённый сервером 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 означает, что веса модели вместе с cache больше не помещаются в VRAM. Обычно это происходит из-за увеличенного num_ctx.

journalctl -u ollama --no-pager | grep -i n_ctx | tail -n 5

Модуль выполнения inference выводит размер контекста в строке, содержащей 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 16384
ollama create llama3.1-16k -f ./Modelfile
ollama run llama3.1-16k

На сервере. OLLAMA_CONTEXT_LENGTH задаёт значение по умолчанию для каждого запроса, в котором отсутствует собственный num_ctx. В systemd добавьте drop-in-файл вместо изменения файла юнита.

sudo systemctl edit ollama.service
[Service]
Environment="OLLAMA_CONTEXT_LENGTH=16384"
sudo systemctl daemon-reload
sudo systemctl restart ollama
ollama ps

Приоритет параметров особенно важен при отладке клиента, которым управляет другой разработчик. Запрос с num_ctx имеет приоритет над значением сервера по умолчанию. Поэтому web-интерфейс чата или агент, который отправляет небольшое значение, может незаметно отменить изменение в systemd. Когда вы подключаете coding agent к серверу Ollama, сначала проверьте, что отправляет клиент, и только потом ищите причину на сервере.

Почему нельзя просто задать 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 слоя и 8 key/value heads. Размер head — это embed, разделённый на heads. В данном случае 4096 / 32 = 128. Некоторые модели публикуют это значение напрямую как llama.attention.key_length. В cache по умолчанию хранятся значения в формате f16, поэтому bytes_per_value равно 2. Расчёт 2 32 8 128 2 даёт 131,072 байта. Это 128 KiB cache на каждый токен контекста. Умножьте это значение на длину контекста, и затраты памяти станут очевидными.

ChartLlama 3.1 8B at f16: KV cache and total RAM by context length, in GiB
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 строк получены арифметически по приведённой выше формуле, а не измерены. В столбце с итогом учтены 4.9 GB загрузки, которую библиотека Ollama указывала для llama3.1:8b в августе 2026 года. Это 4.6 GiB. Буферы вычислений и сам процесс сервера не учтены. Считайте это минимальной оценкой.

Важен общий масштаб. При 8k cache занимает 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-кэш не помещается

На VPS только с CPU процесс просто увеличивается. Наблюдайте за ним во время загрузки модели и выполнения длинного запроса.

free -m
ps -eo rss,comm --sort=-rss | head -n 5

RSS (размер резидентного набора) выводится в килобайтах. Если значение используемого swap в free -m начинает расти, уменьшите размер контекста. KV-кэш, размещённый в swap, приводит к остановкам генерации на несколько секунд для каждого токена, поскольку каждый новый токен считывает весь кэш.

Если память на сервере полностью заканчивается, ядро выбирает самый крупный процесс и завершает его.

sudo dmesg | grep -i "killed process"

Строка с Out of memory: Killed process 1234 (ollama) означает, что запрошенный размер контекста не поместился. Ollama часто отказывает ещё до этого этапа, и запрос завершается ошибкой с указанием объёма требуемой памяти и объёма свободной памяти.

На сервере с GPU ошибка проявляется менее заметно. Слои выгружаются в системную RAM, ollama ps показывает распределение между CPU и GPU, а производительность резко снижается. Степень снижения зависит от оборудования, поэтому измеряйте количество токенов в секунду на своём сервере для каждого размера контекста, а не ориентируйтесь на значение с чужой машины.

Время prefill растёт быстрее, чем длина 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)}'

Запустите это с коротким prompt, затем повторите с длинным и в каждом случае разделите количество tokens на число секунд. На VPS только с CPU prefill обычно занимает больше всего времени при запросах с длинным контекстом, а показатель tokens per second, полученный на коротком prompt, не позволяет спрогнозировать это время. Если prefill длится дольше, чем заданный перед ним timeout, длинный prompt обычно завершается ошибкой превышено время ожидания контекста, а не выдачей ответа. Поэтому сначала выясните, какой слой прекратил ожидание, и только потом сокращайте контекст.

При параллельной обработке это особенно заметно. Для каждого обслуживаемого запроса нужен собственный cache. Поэтому указанное выше потребление памяти относится к одному запросу, а не ко всему серверу. Один длинный запрос может занять сервер, пока короткие запросы стоят в очереди. Настраивайте OLLAMA_NUM_PARALLEL осознанно и ознакомьтесь с материалом о количестве одновременных пользователей, которых может обслуживать self-hosted LLM, прежде чем одновременно увеличивать оба значения.

Сэкономьте память за счёт уменьшения cache

bytes_per_value в формуле — это параметр, которым вы управляете. В FAQ Ollama описан OLLAMA_KV_CACHE_TYPE, при этом по умолчанию используется f16 размером 2 байта, а также q8_0 размером 1 байт и q4_0 с меньшим размером. Переход на q8_0 вдвое уменьшает cache, поэтому строка размером 32k занимает 2 GiB вместо 4 GiB. Квантизация весов освобождает память с другой стороны того же бюджета, а тег GLM, который действительно помещается на VPS рассмотрен с квантизацией каждого уровня, если вы предпочитаете такой компромисс. В том же FAQ описан OLLAMA_FLASH_ATTENTION=1, который некоторые сборки требуют включить до применения квантизированного cache.

[Service]
Environment="OLLAMA_FLASH_ATTENTION=1"
Environment="OLLAMA_KV_CACHE_TYPE=q8_0"

Проверьте результат, а не делайте предположения: перезапустите сервис, загрузите модель с тем же num_ctx, что и раньше, и сравните RSS. Поддержка зависит от модели и backend, поэтому отсутствие изменений после настройки означает, что ваша комбинация не поддерживается. В документации эти параметры перечислены без гарантии приемлемого качества, поэтому проверьте q4_0 на собственных запросах, прежде чем полагаться на него. Если вы перешли к этому разделу из-за этих параметров, Ollama и llama.cpp предоставляют их по-разному.

Как выбрать значение num_ctx

  1. Считайте максимальный размер контекста модели, количество её слоёв и количество голов key/value из /api/show.
  2. Рассчитайте количество байт на токен по формуле, затем умножьте результат на нужный размер контекста.
  3. Прибавьте размер весов, сравните итог с доступным объёмом RAM и оставьте не менее 1 GiB для остальных задач сервера.
  4. Задайте значение, загрузите модель и проверьте применённые параметры с помощью ollama ps и prompt_eval_count.
  5. Запустите рабочую нагрузку и следите за free -m. Если swap начинает использоваться, уменьшите размер контекста вдвое.

Для большинства задач требуется меньший контекст, чем обычно задают. Для суммаризации длинного отчёта достаточно 16k. Интерфейс поиска, который передаёт модели пять фрагментов документов, редко использует более 8k. Агент для работы с кодом, который читает файлы целиком, действительно может требовать 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 ends и agent frameworks.

Сколько дополнительной RAM требуется для большего num_ctx?

Умножьте длину контекста на стоимость cache на токен. Она составляет 2 * layers * kv_heads * head_dim * bytes_per_value. Для Llama 3.1 8B при f16 это 128 KiB на токен, поэтому 32k токенов требуют 4 GiB, а полные 128k требуют 16 GiB сверх памяти под weights. Cache выделяется при загрузке модели, поэтому большое значение num_ctx занимает этот объём памяти, даже если ваши промпты остаются короткими.

Делает ли большее окно контекста Ollama медленнее?

Да, по двум причинам. Объём работы на этапе prefill растёт пропорционально квадрату длины промпта, поэтому длинный ввод задерживает выдачу первого токена сильнее, чем можно предположить по его длине. Больший cache также конкурирует за память: на сервере с GPU он вытесняет слои в system 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, получает этот контекст без передачи каких-либо options. Запрос с собственным значением num_ctx имеет приоритет, поэтому это значение задаёт default, а не верхний предел.