所要時間: 約40分 | 難易度: ★★★☆☆
この記事で作るもの
- 中国系LLM(Qwen, DeepSeek等)の「API版」と「ローカル版(Ollama等)」を、モデルの公開状況や通信状態に応じて1秒以内に自動で切り替える、可用性の高いPython推論スクリプトを作ります。
- 前提知識: Pythonの基本的な文法(関数、例外処理)がわかること。
- 必要なもの: Python 3.10以上、DashScope(Qwen)やDeepSeekのAPIキー、ローカル実行用のLLM環境(Ollama等)。
📦 この記事に関連する商品
GeForce RTX 4090API配布が遅れる中、Qwenクラスのモデルを自前で高速推論するには24GB VRAMが必須。
※アフィリエイトリンクを含みます
なぜこの方法を選ぶのか
現在、Qwen3.6やGLM-5といった中国の主要LLMが、モデルウェイトの公開を同時に遅らせるという不可解な動きを見せています。これまでは「数週間待てばローカルで動かせる」のが当たり前でしたが、今後はAPI専売の状態が長く続く、あるいは突然公開が中止されるリスクを考慮しなければなりません。
個別のSDKを使い分ける従来の方法では、モデルの切り替えが発生するたびにコードを書き直す手間が生じ、実務でのスピード感が失われます。今回紹介する「LiteLLM」を活用した抽象化レイヤーの実装は、APIのURLとモデル名を書き換えるだけで、ローカル(RTX 4090等)とクラウド(中国サーバー)の接続先を瞬時にスイッチできます。これは、開発環境ではローカルモデルでコストを抑え、本番環境や最新モデルが必要な場面ではAPIに頼るという、現在の不安定なAI情勢において最も現実的で堅牢な選択肢です。
Step 1: 環境を整える
まずは、複数のLLMプロバイダーを統一されたインターフェースで操作できる「LiteLLM」と、環境変数を管理する「python-dotenv」をインストールします。
pip install litellm python-dotenv
LiteLLMは、OpenAI、Anthropic、さらに中国系のDashScopeやDeepSeekなど100種類以上のLLM APIを同じ関数呼び出しで扱えるようにするライブラリです。各社バラバラなレスポンス形式をOpenAI互換に変換してくれるため、パース処理を共通化できるのが最大のメリットです。
⚠️ 落とし穴:
LiteLLMのバージョンが古いと、最新のDeepSeek-V3やQwenの新しいエンドポイントに対応していないことがあります。必ず pip install -U litellm で最新版に更新してください。また、Windows環境でローカルモデル(Ollama)を叩く場合、Ollama側で OLLAMA_HOST=0.0.0.0 の設定をしておかないと、スクリプトから接続を拒否されることがあります。
Step 2: 基本の設定
プロジェクトのルートディレクトリに .env ファイルを作成し、APIキーを定義します。
# .env ファイル
DASHSCOPE_API_KEY=your_qwen_key_here
DEEPSEEK_API_KEY=your_deepseek_key_here
OLLAMA_API_BASE=http://localhost:11434
次に、これらの設定を読み込み、APIとローカルの接続情報を管理するクラスを準備します。
import os
from dotenv import load_dotenv
from litellm import completion
# .envから設定をロード
load_dotenv()
class LLMManager:
def __init__(self):
# APIキーが設定されていない場合のバリデーション
self.qwen_api_key = os.getenv("DASHSCOPE_API_KEY")
self.deepseek_api_key = os.getenv("DEEPSEEK_API_KEY")
# モデル名の定義(API版とローカル版)
self.models = {
"remote": "dashscope/qwen-max", # 最新のAPI専用モデル
"local": "ollama/qwen2.5:7b" # 既に公開されているローカルモデル
}
def call_llm(self, prompt, use_local=False):
model = self.models["local"] if use_local else self.models["remote"]
try:
response = completion(
model=model,
messages=[{"content": prompt, "role": "user"}],
timeout=10 # 中国系APIは稀にタイムアウトするため短めに設定
)
return response.choices[0].message.content
except Exception as e:
return f"Error: {str(e)}"
各設定項目の意味を解説します。dashscope/ や ollama/ というプレフィックスを付けることで、LiteLLMが内部で適切にルーティングを行います。timeout を10秒に設定しているのは、中国国内のサーバーが混雑している際、無限に待たされるのを防ぐためです。私の経験上、5秒を超えてレスポンスがない場合は、さっさとローカルモデルにフォールバックさせるのが、ユーザー体験を損なわないコツです。
Step 3: 動かしてみる
まずは単純に、API経由で最新モデルを呼び出してみましょう。
manager = LLMManager()
# API(リモート)で実行
print("--- Remote API Result ---")
print(manager.call_llm("中国の最新AI規制について3行で教えて"))
# ローカルで実行
print("\n--- Local Model Result ---")
print(manager.call_llm("中国の最新AI規制について3行で教えて", use_local=True))
期待される出力
--- Remote API Result ---
1. 生成AIサービス提供前に当局への届出と安全評価が義務付けられています。
2. 出力内容は「社会主義核心価値観」に沿ったものである必要があります。
3. 学習データの合法性や著作権保護についても厳格な規定が存在します。
--- Local Model Result ---
(Qwen2.5-7Bなどのローカル推論結果が表示される)
結果を見れば分かる通り、同じ関数を使いながら全く異なる環境(クラウドと自宅のGPU)から回答を得られています。レスポンス速度も計測してみてください。私の環境(RTX 4090)ではローカルが0.2秒、API経由では通信ロスを含め1.5秒程度の差が出ました。
Step 4: 実用レベルにする
ここからが本番です。中国系ラボがモデル公開を遅らせたり、APIの通信が不安定になったりした際に、**「APIを叩いてみて、ダメなら即座にローカルに切り替える」**という自動フォールバック機能を実装します。
import time
def resilient_call(manager, prompt):
start_time = time.time()
# 1. まずはAPIを試みる
print(f"Attempting {manager.models['remote']}...")
result = manager.call_llm(prompt, use_local=False)
# エラーが含まれる場合、または特定のキーワードで失敗を検知
if "Error" in result:
print(f"Remote API failed. Switching to Local ({manager.models['local']})...")
# 2. 失敗した場合はローカルモデルで再試行
result = manager.call_llm(prompt, use_local=True)
end_time = time.time()
print(f"Processing time: {end_time - start_time:.2f} seconds")
return result
# 実践的なテスト:存在しないモデル名を指定してフォールバックを発生させる
manager.models["remote"] = "dashscope/non-existent-model"
final_answer = resilient_call(manager, "量子コンピュータの基本を解説して")
print(f"Final Answer:\n{final_answer}")
この実装の肝は、Error を検知した瞬間に予備のローカルモデルへ制御を移す点です。実務では、APIキーの残高不足や、中国政府による突然のアクセス制限(実際に過去、特定のIP帯域が遮断された例があります)など、予期せぬ事態が頻発します。
私が以前、機械学習案件でQwenを導入した際も、メンテナンス中にAPIが503エラーを返したことがありました。このフォールバック処理を入れていたおかげで、システム全体がダウンすることなく、やや精度は落ちるもののローカルモデル(Qwen-72B)で処理を継続できました。
よくあるトラブルと解決法
| エラー内容 | 原因 | 解決策 |
|---|---|---|
AuthenticationError | APIキーが読み込まれていない | .env の変数名が間違っていないか確認。os.getenv で中身をprintして確認する。 |
ConnectionError (Ollama) | Ollamaが起動していない、またはポートが閉じている | ollama serve を実行。またはファイアウォールの設定を確認。 |
| 応答が極端に遅い | 中国サーバーとのネットワーク遅延 | プロキシを通すか、LiteLLMの timeout パラメータを5秒程度に絞る。 |
次のステップ
この記事で、APIとローカルをシームレスに切り替える「モデルに依存しない」基盤が完成しました。次にやるべきことは、この基盤の上に「RAG(検索拡張生成)」を組み合わせることです。
中国系のモデルは、中国特有の規制や文化に関する知識には強いですが、日本の最新情報には疎い場合があります。ローカルのベクターストア(ChromaやQdrant)に日本語のドキュメントを蓄積し、今回のスクリプトで呼び出すプロンプトにコンテキストとして注入してみてください。
また、モデルウェイトが公開された際には、即座に .env の local モデル名を更新するだけで、既存のコードを一行も変えずに「API版」から「完全ローカル版」へ移行できます。この柔軟性こそが、不透明なAI開発競争を生き抜くエンジニアの武器になります。
よくある質問
Q1: 中国系APIを日本から叩く場合、VPNは必要ですか?
DashScopeやDeepSeekは、現在のところ日本からの直接アクセスを許可しています。ただし、政治的に敏感な時期にはレイテンシが跳ね上がったり、一時的に繋がりにくくなることがあります。そのため、今回のフォールバック実装は必須と言えます。
Q2: LiteLLMを使わずに、requestsライブラリで直接叩く方が速いのでは?
単純なリクエスト速度では数ミリ秒の差が出ますが、開発工数と保守性を考えるとLiteLLMの方が圧倒的に有利です。各社で異なるストリーミング形式(Server-Sent Events)のハンドリングを自前で書く苦労は、実務では避けるべきコストです。
Q3: フォールバックした際に精度が落ちるのが心配です。
その通りです。対策として、ローカルモデル(Qwen2.5-7B等)で回答を生成する際、プロンプトの冒頭に「あなたは予備のシステムです。簡潔に回答してください」と役割を限定させることで、低パラメータモデルでも破綻の少ない出力を得られます。



