Учебник «Большие языковые модели»
Контекстное окно — вся «оперативная память» языковой модели: системный промпт, история диалога, приложенные документы, порождаемый ответ — всё это одна последовательность токенов, и её максимальная длина жёстко ограничена. Один прямой проход модели не видит ничего за пределами поданного контекста и сам по себе не хранит состояние между вызовами. Продукт или API, однако, может сохранять историю, память либо идентификатор предыдущего ответа и вновь подать связанные данные модели. Условия хранения, приватности и тарификации надо проверять у конкретного сервиса. Эта глава — о физике и экономике контекста и о том, как им грамотно распоряжаться; она завершает вторую часть учебника.
Ограничение — не искусственный лимит, а произведение трёх факторов.
Вычисления. Матрица внимания (глава 3) имеет размер n×n: вдвое длиннее контекст — вчетверо больше вычислений внимания. При этом обработка промпта (prefill) распараллеливается и упирается в вычислительную мощность, а генерация (decode) идёт по токену и упирается в пропускную способность памяти — два режима с разной экономикой, отсюда разница цен входных и выходных токенов.
Память: KV-кэш. Чтобы не пересчитывать на каждом шаге генерации ключи и значения всех предыдущих токенов, их кэшируют. Объём кэша растёт линейно с длиной контекста и числом одновременных запросов; при длинных контекстах или большом батче он способен превысить память весов. Оценка на токен одного запроса без служебных накладных расходов:
Mтокен = 2 · L · nkv · dk · b
(2 — ключи и значения, L слоёв, nkv KV-голов размерности dk, b байт на число). Посчитаем:
def kv_cache_gb(n_layers, n_kv_heads, head_dim, ctx_len,
bytes_per=2): # fp16/bf16
per_token = 2 * n_layers * n_kv_heads * head_dim * bytes_per
return per_token * ctx_len / 2**30
# Модель класса 70B: 80 слоёв, 8 KV-голов по 128 (GQA)
print(kv_cache_gb(80, 8, 128, 128_000)) # ~39 ГБ на ОДИН запрос
# Без GQA (64 KV-головы) было бы:
print(kv_cache_gb(80, 64, 128, 128_000)) # ~312 ГБ -- неподъёмно
Пример показывает, почему во многих моделях используют GQA (grouped query attention) или MQA: несколько запросных голов делят ключи и значения, сокращая кэш. Существуют и обычное MHA, и другие архитектуры; точный объём нужно считать по конфигурации модели, формату кэша, батчу и серверу.
Обучение. Умение пользоваться длинным контекстом надо ещё и выучить, а обучать на длинных последовательностях дорого (та же квадратичность). Стандартный приём — предобучение на умеренных длинах с последующим расширением окна. Для RoPE применяют YaRN и родственные методы, а затем дообучение на длинных примерах; другие архитектуры используют другие приёмы. Заявленный лимит ещё не подтверждает качество работы на всей длине.
У маркетингового числа «окно 200К токенов» есть тонкость: способность вместить не равна способности использовать. Хрестоматийный эффект «потерянного в середине» (lost in the middle): в экспериментах 2023 года качество извлечения факта из длинного контекста проседало, когда факт находился в середине, и было максимальным по краям. Новые модели на некоторых простых тестах «найди иголку в стоге» показывают высокие результаты, но на задачах, требующих связать много разбросанных по контексту фактов или рассуждать над всем документом, деградация с ростом длины по-прежнему измерима. Практический вывод: эффективная длина зависит от задачи, и для ответственных применений её стоит измерить самостоятельно на своих данных (глава 13), а не верить паспорту.
Размещение критичных инструкций и фактов у краёв контекста — полезная гипотеза для теста, а не универсальный закон: эффект зависит от модели и задачи. Нерелевантный материал тоже может снижать качество, подсовывать ложные совпадения и увеличивать цену. Механизм ошибки нельзя свести к простому «размазыванию softmax», поэтому объём и порядок контекста следует проверять экспериментально.
В реальных системах начало контекста повторяется из запроса в запрос: системный промпт, описания инструментов, общие документы, растущая история диалога. KV-кэш общего префикса иногда можно переиспользовать — это кэширование промптов (prompt caching). Механика, минимальная длина, срок жизни, тариф и гарантия попадания в кэш зависят от провайдера. Например, OpenAI описывает автоматическое best-effort-кэширование точных общих префиксов; экономию и задержку надо считать по актуальному тарифу выбранной модели.
Ключевое ограничение: кэш действует по префиксу. Достаточно изменить один токен в начале — и повторно использовать можно только совпавшую часть до изменения; последующий суффикс пересчитывается. Отсюда главное правило компоновки промпта: стабильное — вперёд, переменное — назад. Системный промпт, инструменты, справочные документы — в начало с тем же токенизированным префиксом (даже метка времени в системном промпте убивает кэш); вопрос пользователя и переменные данные — в конец. Для конвейеров, гоняющих один и тот же промпт по тысячам документов (как в новостных или аналитических пайплайнах), правильная компоновка может сократить счёт и задержку без изменения содержания запроса.
Есть три способа сообщить модели то, чего она не знает, и их стоит выбирать в правильном порядке.
Положить в контекст — если знание помещается и нужно целиком: документация проекта, договор, стайлгайд. Просто, надёжно, модель видит всё; дорого при больших объёмах и каждом запросе (смягчается кэшированием).
RAG (глава 10) — если корпус велик, а для ответа нужна малая его часть: базы знаний, архивы, документация масштаба портала. В контекст попадает только найденное релевантное.
Дообучение (глава 12) особенно полезно для поведения: стиля, формата, следования доменным конвенциям. Оно способно изменить и фактические ассоциации, но это неудобный способ хранить часто меняющиеся или требующие цитирования сведения: обновление требует нового обучения, а полноту и происхождение ответа трудно проверить.
Эмпирическое правило: начинайте с контекста, при росте корпуса переходите к RAG, дообучайте — когда проблема в форме, а не в знаниях.
История диалога растёт монотонно, и в какой-то момент её приходится сокращать. Простое отбрасывание старых сообщений (скользящее окно) теряет ранние договорённости; стандартное решение — суммаризация: старая часть истории сворачивается моделью в конспект, который занимает место сообщений. Конспект — это потеря информации, поэтому критичные для задачи вещи (принятые решения, ограничения, целевые файлы) агентные системы выносят из контекста во внешнюю память — файлы заметок, списки задач — и возвращают в контекст по мере надобности. К агентам мы вернёмся в главе 11.
Наконец, ограничения входа, общего контекста и максимального выхода задаются по-разному у разных моделей. Нередко вход и порождаемый ответ делят общий бюджет; у reasoning-моделей в лимиты и тарификацию могут входить внутренние токены рассуждения. Проверяйте контракт API и оставляйте запас на завершение ответа.
Прямой проход модели работает только с поданным контекстом, тогда как состояние продукта может храниться отдельно. Для обычного полного внимания число пар позиций квадратично, KV-кэш линеен по длине и умножается на число активных запросов, а заявленная длина не равна эффективной. Практика — измерять качество на нужной длине, держать стабильный префикс для кэша, убирать нерелевантное, осознанно выбирать между контекстом, RAG и дообучением и явно управлять историей диалога.
На этом заканчивается вторая часть: мы прошли путь от токена до работающего ассистента с его памятью. Третья часть — о применении: промптинг, API, RAG, агенты и дообучение своих моделей.
Упражнения
1. По формуле раздела 7.1 посчитайте KV-кэш модели класса 8B (32 слоя, 8 KV-голов по 128) для контекстов 8К, 32К и 128К токенов. Поместится ли последний вариант вместе с весами модели (~16 ГБ в fp16) в GPU с 24 ГБ памяти?
2. Возьмите свой реальный промпт из рабочего конвейера и разметьте его части на «стабильные» и «переменные». Какая доля токенов кэшируема при правильной перекомпоновке? Оцените экономию по тарифам вашего провайдера.
3. Спрячьте контрольный факт в длинный документ (начало / середина / конец) и задайте модели вопрос по нему. Повторите для задачи, требующей связать два далеко разнесённых факта. Совпадает ли «эффективное окно» вашей модели в этих двух задачах?