AirLLM: 4GBのVRAMでKimi K3大規模モデルを体験する

August 3, 2026

プロジェクト概要

AirLLM は、大規模言語モデルの推論向けに作られた Python ツールです。コアとなる考え方は、モデル全体を一度に VRAM に載せるのではなく、モデルをより細かい層ごとに分割し、推論時に必要なものだけを読み込むというものです。これにより、70B、235B、671B、さらには Kimi K3 のようなさらに巨大な MoE 大規模モデルまで、非常に少ない VRAM 環境で試せるようになります。

Kimi K3 が最近注目されている理由はとてもシンプルです。超大規模な MoE モデルで、パラメータ数は非常に多いものの、実際には各 token ごとに一部の expert しかルーティングされません。AirLLM はまさにこの点を活かし、expert 単位のストリーミング読み込みによって、完全なモデルを一度に VRAM に載せることを避けています。

この記事では、最小構成のプロジェクトを一緒に組み立てていきます。まず Kimi K3 の推論を動かし、その後でシンプルな HTTP API にラップします。最後に、ローカルで低 VRAM 推論を行うべき場面と、Defapi のような互換 API をそのまま使ったほうが手軽な場面についても触れます。

難易度: 中級 | 所要時間: 30〜60 分 | 得られるもの: AirLLM の低 VRAM 推論フローを理解し、Kimi K3 の最小推論サービスを動かせるようになる

想定読者

  • シングル GPU・低 VRAM 環境で超大規模モデルを試したい開発者
  • Kimi K3、DeepSeek-V3、Qwen3-235B のようなモデルの推論コストを見積もりたいエンジニア
  • AI アプリのプロトタイプを作っていて、まずはローカルでモデルの挙動を検証したい人
  • ローカルモデルを API 化して、Agent、RAG、業務システムに接続したい開発者

コア依存関係と環境

Kimi K3 は環境要件がやや厳しめなので、まず依存関係の境界を明確にしておきます。

依存項目推奨バージョン説明
Python3.10+依存関係を隔離するため仮想環境の利用を推奨
NVIDIA DriverCUDA 12 対応CUDA 12 版 PyTorch を正常に実行できる必要がある
PyTorchCUDA 12 ビルドKimi K3 の依存チェーンは CUDA 12 に適している
transformers4.56.xKimi K3 のリモートモデルコードにはバージョン要件がある
airllm最新版AutoModel でモデルを統一的に読み込む
compressed-tensors最新版Kimi K3 関連の重みフォーマットで使用する
flash-attnCUDA 12 互換Kimi K3 のモデルコードは通常 flash attention を要求する

WARNING

AirLLM は VRAM 使用量を下げられますが、モデルファイル自体を小さくするわけではありません。初回実行時にはモデルのダウンロードと分割が必要で、ディスク容量とネットワーク品質が依然として重要です。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 を入力してください。モデル ID は公式に実際公開されているリポジトリ名に合わせる必要があります。ミラーリポジトリや社内同期リポジトリを使う場合は、対応する repo id に直接変更しても構いません。

WARNING

.env を Git リポジトリにコミットしないでください。モデル Token は機密情報であり、漏えいすると非公開モデルの権限が悪用されるおそれがあります。

4. 最小の Kimi K3 推論スクリプトを書く

run_kimi_k3.py を新規作成します。

import os

from dotenv import load_dotenv
from airllm import AutoModel


def main() -> None:
    """Kimi K3 を読み込み、最小限のテキスト生成を 1 回実行する。"""
    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 が大規模モデル推論の VRAM を下げられる理由を3文で説明してください。"

    # tokenizer は引き続き 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 がモデルをダウンロードし、重みファイルを解析し、後続で層単位読み込みできる形式に分割する必要があるためです。2回目以降は、モデルキャッシュと分割結果が用意されているため、かなりスムーズになります。

5. VRAM とディスク使用量を確認する

別のターミナルを開き、VRAM を監視します。

nvidia-smi -l 1

注目する指標は次の 2 つです。

Memory-Usage
GPU-Util

すべて正常なら、従来の transformers.from_pretrained() のように、完全なモデルが一気に VRAM を圧迫することはありません。AirLLM の方式は、イメージとしては「必要なものをその都度取りに行く」動きに近く、どの層・どの expert が必要かに応じて対応する重みを読み込み、使い終わったら解放します。

次にディスクを確認します。

du -sh "$HF_HOME"

Windows PowerShell では次のようにできます。

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

TIP

低 VRAM 推論は無料ではありません。AirLLM は負荷を VRAM からディスク 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 が動くか試したい圧縮なしで、まず経路確認
ディスク I/O の遅さが目立つ8bit を試す
速度と低コストでの検証を重視する4bit を試す
きちんと評価したいパラメータを固定し、複数回出力を比較する

WARNING

圧縮は重みの読み込み方法を変えるため、多くの推論タスクでは影響が小さいとはいえ、モデル評価・長文推論・重要業務の検証を行う場合は、必ず非圧縮版を基準として残してください。

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")

# サービス起動時にモデルを読み込む。本番環境ではヘルスチェックや遅延ロードを追加してもよい。
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:
    """Kimi K3 のテキスト生成を 1 回実行する。"""
    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": "Kimi K3 のような MoE モデルが expert 単位のストリーミング読み込みに向いている理由を中国語で説明してください。"
      }
    ],
    "max_tokens": 200
  }'

これで最小 API ができました。まだ本番レベルではありませんが、ローカル実験、Agent のプロトタイプ、Prompt デバッグ、モデル効果比較には十分使えます。

8. ローカル推論と Defapi の使い分け

AirLLM の価値は非常に明確です。低 VRAM マシンで超大規模モデルに触れられるようにしてくれる点で、学習、検証、評価、オフライン実験に特に向いています。ただし本番環境では、スループット、レイテンシ、並列性、モデル更新、障害対策、運用コストも考慮する必要があります。

もし単にモデル能力を素早くアプリに接続したいだけなら、あるいは OpenAI / Anthropic / Gemini 風の統一 API が必要なら、Defapi のほうが軽快です。価格が公式の半額程度であることが多く、一般的なモデルは次のプロトコルと高い互換性があります。

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

たとえば、上記のローカル /chat 呼び出しを共通クライアントとして抽象化できます。開発段階はローカル AirLLM、本番は Defapi に切り替える、という形です。

import os
import requests


def ask_model(prompt: str) -> str:
    """環境変数に応じてローカル推論か Defapi 互換 API かを選ぶ。"""
    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 の場合は、先に PyTorch、ドライバ、CUDA のバージョンを修正するべきです。Kimi K3 のようなモデルは CUDA 12 ビルドの利用を推奨します。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 のダウンロードに失敗する場合は?

まず Token が有効か確認します。

huggingface-cli whoami

未ログインなら、次のようにします。

huggingface-cli login

.env 内の HF_TOKEN だけを使うこともできます。モデルにアクセス申請が必要な場合は、先にモデルページで利用規約に同意してください。

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. 初回実行が特に遅いのはなぜ?

これは正常です。初回には重みのダウンロード、インデックスの読み取り、モデル分割、キャッシュ書き込みなどが含まれます。2 回目以降はキャッシュを再利用できるため、かなり高速になります。

profiling を有効にすることもできます。

model = AutoModel.from_pretrained(
    model_id,
    hf_token=hf_token,
    profiling_mode=True,  # 読み込みと推論の所要時間を出力し、ボトルネックの特定に役立てる
)

時間の大半がディスク読み込みにかかっているなら、より高速な NVMe SSD に変えるほうが、VRAM を増やすより効果的なことが多いです。

6. VRAM が期待通りに下がらない場合は?

まず、従来の読み込み方法と混在していないか確認します。

from airllm import AutoModel

model = AutoModel.from_pretrained(model_id)

次のような従来の読み込み方式は使わないでください。

from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained(model_id)

後者は従来の読み込み経路を通るため、簡単に VRAM がいっぱいになります。

7. API サービスの並列数が増えると固まる場合は?

ローカルの低 VRAM 推論は、シリアルな実験には向いていますが、高並列を直接受ける用途にはあまり向きません。最も簡単な対策は、まず並列数を制限することです。

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

より安定した本番利用が必要なら、オンラインリクエストは Defapi に切り替え、ローカル AirLLM は評価とデバッグ用に残すのがよいでしょう。

参考・発展方向

  • Kimi K3、DeepSeek-V3、Qwen3-235B を AirLLM で読み込んだときの時間、VRAM、出力品質を比較する。
  • FastAPI サービスを OpenAI 互換の /v1/chat/completions API に改造する。
  • Defapi を接続し、v1/chat/completions または v1/messages でオンラインモデル呼び出しを統一管理する。
  • AirLLM サービスにキューを追加し、複数リクエストが同時にディスク I/O と GPU を奪い合わないようにする。
  • OpenClaw や他の Agent フレームワークでローカルモデルとクラウドモデルを設定し、タスクの複雑さに応じて動的に選択する。
Updated August 3, 2026