Полмиллиона токенов в одном запросе — и локальная модель на одной 3090 нашла обе иголки: одну почти в начале, вторую на позиции 394 540. Упёрлось всё не в видеопамять и не в архитектуру модели, а в строчку конфига, где стояло 131072. Движок под ней держал 262144. Никто об этом не предупредил.
Вот это и есть главный практический вывод: потолок контекста, который вы чувствуете в работе, часто живёт в конфиге, а не в спецификации модели.
Кто в стеке объявляет контекст
Локальный стек — обычно несколько звеньев: движок инференса, прокси перед ним, агент, который ходит к прокси. Каждое звено хранит свою цифру и уверено, что остальные с ней согласны. Сверки нет, предупреждения тоже. Побеждает меньшее число — молча, без ошибки в логах.
| Слой | Где задаётся | Что показывает | Что происходит при расхождении |
|---|---|---|---|
| Движок | --max-context при запуске | /health → max_context | Режет запросы выше своего потолка, отвечает 400 |
| Прокси (llama-swap) | свой конфиг | объявленный размер окна | Прокидывает дальше то, что ему сказали |
| Агент (Hermes) | context_length | advertised context_length | Тихо урезает до своего числа, и вы видите 131k |
Проверка занимает меньше времени, чем чтение этого абзаца. Запросить /health у движка, посмотреть max_context. Потом найти, что агент печатает про свой context_length. Сравнить два числа. Если у агента меньше — вот и весь ваш потолок, независимо от того, что умеет модель.
Порядок действий
- Снять фактические числа со всех звеньев: движок, прокси, агент.
- Согласовать их на одном значении.
- Перезапустить движок (через nssm подъём занял около 40 секунд) и убедиться, что /health печатает новое число до отправки запроса.
- Отправить заведомо огромный промпт и проверить, что его отбивает с кодом 400 — значит лимит реально проверяется движком.
Флаги, которые сняли ограничение
Набор параметров запуска в том случае выглядел так:
- --max-context 524288 — потолок, который движок объявляет и соблюдает.
- --kv q4_0 — квантизация KV-кэша, без неё полмиллиона токенов просто некуда класть.
- --kv-resident 32768 — сколько KV держать в памяти резидентно.
- --rope-scaling yarn и --rope-scale 2 — растяжение позиционного кодирования за пределы обученного окна.
- --yarn-orig-ctx 262144 — исходное обученное окно, от которого yarn считает растяжение.
Само по себе растяжение не даёт качества — оно даёт диапазон. Проверять его приходится иголками в стоге, о них ниже.
Что показал прогон
В один запрос ушло 509 084 токена при потолке 524 288. Тестовый запрос на 1,76 млн движок отбил с кодом 400 — лимит enforced на уровне движка, а не на бумаге.
Prefill занял 381 секунду, это 1336 токенов в секунду, то есть 6,4 минуты до первого токена. Зато повторные вопросы к тому же документу попадают в checkpoint и возвращаются почти мгновенно: замер на повторную отправку дал 0,12 секунды. Prefill — пошлина за документ, платится один раз.
Обе иголки, закопанные в промпт (около позиции 50 и около 394 540), вытащены точными. Вторая лежит далеко за обученным окном 262k, так что yarn на этой модели отработал по всему растянутому диапазону.
Память: ночь в BIOS
Полмиллиона токенов упёрлись в RAM. Четыре планки по 16 ГБ G.Skill во все слоты, 32 → 64 ГБ, видно 63,9. DOCP на 3600 не прошёл POST. Четыре dual-rank модуля под нагрузкой контроллера памяти потянули только 3400 — с этой частотой машина загрузилась, и Windows проверила все планки.
Ловушка, которая съела час: после неудачного POST BIOS в режиме «Auto» тихо переобучается на 2133. Смотришь на частоту, видишь мёртвые 2133 и начинаешь копать не туда. Первым делом проверьте, что DOCP всё ещё включён.
KV-кэш оказался не проблемой
Арифметика простая: 262k токенов при q4_0 — это 1,69 ГБ. Помещается резидентно, флаги стриминга на таком масштабе просто не нужны.
Посчитать до отправки
Калибровка на реальном документе: 3,11 символа на токен и 32,2 токена на строку реестра. Умножьте число строк в своём файле — и узнаете, влезет ли он, ещё до запроса. Оценка грубая, зато спасает от 400 через шесть минут ожидания.
Замеры TTFT
| Сценарий | Окно | RAM | Первый токен |
|---|---|---|---|
| Свежий промпт на 10k, thinking включён | 131k | 32 ГБ | 7,62 с |
| Тот же промпт | 262k | 64 ГБ | 5,10 с |
| Повторный запрос к загруженному документу | 524k | 64 ГБ | 0,12 с |
Удвоение памяти срезало 2,5 секунды, и окно побольше ответило первым токеном быстрее, чем меньшее днём ранее.
При чём тут RAG
RAG прижился во многом потому, что люди упирались в этот конфиг-потолок и читали его как потолок модели. Полмиллиона токенов с правильно настроенным rope scaling держат качество поиска — на конкретном движке и конкретной модели, оговорка важна.
Когда длинный контекст оправдан:
- Один большой документ и много вопросов к нему. Prefill один раз, дальше checkpoint почти бесплатен.
- Нужны связи между кусками текста, разнесёнными на сотни тысяч токенов — retrieval такие связи рвёт по определению.
А вот корпус из тысяч документов, к каждому из которых задают один-два вопроса, длинным контекстом кормить разорительно: 6,4 минуты prefill на каждый файл.
Типичные ошибки
- Верить числу, которое печатает агент, и не заглядывать в /health.
- Поднять --max-context, не согласовав среднее звено — движок умеет больше, а пользователь по-прежнему видит старое число.
- Гоняться за частотой памяти после неудачного POST, не проверив DOCP.
- Включать стриминг KV там, где кэш и так помещается в VRAM.
Если у вас локальный стек и есть подозрение, что контекст короче обещанного, начните с двух чисел: max_context из /health и advertised context_length у агента. Дальше решайте, какое из них вы готовы согласовать — и хватит ли на него RAM.
Комментарии (0)
Войдите, чтобы комментировать.
Пока нет комментариев. Будьте первым.