1. 問題の概要:vLLMでLoRAアダプターを動的にロードする際のエラー
vLLMは、大規模言語モデル(LLM)の高速推論エンジンとして広く利用されています。その重要な機能の一つが、LoRA (Low-Rank Adaptation) アダプターのサポートです。これにより、ベースモデルを微調整した複数の軽量なアダプターファイルを、単一のサーバーインスタンス上で動的に切り替えて使用することが可能になります。
しかし、開発者がこの動的ロード機能を実装しようとすると、以下のようなエラーに頻繁に遭遇します。
ValueError: The adapter 'customer_support_lora' is not found. The available adapters are: [].
あるいは、サーバー起動時にアダプターを指定しても、推論時に別のアダプターをロードしようとすると失敗します。
# サーバー起動コマンド例
python -m vllm.entrypoints.openai.api_server
--model meta-llama/Llama-2-7b-hf
--served-model-name llama-2-7b
--api-key token-abc123
--max-model-len 4096
# クライアントからのリクエスト(エラー発生)
curl http://localhost:8000/v1/completions
-H "Content-Type: application/json"
-H "Authorization: Bearer token-abc123"
-d '{
"model": "llama-2-7b",
"prompt": "商品の返品方法を教えてください。",
"max_tokens": 100,
"lora_request": {
"lora_name": "customer_support_lora",
"lora_path": "/path/to/adapters/customer_support"
}
}'
このエラーの根本的な問題は、アダプターのパスが正しく設定・認識されていないこと、またはサーバーの起動方法に問題があることにあります。本記事では、このエラーをステップバイステップで解決する方法を解説します。
2. 原因の解説:なぜアダプターが見つからないのか?
エラーメッセージ The adapter '...' is not found. The available adapters are: [] は、vLLMサーバーがリクエストで指定されたLoRAアダプターをメモリ内で見つけられなかったことを示しています。主な原因は以下の3つに分類できます。
2.1. サーバー起動時の引数不足
vLLMはデフォルトではLoRA機能が無効化されています。動的ロードを可能にするには、サーバー起動時に明示的に--enable-loraフラグを渡し、LoRAエンジンを有効化する必要があります。このフラグを忘れると、サーバーはLoRAリクエストを一切処理できません。
2.2. アダプターパスの指定ミス
クライアントリクエストのlora_request.lora_pathで指定するパスが、サーバーマシン上で有効な絶対パス(またはサーバーのカレントディレクトリからの相対パス)でない場合、アダプターファイル(通常はadapter_config.jsonとadapter_model.safetensors)を読み込むことができません。
2.3. アダプターファイルの形式または構造の問題
指定したパスにLoRAアダプターファイルが存在していても、vLLMがサポートする形式(PEFTライブラリで保存された形式)でない場合や、ファイルが破損している場合も読み込みに失敗します。
3. 解決方法:動的LoRAロードを成功させるステップバイステップガイド
以下に、確実に動作する設定手順を説明します。
ステップ1: LoRAアダプターの準備
まず、動的ロードしたいLoRAアダプターが正しい形式で保存されていることを確認します。PEFT (Parameter-Efficient Fine-Tuning) ライブラリを使用して保存するのが一般的です。
from peft import PeftModel
# ベースモデルとアダプターのロード(学習時など)
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf")
model = PeftModel.from_pretrained(model, "/path/to/trained/lora/checkpoint")
# アダプターをマージせずに独立したファイルとして保存
model.save_pretrained("/path/to/adapters/customer_support", safe_serialization=True)
保存されたディレクトリには、少なくともadapter_config.jsonとadapter_model.safetensorsの2ファイルが存在するはずです。
ステップ2: vLLMサーバーの正しい起動
最も重要なステップです。--enable-loraフラグを必ず追加してください。また、--max-lora-rankや--max-cpu-lorasなど、必要に応じてリソースパラメータも調整します。
python -m vllm.entrypoints.openai.api_server
--model meta-llama/Llama-2-7b-hf
--served-model-name llama-2-7b
--api-key token-abc123
--max-model-len 4096
--enable-lora
--max-lora-rank 64
--max-cpu-loras 4
--max-num-seqs 256
ポイント: --enable-loraがLoRA機能を有効にします。--max-lora-rankはLoRAのランクの最大値(学習時の設定値以下)、--max-cpu-lorasはメモリに保持するアダプターの数を制御します。
ステップ3: クライアントからの正しいリクエスト送信
サーバー起動時にアダプターを事前ロードしていない(動的ロードを使用する)場合、クライアントリクエストにlora_requestフィールドを含めます。lora_pathはサーバーがアクセス可能な有効なパスである必要があります。
import openai
client = openai.OpenAI(
base_url="http://localhost:8000/v1",
api_key="token-abc123"
)
response = client.completions.create(
model="llama-2-7b", # サーバー起動時の --served-model-name
prompt="商品の返品方法を教えてください。",
max_tokens=100,
extra_body={ # extra_body 内に lora_request を指定
"lora_request": {
"lora_name": "customer_support_lora", # 任意の識別名
"lora_path": "/home/user/adapters/customer_support" # サーバー上の絶対パス
}
}
)
print(response.choices[0].text)
重要: OpenAIクライアントライブラリを使用する場合、lora_requestは標準パラメータではないため、extra_body引数に渡す必要があります。cURLの場合は、最初の例のようにJSONボディに直接記述します。
ステップ4: サーバーログの確認
リクエストが成功すると、vLLMサーバーのログに以下のようなメッセージが出力されます。これは、アダプターが正常にロードされ、キャッシュされたことを示しています。
INFO 07-15 10:30:15 lora.py:150] Loading LoRA adapter: lora_name='customer_support_lora' lora_path='/home/user/adapters/customer_support'
INFO 07-15 10:30:15 lora.py:177] Finished loading LoRA adapter: lora_name='customer_support_lora'
このログが出力されない、またはエラーログが出力される場合は、パスやファイル形式を再確認してください。
4. コード例・コマンド例:完全なワークフロー
ここでは、サーバー起動から複数のアダプターを動的に使い分けるまでの一連の流れを示します。
シナリオ:カスタマーサポートとコード生成のアダプターを使い分ける
2つの異なるタスク用に作成したLoRAアダプターを、同じベースモデルで動的に切り替えます。
# 1. サーバー起動 (ターミナルで実行)
python -m vllm.entrypoints.openai.api_server
--model meta-llama/Llama-2-7b-hf
--served-model-name llama-2-7b
--api-key my-api-key
--enable-lora
--max-lora-rank 64
--port 8000
# 2. クライアントスクリプト (Python)
import openai
import sys
client = openai.OpenAI(base_url="http://localhost:8000/v1", api_key="my-api-key")
def query_with_lora(prompt, lora_name, lora_path):
try:
response = client.completions.create(
model="llama-2-7b",
prompt=prompt,
max_tokens=150,
temperature=0.7,
extra_body={
"lora_request": {
"lora_name": lora_name,
"lora_path": lora_path
}
}
)
return response.choices[0].text
except Exception as e:
return f"Error: {e}"
# カスタマーサポートアダプターを使用
support_response = query_with_lora(
"注文した商品がまだ届きません。どうすればいいですか?",
"lora_support",
"/absolute/path/to/adapters/customer_support_v1" # 実際のパスに置き換え
)
print("【カスタマーサポート回答】n", support_response)
print("n" + "="*50 + "n")
# コード生成アダプターを使用
code_response = query_with_lora(
"Pythonでクイックソートを実装してください。",
"lora_coder",
"/absolute/path/to/adapters/code_llama_7b" # 実際のパスに置き換え
)
print("【コード生成回答】n", code_response)
5. まとめ・補足情報
vLLMでLoRAアダプターを動的にロードするには、1) LoRA機能の有効化(–enable-lora)、2) サーバーからアクセス可能な正しいアダプターパスの指定、3) クライアントリクエストでのlora_requestフィールドの使用の3点が必須です。
よくある落とし穴と追加Tips
・パスの問題: Dockerコンテナ内でvLLMサーバーを実行している場合、lora_pathはコンテナ内のパスである必要があります。ホストのパスをマウントして対応しましょう。
・メモリ不足:</strong 多くのアダプターを同時にロードしようとすると、CUDA out of memoryエラーが発生する可能性があります。--max-cpu-lorasでキャッシュ数を制限し、使用頻度の低いアダプターはメモリからアンロードされるように調整します。
・事前ロードとの併用: 起動時に頻繁に使うアダプターをロードしたい場合は、サーバー起動オプションに--lora-modules customer_support_lora=/path/to/adapters/customer_support ...を追加できます。これにより、初期ロード時間を短縮できます。
・OpenAI API互換性: vLLMのOpenAI APIエンドポイントは標準から拡張されています。ツールによってはextra_bodyをサポートしていない場合があるため、リクエストの送信方法には注意が必要です。
vLLMの動的LoRA機能を活用すれば、単一の強力なベースモデルを共有しながら、様々なタスク特化型の軽量モデルをオンデマンドで提供する、効率的な推論サーバーを構築することができます。本記事の手順を参考に、エラーを解決し、マルチテナントやマルチタスク推論システムの開発を進めてください。