概要
Meta社が公開した大規模言語モデル (LLM) である Llama 4 を、手元のオンプレミスサーバーにデプロイし、その動作検証を行った際の作業記録である。
本プロジェクトの目的は、RAG (Retrieval-Augmented Generation) の手法を用いて、筆者自身の専門分野の論文群を大量に学習させ、AIをその分野に特化させること、および、Google のNotebookLM のように論文内容に関する質疑応答機能を実装することを目指した。
検証環境
- AlmaLinux 8.10
- Ryzen Threadripper 3990x (64コア)
- RAM: 128GB
- GPU: RTX A6000 + RTX 5000 ada
インストール手順
sudo dnf install -y epel-release
# 必要なものをインストール
sudo dnf groupinstall -y "Development Tools"
sudo dnf install -y git cmake gcc-c++ python3 python3-devel
# llama4 の cmake で libcurl-devel が必要
sudo dnf install -y libcurl-devel
# gcc8 だとビルドに失敗するので gcc12 にアップグレードしておく
sudo dnf install -y gcc-toolset-12
scl enable gcc-toolset-12 bash
nvidia-driver と cuda toolkit 関連
# nvidia-driver
# cuda tool-kit
wget https://developer.download.nvidia.com/compute/cuda/13.0.1/local_installers/cuda-repo-rhel8-13-0-local-13.0.1_580.82.07-1.x86_64.rpm
sudo rpm -i cuda-repo-rhel8-13-0-local-13.0.1_580.82.07-1.x86_64.rpm
sudo dnf clean all
sudo dnf -y install cuda-toolkit-13-0
miniconda を入れる
cd /tmp
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh
仮想環境の構築
conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/main
conda tos accept --override-channels --channel https://repo.anaconda.com/pkgs/r
conda create -n llama4 python=3.10 -y
conda activate llama4
llama のビルド
<注意>llama4 では、LLAMA_CUBLAS=ON は非対応。
mkdir -p ~/workspace
cd ~/workspace
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
mkdir build
cd build
cmake .. -DGGML_CUDA=ON -DCMAKE_BUILD_TYPE=Release
make -j64 # 数字は、使用する CPU のコア数に合わせて変えること
Hugging Face トークンの設定
こちらのページ(https://huggingface.co/collections/meta-llama/llama-4 )から Llama-4-Maverick-17B-128E のアカウントを申請する。
こちらのページ(https://huggingface.co/meta-llama/Llama-4-Maverick-17B-128E )のExpand to review and access タブをクリックして、氏名など必要情報を入力して submit する。
submit 後は、こちらのページ(https://huggingface.co/settings/gated-repos ) で、accepted になるのを待つ。
accept 後は、Hugging Face のマイページから新しいトークンを作る。
トークンは、Llama-4-Maverick-17B-128E だけでなく、全てのモデルを入力しておいたほうが後々楽である。途中まで打ってもプルダウンメニューに自動では表示されないので、自分で調べて入力する必要がある。
モデルをダウンロード(Q5_K_M, GGUF)
Hugging Face CLI の導入
conda install -y git-lfs
git lfs install
mkdir -p /home/models/llama4-maverick-17b
cd /home/models/llama4-maverick-17b
# python -m huggingface_hub や huggingface-cli login は非対応なので注意!hf auth 推奨。
hf auth login
# アクセストークンを入力する
# 確認コマンド
hf auth whoami
Llama のモデルについて
Llama 4 には、Scout, Maverick, Behemoth というモデルが存在する。
- Scout:軽量・高速なマルチモーダルモデル。
- Maverick:バランスの取れた性能のマルチモーダルモデル。
- Behemoth:教師モデルとして使われる最高性能のモデル(プレビュー版)。
これらのバージョンごとに、さらにパラメータ数(例:8B, 70B, 405Bなど)によってモデルサイズが分かれている。
🧑💻 パラメータ(Parameter)とは?
- モデルが学習したすべての情報、例えば「単語Aの次に単語Bが来る可能性」や「この文脈ではこの言葉が適切」といった判断を下すための『重み(数値)』のこと。
- パラメーター数が多いほど、モデルはより巨大になり、多くの複雑な知識を持つ傾向がある。(例:80億パラメータ、700億パラメータ)
📊 量子化(Quantization)とは?
- 元の大きなモデルの数字(重み)は、非常に正確な『32ビットの細かい小数(FP32)』で表現されている。量子化は、この細かい小数を『4ビットや8ビットの、より粗い数字』に置き換える作業である。
🔠 量子化の具体例とファイル形式
- 『どれだけデータを小さくするか』を示す量子化の『圧縮レベル』のようなもの。
- Q4_K_M / Q5_K_L:これは、特にローカル実行向けに開発されたより高度な量子化技術(llama.cppなどで利用)の名称である。数字の「4」や「5」は、主に重みを何ビットで表現するかを示しています。(数字が小さいほどファイルサイズが小さく、速い)。FP8 の場合は、浮動小数点数を8ビットで表現している。
- 「_K」や「_L」「_M」は、精度の低下を最小限に抑えるための工夫(アルゴリズム)の違いを示している。
💾 GGUF(ジー・ジー・ユー・エフ)とは?
- GGUFは、量子化されたAIモデルを、誰でもローカルPCで簡単に動かせるようにしたファイル形式である。
- GGUFは、llama.cppという、ローカル環境でのAI実行に特化したプロジェクトで使われる標準のファイル形式である。
- この形式にすることで、モデルを動かすために必要な設定や情報がすべてファイル内に含まれるため、複雑なプログラミング知識がなくてもすぐに実行できる。
- Hugging Faceなどで公開されているのは、このGGUF形式に変換され、量子化されたモデルが多く、ローカルAI利用者の間で広く使われている。
動作検証
Maverick を RTX A6000 の 48GB の vRAM で動かすのは難しいので、今回は llama4-scout を使用する。llama4-scount の GGUF 版は公式には提供されていないが、提供してくれている HuggingFace user がいるので、そのユーザーのリポジトリからダウンロードする。
今回は、unsloth のページ(https://huggingface.co/unsloth/Llama-4-Scout-17B-16E-Instruct-GGUF/tree/main/Q4_K_M )からダウンロード。モデルダウンロードには 1 時間程度かかるので、バックグラウンドで実行すると良い。
大きめのモデルだと、ファイルが分割されているので、全てダウンロードするように!
#例 Q3_K_S をダウンロード
hf download unsloth/Llama-4-Scout-17B-16E-Instruct-GGUF \
--include "Llama-4-Scout-17B-16E-Instruct-Q3_K_S.gguf" \
--local-dir ./llama4-scout-q3_k_s
#例 Q5_K_M をダウンロード
hf download unsloth/Llama-4-Scout-17B-16E-Instruct-GGUF \
--include "Q5_K_M/Llama-4-Scout-17B-16E-Instruct-Q5_K_M-*.gguf" \
--local-dir ./llama4-scout-q5_k_m
llama.cpp で推論する
メモ:最新版の llama では、build 内の main は廃止されました。代わりに llama-cli を使用します。
pip install vllm
以下のコマンドで Llama を起動する。gguf ファイルのファイルパスを指定すること。gguf が複数に分割されている場合は、一つ目のファイルパスだけ指定すれば良い。
llama-server -m Llama-4-Scout-17B-16E-Instruct-Q5_K_M-00001-of-00002.gguf --host 127.0.0.1 --port 8888 --n-gpu-layers 45
--n-gpu-layers 45 は、何層まで GPU の vRAM に載せるかを意味する。できる限り大きな値を指定した方が高速に動作する。載り切らない分は、普通の RAM を使用する。マルチ GPU も対応している。
起動時に以下のように vRAM の使用量が表示される。GPU に載り切らない場合は、エラーで強制終了する。
load_tensors: loading model tensors, this can take a while... (mmap = true)
load_tensors: offloading 45 repeating layers to GPU
load_tensors: offloaded 45/49 layers to GPU
load_tensors: CPU_Mapped model buffer size = 6092.81 MiB
load_tensors: CUDA0 model buffer size = 26721.64 MiB
load_tensors: CUDA1 model buffer size = 40173.44 MiB
上記のコマンドで起動した後に、web ブラウザで localhost:8888 にアクセスする。
こちらは、あらかじめ .ssh/config でポートの設定をしておく必要がある。
Host llama_server
HostName 192.168.0.69
User username
LocalForward 8888 127.0.0.1:8888 #webブラウザでのアクセス用
ServerAliveInterval 60
web ブラウザでアクセスすると以下の画面が表示される。
質問すると以下のような感じで回答が表示される。
RAG を用いて論文を読み込ませる
PDF を読み込ませるためには、以下の手順が必要です。
- PDF をテキスト化
- テキストをチャンク化
- embedding 生成
- ベクトルDB に保存
llamaindex_openai_chat.py を作成する。
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.vector_stores.chroma import ChromaVectorStore
from llama_index.core import StorageContext, Settings
from llama_index.core.chat_engine import CondensePlusContextChatEngine # ★ 新しくインポート
import chromadb
import os
# ----------------------------------------------------
# 1. セットアップと基本設定
# ----------------------------------------------------
LLM_API_BASE = "http://127.0.0.1:8888/v1"
DUMMY_API_KEY = "sk-dummy-key"
# LlamaIndexのグローバル設定
llama_llm = OpenAI(
api_key=DUMMY_API_KEY,
api_base=LLM_API_BASE,
model="gpt-3.5-turbo",
temperature=0.1,
request_timeout=60.0 # タイムアウト延長
)
Settings.llm = llama_llm
# エンベディングモデルの設定
embed_model = HuggingFaceEmbedding(model_name="intfloat/multilingual-e5-large")
Settings.embed_model = embed_model
# データとDBのパス
DOCS_DIR = "/home/papers"
CHROMA_DB_PATH = "./chroma_db"
COLLECTION_NAME = "llama4_rag_index"
print(f"✅ LLM API Base (using OpenAI class): {LLM_API_BASE}")
print(f"✅ Embed Model: {Settings.embed_model.model_name}")
# ----------------------------------------------------
# 2. ベクトルストアの準備 (ChromaDB)
# ----------------------------------------------------
try:
db = chromadb.PersistentClient(path=CHROMA_DB_PATH)
chroma_collection = db.get_or_create_collection(COLLECTION_NAME)
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
print(f"✅ ChromaDB setup successful. Collection: {COLLECTION_NAME}")
except Exception as e:
print(f"❌ Error setting up ChromaDB: {e}")
exit()
# ----------------------------------------------------
# 3. データのロードとインデックス化
# ----------------------------------------------------
print(f"⏳ Loading documents from {DOCS_DIR}...")
if not os.path.exists(DOCS_DIR):
print(f"❌ Document directory not found: {DOCS_DIR}")
exit()
documents = SimpleDirectoryReader(
input_dir=DOCS_DIR,
required_exts=[".pdf"]
).load_data()
if not documents:
print(f"⚠️ No PDF documents found in {DOCS_DIR}. Indexing will proceed without documents.")
print("⏳ Creating/Loading index (This may take a while for large documents)...")
index = VectorStoreIndex.from_documents(
documents,
storage_context=storage_context,
)
print("✅ Indexing complete.")
# ----------------------------------------------------
# 4. 対話の実行 (RAG Chat Engine)
# ----------------------------------------------------
# ★ 修正箇所: ChatEngine のセットアップ ★
# Retriever (検索エンジン) を設定
retriever = index.as_retriever(similarity_top_k=3)
# CondensePlusContextChatEngine を使用して対話エンジンを構築
# これが、会話履歴を考慮しながらRAG検索を実行します
chat_engine = CondensePlusContextChatEngine.from_defaults(
retriever=retriever,
llm=llama_llm,
verbose=True # 詳細なログを表示
)
print("\n--- ✅ Llama-4 RAG 対話エンジン 起動 ---")
# 対話ループの開始
while True:
try:
prompt = input("👤 あなたの質問 (終了する場合は 'exit'): ")
if prompt.lower() == 'exit':
print("👋 対話を終了します。")
break
print("⏳ Querying Llama-4 via RAG...")
# chat_engine.chat() で質問と履歴を処理
response = chat_engine.chat(prompt)
print("\n--- ✅ Llama-4 からの回答 (RAG) ---")
print(response.response)
print("-----------------------------------")
# 参照ソースの表示
print("\n--- 参照ソース ---")
# ChatEngineでは source_nodes は response.source_nodes で取得
source_nodes = response.source_nodes
if source_nodes:
for i, node in enumerate(source_nodes):
filename = node.metadata.get('file_name', 'Unknown File')
score = node.score
print(f"- Source {i+1}: {filename} (Similarity Score: {score:.4f})")
else:
print("参照されたソースノードはありませんでした。")
except Exception as e:
print(f"\n❌ エラーが発生しました: {e}")
# Llama Server の状態確認を促す
print("Llama Serverが動作していることを確認してください。")
break
/home/papers に pdf ファイルを格納しておく。
llama4 を実行した状態で、以下のコマンドを実行する。
RAG でも vRAM を消費するので、--n-gpu-layers 45 をいつも使用している場合は、RAG 使用時は --n-gpu-layers 40 程度にした方が良い。
python llamaindex_openai_chat.py
今回のようにシンプルに pdf を読み込ませただけの場合、llama4 は論文の内容までは理解してないようである。論文内の単語検索等はできるが、内容についての質問では期待する回答が得られなかった。NotebookLM のように論文の内容まで学習させるには、もう少し工夫が必要なようである。

