Контекстное окно и память: как считать
«Модель поддерживает 128k контекста» — строка из карточки, которая не говорит, сколько это весит в оперативной памяти и сколько токенов останется на ответ после истории диалога. Контекстное окно — это общий бюджет токенов, а не резиновая величина, и его нехватка выглядит не как понятная ошибка, а как модель, которая вдруг «забыла» начало разговора или обрывает ответ на полуслове. Разберём, как токены считаются для русского текста, откуда берётся память под контекст и как посчитать её заранее — а не по факту падения сервиса.
Содержание
- Контекстное окно — это токены, а не мегабайты текста
- Токены: как считать по-русски, а не по правилу из англоязычного гайда
- Почему память растёт вместе с контекстом: KV-кэш и разная цена у похожих моделей
- Таблица: сколько памяти добавляет контекст на разных моделях
- RoPE-масштабирование: почему заявленные 128k — не всегда 128k без потерь
- Многоходовые диалоги: контекст — это весь разговор, а не последнее сообщение
- Какой сервер под контекст брать в MAATRIX
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Контекстное окно — это токены, а не мегабайты текста
Контекстное окно — не «сколько текста понимает модель», а общее число токенов, которое одновременно помещается в одном обмене: системный промпт, история диалога, новый вопрос и место под ответ модели. Один бюджет на всё сразу, а не отдельный лимит на вход и отдельный на выход.
У путаницы два источника: архитектурный максимум модели, заложенный при обучении и зашитый в веса, и num_ctx — реальный размер окна, который выставляется при запуске и упирается в доступную память. Числа разные: в карточке модели указано первое, а падает у вас именно второе.
Посмотреть архитектурный максимум конкретной модели:
ollama show llama3.1:8b
Model
architecture llama
parameters 8.0B
context length 131072
embedding length 4096
quantization Q4_K_M
context length здесь — не то, что реально запущено, а потолок, который поддерживает архитектура. По умолчанию Ollama выделяет под диалог num_ctx = 4096 — из паспортных 131072 токенов без явной настройки работает тридцать вторая часть. Изменить дефолт на весь сервис можно переменной OLLAMA_CONTEXT_LENGTH в systemd-юните, а под конкретный запрос — параметром num_ctx в теле запроса к /api/generate или /api/chat. Полную формулу перевода токенов в гигабайты разбирали в статье «Сколько RAM нужно для Ollama»; здесь — откуда берутся сами токены и почему у моделей одного размера разная цена контекста.
Токены: как считать по-русски, а не по правилу из англоязычного гайда
Токен — не буква и не слово, а кусок, который выделил токенизатор конкретной модели: частое слово превращается в один токен, редкое или составное — распадается на два-три, а для не-латиницы кусков обычно требуется больше. Llama, Qwen и Mistral используют BPE-токенизатор, обученный на корпусе с сильным перекосом в сторону английского и кода; кириллица в такой словарь входит менее эффективными кусками, чем латиница. Формулы «столько-то символов на токен» из англоязычных гайдов для русского текста систематически завышают, сколько у вас реально влезет в num_ctx.
Правильный способ — не гадать по правилу, а посчитать на своём тексте. Быстрее всего — через --verbose у ollama run:
ollama run qwen2.5:7b --verbose
>>> Объясни в двух предложениях разницу между контекстным окном и памятью модели.
[текст ответа]
prompt eval count: 32 token(s)
prompt eval rate: 68.0 tokens/s
eval count: 214 token(s)
eval rate: 7.4 tokens/s
prompt eval count — сколько токенов занял ваш запрос, eval count — сколько сгенерировано в ответе; их сумма и есть то, что реально израсходовано из num_ctx за один обмен. Ставки eval rate и prompt eval rate в примере — наш замер qwen2.5:7b в Q4_K_M на AMD EPYC 9554 при 16 потоках (Ollama 0.33.1); на другом железе цифры будут своими, а число токенов в запросе от процессора не зависит.
То же самое видно из API без интерактивного режима — оба поля приходят в финальном JSON ответа:
curl -s http://127.0.0.1:11434/api/generate \
-d '{"model":"qwen2.5:7b","prompt":"Тест","stream":false}' \
| jq '.prompt_eval_count, .eval_count'
Для офлайн-подсчёта до отправки — например, чтобы заранее обрезать историю, а не ловить обрыв ответа, — нужен токенизатор именно вашей модели: у Qwen, Llama и Mistral разные BPE-словари, и счёт одного на тексте другого ошибается на десятки процентов. Библиотека transformers грузит родной токенизатор по имени модели — AutoTokenizer.from_pretrained('Qwen/Qwen2.5-7B-Instruct') — и считает точно; универсального «токенизатора вообще» не существует.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть OllamaПочему память растёт вместе с контекстом: KV-кэш и разная цена у похожих моделей
Каждый токен контекста не растворяется бесследно — модель хранит его векторы ключей и значений (KV, key-value), чтобы на следующем шаге не пересчитывать внимание по всей истории заново. Это и есть KV-кэш, и растёт он линейно с числом токенов в num_ctx, независимо от того, заполнен контекст текстом или просто зарезервирован под будущее.
Дело в архитектуре внимания: у классического multi-head attention число голов для ключей-значений равно числу голов внимания вообще, и KV-кэш растёт вместе с обоими. Современные модели почти поголовно перешли на GQA (grouped-query attention) — голов внимания по-прежнему много, а голов для ключей-значений заметно меньше, несколько голов делят одну KV-голову между собой. Качество почти не страдает, память под контекст падает кратно.
Разница видна на двух моделях сходного размера. У llama3.1:8b — 32 слоя, 32 головы внимания и только 8 KV-голов, размер головы 128. У qwen2.5:7b — 28 слоёв, 28 голов внимания и всего 4 KV-головы при том же размере головы 128. В байтах на токен по формуле KV = 2 × слои × KV-головы × размер головы × 2 байта (fp16): у Llama 3.1 8B — 2 × 32 × 8 × 128 × 2 = 131 072 байта на токен, у Qwen2.5 7B — 2 × 28 × 4 × 128 × 2 = 57 344 байта. Разница — почти в 2,3 раза, и она не связана с тем, что одна модель «умнее» другой, только с формой внимания. Точное число KV-голов смотрите в поле num_key_value_heads файла config.json модели на HuggingFace.
Таблица: сколько памяти добавляет контекст на разных моделях
Переведя цену токена в гигабайты по длине контекста, разница становится наглядной:
| Контекст | KV-кэш, Llama 3.1 8B (8 KV-голов) | KV-кэш, Qwen2.5 7B (4 KV-головы) |
|---|---|---|
| 4096 | 0,5 ГБ | 0,22 ГБ |
| 8192 | 1,0 ГБ | 0,44 ГБ |
| 32768 | 4,0 ГБ | 1,75 ГБ |
| 65536 | 8,0 ГБ | 3,5 ГБ |
| 131072 | 16,0 ГБ | 7,0 ГБ |
Таблица — расчёт по формуле, не замер, без +10% на буферы вычислительного графа из разбора RAM. Масштаб виден и так: на полном паспортном контексте KV-кэш qwen2.5:7b — 7 ГБ, больше, чем сама модель в памяти: в наших тестах на AMD EPYC 9554 qwen2.5:7b в Q4_K_M резидентно занимает 5,1 ГБ. При контексте 128k сам контекст обходится дороже, чем всё знание модели, сжатое в веса.
Вывод жёстче, чем кажется: паспортный максимум не бесплатен даже тогда, когда вы им не пользуетесь. Ollama резервирует KV-кэш под весь заявленный num_ctx сразу при загрузке, а не постепенно по мере заполнения диалога — настройка «на всякий случай» это гигабайты, съеденные без единого токена в истории. Снизить цену без потери длины помогает квантование кэша — OLLAMA_FLASH_ATTENTION=1 с OLLAMA_KV_CACHE_TYPE=q8_0 режут числа из таблицы почти вдвое.
RoPE-масштабирование: почему заявленные 128k — не всегда 128k без потерь
Число в карточке модели — не гарантия ровного качества на всей его длине. Многие модели достигают заявленного контекста не тем, что их с нуля обучили на текстах такой длины, а расширением через масштабирование позиционных эмбеддингов — RoPE scaling: линейное, NTK-aware, YaRN. Механизм рабочий, но за пределами исходной, «нативной» длины обучения точность поиска нужного факта внутри длинного контекста обычно падает — модель не столько «не помнит», сколько хуже находит фрагмент среди тысяч нерелевантных токенов, особенно ближе к середине контекста.
Практический вывод: не берите паспортный максимум как точку по умолчанию. Если задаче нужно 32k, а не 128k, не выставляйте num_ctx в максимум «на будущее» — это не только лишняя память из таблицы выше, но и работа там, где модель не тестировалась так же тщательно, как на нативной длине. Нерасширенную длину обучения смотрите в config.json модели на HuggingFace, в поле max_position_embeddings до применения rope_scaling — ollama show отдаёт уже итоговое, расширенное число.
Если большой контекст нужен по задаче, а не по привычке, проверяйте качество на своих данных до продакшна: положите релевантный факт в разных позициях контекста — в начале, середине, ближе к концу — и убедитесь, что модель находит его на интересующей вас длине, а не только на коротких примерах из документации.
Многоходовые диалоги: контекст — это весь разговор, а не последнее сообщение
В чате num_ctx делится между входом и выходом одновременно и заполняется не только последним сообщением, а всей историей: система, прошлые реплики, новый вопрос — и только то, что осталось, достаётся на генерацию. Каждый запрос к /api/chat заново отправляет весь массив сообщений целиком: не Ollama «помнит» разговор между запросами, а клиент — Open WebUI, скрипт, любое приложение — присылает нарастающую историю заново.
Отсюда конкретная ловушка: если история уже заняла 3900 токенов из num_ctx = 4096, модели физически некуда генерировать ответ — резерва в 196 токенов хватит на пару предложений, и вывод оборвётся на середине мысли. В JSON-ответе это видно по полю done_reason: "stop" — модель закончила сама, встретив стоп-токен, "length" — её остановил потолок контекста:
curl -s http://127.0.0.1:11434/api/chat -d '{...}' | jq -r '.done_reason'
Значение length — сигнал не «модель отвечает криво», а «увеличьте num_ctx или обрежьте историю», и это почти всегда дешевле решить укорачиванием контекста, чем добавлением памяти в сервер.
Для RAG бюджет ещё жёстче: в контекст помимо истории добавляются найденные фрагменты документов, и формула держит все слагаемые сразу — промпт, история, top_k фрагментов по chunk_size каждый, вопрос и резерв под ответ, а сумма не должна подходить к num_ctx вплотную. При top_k=5 и chunk_size=512 пять фрагментов уже съедают 2560 токенов до того, как модель увидела вопрос — на num_ctx=4096 это почти не оставляет места для ответа. Как собирать данные под RAG — тема статьи про сбор данных парсингом сайтов; здесь важно, что бюджет считается до обрезанного ответа на проде, а не после.
Какой сервер под контекст брать в MAATRIX
Бюджет памяти под контекст стоит посчитать до заказа. Три ориентира: короткий чат — хватает num_ctx 4–8k; RAG над документами — обычно 16–32k с запасом под фрагменты; целый документ или часть кодовой базы в промпте — 64–128k, и здесь разница Llama-подобной и Qwen-подобной формы внимания становится разницей между «влезло» и OOM, а не теорией.
На машине с 16 ГБ RAM: qwen2.5:7b (5,1 ГБ резидентно, наш замер) при 32k добавляет 1,75 ГБ KV — вместе 6,85 ГБ, комфортно и с Open WebUI рядом. llama3.1:8b (5,6 ГБ) на том же контексте берёт 4 ГБ KV — вместе 9,6 ГБ, тоже влезает, но запаса на второй запрос или эмбеддер уже нет.
Больше vCPU не значит больше контекста и не всегда быстрее: на нашем стенде (AMD EPYC 9554, 16 vCPU, Ollama 0.33.1) генерация qwen2.5:7b выходит на полку уже на 4 потоках (7,6 ток/с) и держится там до 16 (7,4 ток/с), а обработка промпта растёт с потоками — 12,6 → 31,0 → 61,7 → 68,0 на 2/4/8/16 — и обваливается на 32 при 16 физических vCPU: 0,35 и 10,9 ток/с. За скорость первого токена отвечают ядра, за то, влезет ли контекст вообще, — память.
Честный минимум — 8 vCPU, 16 ГБ RAM, 100 ГБ NVMe: модели до 8B с GQA уровня Qwen тянут 32k, у Llama-подобных — ближе к 16–24k. Комфорт — 16 vCPU, 32 ГБ RAM, 200 ГБ NVMe: помещается 64k почти на любой архитектуре или умеренный контекст на 24–32B. Для регулярного разбора документов на 100k+ токенов на скорости — выбор GPU для Великобритании.
Ollama — приложение каталога apps.maatrix.io, на тарифе Heka разворачивается автоматически при заказе, доступ появляется в кабинете сразу после установки. Локация — Лондон (UK): модель считает локально, расстояние до провайдеров ИИ ни при чём, а вот содержимое контекста — часто чужие документы и код — делает юрисдикцию небезразличной; для данных из ЕС площадка в Великобритании привычна по соседству с GDPR. Оплата — картами российских банков, по СБП, криптовалютой или токеном MAAT, зарубежная карта не нужна. Если Ollama ещё нет — пошаговая инструкция; если генерация медленная сама по себе — отдельный разбор.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть OllamaОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Сколько токенов выходит из N символов русского текста?
Однозначного коэффициента нет — считайте на своей модели: ollama run <модель> --verbose печатает prompt eval count для реального запроса, а curl .../api/generate со "stream":false отдаёт то же число полем prompt_eval_count в JSON. Готовые «символов на токен» из англоязычных гайдов для кириллицы обычно занижают реальный расход.
Можно поставить num_ctx в максимум, который поддерживает модель?
Не стоит: Ollama резервирует память под весь num_ctx сразу при загрузке, даже если диалог короткий, а качество поиска у RoPE-расширенных моделей за пределами нативной длины обучения обычно снижается. Берите контекст под задачу, а не с запасом «на всякий случай».
Почему две модели на 7–8 миллиардов параметров требуют разной памяти под один контекст?
Дело в числе KV-голов архитектуры внимания (GQA): у llama3.1:8b их 8, у qwen2.5:7b — 4 при том же размере головы, и цена токена контекста у Qwen выходит больше чем вдвое ниже. Смотрите num_key_value_heads в config.json модели на Hugging Face.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.