Настройка контекста в Claude Code: решение OOM, принудительная компрессия | AiManual
AiManual Logo Ai / Manual.
25 Янв 2026 Гайд

Контекстное окно в Claude Code сожрало всю память? Вот как заставить локальную модель работать без OOM

Пошаговое руководство по настройке контекстного окна для локальных моделей в Claude Code. Решаем проблему нехватки памяти, настраиваем принудительную компрессию

Почему Claude Code убивает вашу память с локальными моделями

Вы скачали свежую модель с Hugging Face, запустили через llama.cpp, подключили к Claude Code. Все работает. Пока не отправляете файл побольше. Или не пытаетесь обработать длинный чат. И тогда - бац - Out of Memory. Модель падает, VRAM переполнена, а вы смотрите на ошибку и думаете: "Но я же указал контекст в 4K токенов!"

Дело в том, что Claude Code по умолчанию пытается зарезервировать память под максимально возможный контекст. Не под тот, что указали вы. А под тот, что зашит в модели. И если у вас модель с 32K контекстом, а видеокарты на 8 ГБ - вы обречены на OOM еще до первой строки кода.

Ошибка не в вашей карте. Ошибка в том, как Claude Code общается с сервером llama.cpp. Он не спрашивает "сколько можешь". Он говорит "давай все". И получает все - вместе с крахом.

Что на самом деле происходит под капотом

Когда вы запускаете локальную модель через Claude Code, происходит диалог между клиентом и сервером. Claude Code отправляет запрос на /v1/models. Сервер llama.cpp возвращает параметры модели. Включая max_tokens. И вот здесь начинается магия (точнее, ее отсутствие).

Claude Code берет это значение как священную истину. И резервирует память под него. Не важно, что вы запустили модель с флагом --ctx-size 4096. Если в модели зашито 32768 - Claude Code будет готовиться к 32K. И упадет, потому что физически не поместится.

1 Диагностика: находим реальную проблему

Прежде чем лечить, нужно понять, что болит. Откройте терминал и выполните:

curl -X GET http://localhost:8080/v1/models

Вы увидите что-то вроде:

{
  "object": "list",
  "data": [
    {
      "id": "llama-3.2-3b",
      "object": "model",
      "max_tokens": 131072,
      "owned_by": "llama.cpp"
    }
  ]
}

Видите этот max_tokens: 131072? Это и есть корень зла. Claude Code увидит 128K контекста и попытается подготовиться к работе с ним. На 8 ГБ VRAM это невозможно физически. Модель просто не влезет.

💡
Это значение берется не из флагов запуска. Оно зашито в GGUF-файле модели. Или вычисляется на основе архитектуры. И никакие --ctx-size его не меняют в ответе API.

Решение: принудительная компрессия контекста

Есть два пути: правильный и простой. Правильный - патчить llama.cpp, чтобы он возвращал реальное значение контекста. Простой - обмануть Claude Code, заставив его думать, что контекста меньше.

Мы пойдем простым путем. Потому что он работает прямо сейчас, без перекомпиляции.

2 Прокси-сервер: перехватываем и подменяем

Создадим простой Python#endif скрипт, который будет сидеть между Claude Code и llama.cpp. Его задача - перехватывать запрос к /v1/models и подменять max_tokens на наше значение.

from http.server import HTTPServer, BaseHTTPRequestHandler
import json
import urllib.request
import urllib.parse

class ProxyHandler(BaseHTTPRequestHandler):
    llama_server = "http://localhost:8080"
    max_context = 4096  # Ваше значение здесь
    
    def do_GET(self):
        if self.path == "/v1/models":
            # Перехватываем запрос к моделям
            self.send_response(200)
            self.send_header('Content-type', 'application/json')
            self.end_headers()
            
            # Получаем реальный ответ от llama.cpp
            with urllib.request.urlopen(f"{self.llama_server}{self.path}") as response:
                data = json.load(response)
                
            # Подменяем max_tokens
            for model in data.get("data", []):
                model["max_tokens"] = self.max_context
                
            self.wfile.write(json.dumps(data).encode())
        else:
            # Проксируем все остальные запросы
            with urllib.request.urlopen(f"{self.llama_server}{self.path}") as response:
                self.send_response(response.status)
                for header, value in response.headers.items():
                    self.send_header(header, value)
                self.end_headers()
                self.wfile.write(response.read())
    
    def do_POST(self):
        # Проксируем POST-запросы
        content_length = int(self.headers['Content-Length'])
        post_data = self.rfile.read(content_length)
        
        req = urllib.request.Request(
            f"{self.llama_server}{self.path}",
            data=post_data,
            headers={key: value for key, value in self.headers.items() if key != 'Host'},
            method='POST'
        )
        
        with urllib.request.urlopen(req) as response:
            self.send_response(response.status)
            for header, value in response.headers.items():
                self.send_header(header, value)
            self.end_headers()
            self.wfile.write(response.read())

if __name__ == "__main__":
    server = HTTPServer(('localhost', 8081), ProxyHandler)
    print("Прокси запущен на http://localhost:8081")
    print(f"Подменяем контекст на {ProxyHandler.max_context} токенов")
    server.serve_forever()

Сохраните как proxy_server.py и запустите:

python proxy_server.py

Теперь в Claude Code указываете адрес http://localhost:8081 вместо 8080. И он увидит ваш ограниченный контекст. И перестанет пытаться зарезервировать память под 128K.

3 Настройка llama.cpp: режем по живому

Прокси - это костыль. Хороший, рабочий, но костыль. Настоящее решение - правильно запустить llama.cpp с самого начала.

Запускайте сервер так:

./server -m models/llama-3.2-3b.Q4_K_M.gguf \
  --ctx-size 4096 \
  --batch-size 512 \
  --ubatch-size 512 \
  --parallel 1 \
  --cont-batching \
  --no-mmap \
  --mlock \
  --host 0.0.0.0 \
  --port 8080

Ключевые флаги:

  • --ctx-size 4096 - реальный размер контекста. Не обещайте больше, чем можете отдать
  • --batch-size 512 - размер батча. Меньше = меньше пикового потребления памяти
  • --ubatch-size 512 - размер микро-батча. Критично для больших контекстов
  • --no-mmap --mlock - загружаем модель полностью в RAM. Медленнее запуск, но стабильнее работа

Не верьте мифу про --no-mmap. "Но он же медленнее!" Да, на 5-10%. Зато не будет внезапных OOM при обращении к странице памяти, которую система решила выгрузить на диск.

Почему это работает (и когда не работает)

Принудительное ограничение контекста через прокси или правильные флаги llama.cpp решает 80% проблем с OOM. Оставшиеся 20% - это когда вы действительно пытаетесь обработать больше токенов, чем помещается в память.

Допустим, у вас 8 ГБ VRAM. Модель 3B параметров в Q4_K_M занимает ~2 ГБ. На контекст остается ~6 ГБ. При 4K контекста - все ок. При 8K - уже на грани. При 16K - гарантированный OOM.

Размер модели Квантование Память модели Макс. контекст на 8 ГБ
3B Q4_K_M ~2 ГБ 12-16K
7B Q4_K_M ~4 ГБ 8-10K
13B Q4_K_M ~7 ГБ 2-4K

Видите проблему? С моделью 13B на 8 ГБ VRAM вы физически не можете иметь контекст больше 4K. И если Claude Code попытается зарезервировать под 32K - он упадет сразу при запуске.

Экстренные меры: когда память уже на нуле

Бывает: модель запущена, работает, и вдруг - OOM. Чаще всего это не внезапно. Это накопление. Каждый запрос оставляет что-то в памяти. Кэш внимания. Промежуточные результаты. И через 20-30 запросов память переполняется.

Решение - принудительная очистка. В llama.cpp есть флаг --no-kv-offload. Он отключает сохранение кэша внимания на GPU. Да, это замедляет генерацию при длинных контекстах. Но сохраняет память.

Еще лучше - использовать техники компрессии вроде DroPE. Они радикально уменьшают потребление памяти при работе с длинными контекстами.

4 Мониторинг: видеть проблему до того, как она ударит

Не ждите OOM. Отслеживайте потребление памяти в реальном времени:

# Для NVIDIA
watch -n 1 nvidia-smi

# Или с детализацией по процессам
nvidia-smi --query-compute-apps=pid,process_name,used_memory --format=csv -l 1

Увидели, что память стабильно растет с каждым запросом? Это утечка. Или накопление кэша. Остановите сервер. Перезапустите с --no-kv-offload.

Частые ошибки (и как их не делать)

Ошибка 1: Доверять значениям по умолчанию. "llama.cpp сам все настроит" - нет, не настроит. Он настроит для максимальной производительности. А не для стабильности на вашем железе.

Ошибка 2: Запускать с --ctx-size 32768 на карте 8 ГБ. Математика простая: модель + контекст + overhead должны помещаться в VRAM. Если нет - вы получите OOM при первом же длинном запросе.

Ошибка 3: Игнорировать --batch-size и --ubatch-size. Эти параметры контролируют, сколько токенов обрабатывается за раз. Большие значения = быстрее, но больше пиковое потребление памяти.

Если вы уже наступили на эти грабли, посмотрите практический гайд по избеганию ошибок. Там разобраны еще десятки подобных случаев.

Альтернативы: когда Claude Code слишком прожорлив

Иногда проблема не в настройках, а в архитектуре. Claude Code создан для облачных моделей с гигабайтами свободной памяти. Для локального использования есть специализированные инструменты.

Попробуйте LMStudio-Ollama модификацию VS Code. Она изначально заточена под работу с ограниченными ресурсами. Или Open WebUI для браузерного интерфейса.

Но если нужен именно Claude Code - наш прокси-метод работает. Проверено на моделях до 13B параметров.

Что в итоге

Проблема OOM в Claude Code с локальными моделями - это не баг. Это недоработка коммуникации. Claude Code верит тому, что говорит сервер. А сервер говорит "я могу все", даже если на деле может только часть.

Решений три:

  1. Прокси-сервер для подмены max_tokens (быстро, грязно, работает)
  2. Правильные флаги запуска llama.cpp (правильно, требует понимания)
  3. Специализированные инструменты вместо Claude Code (радикально, но эффективно)

Мой выбор - второй вариант с элементами первого. Запускайте llama.cpp с адекватными --ctx-size, --batch-size. И если нужно - добавьте прокси для подстраховки.

И запомните: память не резиновая. Даже с самыми оптимизированными локальными моделями физические ограничения железа никуда не деваются. Работайте в их рамках. И не пытайтесь впихнуть невпихуемое.

P.S. Если после всех настроек модель все равно падает - возможно, дело не в контексте. Проверьте, не зацикливается ли она на тул-коллах. Или не пытается ли обработать бинарный файл как текст. Но это уже совсем другая история.