AirLLM: испытайте модель Kimi K3 с объёмом видеопамяти всего 4 ГБ

August 3, 2026

Обзор проекта

AirLLM — это Python-инструмент, ориентированный на инференс (вычисление) больших языковых моделей. Его ключевая идея не в том, чтобы разом загрузить всю модель целиком в видеопамять, а в том, чтобы разбить модель на более мелкие уровни и подгружать их по требованию во время инференса. Благодаря этому можно попробовать запустить 70B, 235B, 671B и даже такие чрезмерно масштабные MoE-модели, как Kimi K3, в среде с очень низкими требованиями к видеопамяти.

Kimi K3 в последнее время особенно заметен, и причина довольно прямая: это сверхкрупная MoE-модель с огромным количеством параметров, но фактически каждый токен маршрутизируется лишь в часть экспертов. AirLLM как раз использует это: применяет потоковую (streaming) загрузку уровнями по экспертам, тем самым избегая необходимости загружать полную модель целиком в видеопамять.

В этой статье давайте вместе соберём минимальный проект: сначала запустим инференс Kimi K3, а затем завернём его в простой HTTP API. В конце также поговорим о том, когда для локального инференса с низкой видеопамятью действительно подходит локальная схема, а когда использовать совместимый интерфейс вроде Defapi будет заметно проще.

Сложность: средняя | Время: 30–60 минут | Результат: понять процесс инференса AirLLM с низким потреблением видеопамяти и запустить минимальный инференс-сервис Kimi K3

Портрет целевой аудитории

  • Разработчики, которые хотят пощупать разработку сверхбольших моделей на одной видеокарте и на машинах с низкой видеопамятью
  • Инженеры, оценивающие стоимость инференса таких моделей, как Kimi K3, DeepSeek-V3, Qwen3-235B
  • Те, кто делает прототипы AI-приложений и хочет сначала локально проверить качество работы модели
  • Разработчики, которым нужно завернуть локальную модель в API, а затем подключить её к Agent, RAG или бизнес-системе

Ключевые зависимости и окружение

Kimi K3 довольно требователен к среде — давайте сначала чётко обозначим границы по зависимостям:

ЗависимостьРекомендуемая версияПояснение
Python3.10+Рекомендуется использовать виртуальное окружение для изоляции зависимостей
NVIDIA Driverподдержка CUDA 12Нужно, чтобы PyTorch мог нормально работать с CUDA 12
PyTorchсборка под CUDA 12В цепочке зависимостей Kimi K3 наиболее удачно подходит CUDA 12
transformers4.56.xДля кода удалённой модели Kimi K3 есть требования к версии
airllmпоследняя версияИспользует AutoModel для унифицированной загрузки модели
compressed-tensorsпоследняя версияВ форматах весов Kimi K3 будут использоваться соответствующие структуры
flash-attnсовместимо с CUDA 12Код моделей Kimi K3 обычно требует flash attention

WARNING

AirLLM может снизить потребление видеопамяти, но не уменьшает размер файлов модели. При первом запуске будет выполнена загрузка и разбиение модели, поэтому дисковое пространство и качество сети по-прежнему критически важны. Модели вроде Kimi K3 имеют колоссальный объём — заранее подготовьте достаточно места под кэш.

Полное дерево структуры проекта

Сначала подготовим минимальный проект — структура должна оставаться простой:

airllm-kimi-k3-demo/
├── .env.example
├── requirements.txt
├── run_kimi_k3.py
├── server.py
└── README.md

1. Создание Python-виртуального окружения

Сначала создайте каталог и виртуальное окружение:

mkdir airllm-kimi-k3-demo
cd airllm-kimi-k3-demo

python -m venv .venv
source .venv/bin/activate

В Windows PowerShell можно так активировать:

mkdir airllm-kimi-k3-demo
cd airllm-kimi-k3-demo

python -m venv .venv
.venv\Scripts\Activate.ps1

Проверьте версию Python:

python --version

Рекомендуемый вывод — как минимум Python 3.10.x. Если на вашей машине установлено несколько версий Python, можно явно указать так: py -3.10 -m venv .venv.

2. Установка AirLLM и зависимостей для Kimi K3

Создайте requirements.txt:

airllm
accelerate
sentencepiece
safetensors
compressed-tensors
python-dotenv
fastapi
uvicorn[standard]

Сначала установите PyTorch. Например, для CUDA 12.1:

pip install --upgrade pip
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121

Далее установите ключевые зависимости:

pip install -r requirements.txt
pip install "transformers>=4.56,<4.57"

В конце установите flash-attn:

pip install flash-attn --no-build-isolation

TIP

Если сборка flash-attn идёт слишком медленно, сначала убедитесь, что текущая среда корректно выполняет import torch, и что torch.version.cuda показывает CUDA из серии 12. Зависимости моделей вроде Kimi K3 больше ориентированы на инженерную среду — не рекомендуется ставить их прямо в хаотично настроенное глобальное окружение Python.

3. Настройка прав доступа к модели и каталога кэша

Некоторым моделям Hugging Face требуется логин или авторизация. Подготовим .env.example:

HF_TOKEN=hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
HF_HOME=/data/huggingface
AIRLLM_MODEL_ID=moonshotai/Kimi-K3

На практике скопируйте файл:

cp .env.example .env

Windows PowerShell:

Copy-Item .env.example .env

Затем вставьте свой Hugging Face Token. Идентификатор модели (model id) должен соответствовать реальному имени репозитория, указанному в официальной публикации. Если вы используете зеркальный репозиторий или внутреннюю синхронизацию, можно просто заменить на нужный repo id.

WARNING

Не коммитьте .env в Git-репозиторий. Токен модели — это чувствительная информация: утечка может привести к злоупотреблениям и использованию прав на приватные модели.

4. Написание минимального скрипта инференса Kimi K3

Создайте run_kimi_k3.py:

import os

from dotenv import load_dotenv
from airllm import AutoModel


def main() -> None:
    """Загружает Kimi K3 и выполняет один минимальный текстовый вывод (generation)."""
    load_dotenv()

    model_id = os.getenv("AIRLLM_MODEL_ID", "moonshotai/Kimi-K3")
    hf_token = os.getenv("HF_TOKEN")

    # Управляйте длиной входа: сначала короткий prompt, чтобы быстро проверить связку и не ждать слишком долго при первой валидации.
    max_length = 256

    # AutoModel автоматически определит тип модели; hf_token используется для доступа к репозиториям моделей, требующим авторизации.
    model = AutoModel.from_pretrained(
        model_id,
        hf_token=hf_token,
        profiling_mode=True,
    )

    prompt = "Объясни AirLLM, почему он может снижать видеопамять при инференсе больших моделей, тремя предложениями."

    # Токенизатор остаётся в стиле Hugging Face — стоимость миграции невысока.
    input_tokens = model.tokenizer(
        [prompt],
        return_tensors="pt",
        return_attention_mask=False,
        truncation=True,
        max_length=max_length,
        padding=False,
    )

    # Во время инференса AirLLM загружает веса по уровням; max_new_tokens лучше задать небольшим, чтобы быстро проверить.
    generation_output = model.generate(
        input_tokens["input_ids"].cuda(),
        max_new_tokens=128,
        use_cache=True,
        return_dict_in_generate=True,
    )

    output = model.tokenizer.decode(
        generation_output.sequences[0],
        skip_special_tokens=True,
    )

    print(output)


if __name__ == "__main__":
    main()

Запуск:

python run_kimi_k3.py

Первый запуск обычно занимает больше времени: AirLLM должен скачать модель, проанализировать файлы весов и разложить модель на формат, который затем можно подгружать по слоям. Второй запуск, как правило, будет заметно более плавным — потому что кэш модели и результаты разбиения уже подготовлены.

5. Наблюдение за потреблением видеопамяти и диска

Откройте ещё одно окно терминала, чтобы следить за видеопамятью:

nvidia-smi -l 1

Смотрите на два показателя:

Memory-Usage
GPU-Util

Если всё работает нормально, видеопамять не будет моментально «распухать» так, как при обычном transformers.from_pretrained(), когда целая модель резко заполняет VRAM. Подход AirLLM больше похож на «берём по дороге»: нужны конкретные слои и части экспертов — соответствующие веса загружаются, используются и затем освобождаются.

Затем посмотрите, сколько диска занято:

du -sh "$HF_HOME"

В Windows PowerShell можно так:

Get-ChildItem $env:HF_HOME -Recurse | Measure-Object Length -Sum

TIP

Локальный инференс с низкой видеопамятью — не бесплатный обед. AirLLM переносит нагрузку с видеопамяти на дисковый I/O, CPU-память и кэш модели, поэтому скорость SSD напрямую влияет на впечатления.

6. Включение сжатия параметров

AirLLM поддерживает снижение объёма загружаемых весов через параметр compression. При инициализации модели можно добавить 4bit:

model = AutoModel.from_pretrained(
    model_id,
    hf_token=hf_token,
    compression="4bit",  # сжатие весов до 4bit: уменьшает объём загрузки и улучшает скорость в некоторых сценариях
    profiling_mode=True,
)

Если хотите более консервативный вариант — сначала попробуйте 8bit:

model = AutoModel.from_pretrained(
    model_id,
    hf_token=hf_token,
    compression="8bit",  # 8bit более консервативно: балансирует скорость и точность
    profiling_mode=True,
)

Обычно мы выбираем так:

СценарийРекомендация
Просто проверить, можно ли запустить Kimi K3без сжатия — сначала подтвердить цепочку (pipeline)
Диск I/O сильно тормозитпопробовать 8bit
Больше важны скорость и недорогая валидацияпопробовать 4bit
Делать серьёзное сравнениефиксировать параметры и проводить многократные сравнения качества вывода

WARNING

Сжатие меняет способ загрузки весов. Хотя во многих задачах инференса разница невелика, но если вы проводите оценку модели, делаете инференс длинного текста или проверяете чувствительный бизнес-кейс, обязательно сохраните версию без сжатия как базовую точку (baseline).

7. Упаковка в простой HTTP API

После того как локальный скрипт успешно прошёл, обычно хочется встроить это в приложение. Ниже — минимальный сервис на FastAPI.

Создайте server.py:

import os
from typing import List, Literal

from dotenv import load_dotenv
from fastapi import FastAPI
from pydantic import BaseModel
from airllm import AutoModel


class ChatMessage(BaseModel):
    """Структура сообщений в стиле OpenAI — удобно для дальнейшей замены на совместимый API."""
    role: Literal["system", "user", "assistant"]
    content: str


class ChatRequest(BaseModel):
    """Минимальный запрос для чата: оставляем только поля, нужные для туториала."""
    messages: List[ChatMessage]
    max_tokens: int = 256


class ChatResponse(BaseModel):
    """Возвращаем текстовый результат: пока простота важнее, чтобы было удобно отлаживать."""
    text: str


load_dotenv()

app = FastAPI(title="AirLLM Kimi K3 Demo")

model_id = os.getenv("AIRLLM_MODEL_ID", "moonshotai/Kimi-K3")
hf_token = os.getenv("HF_TOKEN")

# При запуске сервиса загружаем модель; в реальном проде можно добавить health-check и ленивую загрузку.
model = AutoModel.from_pretrained(
    model_id,
    hf_token=hf_token,
    profiling_mode=False,
)


def build_prompt(messages: List[ChatMessage]) -> str:
    """Склеивает сообщения из нескольких раундов в простой prompt; позже можно заменить на официальный chat template модели."""
    lines: list[str] = []
    for message in messages:
        lines.append(f"{message.role}: {message.content}")
    lines.append("assistant:")
    return "\n".join(lines)


@app.post("/chat", response_model=ChatResponse)
def chat(request: ChatRequest) -> ChatResponse:
    """Выполняет один текстовый вывод (generation) для Kimi K3."""
    prompt = build_prompt(request.messages)

    input_tokens = model.tokenizer(
        [prompt],
        return_tensors="pt",
        return_attention_mask=False,
        truncation=True,
        max_length=1024,
        padding=False,
    )

    generation_output = model.generate(
        input_tokens["input_ids"].cuda(),
        max_new_tokens=request.max_tokens,
        use_cache=True,
        return_dict_in_generate=True,
    )

    text = model.tokenizer.decode(
        generation_output.sequences[0],
        skip_special_tokens=True,
    )

    return ChatResponse(text=text)

Запуск сервиса:

uvicorn server:app --host 0.0.0.0 --port 8000

Проверка вызова:

curl -X POST http://localhost:8000/chat \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {
        "role": "user",
        "content": "Поясни на китайском, почему MoE-модели типа Kimi K3 подходят для потоковой загрузки по экспертам."
      }
    ],
    "max_tokens": 200
  }'

Теперь у нас есть минимальный API. Это ещё не production-уровень, но его более чем достаточно для локальных экспериментов, прототипов Agent, отладки промптов и сравнения качества работы моделей.

8. Как выбрать между локальным инференсом и интерфейсом Defapi

Ценность AirLLM предельно ясна: он позволяет добраться до сверхбольших моделей на компьютерах с низкой видеопамятью, особенно хорошо подходит для обучения, проверки, оценивания и офлайн-экспериментов. Но в продакшене нужно учитывать пропускную способность (throughput), задержки (latency), параллелизм, обновления модели, отказоустойчивость и стоимость эксплуатации.

Если вам нужно лишь быстро встроить возможности модели в приложение или вы хотите единый API в стиле OpenAI/Anthropic/Gemini, то Defapi будет удобнее. Его преимущества: цена обычно примерно вдвое меньше, чем у официальных решений, а большинство распространённых моделей базово совместимы с этими протоколами:

  • v1/chat/completions
  • v1/messages
  • v1beta/models/

Например, мы можем абстрагировать локальный /chat выше в единый клиент. На этапе разработки ходим через локальный AirLLM, а в онлайне переключаемся на Defapi:

import os
import requests


def ask_model(prompt: str) -> str:
    """Выбирает локальный инференс или Defapi-совместимый интерфейс в зависимости от переменных окружения."""
    provider = os.getenv("MODEL_PROVIDER", "local")

    if provider == "defapi":
        response = requests.post(
            "https://api.defapi.org/api/v1/chat/completions",
            headers={
                "Authorization": f"Bearer {os.environ['DEFAPI_API_KEY']}",
                "Content-Type": "application/json",
            },
            json={
                "model": os.getenv("DEFAPI_MODEL", "anthropic/claude-sonnet-4.5"),
                "messages": [{"role": "user", "content": prompt}],
                "temperature": 0.7,
            },
            timeout=60,
        )
        response.raise_for_status()
        return response.json()["choices"][0]["message"]["content"]

    response = requests.post(
        "http://localhost:8000/chat",
        json={
            "messages": [{"role": "user", "content": prompt}],
            "max_tokens": 256,
        },
        timeout=300,
    )
    response.raise_for_status()
    return response.json()["text"]

Плюс такой схемы в том, что границы очень чёткие: локальная модель отвечает за исследование и валидацию, а Defapi — за стабильный, единый и недорогой доступ к онлайн-моделям. Для OpenClaw, RAG-сервисов и автоматизированных Agent такой двойной режим очень полезен.

Частые проблемы и способы устранения

1. Что делать, если установка flash-attn не удалась?

Сначала проверьте, что PyTorch корректно видит CUDA:

python -c "import torch; print(torch.__version__); print(torch.version.cuda); print(torch.cuda.is_available())"

Если torch.cuda.is_available() — False, не спешите ставить flash-attn. Сначала нужно починить PyTorch, драйвер и версии CUDA. Для Kimi K3 рекомендуется использовать сборку под CUDA 12 — это поможет избежать ситуаций, когда из‑за отсутствия подходящих precompiled-пакетов для CUDA 13 компиляция падает.

2. Что делать, если transformers ругается на версию?

Зафиксируйте версию на 4.56.x:

pip uninstall -y transformers
pip install "transformers>=4.56,<4.57"

Затем запустите заново:

python run_kimi_k3.py

Если вы видите, что загрузка удалённого кода модели не проходит, обычно это означает, что версия transformers не соответствует коду модели.

3. Что делать, если не получается скачать с Hugging Face?

Сначала убедитесь, что токен рабочий:

huggingface-cli whoami

Если вы не залогинены:

huggingface-cli login

Можно также использовать только HF_TOKEN из .env. Если модели требуется доступ по запросу, сначала нужно принять условия на странице модели.

4. Что делать, если не хватает места на диске?

При первом запуске AirLLM скачивает исходные веса и также генерирует файлы модели после разбиения. Можно перенести каталог кэша на диск большего объёма:

export HF_HOME=/mnt/models/huggingface

Или настроить в .env:

HF_HOME=/mnt/models/huggingface

Если диска всё равно не хватает, можно попробовать опцию AirLLM delete_original=True, чтобы оставить только преобразованные файлы:

model = AutoModel.from_pretrained(
    model_id,
    hf_token=hf_token,
    delete_original=True,  # после завершения преобразования удаляем исходные веса, чтобы сэкономить место на диске
)

5. Почему первый запуск такой медленный?

Это нормально. Первый запуск включает скачивание весов, чтение индексов, разбиение модели, запись кэша и другие шаги. Второй запуск использует уже готовый кэш — и скорость заметно вырастает.

Можно включить profiling:

model = AutoModel.from_pretrained(
    model_id,
    hf_token=hf_token,
    profiling_mode=True,  # выводит время загрузки и инференса, помогая определить узкие места
)

Если основное время уходит на чтение с диска, более быстрый NVMe SSD часто эффективнее, чем просто увеличение объёма видеопамяти.

6. Видеопамять не снизилась до ожидаемого уровня — что делать?

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

from airllm import AutoModel

model = AutoModel.from_pretrained(model_id)

Не смешивайте с традиционным способом загрузки:

from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained(model_id)

Последний использует традиционный путь загрузки и легко может сразу заполнить всю видеопамять.

7. Почему сервис API зависает, когда параллельных запросов становится много?

Локальный инференс с низкой видеопамятью лучше подходит для последовательных экспериментов и не рассчитан на прямую обработку высокой параллельности. Самый простой способ — сначала ограничить параллелизм:

uvicorn server:app --host 0.0.0.0 --port 8000 --workers 1

Если вам нужна более стабильная продакшен-обработка, перенаправьте запросы на Defapi онлайн, а локальный AirLLM оставьте для оценки и отладки.

Дополнительное чтение / направления развития

  • Сравните время загрузки, объём видеопамяти и качество вывода Kimi K3, DeepSeek-V3 и Qwen3-235B при работе через AirLLM.
  • Переделайте FastAPI-сервис в OpenAI-совместимый интерфейс /v1/chat/completions.
  • Подключите Defapi и используйте v1/chat/completions или v1/messages, чтобы единообразно управлять вызовами онлайн-моделей.
  • Добавьте очередь для сервиса AirLLM, чтобы несколько запросов не пытались одновременно «драться» за дисковый I/O и GPU.
  • В OpenClaw или других фреймворках Agent настройте локальную и облачную модели и выбирайте подходящую схему в зависимости от сложности задачи.
Updated August 3, 2026