
LiteLLM を使ったモデル間の精度検証
はじめに
本記事では、LiteLLM を使用して複数のプロバイダー・モデル間での精度検証を行う方法について説明します。
LiteLLM を使うことで、複数のモデルに対して同一のプロンプトを送信することができ、簡単に比較・評価が可能になります。
今回は、GPT-5.2 Codex、Claude Opus 4.5、Gemini 3 Pro の 3 つのモデルに対して、独自の FizzBuzz 問題を解くためのソースコード生成を依頼し、その出力結果を比較・評価します。なお、精度検証の方法を示すことが本記事の主題であるため、どのモデルが一番優れていたかについては本記事では言及いたしません。
LiteLLM とは
LiteLLM は、100 以上の各種 LLM プロバイダーに対して、OpenAI の入出力のフォーマットを使ってリクエストできるツールで、複数のモデルに対して同一のプロンプトを容易に送信することができます。
LiteLLM は、プロキシサーバーと Python クライアントを提供しており、本記事では後者の Python クライアントである LiteLLM python SDK を使って実装を進めていきます。
検証環境
本記事の検証は以下の環境で実施しています。
OS
macOS Tahoe 26.1
使用するライブラリ・ソフトウェア
Python 3.14
LiteLLM 1.81.1
uv 0.9.26
使用するモデル
GPT-5.2 Codex
Claude Opus 4.5
Gemini 3 Pro
プロジェクトセットアップ
今回はuvを使ってプロジェクトをセットアップしていきます。uv は Rust で書かれた高速な Python プロジェクトマネージャーです。uv 自体のインストール方法や詳細な使い方は本記事では解説しませんので、公式ドキュメントをご参照ください。
まずは任意のディレクトリで以下のコマンドを実行してプロジェクトを初期化します。
$ uv initサンプルの main.py を作成して実行してみましょう。
def main():print("Hello, litellm!")
if __name__ == "__main__":main()
$ uv run python main.pyLiteLLM の導入
続いて LiteLLM ライブラリをプロジェクトに追加するために以下のコマンドを実行します。
$ uv add litellmmain.py を編集して LiteLLM の動作確認を行いましょう。
本段階では LLM プロバイダーの設定が完了していないため、引数 mock_response を使って仮のレスポンスを返すようにしています。
import osfrom litellm import completion
def main():try:response = completion(model="gpt-5.2-codex",messages=[{"role": "user", "content": "Hello, how are you?"}],mock_response="Hi, I'm fine, thank you!",)except Exception as e:print(e.message)
print(response.choices[0].message["content"])
if __name__ == "__main__":main()
API キーの設定
続いて、使用する LLM プロバイダーの API キーを環境変数に設定します。
それぞれの API キーの取得方法については各プロバイダーの公式ドキュメントをご参照ください。
LiteLLM ではリクエストの引数に API キーを直接指定することも可能ですが、環境変数に設定しておくことでコードの汎用性が向上します。
$ export OPENAI_API_KEY="sk-proj-********************************"
$ export ANTHROPIC_API_KEY="sk-ant-********************************"
$ export GEMINI_API_KEY="AI********************************"以降、ソースコードを実行して API リクエストが発生するたびに料金が発生するようになりますのでご注意ください。
メッセージの用意
今回の検証では、独自の FizzBuzz 問題を解く Python プログラムを各モデルに生成してもらいます。
Open AI のメッセージフォーマットに従って、システムメッセージとユーザーメッセージをそれぞれ用意します。システムメッセージとは、モデルに対して役割や振る舞いを指示するためのメッセージで、ユーザーメッセージとは、実際にモデルに対して質問やタスクを指示するためのメッセージです。
各メッセージは、Claude と対話しながら雛形を作り微修正を加えながら作成しました。
システムメッセージ
あなたは経験豊富で優秀なPythonエンジニアです。 |
ユーザーメッセージ
# 拡張版FizzBuzz問題 |
精度検証コードの作成
まず、前章で作ったメッセージは可読性に配慮して、main.py でなく別ファイルの prompt.py に分離しておきます。
system_message = """あなたは経験豊富で優秀なPythonエンジニアです。(# 中略)"""
user_message = """# 拡張版FizzBuzz問題(# 中略)"""
次に、main.py を以下のように編集して、各モデルに対して同一のメッセージを送信し、レスポンスを収集できるようにします。
import osimport sysfrom litellm import completion, completion_cost
from prompt import system_message, user_message
def main():
# 検証するモデルmodels = ["openai/gpt-5.2-codex","anthropic/claude-opus-4-5-20251101","gemini/gemini-3-pro-preview",]
# 各モデルに対してプロンプトを送信してレスポンスを出力for model in models:try:messages = [{"role": "system", "content": system_message},{"role": "user", "content": user_message}]response = completion(model=model,messages=messages,reasoning_effort="low",cache={"no-cache": True},)content = response.choices[0].message["content"]cost = completion_cost(completion_response=response)print(f"Model: {response.model}")print(f"Response:\n {content}\n")print(f"Latency: {response._response_ms} ms\n")print(f"Cost: {cost}")
except Exception as e:print(e.message)if __name__ == "__main__":main()
上記のコードでは精度検証のためレイテンシとコストを計測しています。コストを計測には`completion_cost()`を使用しました。また、前後の実行結果に影響を与えないようにキャッシュを無効にしています。
それでは実際に実行してみましょう。
$ uv run python main.py生成結果
各モデルの生成結果は以下のようになりました。
Gemini 3 Pro については、ソースコードだけなく説明文も生成結果の一部になりますのでご留意ください。
GPT-5.2 Codex の生成結果
from typing import List
def generate_sequence(start: int = 1, end: int = 100) -> List[str]:"""指定範囲の拡張FizzBuzzシーケンスを生成する。"""results: List[str] = []for i in range(start, end + 1):if i % 4 == 0 and i % 6 == 0:results.append("わんにゃふる!")elif i % 4 == 0:results.append("わん")elif i % 6 == 0:results.append("にゃー")else:results.append(str(i))return resultsdef main() -> None:"""1から100までの拡張FizzBuzzを出力する。"""try:for line in generate_sequence(1, 100):print(line)except Exception as exc:# 想定外のエラーが発生した場合のハンドリングraise RuntimeError("シーケンスの生成中にエラーが発生しました") from excif __name__ == "__main__":main()
Claude Opus 4.5 の生成結果
for i in range(1, 101):if i % 4 == 0 and i % 6 == 0:print("わんにゃふる!")elif i % 4 == 0:print("わん")elif i % 6 == 0:print("にゃー")else:print(i)
Gemini 3 Pro の生成結果
要件に基づき、拡張版FizzBuzz問題を実装したPythonコードを生成します。 この実装では、保守性と可読性を高めるために、条件判定ロジックを関数として切り出し、型ヒントを使用しています。
from typing import Iterator
def generate_animal_sounds(start: int, end: int) -> Iterator[str]:
"""指定された範囲の数字に対して、特定のルールに基づいた文字列を生成するジェネレータ関数。Args:start (int): 開始する数字end (int): 終了する数字(この数字を含む)Yields:str: ルールに基づいて変換された文字列、または数字の文字列表現"""for i in range(start, end + 1):# 4と6の最小公倍数は12なので、i % 12 == 0 と同義だが、# 仕様の意図を明確にするために論理積で記述if i % 4 == 0 and i % 6 == 0:yield "わんにゃふる!"elif i % 4 == 0:yield "わん"elif i % 6 == 0:yield "にゃー"else:yield str(i)
def main() -> None:"""メイン実行関数"""START_NUM = 1END_NUM = 100
try:# ジェネレータから値を順次取得して出力for sound in generate_animal_sounds(START_NUM, END_NUM):print(sound)
except Exception as e:print(f"予期せぬエラーが発生しました: {e}")if __name__ == "__main__":main()
評価
それでは、各モデルの生成結果を評価していきます。
モデルの評価方法は多岐にわたりますが、今回は Claude の開発者ガイドの考慮すべき一般的な成功基準を参考に、今回の検証内容に適した評価基準を選定して定義しました。
評価基準 | 本検証における定義 |
タスク忠実性 | 出力結果がユーザーの要求通りか |
トーンとスタイル | 出力スタイルがユーザーの要求通りか |
レイテンシ(ms) | リクエストの応答時間。3回試行した平均を計測 |
価格(USD) | リクエストにかかる料金。3回試行した平均を計測 |
タスクの忠実性
各モデルが生成したコードを実際に実行し、要求通りの出力が得られるかを確認しました。
結果、全てのモデルで期待する出力が得られモデルの優劣はつきませんでした。
トーンとスタイル
システムメッセージの指示の観点に沿って評価しました。
モデル/観点 | 可読性 | 保守性 | 文書化 | 効率性 | 安全性 | 出力形式 |
GPT-5.2 Codex | ○ | ○ | ○ | ○ | ○ | ○ |
Claude Opus 4.5 | ○ | △ | △ | ○ | ○ | ○ |
Gemini 3 Pro | ○ | ◎ | ○ | ○ | ○ | △ |
GPT-5.2 Codex は実装も理解しやすくコメントも適度にあり、とてもバランスが良く感じました。
Claude Opus 4.5 は最もシンプルで理解しやすかったですが、コメントが一切なかったりマジックナンバー(101)が使われていたりする点が若干気になります。
Gemini 3 Pro は、GPT-5.2 Codexの実装を重厚にした印象で、コメントが構造的になっています。
ただし、出力形式が要件通りではなく説明文が含まれてしまっている点がマイナス評価です。
レイテンシ(ms)
モデル/試行 | 1 回目 | 2 回目 | 3 回目 | 平均 |
GPT-5.2 Codex | 4988.746 | 4326.964 | 5110.425 | 4808.7117 |
Claude Opus 4.5 | 3163.34 | 3785.804 | 3315.062 | 3421.402 |
Gemini 3 Pro | 9733.223 | 11690.332 | 10159.823 | 10527.792 |
レイテンシは、 Claude Opus 4.5 < GPT-5.2 Codex << Gemini 3 Pro という結果になりました。
価格(USD)
モデル/試行 | 1 回目 | 2 回目 | 3 回目 | 平均 |
GPT-5.2 Codex | 0.004508 | 0.003402 | 0.002996 | 0.003635 |
Claude Opus 4.5 | 0.00719 | 0.00781 | 0.0073 | 0.007433 |
Gemini 3 Pro | 0.00703 | 0.00968 | 0.008 | 0.00824 |
価格は、GPT-5.2 Codex << Claude Opus 4.5 < Gemini 3 Pro という結果になりました。
まとめ
LiteLLM を使うことで、異なるプロバイダー・モデル間での精度検証を容易に行うことができました。
また、モデル間の評価方法について具体的な実践例を示すことができました。
本記事の内容を参考に、比較したいモデルや生成 AI で解決したタスクなど自身のニーズに合わせて実践していただければ幸いです。
参考
ツール
・LiteLLM
・Mock Completion Responses
・Completion Token Usage & Cost
・uv
モデル
・GPT-5.2 Codex
・Introducing Claude Opus 4.5
・Gemini 3 デベロッパー ガイド


