PythonプロジェクトにおけるマルチLLM統合アプローチの比較
単一のプロジェクト内でOpenAI、Claude、Geminiを同時に呼び出した経験がある方なら、各プロバイダーごとにリクエストペイロードの形式が異なる煩わしさに直面したことがあるでしょう。OpenAIはmessagesを辞書のリスト形式で受け取ります。Anthropicはsystemパラメータを個別に分離しています。さらにGoogle Geminiでは、データをcontentsとpartsでラップする必要があります。
このようなマルチモデル構成の課題に対し、開発チームは通常、以下の3つのアプローチのいずれかを選択します:
- アプローチ1:公式SDK(openai、anthropic、google-genai)を直接利用する。プロバイダー間の入力と出力を相互にマッピングするラッパーを自前で実装します。
- アプローチ2:LangChainやLlamaIndexなどの高レベルフレームワークを採用する。既存の抽象化レイヤーを活用し、クラスローダーを差し替えることでプロバイダーを切り替えます。
- アプローチ3:LiteLLM(Pythonライブラリ / プロキシ)を導入する。OpenAI Chat Completionの標準フォーマットを100%維持したまま、モデル名(例:
claude-3-5-sonnet-20240620やgemini/gemini-1.5-flash)を変更するだけで対応します。
各ソリューションのメリット・デメリットを徹底比較
1. 公式SDK向けに独自のラッパーを作成する
この手法の最大の利点は、送受信するすべてのバイトデータをチーム自身で完全に制御でき、サードパーティ製ライブラリへの依存を排除できる点です。その反面、メンテナンスコストは極めて高くなります。
プロバイダーが新しいモデルをリリースしたり、トークン使用量のレスポンススキーマを変更したりするたびに、自作ラッパーのコードが破損するリスクがあります。また、3つの異なるSDK間でストリーミングや非同期(async)処理のメカニズムを標準化する作業は、潜在的なバグを生み出しやすい要因となります。
2. LangChainまたはLlamaIndexを採用する
これら2つのフレームワークは、複雑なAIエージェントの構築、多段階のRAGパイプライン、ワークフローグラフの実装には非常に適しています。しかし、単にAPIを呼び出すだけであれば、LangChainはあまりにも過剰で重量級になりがちです。
例えば、システムに負荷がかかりレートリミット(429エラー)が発生した場合を想像してみてください。LangChainの幾重にも重なる抽象化ラッパーを介してコールスタックをトレースする作業は、デバッグに膨大な時間を費やす原因となります。
3. LiteLLMライブラリを活用する
LiteLLMは、「他社プロバイダー(Anthropic、Gemini、Mistral、Cohere、Bedrock、Ollamaなど)の構文をOpenAI標準のcompletion()形式に変換する」という単一のコアな課題を解決します。レスポンスは常に標準化されたオブジェクトとして返され、使い慣れたchoices[0].message.contentやusage.total_tokensでデータを取得できます。
注意点としては、各ベンダーのプレフィックス(例:gemini/やbedrock/)を指定することくらいです。なお、このライブラリは毎週のように新機能がリリースされているため、依存関係の競合を防ぐためにrequirements.txtで特定のバージョンを固定(ピン留め)しておくことを推奨します。
どのような場面でLiteLLMへ移行すべきか?
バックエンドがOpenAI SDKで安定稼働している状況を想定してみましょう。突然、上長から「OpenAIで障害や遅延が発生した場合は自動的にClaudeへフォールバックできるようにしてほしい」、あるいは「APIコストを70%削減するために、分類タスクをGemini 1.5 Flashへ移行してほしい」と指示されたとします。これこそが、まさにLiteLLMが真価を発揮する瞬間です。
プロンプトパーサーやJSON抽出ロジックを一から書き直す必要はなく、import文を1行変更するだけで、データ処理パイプライン全体をそのまま維持できます。
LiteLLMの実装ステップ:環境構築から実践まで
ステップ1:ライブラリのインストールと環境設定
pipコマンドを使用して、LiteLLMのコアパッケージとpython-dotenvをインストールします:
pip install litellm python-dotenv
各APIキーを安全に管理するため、プロジェクトのルートディレクトリに.envファイルを作成します:
OPENAI_API_KEY="sk-..."
ANTHROPIC_API_KEY="sk-ant-..."
GEMINI_API_KEY="AIza..."
ステップ2:単一関数によるマルチモデル呼び出し
以下のコードは、レスポンス解析ロジックを一切変更することなく、GPT-4o、Claude 3.5 Sonnet、Gemini 1.5 Flashを順次呼び出す実装例です:
import os
from dotenv import load_dotenv
from litellm import completion
load_dotenv()
messages = [
{"role": "system", "content": "あなたは簡潔に回答するIT技術アシスタントです。"},
{"role": "user", "content": "Dockerコンテナとは何か、2文で簡潔に説明してください。"}
]
# 1. GPT-4oを呼び出し
res_openai = completion(
model="gpt-4o",
messages=messages
)
print("OpenAI:", res_openai.choices[0].message.content)
# 2. Claude 3.5 Sonnetを呼び出し(LiteLLMが自動的にAnthropicフォーマットへ変換)
res_claude = completion(
model="claude-3-5-sonnet-20240620",
messages=messages
)
print("Claude:", res_claude.choices[0].message.content)
# 3. Google Geminiを呼び出し(gemini/プレフィックスを付与)
res_gemini = completion(
model="gemini/gemini-1.5-flash",
messages=messages
)
print("Gemini:", res_gemini.choices[0].message.content)
ステップ3:障害発生時の自動フォールバック設定
本番環境で非常に役立つ機能がfallbacksパラメータです。プライマリモデルがレートリミット(429)に達した場合や、ベンダー側のサーバー障害(500/503)が発生した場合、LiteLLMは即座にリクエストを予備モデルへ自動ルーティングします:
from litellm import completion
try:
response = completion(
model="gpt-4o",
messages=[{"role": "user", "content": "以下のテキストからJSONデータを抽出してください..."}],
fallbacks=["claude-3-5-sonnet-20240620", "gemini/gemini-1.5-flash"],
timeout=10 # 10秒以内に応答がない場合、次のフォールバック先へ自動遷移
)
print(response.choices[0].message.content)
except Exception as e:
print(f"フォールバックリスト内のすべてのモデル呼び出しに失敗しました: {e}")
ステップ4:リアルタイムデータストリーミング
チャットUIを構築する際、Time To First Token(TTFT)を最適化するためにストリーミング処理は不可欠です。LiteLLMを使用すると、OpenAIクライアントとまったく同じ構文でストリーミングチャンクを受信できます:
response = completion(
model="claude-3-5-sonnet-20240620",
messages=[{"role": "user", "content": "MySQLデータベースをバックアップするBashスクリプトを作成してください。"}] ,
stream=True
)
for chunk in response:
content = chunk.choices[0].delta.content or ""
print(content, end="", flush=True)
LLMから構造化データをパースする際のTips
多くのモデルは、出力の冒頭に挨拶文を付けたり、JSONブロックを“`jsonのようなマークダウン記法で囲んだりする傾向があります。そのため、開発者は正規表現(Regex)を用いて目的のJSONブロックを抽出することがよくあります。
コードを何度も再実行することなく正規表現を素早く検証したい場合は、ブラウザ上でパターンをテストしてマッチ結果をハイライト表示できる便利な正規表現テスター(toolcraft.app/ja/tools/developer/regex-tester)などを活用するのが効率的です。
パターンが正しく動作することを確認した上でPythonのパース関数に組み込めば、構文エラーを防ぎつつ安全にデータを取得できます。
リアルタイムでのトークンコスト追跡(Cost Tracking)
月末まで待ってOpenAI、Anthropic Console、Google Cloud Consoleの各ダッシュボードにログインして請求額を確認する代わりに、LiteLLMならリクエスト単位でリアルタイムにコストを算出できます:
from litellm import completion, completion_cost
resp = completion(
model="gpt-4o",
messages=[{"role": "user", "content": "ITに関する詩を書いてください。"}]
)
cost = completion_cost(completion_response=resp)
print(f"入力トークン数: {resp.usage.prompt_tokens}")
print(f"出力トークン数: {resp.usage.completion_tokens}")
print(f"このリクエストのコスト: ${cost:.6f} USD")
このコストデータはデータベースやシステムログに直接記録できるため、ユーザーごとや機能ごとの利用予算をきめ細かく管理・把握することが可能になります。

