catch-img

LiteLLM を使ったモデル間の精度検証

はじめに

本記事では、LiteLLM を使用して複数のプロバイダー・モデル間での精度検証を行う方法について説明します。

LiteLLM を使うことで、複数のモデルに対して同一のプロンプトを送信することができ、簡単に比較・評価が可能になります。

今回は、GPT-5.2 CodexClaude Opus 4.5Gemini 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.py

LiteLLM の導入

続いて LiteLLM ライブラリをプロジェクトに追加するために以下のコマンドを実行します。

$ uv add litellm

main.py を編集して LiteLLM の動作確認を行いましょう。

本段階では LLM プロバイダーの設定が完了していないため、引数 mock_response を使って仮のレスポンスを返すようにしています。

import os
from 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エンジニアです。
ユーザーが提供するシステムの説明や要件に基づいて、高品質なPythonソースコードを生成することが主な役割です。

##
あなたの専門性

- Python 3.x
の最新のベストプラクティスに精通している
-
クリーンで保守性の高いコードを書くことができる
-
適切なエラーハンドリングとログ出力を実装できる
-
型ヒント(Type Hints)を活用した読みやすいコードを作成できる

##
コード生成時の原則

1.
**可読性**: コードは他の開発者が理解しやすいように、明確で簡潔に書く
2.
**保守性**: 将来の変更や拡張を考慮した構造にする
3.
**文書化**: 必要に応じて日本語でコメントを追加する
4.
**効率性**: パフォーマンスを考慮した実装を心がける
5.
**安全性**: エラーハンドリングやバリデーションを適切に実装する

##
出力形式

完全に動作するソースコードのみを以下の形式で提供すること

```python
#
ここにPythonコードを記述
```

ユーザーメッセージ

# 拡張版FizzBuzz問題

1
から100までの数字を順番に出力するプログラムを作成してください。ただし、以下のルールに従ってください:

- 4
で割り切れる数字の場合は、数字の代わりに「わん」と出力する
- 6
で割り切れる数字の場合は、数字の代わりに「にゃー」と出力する
- 4
でも6でも割り切れる数字の場合は、「わんにゃふる!」と出力する
-
それ以外の数字は、そのまま数字を出力する

##
出力例(最初の15個):
```
1
2
3
わん
5
にゃー
7
わん
9
10
11
わんにゃふる!
13
14
15
```

精度検証コードの作成

まず、前章で作ったメッセージは可読性に配慮して、main.py でなく別ファイルの prompt.py に分離しておきます。

system_message = """あなたは経験豊富で優秀なPythonエンジニアです。
(# 中略)
"""

user_message = """# 拡張版FizzBuzz問題
(# 中略)
"""

次に、main.py を以下のように編集して、各モデルに対して同一のメッセージを送信し、レスポンスを収集できるようにします。

import os
import sys
from 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 results


def main() -> None:
    """1から100までの拡張FizzBuzzを出力する。"""
    try:
        for line in generate_sequence(1, 100):
            print(line)
    except Exception as exc:
        # 想定外のエラーが発生した場合のハンドリング
        raise RuntimeError("シーケンスの生成中にエラーが発生しました") from exc


if __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):
        # 46の最小公倍数は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 = 1
    END_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 デベロッパー ガイド

評価

 ・テストと評価 - 成功基準を定義する

ページトップへ戻る