メインコンテンツへスキップ
友田 陽大
量子化LLM・セルフホスト
Qwen
AWQ
量子化
vLLM
生成AI
セルフホスト
Python

Qwen3-8B-AWQ 実践ガイド:4bit量子化で“思考するLLM”をGPU1枚にセルフホストする

Qwen3-8B-AWQを公式ドキュメントに忠実に解説。AWQ 4bit量子化で重みを約6GBに圧縮し24GBのGPU1枚で本番運用。ハイブリッド思考(thinking/non-thinking)の切替、vLLMでのOpenAI互換サーブ、モード別の推奨サンプリング、YaRNで131K拡張、ツール呼び出し、量子化特有の落とし穴(presence_penalty/greedy禁止)まで実コードで。

公開日
読了時間
17分
著者
友田 陽大
シェア

この記事のゴール

オープンウェイトLLMを本番投入する全体像で「自前運用なら vLLM」「原価を決めるのは量子化と稼働率」と書きました。本稿はその具体例の決定版です。題材は Qwen3-8B-AWQ——アリババ Qwen チームの 8B モデルを AWQ で 4bit に量子化した、Apache-2.0 のオープンウェイトです。

このモデルが面白いのは、**「小さくて安いのに“考える”」**という一点に尽きます。AWQ で重みが約 1/3 に圧縮されるので 24GB の GPU 1枚に載り、しかも 思考(reasoning)モードと高速対話モードを 1 モデルで切り替えられる。つまり「o1 系のような段階推論を、自分のサーバで、安く」が現実になります。

ゴールは、vllm serve を打てることではなく、公式ドキュメントに忠実なまま、どの場面でどう使い、何を外すと品質が崩れるかまで分かった状態になることです。コードはすべて手元で動く形で示します。

信頼性の開示:GPU で LLM を本番運用する難しさ(VRAM・スループット・回復性)は、動画AIローカライズ基盤で実際に踏んだ領域です。本稿のスペック・コマンド・サンプリング値は、すべて公式一次情報——Qwen3-8B-AWQ モデルカードQwen 公式ドキュメントvLLM ドキュメント——に基づきます。VRAM とスループットの実数は環境依存・要ベンチであることを明記します。


30秒の結論:いつ Qwen3-8B-AWQ を選ぶか

Qwen3-8B-AWQ(4bit)Qwen3-8B(FP16/BF16)クローズドAPI
重みの VRAM≈6GB(要実測)≈16GB0(自前不要)
載るGPU24GBクラス1枚(L4 / A10 / RTX 4090 等)24GB〜
思考モードあり(切替可)ありモデル依存
ライセンスApache-2.0(商用可)Apache-2.0利用規約
データ主権自前で完結自前で完結外部送出
運用自前(本記事)自前ほぼゼロ

本質はこの一行:Qwen3-8B-AWQ は「思考できる小型モデルを、データを外に出さず、1枚のGPUで安く回す」ための選択肢です。

  • 向く:オンプレ/VPC内での推論、機微データを外に出せない案件、RAG やエージェントの“推論役”を原価最適化したい、検証〜小規模本番を 1 GPU で回したい。
  • 向かない:とにかく最高品質が要る(より大きいモデルへ)/運用ゼロで始めたい(まずはAPI)。判断軸の全体像はAPI vs セルフホストの損益分岐に揃えてください。

Qwen3-8B-AWQ とは(公式スペックを正確に)

まず公式の事実を、盛らずに置きます(出典:モデルカード)。

項目
総パラメータ8.2B(うち非埋め込み 6.95B)
レイヤー数36
アテンションGQA:Q ヘッド 32 / KV ヘッド 8
ネイティブ文脈長32,768 トークン
拡張文脈長131,072 トークン(YaRN 使用時)
量子化AWQ 4bit
ライセンスApache-2.0
引用Qwen3 Technical Report(arXiv:2505.09388)

公式は、Qwen3 が推論能力で過去の QwQ・Qwen2.5 系を上回り、創作・ロールプレイ・指示追従での人間嗜好との整合性も向上したと述べています(具体スコアは技術報告書を参照)。本稿はベンチ数値の主張ではなく、**「公式仕様どおりに本番で動かす」**ことに集中します。

🔎 派生に注意:Hugging Face には Qwen/Qwen3-8B(フル精度)、Qwen/Qwen3-8B-FP8Qwen/Qwen3-8B-Base、コミュニティの MLX 版などが並びます。本稿が扱うのは公式 Qwen/Qwen3-8B-AWQ(4bit)です。GQA は Q32/KV8——KV ヘッドが少ない設計は、KVキャッシュが軽く、同時実行を載せやすい=セルフホスト向きという含意があります。


AWQ(4bit量子化)とは:なぜ“1枚のGPU”に載るのか

AWQ = Activation-aware Weight Quantization。公式は「ハードウェアに優しい低ビット重み量子化」と説明します。重要なのは activation-aware——「出力に効く重みほど壊さない」ように量子化するため、4bit でも品質劣化を抑えられます。AutoAWQ の実装では FP16 比で約3倍のメモリ削減・約3倍の高速化が示されています(AWQ ドキュメント)。

VRAM の概算で“なぜ1枚に載るか”が腑に落ちます。

FP16 の重み  ≈ 8.2B × 2 byte ≈ 16.4 GB
AWQ 4bit     ≈ 8.2B × 0.5 byte ≈ 4.1 GB(+ スケール/ゼロ点で実測 6GB 前後)

つまり重みは概ね 6GB 前後。残りの VRAM を **KVキャッシュ(同時実行と文脈長を決める)**に回せます。24GB のGPU 1枚なら、重み 6GB + KV 余裕十分、という構図です(実際の同時実行数とスループットは必ず負荷試験で確定してください)。

量子化重みVRAM品質主用途
FP16/BF16≈16GB基準余裕がある時の最高品質
AWQ 4bit≈6GB実用上わずかな劣化1GPUセルフホスト・原価最適化
FP8≈8GBほぼ無劣化対応GPU(H100等)で速度重視

💡 使い分け:H100 のような FP8 対応GPUがあるなら FP8 も有力です(Llama を FP8 でサーブする回参照)。一方、L4 / A10 / RTX 4090 のような 24GB GPU で“とにかく載せて安く回す”なら AWQ 4bit が王道です。AWQ・GPTQ・FP8・GGUF の選び分けは量子化方式の選び方で詳説しています。


キラー機能:ハイブリッド思考(thinking / non-thinking)

Qwen3 最大の差別化が、1つのモデルで「考える」と「即答する」を切り替えられることです。

  • 思考モード(thinking)<think> … </think> の中で段階推論してから答える。数学・コード・複雑な判断に強い。
  • 非思考モード(non-thinking):推論ブロックを出さず即答。分類・抽出・定型対話など速度と原価が効く用途向け。

切り替えは2通り(公式仕様)

  1. ハードスイッチapply_chat_template(..., enable_thinking=True/False)(API では chat_template_kwargs)。
  2. ソフトスイッチenable_thinking=True の状態で、ユーザー発話に /think / /no_think を書くとターン単位で上書きできる。

モード別の推奨サンプリング(外すと壊れる)

公式がモードごとに別のサンプリングを指定している点が要注意です。

パラメータ思考モード非思考モード
Temperature0.60.7
TopP0.950.8
TopK2020
MinP00
greedy decoding禁止

⚠️ 公式の明確な警告:思考モードで greedy decoding(temperature=0 相当)を使ってはいけません。無限ループ・繰り返し・性能劣化を招きます。「reasoning は決定的に出したいから temp=0」は逆効果です。

出力長の目安も公式にあります:ほとんどのクエリは 32,768 トークン、数学やプログラミングのような複雑問題は 38,912 トークンまで見込む。思考モードは答えの前に長く“考える”ため、max_tokens をケチると結論に到達する前に切れます


動かす①:transformers で最短確認(開発用)

まずはローカルで最小確認。AWQ 重みの実行には awq カーネルが要るので、autoawq を入れます(本番は後述の vLLM 推奨)。

# pip install -U transformers accelerate autoawq
from transformers import AutoModelForCausalLM, AutoTokenizer

model_name = "Qwen/Qwen3-8B-AWQ"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype="auto", device_map="auto")

messages = [{"role": "user", "content": "9.11 と 9.9 はどちらが大きい?理由も。"}]

# enable_thinking=True で <think>...</think> による段階推論を有効化(ハードスイッチ)
text = tokenizer.apply_chat_template(
    messages, tokenize=False, add_generation_prompt=True, enable_thinking=True,
)
inputs = tokenizer(text, return_tensors="pt").to(model.device)

# 思考モードの公式推奨サンプリング(greedy は使わない)
generated = model.generate(
    **inputs, max_new_tokens=32768,
    temperature=0.6, top_p=0.95, top_k=20,
)
output_ids = generated[0][len(inputs.input_ids[0]):].tolist()
print(tokenizer.decode(output_ids, skip_special_tokens=True))

開発の単機・お試しはこれで十分。ただし transformersgenerate連続バッチを持たないため、本番の同時多数リクエストには向きません。そこで vLLM に移ります。


動かす②:vLLM で本番サーブ(OpenAI互換)

本番は vLLM。連続バッチと PagedAttention で GPU を遊ばせず、OpenAI 互換エンドポイントを出すので、アプリ側のコードを変えずに向け先だけ差し替えられます(基盤づくりの全体はvLLM 本番セルフホスト運用記に集約)。

# Qwen3-8B-AWQ を OpenAI 互換でサーブ。思考の分離パースを有効化
vllm serve Qwen/Qwen3-8B-AWQ \
  --reasoning-parser qwen3 \
  --max-model-len 32768 \
  --gpu-memory-utilization 0.90 \
  --port 8000
  • --reasoning-parser qwen3vLLM 0.9.0 以降の指定。<think> ブロックを本文と分離し、レスポンスに reasoning_content フィールドを足してくれる。古い vLLM では --enable-reasoning --reasoning-parser deepseek_r1 を使います。
  • --max-model-len 32768:ネイティブ上限。実際に必要な長さに絞るのが原価とレイテンシの鉄則(青天井にしない)。
  • --gpu-memory-utilization 0.90:確保率。上げすぎ=OOM、低すぎ=同時実行が減る。

立ち上がれば、OpenAI クライアントでそのまま叩けます。思考のオン/オフは extra_body.chat_template_kwargs.enable_thinking で制御します。

from openai import OpenAI
client = OpenAI(api_key="EMPTY", base_url="http://localhost:8000/v1")

resp = client.chat.completions.create(
    model="Qwen/Qwen3-8B-AWQ",
    messages=[{"role": "user", "content": "在庫が負になりうる箇所をこのSQLから指摘して"}],
    temperature=0.6, top_p=0.95, extra_body={
        "top_k": 20,
        "chat_template_kwargs": {"enable_thinking": True},  # 思考モード
        # 量子化モデルで“終わらない繰り返し”が出たら presence_penalty を 0〜2 で(推奨 1.5)
        "presence_penalty": 1.5,
    },
)
msg = resp.choices[0].message
print("思考:", getattr(msg, "reasoning_content", None))  # <think> の中身(ログ/監査用)
print("回答:", msg.content)                               # ユーザーに返す最終回答

reasoning_content(思考過程)と content(最終回答)が構造的に分かれるのが本番で効きます。ユーザーには content だけ返し、reasoning_content は監査・評価用に内部で扱う——この分離が後述の型安全・可観測性の土台になります。


長文脈:YaRN で 32K → 131K(必要な時だけ)

ネイティブは 32,768。それ以上の文脈が要るときだけ YaRN で拡張します。CLI でも宣言できます。

vllm serve Qwen/Qwen3-8B-AWQ \
  --reasoning-parser qwen3 \
  --rope-scaling '{"rope_type":"yarn","factor":4.0,"original_max_position_embeddings":32768}' \
  --max-model-len 131072

config.json に同等を書く形(factor:4.0, original_max_position_embeddings:32768)も公式に示されています。

⚠️ 常時 YaRN を有効化しない。公式は「必要な時だけ」と明言しています。短い入力にまで長文脈スケーリングを掛けると、短文の品質が落ちる副作用があります。32K で足りるなら YaRN は外す——「念のため最大」は逆効果です。長文脈ほど KVキャッシュが膨らみ VRAM とレイテンシも増えるので、max-model-len実需に合わせて設定してください。


ツール呼び出し / エージェント

Qwen3 は関数呼び出し(tool use)に対応します。vLLM ではフラグで有効化します。

vllm serve Qwen/Qwen3-8B-AWQ \
  --reasoning-parser qwen3 \
  --enable-auto-tool-choice \
  --tool-call-parser hermes

あとは OpenAI 互換の tools を渡せば、モデルが必要に応じて関数呼び出しを返します。エージェント的なツール連携を組むなら、公式の Qwen-Agent(ツール定義とパースのテンプレートが揃う)を使うと、tool-call の取り回しを自前で書かずに済みます。引数のZod検証・反復上限・冪等な副作用まで含む安全なループの実装はQwen3 のエージェント化で具体化します。設計の勘所——「LLMに任せる判断決定的コードに寄せる実行を分ける」——はツール使用・関数呼び出しの設計に揃えてください。


どの場面で使うか:型安全な本番クライアント(応用)

ここからが応用です。Qwen3-8B-AWQ の強みは「思考できる」「安い」「自前」。これを型安全・冪等・回復性で包むと、本番で稼げるコンポーネントになります。代表的な応用は、機微データを外に出さない自前RAGです。

設計方針(CLAUDE.md の原則どおり、SRP / KISS / 型安全境界を効かせます):

  1. モードを難度でルーティング——簡単なタスクは非思考(速い・安い)、難所だけ思考(原価最適化の本丸)。
  2. 思考過程と回答を分離——reasoning_content はログ、content だけ検証して返す。
  3. 構造化出力は境界で Zod 検証——LLM 出力は外部入力。parse で不正を弾く(型安全の規律)。生成段階で不正JSONを作らせない guided decoding との二段構えは型安全な構造化出力へ。
  4. タイムアウト+冪等キャッシュ——同じ入力を二度生成しない=原価も安定。
// lib/qwen-client.ts — 思考/非思考をルーティングし、出力を境界で型検証する薄いクライアント
import OpenAI from "openai";
import { z } from "zod";
import { createHash } from "node:crypto";

const client = new OpenAI({
  baseURL: process.env.QWEN_BASE_URL, // 例: http://qwen-internal:8000/v1(privateで公開しない)
  apiKey: "internal",
  timeout: 60_000, // 思考モードは長い。短すぎる timeout は“正常な熟考”を切る
});

/** タスク難度 → モードと公式推奨サンプリングを決める(SSoT) */
const MODE = {
  fast: { enable_thinking: false, temperature: 0.7, top_p: 0.8, top_k: 20 },
  think: { enable_thinking: true, temperature: 0.6, top_p: 0.95, top_k: 20 },
} as const;
type Difficulty = keyof typeof MODE;

/** 期待する構造化出力。LLMの“それっぽい文字列”を信用せず、ここで弾く */
const RiskFinding = z.object({
  hasRisk: z.boolean(),
  severity: z.enum(["low", "medium", "high"]),
  reason: z.string().min(1),
});
type RiskFinding = z.infer<typeof RiskFinding>;

const cache = new Map<string, RiskFinding>(); // 実運用は Redis 等に置換

/** 入力が同じなら生成も同じ(冪等)。連打・リトライ・重複依頼でコストを無駄にしない */
const keyOf = (prompt: string, d: Difficulty) =>
  createHash("sha256").update(`qwen3-8b-awq:${d}:${prompt}`).digest("hex");

export async function assessRisk(prompt: string, difficulty: Difficulty = "think"): Promise<RiskFinding> {
  const key = keyOf(prompt, difficulty);
  const hit = cache.get(key);
  if (hit) return hit;

  const m = MODE[difficulty];
  const resp = await client.chat.completions.create({
    model: "Qwen/Qwen3-8B-AWQ",
    messages: [
      { role: "system", content: 'JSONのみで返答: {"hasRisk":bool,"severity":"low|medium|high","reason":string}' },
      { role: "user", content: prompt },
    ],
    temperature: m.temperature,
    top_p: m.top_p,
    response_format: { type: "json_object" },
    presence_penalty: 1.5, // 量子化モデルの繰り返し対策(公式推奨レンジ 0〜2・OpenAI互換)
    // vLLM拡張はトップレベルで送る。Node SDKは未知キーも本文へ転送し、spreadなので型エラーも出ない。
    // ※ Python SDK の extra_body は TS SDK には存在しないので使わない。
    ...{ top_k: m.top_k, chat_template_kwargs: { enable_thinking: m.enable_thinking } },
  });

  // content だけを検証対象に。reasoning_content(思考過程)は監査ログへ(PIIは載せない)
  const raw = resp.choices[0]?.message.content ?? "{}";
  const finding = RiskFinding.parse(JSON.parse(raw)); // 不正な形なら throw → 上位で握る

  cache.set(key, finding);
  return finding;
}

このクライアントは、“思考するLLM”の出力を決して鵜呑みにしない点が肝です。reasoning_content は人間の監査と評価のために残し、ユーザーに返すのは Zod を通った型だけ。さらに enable_thinking をタスク難度で出し入れすることで、簡単8割を非思考で安く・難所2割だけ思考で正確に——という原価設計が、1つのモデルで成立します。


本番の作り込み(重複は避け、要点だけ)

可観測性・オートスケール・グレースフルドレイン・回復性・ネットワーク隔離は、モデルが Qwen でも Llama でも同じ作法です。詳細は重複させず、vLLM 本番セルフホスト運用記に委ねます。Qwen3-8B-AWQ で特に効くポイントだけ:

  • 可観測性:vLLM の /metrics(Prometheus)で num_requests_waiting / gpu_cache_usage_perc / TTFT を監視。思考モードは出力が長くなりがちなので、reasoning のトークン消費を用途別に可視化すると原価の当たりがつきます(OpenTelemetry の相関設計)。
  • 回復性:自前ノードの障害を全体障害にしない。タイムアウト+リトライ+フォールバック。8B が落ちたら別ノード/上位モデルへ逃がす(リトライ・サーキットブレーカー)。
  • セキュリティ:vLLM の OpenAI 互換サーバはそれ自体に強い認証がないインターネットに直接晒さない。private VPC に置き、前段の API Gateway で認証・レート制限・監査。プロンプト本文(PII)はログに残さない——そもそも「外に出さない」がセルフホストの動機です。

ハマりどころ & 公式ベストプラクティス

公式ドキュメントから、外すと品質が崩れるものを抜き出します。

  • 🔴 思考モードで greedy decoding 禁止。temp=0 にしない。繰り返し・無限ループの原因。
  • 🟠 量子化モデルの繰り返し対策に presence_penalty ≈ 1.5(レンジ 0〜2)。ただし上げすぎると稀に言語混在やわずかな性能低下があるため、出たら効かせる程度に。
  • 🟠 マルチターンで履歴に思考内容(<think>)を残さない。次ターンの入力には最終回答だけを積む。思考を積み続けると文脈が汚れ、品質・原価とも悪化。
  • 🟠 出力長を絞りすぎない。思考は答えの前に長い。通常 32,768 / 複雑問題 38,912 トークンを目安に max_tokens を確保。
  • 🟢 数学は出力フォーマットを指定:「Please reason step by step, and put your final answer within \boxed{}.」で最終解が機械抽出しやすくなる。
  • 🟢 YaRN は必要な時だけ。常時有効化は短文の品質を落とす。
  • 🟢 AWQ は transformers だと awq カーネル依存。本番スループットは vLLM(連続バッチ)に寄せる。

よくある質問(FAQ)

Q. Qwen3-8B-AWQ と FP8 版、どちらを使う? A. 24GB級の汎用GPU(L4/A10/RTX 4090)で“載せて安く回す”なら AWQ 4bit。H100 など FP8 対応GPUで速度最優先なら FP8。重みは AWQ≈6GB / FP8≈8GB / FP16≈16GB が目安です(要実測)。

Q. “思考”は常にオンにすべき? A. いいえ。分類・抽出・定型対話は非思考(速い・安い)で十分。数学・コード・複雑な判断だけ思考に。タスク難度でルーティングするのが原価設計の本丸です(本文のクライアント例)。

Q. greedy(temp=0)で再現性を出したいのですが? A. 思考モードでは公式が禁止しています。決定的な出力が要るなら、reasoning ではなく最終回答のスキーマ(Zod)と冪等キャッシュで再現性を担保してください。サンプリング自体を殺すのは逆効果です。

Q. 何 GPU 要りますか? A. まず 1 枚。重み≈6GB なので 24GB 1枚で動きます。同時実行とスループットは KVキャッシュ次第なので、負荷試験で飽和点を測り、そこから台数を逆算します。

Q. Ollama でも動く? A. ローカル開発の単機お試しには手軽です。ただし本番の高スループット(連続バッチ)は vLLM。開発は手軽な方、本番は vLLM、と使い分けます。

Q. ライセンスは商用利用できる? A. Apache-2.0 です。重みを所有し、改造し、自社環境で動かせます。Llama の「700M MAU 制限/Built with Llama 表記」のような制約は無く、ライセンス面はよりシンプルです(クローズドAPIとの違いはピラー記事)。


まとめ

Qwen3-8B-AWQ は、「思考できる小型モデルを、データを外に出さず、1枚のGPUで安く回す」という、これまで両立しにくかった要件を素直に満たします。

  1. AWQ 4bit で重み ≈6GB → 24GB GPU 1枚に載る(Apache-2.0・商用可)。
  2. ハイブリッド思考を難度でルーティング——簡単は非思考で安く、難所は思考で正確に。
  3. vLLM で OpenAI 互換サーブ--reasoning-parser qwen3)、reasoning_content で思考と回答を分離。
  4. 公式サンプリングを厳守(思考: 0.6/0.95/20、greedy禁止、presence_penalty≈1.5、履歴に思考を残さない)。
  5. 出力は境界で型検証(Zod)+冪等キャッシュ。本番の作法はvLLM 運用記に集約。

オンプレ/VPC内で「思考するLLM」を、可観測・回復性・型安全まで含めて構築します。GPU 本番運用の実績をご覧のうえ、モデル選定・原価設計・セルフホスト移行までご相談ください。一人 × 生成AIで、速く・安く・安全に。

出典・公式リソース

※ スペック・フラグ・サンプリング推奨は更新されます。VRAM とスループットは環境依存・要ベンチです。実装前に一次情報と自社ベンチで必ず確認してください。

友田

友田 陽大

経済産業大臣賞 受賞プロダクト開発者。TypeScript + Python + AWS で、SaaS・業界DX・ 実用レベルの生成AI(RAG)を、要件定義からインフラ・運用まで一人で完遂します。

この記事で解説した技術の適用事例

AI動画ローカライズ・リップシンク基盤

ケーススタディを見る