llm-gateway-routing について
llm-gateway-routingは、OpenRouterやLiteLLMなどを使ったマルチモデルアクセスとルーティングを解説するスキルガイドです。フォールバック、コスト・レイテンシ・タスク別ルーティング、A/Bテストを扱い、LLMアプリを構築する開発者を対象としています。
主な機能
- 01複数モデルへの統一アクセスを設定
- 02モデルのフォールバックチェーンを設定
- 03コスト・レイテンシ・タスク別にルーティング
- 04モデルのA/Bテストを計画
- 05コスト追跡とトークン上限の設定
- 06LiteLLMのセルフホスト型プロキシを構成
活用シーン
- 01LLMアプリに複数のモデルプロバイダーを接続
- 02主モデルが利用できない場合に予備モデルへ切り替え
- 03リクエストの複雑さや予算に応じてモデルを選択
- 04モデルの挙動を比較し呼び出しコストを追跡
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ phrazzld/ claude-config --skill llm-gateway-routingインストール後、Claude Code で/llm-gateway-routingを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/alternatives.mdlitellm-guide.mdopenrouter-guide.mdrouting-strategies.mdtemplates/fallback-chain.tslitellm-config.yamlopenrouter-config.ts詳細
LLM ゲートウェイとルーティング
マルチモデルアクセス、フォールバック、コスト最適化、A/B テストを設定します。
ゲートウェイを使う理由
ゲートウェイを使わない場合:
- ベンダーロックイン(プロバイダーが1つ)
- フォールバックがない(プロバイダーの停止=アプリの停止)
- モデルの A/B テストが難しい
- API キーと設定が分散する
ゲートウェイを使う場合:
- 400 以上のモデルに対応する単一の API
- 自動フォールバック
- モデルの切り替えが簡単
- コストを一元管理
すぐに選ぶなら
| ニーズ | ソリューション |
|---|---|
| 最速のセットアップ、マルチモデル | OpenRouter |
| 完全な制御、セルフホスト可能 | LiteLLM |
| 可観測性とルーティング | Helicone |
| エンタープライズ、ガードレール | Portkey |
OpenRouter(推奨)
OpenRouter を選ぶ理由
- 400 以上のモデル:OpenAI、Anthropic、Google、Meta、Mistral など
- 単一の API:すべてのプロバイダーに1つのキーでアクセス
- 自動フォールバック:信頼性を高める機能を内蔵
- A/B テスト:モデルの比較が簡単
- コスト追跡:請求ダッシュボードを一元化
- 無料クレジット:開始時に1ドル分が無料
セットアップ
# 1. Sign up at openrouter.ai
# 2. Get API key from dashboard
# 3. Add to .env:
OPENROUTER_API_KEY=sk-or-v1-...
基本的な使い方
// Using fetch
const response = await fetch('https://openrouter.ai/api/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.OPENROUTER_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'anthropic/claude-3-5-sonnet',
messages: [{ role: 'user', content: 'Hello!' }],
}),
});
Vercel AI SDK を使用する場合(推奨)
import { createOpenAI } from "@ai-sdk/openai";
import { generateText } from "ai";
const openrouter = createOpenAI({
baseURL: "https://openrouter.ai/api/v1",
apiKey: process.env.OPENROUTER_API_KEY,
});
const { text } = await generateText({
model: openrouter("anthropic/claude-3-5-sonnet"),
prompt: "Explain quantum computing",
});
モデル ID
// Format: provider/model-name
const models = {
// Anthropic
claude35Sonnet: "anthropic/claude-3-5-sonnet",
claudeHaiku: "anthropic/claude-3-5-haiku",
// OpenAI
gpt4o: "openai/gpt-4o",
gpt4oMini: "openai/gpt-4o-mini",
// Google
geminiPro: "google/gemini-pro-1.5",
geminiFlash: "google/gemini-flash-1.5",
// Meta
llama3: "meta-llama/llama-3.1-70b-instruct",
// Auto (OpenRouter picks best)
auto: "openrouter/auto",
};
フォールバックチェーン
// Define fallback order
const modelChain = [
"anthropic/claude-3-5-sonnet", // Primary
"openai/gpt-4o", // Fallback 1
"google/gemini-pro-1.5", // Fallback 2
];
async function callWithFallback(messages: Message[]) {
for (const model of modelChain) {
try {
return await openrouter.chat({ model, messages });
} catch (error) {
console.log(`${model} failed, trying next...`);
}
}
throw new Error("All models failed");
}
コストベースのルーティング
// Route based on query complexity
function selectModel(query: string): string {
const complexity = analyzeComplexity(query);
if (complexity === "simple") {
// Simple queries → cheap model
return "openai/gpt-4o-mini"; // ~$0.15/1M tokens
} else if (complexity === "medium") {
// Medium → balanced
return "google/gemini-flash-1.5"; // ~$0.075/1M tokens
} else {
// Complex → best quality
return "anthropic/claude-3-5-sonnet"; // ~$3/1M tokens
}
}
function analyzeComplexity(query: string): "simple" | "medium" | "complex" {
// Simple heuristics
if (query.length < 50) return "simple";
if (query.includes("explain") || query.includes("analyze")) return "complex";
return "medium";
}
A/B テスト
// Random assignment
function getModel(userId: string): string {
const hash = userId.charCodeAt(0) % 100;
if (hash < 50) {
return "anthropic/claude-3-5-sonnet"; // 50%
} else {
return "openai/gpt-4o"; // 50%
}
}
// Track which model was used
const model = getModel(userId);
const response = await openrouter.chat({ model, messages });
await analytics.track("llm_call", { model, userId, latency, cost });
LiteLLM(セルフホスト)
LiteLLM を選ぶ理由
- セルフホスト可能:データを完全に制御できます
- 100 以上のプロバイダー:OpenRouter と同等の対応範囲
- ロードバランシング:複数のプロバイダーに分散
- コスト追跡:支出管理機能を内蔵
- キャッシュ:Redis またはインメモリ
- レート制限:ユーザーごとの上限を設定
セットアップ
# Install
pip install litellm[proxy]
# Run proxy
litellm --config config.yaml
# Use as OpenAI-compatible endpoint
export OPENAI_API_BASE=http://localhost:4000
設定
# config.yaml
model_list:
# Claude models
- model_name: claude-sonnet
litellm_params:
model: anthropic/claude-3-5-sonnet-latest
api_key: sk-ant-...
# OpenAI models
- model_name: gpt-4o
litellm_params:
model: openai/gpt-4o
api_key: sk-...
# Load balanced (multiple providers)
- model_name: balanced
litellm_params:
model: anthropic/claude-3-5-sonnet-latest
litellm_params:
model: openai/gpt-4o
# Requests distributed across both
# General settings
general_settings:
master_key: sk-master-...
database_url: postgresql://...
# Routing
router_settings:
routing_strategy: simple-shuffle # or latency-based-routing
num_retries: 3
timeout: 30
# Rate limiting
litellm_settings:
max_budget: 100 # $100/month
budget_duration: monthly
LiteLLM のフォールバック
model_list:
- model_name: primary
litellm_params:
model: anthropic/claude-3-5-sonnet-latest
fallbacks:
- model_name: fallback-1
litellm_params:
model: openai/gpt-4o
- model_name: fallback-2
litellm_params:
model: google/gemini-pro
使い方
// Use like OpenAI SDK
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "http://localhost:4000",
apiKey: "sk-master-...",
});
const response = await client.chat.completions.create({
model: "claude-sonnet", // Maps to configured model
messages: [{ role: "user", content: "Hello!" }],
});
ルーティング戦略
1. コストベースのルーティング
const costTiers = {
cheap: ["openai/gpt-4o-mini", "google/gemini-flash-1.5"],
balanced: ["anthropic/claude-3-5-haiku", "openai/gpt-4o"],
premium: ["anthropic/claude-3-5-sonnet", "openai/o1-preview"],
};
function routeByCost(budget: "cheap" | "balanced" | "premium"): string {
const models = costTiers[budget];
return models[Math.floor(Math.random() * models.length)];
}
2. レイテンシベースのルーティング
// Track latency per model
const latencyStats: Record<string, number[]> = {};
function routeByLatency(): string {
const avgLatencies = Object.entries(latencyStats)
.map(([model, times]) => ({
model,
avg: times.reduce((a, b) => a + b, 0) / times.length,
}))
.sort((a, b) => a.avg - b.avg);
return avgLatencies[0].model;
}
// Update after each call
function recordLatency(model: string, latencyMs: number) {
if (!latencyStats[model]) latencyStats[model] = [];
latencyStats[model].push(latencyMs);
// Keep last 100 samples
if (latencyStats[model].length > 100) {
latencyStats[model].shift();
}
}
3. タスクベースのルーティング
const taskModels = {
coding: "anthropic/claude-3-5-sonnet", // Best for code
reasoning: "openai/o1-preview", // Best for logic
creative: "anthropic/claude-3-5-sonnet", // Best for writing
simple: "openai/gpt-4o-mini", // Cheap and fast
multimodal: "google/gemini-pro-1.5", // Vision + text
};
function routeByTask(task: keyof typeof taskModels): string {
return taskModels[task];
}
4. ハイブリッドルーティング
interface RoutingConfig {
task: string;
maxCost: number;
maxLatency: number;
}
function hybridRoute(config: RoutingConfig): string {
// Filter by cost
const affordable = models.filter(m => m.cost <= config.maxCost);
// Filter by latency
const fast = affordable.filter(m => m.avgLatency <= config.maxLatency);
// Select best for task
const taskScores = fast.map(m => ({
model: m.id,
score: getTaskScore(m.id, config.task),
}));
return taskScores.sort((a, b) => b.score - a.score)[0].model;
}
ベストプラクティス
1. 必ずフォールバックを用意する
// Bad: Single point of failure
const response = await openai.chat({ model: "gpt-4o", messages });
// Good: Fallback chain
const models = ["gpt-4o", "claude-3-5-sonnet", "gemini-pro"];
for (const model of models) {
try {
return await gateway.chat({ model, messages });
} catch (e) {
continue;
}
}
2. モデルのバージョンを固定する
// Bad: Model can change
const model = "gpt-4";
// Good: Pinned version
const model = "openai/gpt-4-0125-preview";
3. コストを追跡する
// Log every call
async function trackedCall(model: string, messages: Message[]) {
const start = Date.now();
const response = await gateway.chat({ model, messages });
const latency = Date.now() - start;
await analytics.track("llm_call", {
model,
inputTokens: response.usage.prompt_tokens,
outputTokens: response.usage.completion_tokens,
cost: calculateCost(model, response.usage),
latency,
});
return response;
}
4. トークン数の上限を設定する
// Prevent runaway costs
const response = await gateway.chat({
model,
messages,
max_tokens: 500, // Limit output length
});
5. キャッシュを使う
// LiteLLM caching
litellm_settings:
cache: true
cache_params:
type: redis
host: localhost
port: 6379
ttl: 3600 # 1 hour
参考資料
references/openrouter-guide.md- OpenRouter の詳細ガイドreferences/litellm-guide.md- LiteLLM のセルフホストreferences/routing-strategies.md- 高度なルーティングパターンreferences/alternatives.md- Helicone、Portkey など
テンプレート
templates/openrouter-config.ts- TypeScript による OpenRouter のセットアップtemplates/litellm-config.yaml- LiteLLM プロキシの設定templates/fallback-chain.ts- フォールバックの実装
コメント
Markdown 対応