所要時間: 約45分 | 難易度: ★★★☆☆

この記事で作るもの

  • 自分の業務ドキュメントやコードを元に、ローカルLLMの「実務正解率」を算出する評価ハーネス(検証用スクリプト)
  • Qwen2.5-CoderやLlama 3.1などのモデルを同一条件で比較し、token/secと精度を自動集計する仕組み
  • 前提知識: Pythonの基本的な読み書き、ターミナルでのコマンド操作
  • 必要なもの: Dockerが動く環境、またはPython 3.10以上、NVIDIA製GPU(VRAM 12GB以上推奨)

📦 この記事に関連する商品(楽天メインで価格確認)

GeForce RTX 4090

24GBのVRAMは7Bモデルをフルスピードで動かし、30B超も視野に入る最強の選択肢です

楽天で価格を見る Amazonでも確認

※アフィリエイトリンクを含みます

先に確認するスペック・料金

ローカルLLMを実務で使うなら、VRAM(ビデオメモリ)が全てです。 最低でもRTX 3060 12GB、できればRTX 3090/4090の24GBを用意してください。 メインメモリ(RAM)で動かすのは、検証用としては「遅すぎて仕事にならない」というのが私の結論です。 Macユーザーなら、メモリ32GB以上のM2/M3 Pro/Max搭載モデルが最低ラインになります。 API費用は、ローカルで完結させるため電気代以外は0円ですが、比較対象としてGPT-4oを叩く場合は1,000円程度のプリペイド残高があると安心です。

なぜこの方法を選ぶのか

Redditの投稿でも議論されている通り、ローカルLLMのベンチマーク結果は「自分のタスク」に当てはまるとは限りません。 Qwen 3.8B Flashなどの軽量モデルは、特定のプロンプト形式(ハーネス)で劇的に性能が変わります。 公開されている評価用データセットは既にモデルが学習済み(汚染済み)である可能性が高く、実力を測るには自分の未公開データで試すしかありません。 今回、汎用的な「評価フレームワーク」を自作することで、将来新しいモデル(Llama 4やClaude 3.5の軽量版など)が出た際にも、30分で実務適性を判断できるようになります。

Step 1: 環境を整える

まずは推論サーバーとして「Ollama」をインストールします。 自前でサーバーを立てる方法もありますが、実務では「モデルの切り替えが一瞬で終わる」という運用効率が何よりも優先されるからです。

# Ollamaのインストール(Linux/WSL2の場合)
curl -fsSL https://ollama.com/install.sh | sh

# 評価対象のモデルをダウンロード
# Qwen2.5-Coder 7Bは現時点でコーディングにおいてGPT-4に近い性能を出します
ollama pull qwen2.5-coder:7b

# 比較用の軽量モデルも入れておく
ollama pull llama3.1:8b

インストール後、ollama listを実行してモデルが表示されれば準備完了です。 Ollamaはデフォルトでポート11434で待機しており、OpenAI互換のAPIを提供してくれるため、既存のライブラリがそのまま使えます。

⚠️ 落とし穴: WSL2で動かす場合、Windows側のGPUを認識させるためにNVIDIA Container Toolkitの設定が必要です。これを忘れるとCPU推論になり、レスポンスが100倍遅くなって「ローカルLLMは使い物にならない」という誤った結論に至ります。

Step 2: 評価用データセットの作成

評価用のデータはJSONL形式で作成します。 「正しい答え」が明確なコーディング課題や、社内規定に基づいた要約タスクなどが適しています。

# evaluation_data.jsonl
{"input": "Pythonでリストの重複を削除する最短のコードを書いて。", "expected": "list(set(items))"}
{"input": "以下の関数のバグを修正して: def add(a, b): return a - b", "expected": "return a + b"}

このように、入力と期待される出力を対にしたデータを最低20個は用意してください。 データの質が評価環境の信頼性を決めます。

Step 3: 評価ハーネスの実装

ここが核心です。 単に回答を得るだけでなく、推論時間、消費トークン数、そして「期待される出力が含まれているか」を自動判定するスクリプトを書きます。

import os
import time
import json
from openai import OpenAI

# OllamaをOpenAI互換APIとして利用する設定
# base_urlを指定することで、ローカルサーバーへ接続を向ける
client = OpenAI(
    base_url='http://localhost:11434/v1',
    api_key='ollama',  # ローカルなので任意の値でOK
)

def evaluate_model(model_name, data_path):
    results = []
    with open(data_path, 'r', encoding='utf-8') as f:
        for line in f:
            task = json.loads(line)

            start_time = time.time()
            # 実際の業務では温度(temperature)を0に設定して再現性を確保する
            response = client.chat.completions.create(
                model=model_name,
                messages=[{"role": "user", "content": task["input"]}],
                temperature=0
            )
            elapsed_time = time.time() - start_time

            answer = response.choices[0].message.content
            # 簡易的な評価:期待される文字列が含まれているか
            is_correct = task["expected"] in answer

            results.append({
                "model": model_name,
                "is_correct": is_correct,
                "time": elapsed_time,
                "tokens": response.usage.total_tokens
            })

    return results

# 実行例
models = ["qwen2.5-coder:7b", "llama3.1:8b"]
all_results = {}

for m in models:
    print(f"Testing {m}...")
    all_results[m] = evaluate_model(m, "evaluation_data.jsonl")

print(json.dumps(all_results, indent=2))

このコードのポイントは temperature=0 です。 クリエイティブな用途以外では、評価時に回答がブレると比較になりません。 また、APIキーを環境変数から読み込む癖をつけておかないと、将来的にOpenAI APIなどと併用する際にキーをハードコードしてGitHubに晒す事故に繋がります。

期待される出力

{
  "qwen2.5-coder:7b": [
    {
      "model": "qwen2.5-coder:7b",
      "is_correct": true,
      "time": 1.2,
      "tokens": 45
    }
  ]
}

この出力から「1問あたり何秒かかったか」「正解率は何%か」を算出できます。

Step 4: 実用レベルにする

実務では「正解か不正解か」の二択では不十分な場合が多いです。 そこで、GPT-4oを「試験官」として使い、ローカルLLMの回答を5段階評価させる「LLM-as-a-judge」という手法を導入します。

def get_judge_score(input_text, model_answer, expected_answer):
    # 試験官役のOpenAI API設定(ここは本家のAPIキーが必要)
    judge_client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])

    prompt = f"""
    以下の問題に対する回答を1-5点で採点してください。
    問題: {input_text}
    期待される正解のヒント: {expected_answer}
    モデルの回答: {model_answer}

    採点基準:
    5: 完璧。無駄がなく正確。
    1: 全くの間違い、または指示無視。

    出力は数字1点のみを返してください。
    """

    res = judge_client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": prompt}]
    )
    return int(res.choices[0].message.content)

この方法を組み合わせることで、「コードは動くが冗長(3点)」といった微妙なニュアンスを数値化できます。 私が実務で導入した際は、このスコアリングによって「Qwen2.5-Coder 7Bは、特定の社内ライブラリの使い方においてGPT-4と同等のスコアを出す」ことが証明でき、月額数十万円のAPIコストを削減できました。

よくあるトラブルと解決法

エラー内容原因解決策
ConnectionRefusedErrorOllamaが起動していないollama serveが裏で動いているか確認
回答が毎回変わるtemperatureが0になっていないAPIリクエスト時にtemperature=0を明示する
メモリ不足で落ちるVRAMに対してモデルが大きすぎる量子化モデル(Q4_K_M等)を使用するか、より小さいモデル(1.5B等)に変更する

次のステップ

この評価ハーネスが完成したら、次は「RAG(検索拡張生成)」との組み合わせをテストしてください。 ローカルLLMが賢いかどうかよりも、「与えられたコンテキスト(資料)をどれだけ正確に読み取れるか」の方が実務では重要だからです。 具体的には、Step 2のデータセットに「参考ドキュメント」という項目を追加し、それをプロンプトに注入した状態で回答精度を測ってみてください。

また、Redditの投稿者が触れていた「Qwen 3.8B Flash」のような軽量モデルは、システムプロンプトの書き方一つでスコアが20〜30%変動します。 「あなたは世界最高のPythonエンジニアです」といったロール付与の有無で、どれだけ正解率が変わるかをこのスクリプトで実験してみるのも面白いでしょう。 数字で語れるようになれば、上司やクライアントへの「なぜローカルLLMを使うのか」という説明に説得力が生まれます。

よくある質問

Q1: RTX 4060(VRAM 8GB)しか持っていませんが、試せますか?

8GBだと7Bクラスのモデルを4-bit量子化で動かすのが限界です。動くことは動きますが、複雑なタスクだとコンテキスト長を伸ばした際にメモリ不足(OOM)で落ちる可能性が高いです。まずは1.5Bや3Bのモデルから試すことをおすすめします。

Q2: 評価用データの作成が一番大変なのですが、自動化できませんか?

既存のコードベースからGPT-4oを使って「このコードを元に問題と正解のペアを作って」と指示して生成させるのが最も効率的です。ただし、そのデータにはGPT-4oの癖が含まれるため、最終的なチェックは人間が行う必要があります。

Q3: Ollama以外の推論エンジン(vLLMやllama.cpp)を使うべきですか?

スループット(並列処理能力)を極限まで求めるならvLLMですが、個人の検証や小規模な業務ツールならOllamaで十分です。今回のスクリプトはOpenAI互換APIを使っているので、バックエンドをvLLMに差し替えてもそのまま動きます。


あわせて読みたい