2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

OpenAI→Claude→Geminiを自由に切り替え⚙️any-llmについて

Posted at

はじめに

LLM(Large Language Model)を使ったアプリケーション開発で、こんな悩みを抱えていませんか?

  • OpenAIのAPIを使っているが、障害時の代替手段がない
  • Anthropic Claudeも試したいが、コード全体を書き換えるのが面倒
  • 複数のLLMプロバイダーのコスト管理が煩雑
  • チーム開発でAPIキーの管理が難しい

any-llmは、これらの課題を一気に解決するMozilla.aiが開発したPythonライブラリです。プロバイダーを切り替える際もモデル名の文字列を変更するだけで対応できる、シンプルで強力なツールです。

LLMプロバイダーのロックイン問題を解決するany-llmの基礎から実践的な活用法までまとめました。

この記事は、2025年11月にリリースされたany-llm v1.0の情報に基づいています。

any-llmとは?

any-llmは、単一のインターフェースでOpenAI、Anthropic、Google、Mistral、Ollamaなど、複数のLLMプロバイダーと通信できるPythonライブラリです。

主な特徴

  1. 統一されたAPI: プロバイダーが変わってもコードはほぼそのまま
  2. 公式SDK活用: 各プロバイダーの公式SDKを内部で使用し、最大限の互換性を確保
  3. プロキシ不要: 直接接続でシンプルな構成
  4. 開発者フレンドリー: 型ヒント完備、明確なエラーメッセージ

LangChainとの違い

項目 any-llm LangChain
目的 プロバイダー抽象化に特化 LLMアプリケーション全般のフレームワーク
学習コスト 低い(既存コードをほぼ変更不要) 高い(独自の概念が多い)
依存関係 軽量 多数のパッケージが必要
適用場面 プロバイダー切り替え、コスト最適化 複雑なRAG、エージェント構築

any-llmは**「シンプルに複数のLLMを使いたい」**というニーズに最適化されています。

インストールと基本的な使い方

インストール

# 特定のプロバイダーのみ
pip install any-llm-sdk[anthropic]

# 複数のプロバイダー
pip install any-llm-sdk[anthropic,openai,mistral]

# すべてのプロバイダー
pip install any-llm-sdk[all]

必要なプロバイダーのみインストールすることで、依存関係を最小限に抑えられます。

最初のコード

プロバイダーを切り替える様子を見てみましょう。

from any_llm import completion

# OpenAI GPT-4o-miniを使用
response = completion(
    model="openai:gpt-4o-mini",
    messages=[{"role": "user", "content": "Pythonの特徴を3つ教えて"}]
)
print(response.choices[0].message.content)

# Anthropic Claude Haiku 4.5に切り替え(モデル名を変えるだけ!)
response = completion(
    model="anthropic:claude-haiku-4-5-20251001",
    messages=[{"role": "user", "content": "Pythonの特徴を3つ教えて"}]
)
print(response.choices[0].message.content)

たったこれだけで異なるLLMプロバイダーを使い分けられます!

環境変数の設定

APIキーは環境変数で管理します。

# OpenAI
export OPENAI_API_KEY="sk-..."

# Anthropic
export ANTHROPIC_API_KEY="sk-ant-..."

# Google
export GOOGLE_API_KEY="..."

または.envファイルで管理:

from dotenv import load_dotenv
load_dotenv()

実践: プロバイダー切り替えとフォールバック

実際のアプリケーションでは、メインプロバイダーが使えない時の代替手段が必要です。

フォールバック実装

from any_llm import completion
import os

def smart_completion(user_message: str, use_fallback: bool = True):
    """
    プライマリプロバイダー失敗時に自動的にフォールバック
    """
    # プライマリ: Anthropic Claude
    primary_model = "anthropic:claude-sonnet-4-5-20250929"
    # フォールバック: OpenAI GPT-4o-mini
    fallback_model = "openai:gpt-4o-mini"
    
    messages = [{"role": "user", "content": user_message}]
    
    try:
        response = completion(model=primary_model, messages=messages)
        print(f"✓ 使用モデル: {primary_model}")
        return response.choices[0].message.content
    
    except Exception as e:
        if not use_fallback:
            raise
        
        print(f"⚠ プライマリ失敗: {e}")
        print(f"→ フォールバックへ切り替え: {fallback_model}")
        
        response = completion(model=fallback_model, messages=messages)
        return response.choices[0].message.content

# 使用例
result = smart_completion("機械学習とディープラーニングの違いは?")
print(result)

コスト最適化: タスク別モデル選択

def cost_optimized_completion(user_message: str, task_complexity: str = "simple"):
    """
    タスクの複雑さに応じて最適なモデルを選択
    """
    # タスク複雑度別のモデルマッピング
    model_mapping = {
        "simple": "openai:gpt-4o-mini",           # 低コスト・高速
        "medium": "anthropic:claude-haiku-4-5-20251001",  # バランス
        "complex": "anthropic:claude-sonnet-4-5-20250929" # 高性能
    }
    
    model = model_mapping.get(task_complexity, "openai:gpt-4o-mini")
    
    response = completion(
        model=model,
        messages=[{"role": "user", "content": user_message}]
    )
    
    print(f"選択モデル: {model} (複雑度: {task_complexity})")
    return response.choices[0].message.content

# シンプルなタスク → 低コストモデル
simple_result = cost_optimized_completion(
    "こんにちは、元気ですか?",
    task_complexity="simple"
)

# 複雑なタスク → 高性能モデル
complex_result = cost_optimized_completion(
    "量子コンピューティングがブロックチェーンのセキュリティに与える影響について、技術的な観点から詳しく説明してください。",
    task_complexity="complex"
)

FastAPIとの統合例

実際のWebアプリケーションでの使用例を見てみましょう。

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from any_llm import completion
import logging

app = FastAPI()
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class ChatRequest(BaseModel):
    message: str
    model: str = "openai:gpt-4o-mini"
    max_tokens: int = 500

class ChatResponse(BaseModel):
    response: str
    model_used: str
    fallback_used: bool = False

@app.post("/chat", response_model=ChatResponse)
async def chat_endpoint(request: ChatRequest):
    """
    LLMチャットエンドポイント
    プライマリモデル失敗時は自動的にフォールバック
    """
    fallback_model = "anthropic:claude-haiku-4-5-20251001"
    fallback_used = False
    
    try:
        response = completion(
            model=request.model,
            messages=[{"role": "user", "content": request.message}],
            max_tokens=request.max_tokens
        )
        model_used = request.model
        
    except Exception as e:
        logger.warning(f"Primary model failed: {e}")
        logger.info(f"Falling back to: {fallback_model}")
        
        try:
            response = completion(
                model=fallback_model,
                messages=[{"role": "user", "content": request.message}],
                max_tokens=request.max_tokens
            )
            model_used = fallback_model
            fallback_used = True
            
        except Exception as fallback_error:
            logger.error(f"Fallback also failed: {fallback_error}")
            raise HTTPException(
                status_code=503,
                detail="All LLM providers are currently unavailable"
            )
    
    return ChatResponse(
        response=response.choices[0].message.content,
        model_used=model_used,
        fallback_used=fallback_used
    )

# 使用例
# curl -X POST "http://localhost:8000/chat" \
#   -H "Content-Type: application/json" \
#   -d '{"message": "Hello, world!"}'

ストリーミングレスポンス

リアルタイムでLLMの応答を受け取る方法です。

from any_llm import completion

def stream_chat(user_message: str):
    """
    ストリーミングでLLMの応答を逐次表示
    """
    response = completion(
        model="openai:gpt-4o-mini",
        messages=[{"role": "user", "content": user_message}],
        stream=True
    )
    
    print("AI: ", end="", flush=True)
    
    for chunk in response:
        if chunk.choices[0].delta.content:
            print(chunk.choices[0].delta.content, end="", flush=True)
    
    print()  # 改行

# 使用例
stream_chat("Pythonの非同期処理について簡潔に説明してください")

any-llm Gateway: チーム開発を加速する

v1.2.0で追加されたGateway機能は、組織でのLLM利用を一元管理できる強力な機能です。

Gatewayが解決する課題

従来の問題:

  • 各開発者が個別にAPIキーを管理 → セキュリティリスク
  • 誰がいくら使ったか不明 → コスト超過
  • プロバイダーごとにバラバラの管理 → 運用負担

Gatewayによる解決:

  • ✅ APIキーを一元管理(暗号化保存)
  • ✅ ユーザー/チーム別の予算設定
  • ✅ 使用状況のリアルタイム追跡
  • ✅ 仮想APIキーでアクセス制御

Gateway基本セットアップ

# Dockerで起動
docker run -p 8080:8080 \
  -e OPENAI_API_KEY=sk-... \
  -e ANTHROPIC_API_KEY=sk-ant-... \
  mozilla/any-llm-gateway

Gateway経由でのLLM呼び出し

from any_llm import completion

# Gateway URLを指定
response = completion(
    model="openai:gpt-4o-mini",
    messages=[{"role": "user", "content": "Hello!"}],
    api_base="http://localhost:8080",  # Gateway URL
    api_key="your-virtual-key"  # 仮想APIキー
)

チーム別予算管理の例

# gateway-config.yaml
users:
  - id: "team-frontend"
    virtual_key: "vk-frontend-xxx"
    budget:
      monthly_limit: 50.00  # 月額50ドルまで
      alert_threshold: 40.00  # 40ドルで警告
    allowed_models:
      - "openai:gpt-4o-mini"
      - "anthropic:claude-haiku-4-5-20251001"
  
  - id: "team-backend"
    virtual_key: "vk-backend-yyy"
    budget:
      monthly_limit: 200.00
      alert_threshold: 160.00
    allowed_models:
      - "openai:gpt-4o"
      - "anthropic:claude-sonnet-4-5-20250929"

プロバイダー比較: どのモデルを選ぶべきか

実際のプロジェクトでは、タスク特性に応じた適切なモデル選択が重要です。

タスク別推奨モデル

タスク種別 推奨モデル 理由
簡単な会話・要約 OpenAI: gpt-4o-mini 低コスト・高速
コード生成・レビュー Anthropic: Claude Sonnet コード理解に優れる
複雑な推論タスク Anthropic: Claude Opus 最高品質の出力
大量の軽量処理 OpenAI: gpt-4o-mini コスパ最高
ローカル実行 Ollama: llama3.2 プライバシー重視

コスト比較(例)

# 各モデルの概算コスト(1M tokens)
cost_comparison = {
    "openai:gpt-4o-mini": {
        "input": 0.15,   # USD per 1M tokens
        "output": 0.60
    },
    "anthropic:claude-haiku-4-5-20251001": {
        "input": 0.25,
        "output": 1.25
    },
    "anthropic:claude-sonnet-4-5-20250929": {
        "input": 3.00,
        "output": 15.00
    }
}

def estimate_cost(input_tokens: int, output_tokens: int, model: str):
    """
    概算コストを計算
    """
    costs = cost_comparison.get(model)
    if not costs:
        return "Unknown model"
    
    input_cost = (input_tokens / 1_000_000) * costs["input"]
    output_cost = (output_tokens / 1_000_000) * costs["output"]
    total = input_cost + output_cost
    
    return f"${total:.4f}"

# 使用例
print(estimate_cost(1000, 500, "openai:gpt-4o-mini"))
# 出力: $0.0004

v1.0の新機能

2025年11月リリースのv1.0では、以下の機能が追加されました:

1. 標準化された推論出力

from any_llm import completion

# どのプロバイダーでも同じ形式で推論過程を取得
response = completion(
    model="anthropic:claude-sonnet-4-5-20250929",
    messages=[{"role": "user", "content": "2+2は?"}],
    reasoning=True  # 推論過程を含める
)

# 推論過程へのアクセス(プロバイダーに依らず統一)
if response.reasoning:
    print("推論:", response.reasoning)
print("回答:", response.choices[0].message.content)

2. List Models API

from any_llm import list_models

# プロバイダーがサポートするモデル一覧を取得
models = list_models(provider="openai")
for model in models:
    print(f"- {model.id}: {model.description}")

3. 再利用可能なクライアント接続

from any_llm import CompletionClient

# クライアントを再利用してパフォーマンス向上
client = CompletionClient(model="openai:gpt-4o-mini")

for i in range(10):
    response = client.complete(
        messages=[{"role": "user", "content": f"質問{i}"}]
    )
    print(response.choices[0].message.content)

client.close()

まとめ

any-llmを使うことで
プロバイダーロックインから解放される
1行の変更でLLMを切り替えできる
コスト最適化が簡単に実現
チーム開発でのAPI管理が一元化

LLM活用の柔軟性を手に入れるために、ぜひany-llmを試してみてください!

参考文献

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?