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

この記事で作るもの

LLMの応答品質をリアルタイムでスコアリングし、基準を下回った場合に自動でプロンプトを修正して再試行、あるいは別モデルへフォールバック(切り替え)を行うPythonスクリプトを構築します。

  • 応答の「論理的整合性」と「命令遵守」を自動評価するロジック
  • GPT-4oからClaude 3.5 Sonnet、あるいはローカルLLMへ自動で切り替えるパイプライン
  • プロンプトの「劣化」を検知するためのログ保存機能

前提知識として、Pythonの基本的な文法と、環境変数の設定方法を理解している必要があります。 必要なものは、OpenAIとAnthropicのAPIキー、そしてPython 3.10以上の実行環境です。

なぜこの方法を選ぶのか

Redditのr/LocalLLaMAなどで議論されている「モデルの知能低下(Intelligence Drop)」は、API背後のモデル更新や量子化、あるいは安全性のための過度なガードレール設置が原因と推測されます。 これを回避するために「一つのモデルを信じる」運用は、現在のAI開発において最もリスクが高い選択です。

従来のように「プロンプトを工夫して終わり」にするのではなく、コード側で「期待する出力が得られたか」を判定するバリデータ(検印機)を実装するのが、実務における正解です。 特定のモデルが「不機嫌(Grumpy)」になった際に、即座に別の推論エンジンへルーティングする動的なパイプラインを構築することで、システム全体の可用性を担保します。

Step 1: 環境を整える

まずは必要なライブラリをインストールします。 今回は構造化データの扱いに長けたinstructorと、複数のAPIを統合管理するライブラリを使用します。

pip install openai anthropic python-dotenv pydantic instructor

instructorはPydanticを使ってLLMの出力をバリデーションするための必須ライブラリです。 「モデルが指示を無視する」問題に対し、型定義によって出力を強制的に矯正する役割を果たします。

⚠️ 落とし穴: APIライブラリのバージョンが古いと、最新モデル(Claude 3.5やGPT-4o)のトークン計算やストリーミング処理でエラーが出ます。必ずpip install -Uで最新版に更新してください。

Step 2: 基本の設定

APIキーをソースコードに直書きするのは、SIer時代なら即刻クビ案件です。 .envファイルを作成し、そこにキーを記述してpython-dotenvで読み込みます。

import os
from dotenv import load_dotenv
from openai import OpenAI
from anthropic import Anthropic
import instructor
from pydantic import BaseModel, Field, field_validator

# 環境変数の読み込み
load_dotenv()

# クライアントの初期化
# instructor.patch()を使うことで、OpenAIのレスポンスをPydanticモデルで受け取れるようにします
client_openai = instructor.from_openai(OpenAI(api_key=os.environ["OPENAI_API_KEY"]))
client_anthropic = instructor.from_anthropic(Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"]))

ここではinstructorによるパッチ適用が肝です。 これにより、LLMの応答が「文字列」ではなく「検証済みのオブジェクト」として返ってくるため、知能低下による「フォーマット崩れ」をコードレベルで即座に検知できます。

Step 3: 品質評価ロジックの実装

モデルが「指示を無視しているか」を判定するための、評価用データ構造を定義します。

class LLMResponse(BaseModel):
    answer: str = Field(..., description="ユーザーへの回答内容")
    logic_score: int = Field(..., description="回答の論理的整合性 (1-10)")
    instruction_followed: bool = Field(..., description="指示を全て遵守したか")

    @field_validator("logic_score")
    @classmethod
    def check_score(cls, v):
        if v < 7:
            # スコアが低い場合は意図的にエラーを投げ、リトライを促す設定にする
            raise ValueError("論理スコアが低すぎます。再考してください。")
        return v

期待される出力

この定義を使うと、モデルが適当な回答を返した場合、Python側でValidationErrorが発生します。 「出力が浅い」「指示を無視している」という曖昧な問題を、プログラムが処理可能な「例外」に変換できるわけです。

Step 4: 実用レベルの自動切替パイプライン

知能低下を感じた際に、自動でモデルを切り替えてリトライする関数を作成します。 私は過去、GPT-4が数式計算を間違え始めた際、この手法でClaude 3 Opusにバイパスさせることで、本番環境のダウンタイムをゼロに抑えました。

def smart_generate(prompt: str):
    # まずはメインモデル(GPT-4o)で試行
    try:
        print("Trying GPT-4o...")
        return client_openai.chat.completions.create(
            model="gpt-4o",
            response_model=LLMResponse,
            messages=[{"role": "user", "content": prompt}],
            max_retries=2 # instructorが自動でリトライしてくれる
        )
    except Exception as e:
        print(f"GPT-4o failed or quality too low: {e}")
        # フォールバックとしてClaude 3.5 Sonnetを使用
        print("Falling back to Claude 3.5 Sonnet...")
        return client_anthropic.messages.create(
            model="claude-3-5-sonnet-20240620",
            response_model=LLMResponse,
            max_tokens=1024,
            messages=[{"role": "user", "content": prompt}]
        )

# 実行例
user_input = "2026年時点での分散コンピューティングの課題を、技術的・経済的視点で3000文字程度で分析して。"
final_output = smart_generate(user_input)
print(f"Final Answer: {final_output.answer[:100]}...")
print(f"Score: {final_output.logic_score}")

このコードのポイントは、response_modelに先ほど定義したLLMResponseを渡している点です。 LLMは「自分の回答の質」を客観的に評価するのが苦手ですが、instructorによる強制的な構造化とPydanticのバリデーションを組み合わせることで、低品質な出力を「失敗」としてトラップできます。

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

エラー内容原因解決策
ValidationError が頻発するモデルの性能に対して指示が複雑すぎるSystem Promptを分割し、1回1タスクに絞る
RateLimitError短時間の過剰なリトライ指数バックオフ(待機時間を増やす)処理をtenacity等で実装する
JSONDecodeErrorLLMがJSON以外の余計な文章を出力したinstructorの利用を徹底するか、Promptに「出力はJSONのみ」と明記

次のステップ

今回のスクリプトで、知能低下に対する「防御策」は整いました。 次のステップとしては、私の自宅サーバーのようにRTX 4090を積んだ環境で、Llama 3等のローカルLLMをバリデータとして組み込むことをおすすめします。

外部APIの知能低下は、私たちのコントロール外で発生します。 しかし、ローカルLLMなら「昨日の重み」をそのまま保持できるため、APIの挙動がおかしくなった際の「不変の基準点」として機能します。 Ollamaを使ってローカルにエンドポイントを立て、今回作ったsmart_generateの第3の選択肢(最終防衛ライン)として組み込んでみてください。 AIに「仕事」を任せるなら、常に最悪のケースを想定した冗長化設計が不可欠です。

よくある質問

Q1: モデルの切り替えでコストが跳ね上がりませんか?

コストは上がりますが、品質が低い回答を垂れ流して手動で修正する「人件費」の方が遥かに高価です。実務では、まず軽量なモデル(GPT-4o-mini等)で試し、バリデーションに落ちた場合のみ高性能モデルへ昇格させる「カスケード戦略」を推奨します。

Q2: 4090を2枚挿ししていなくてもローカルLLMは動きますか?

8Bクラスのモデルであれば、VRAM 8GB〜12GB程度のミドルエンドGPUでも十分動きます。ただし、知能低下を検知するための「高度な論理推論」をローカルでやらせるなら、最低でも70Bクラスのモデルが必要になり、その場合はVRAM 48GB(4090 2枚分)が現実的なラインになります。

Q3: バリデーション自体が間違っている可能性は?

あります。そのため、Pydanticのlogic_scoreは絶対的な指標ではなく「異常検知」のトリガーとして使います。ログを保存しておき、定期的に人間が「モデルが悪いのか、バリデータが厳しすぎるのか」を評価するフィードバックループを回すのがプロの仕事です。

📦 この記事に関連する商品

GeForce RTX 4090

ローカルLLMでの検証や高品質なバリデーションには24GB以上のVRAMが必須です

Amazonで見る 楽天で見る

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


あわせて読みたい