- 概要
- 1. なぜゲートウェイ層が必要なのか
- 2. コアとなる概念
- 3. キー発行と最初の curl リクエスト
- 4. OpenAI SDK ドロップイン
- 5. モデル選択とルーティング
- 6. ストリーミング / ツール呼び出し / 構造化出力
- 7. アトリビューションヘッダと使用量の確認
- 8. 実務のヒントと注意点
- 参考資料
概要
複数の LLM を扱い始めると、すぐに同じ問題にぶつかる。OpenAI、Anthropic、Google、Meta のモデルを混ぜて使いたいのに、プロバイダごとに別々の SDK、別々の認証、別々の課金、別々のリクエストスキーマがある。モデルを一つ差し替えるだけでクライアントコードを書き直すことになり、プロバイダの一つがダウンするとサービスも止まる。
OpenRouter はこの部分を整理する。一つのエンドポイントと一つの API キーで、60以上のプロバイダの300以上(最大およそ500)のモデルにアクセスでき、インターフェースは OpenAI API と完全に互換だ。つまり、すでに OpenAI SDK を使っているなら、base_url と api_key を変えるだけで Claude、Gemini、Llama をそのまま呼び出せる。
この記事では、なぜ OpenRouter をゲートウェイとして使うのか、コアとなる概念は何か、そしてキー発行からルーティング/フォールバック/ストリーミングまで、実際にどう組み込むかを段階的に扱う。
1. なぜゲートウェイ層が必要なのか
LLM アプリケーションは、最初は単一モデルで十分に見える。しかし運用に入ると共通の要求が出てくる。
- タスクごとに最適なモデルが違う。要約は安価なモデルで、複雑な推論はフロンティアモデルで分けたい。
- 一つのプロバイダに縛られたくない。価格が上がったり障害が起きたら別のモデルに移す必要がある。
- 課金と使用量を一か所で見たい。プロバイダごとにダッシュボードを別々に開くのは非効率だ。
ゲートウェイはこの問題をアプリケーションコードの外に出す。クライアントは常に同じエンドポイントにリクエストし、モデルの切り替えは文字列一つ(model フィールド)の差し替えになる。プロバイダのルーティング、フォールバック、課金の集約はゲートウェイが処理する。
| 直接呼び出す方式 | OpenRouter ゲートウェイ |
|---|---|
| プロバイダごとに SDK/認証/スキーマが異なる | 一つのエンドポイント、一つのキー、OpenAI 互換スキーマ |
| モデル差し替えでコード変更 | model 文字列だけ差し替え |
| プロバイダごとの課金アカウント | 一つのクレジットで統合課金 |
| 障害時に自前でフォールバック実装 | models 配列/provider ルーティングで自動フォールバック |
2. コアとなる概念
一つのエンドポイント
すべての呼び出しは一つのベース URL に向かう。
https://openrouter.ai/api/v1
チャット補完(chat completions)は https://openrouter.ai/api/v1/chat/completions にリクエストする。認証は標準的な Bearer トークンヘッダを使う。
Authorization: Bearer YOUR_OPENROUTER_API_KEY
モデル ID
モデルは provider/model 形式の文字列で指定する。代表的な例は次のとおり。
| モデル ID | 説明 |
|---|---|
openai/gpt-4o | OpenAI GPT-4o |
anthropic/claude-3.5-sonnet | Anthropic Claude 3.5 Sonnet |
google/gemini-2.0-flash-exp | Google Gemini 2.0 Flash(実験) |
meta-llama/llama-3.3-70b-instruct | Meta Llama 3.3 70B Instruct |
openrouter/auto | 自動ルーター — OpenRouter がリクエストに合うモデルを選択 |
無料バリアントは ID の末尾に :free が付く。全リストと各モデルの価格/コンテキスト長はモデルページで確認でき、プログラム的には /api/v1/models エンドポイントで取得する。
クレジットと無料ティア
無料ティアは1日およそ50件の無料リクエストと、25以上の無料モデル(ID が :free で終わる)を提供する。有料の利用はクレジットベースの従量課金で、実際に実行されたモデルのトークン単位で課金される。クレジットをチャージする際に約5.5%の少額の手数料が付くが、呼び出し自体のコストは、そのリクエストを実際に処理したモデルの単価に従う。
3. キー発行と最初の curl リクエスト
まず openrouter.ai/keys で API キーを発行する。キーを環境変数に入れておくと扱いやすい。
export OPENROUTER_API_KEY="sk-or-ここに発行したキー"
では、最も単純なリクエストを curl で送ってみる。
curl https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "model": "openai/gpt-4o", "messages": [{"role":"user","content":"Hello"}] }'
レスポンスは OpenAI の chat completions と同じ構造で返ってくる。モデルを変えたければ、model の値を anthropic/claude-3.5-sonnet や google/gemini-2.0-flash-exp に差し替えるだけでよい。リクエストの残りの形はそのままだ。
4. OpenAI SDK ドロップイン
「OpenRouter は OpenAI 互換」という言葉の実質的な意味は、公式の OpenAI SDK をそのまま使い、接続先だけを OpenRouter に向けるということだ。
Python
from openai import OpenAI
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key="YOUR_OPENROUTER_API_KEY",
)
completion = client.chat.completions.create(
model="anthropic/claude-3.5-sonnet",
messages=[
{"role": "user", "content": "ゲートウェイが便利な理由を一文で説明して"},
],
)
print(completion.choices[0].message.content)
OpenAI(...) のコンストラクタで base_url と api_key を OpenRouter の値に変えるだけで、以降の client.chat.completions.create(...) の呼び出し方は普段と完全に同じだ。レスポンス本文は completion.choices[0].message.content で読む。
TypeScript
TypeScript も同じ考え方だ。openai の npm クライアントに baseURL と apiKey を指定する。
import OpenAI from 'openai';
const client = new OpenAI({
baseURL: 'https://openrouter.ai/api/v1',
apiKey: process.env.OPENROUTER_API_KEY,
});
const completion = await client.chat.completions.create({
model: 'anthropic/claude-3.5-sonnet',
messages: [{ role: 'user', content: 'Hello' }],
});
console.log(completion.choices[0].message.content);
SDK を使わず、素の fetch で POST してもよい。エンドポイントとヘッダを合わせれば同じように動作する。
const res = 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: 'openai/gpt-4o',
messages: [{ role: 'user', content: 'Hello' }],
}),
});
const data = await res.json();
console.log(data.choices[0].message.content);
5. モデル選択とルーティング
プロバイダルーティングのオーバーライド
同じモデルを複数のプロバイダが提供している場合がある。このとき OpenRouter はデフォルトで、価格・レイテンシ・可用性を基準にプロバイダを自動選択する。特定のポリシーを強制したい場合は、リクエストに provider フィールドを入れてオーバーライドする。たとえばプロバイダの優先順位(order)、フォールバックを許可するか(allow_fallbacks)、ソート基準(sort)などを指定できる。
{
"model": "meta-llama/llama-3.3-70b-instruct",
"messages": [{ "role": "user", "content": "Hello" }],
"provider": {
"sort": "throughput",
"allow_fallbacks": true
}
}
モデルレベルのフォールバック — models 配列
プロバイダルーティングとは別に、複数のモデルを順番に試すフォールバックも指定できる。models 配列を渡すと、先頭から順に試す。
{
"models": [
"openai/gpt-4o",
"anthropic/claude-3.5-sonnet",
"meta-llama/llama-3.3-70b-instruct"
],
"messages": [{ "role": "user", "content": "Hello" }]
}
フォールバックは、レートリミット、ダウンタイム、コンテキスト長の超過、モデレーションエラーといった状況でトリガーされる。重要なのは課金の仕組みだ。複数のモデルを並べても、実際に実行されてレスポンスを生成したモデルのトークンに対してのみ課金される。試して失敗したモデルにはコストが付かない。
自動ルーター — openrouter/auto
モデルを自分で選ぶのが難しいときは、model の値に openrouter/auto を指定すればよい。OpenRouter がリクエストの内容を見て、適切なモデルにルーティングする。初期のプロトタイピングや、「とりあえずうまく動くモデル」が必要な段階で役立つ。
6. ストリーミング / ツール呼び出し / 構造化出力
この三つの機能はすべて、OpenAI API と同じ方式で動作する。
ストリーミング
stream=True(TypeScript は stream: true)を渡すと、レスポンスをチャンク単位で受け取る。
stream = client.chat.completions.create(
model="openai/gpt-4o",
messages=[{"role": "user", "content": "短い詩を一つ書いて"}],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="")
ツール/関数呼び出し
ツール(関数)呼び出しも OpenAI のスキーマそのままだ。tools 配列に関数定義を入れ、モデルが返した tool_calls を処理したうえで、結果を再びメッセージとして渡す。
{
"model": "openai/gpt-4o",
"messages": [{ "role": "user", "content": "ソウルの天気を教えて" }],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "都市の現在の天気を返す",
"parameters": {
"type": "object",
"properties": { "city": { "type": "string" } },
"required": ["city"]
}
}
}
]
}
構造化出力
JSON スキーマベースの構造化出力もサポートされる。response_format に json_schema を指定すると、レスポンスがそのスキーマに従うよう強制できる。
{
"model": "openai/gpt-4o",
"messages": [{ "role": "user", "content": "サンプルユーザーを一つ作って" }],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "user",
"schema": {
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "integer" }
},
"required": ["name", "age"]
}
}
}
}
7. アトリビューションヘッダと使用量の確認
OpenRouter は、openrouter.ai のリーダーボード(どのアプリがどのモデルを多く使っているか)向けのオプションのアトリビューションヘッダをサポートする。必須ではなく、付ければ自分のアプリをリーダーボードに表示できる。
HTTP-Referer— 自分のサイト URLX-Title— 自分のアプリ名
OpenAI SDK では、これらをデフォルトヘッダとして渡す。Python は default_headers、JavaScript は defaultHeaders を使う。
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key="YOUR_OPENROUTER_API_KEY",
default_headers={
"HTTP-Referer": "https://your-site.example",
"X-Title": "My App",
},
)
const client = new OpenAI({
baseURL: 'https://openrouter.ai/api/v1',
apiKey: process.env.OPENROUTER_API_KEY,
defaultHeaders: {
'HTTP-Referer': 'https://your-site.example',
'X-Title': 'My App',
},
});
利用可能なモデルの一覧とメタデータは /api/v1/models エンドポイントで取得する。
curl https://openrouter.ai/api/v1/models \
-H "Authorization: Bearer $OPENROUTER_API_KEY"
8. 実務のヒントと注意点
- コストは常に、実際に実行された下位モデルの単価に従う。
openrouter/autoやmodelsフォールバックを使うときは、どのモデルが実行されるかによって単価が変わる点を念頭に置く。 :freeモデルは無料だがレートリミットが低い。プロダクションのトラフィックを無料モデルだけに頼ると、すぐに上限に達する。プロトタイピングや低負荷の用途に使うのが安全だ。- API キーは必ずサーバーサイドに置く。ブラウザのバンドルやクライアントコードにキーを露出すると、そのまま盗まれる。フロントエンドから呼び出す必要があるなら、自前のバックエンドをプロキシとして前に置き、その背後で OpenRouter を呼び出す。
- モデルを変えてもレスポンススキーマは OpenAI 互換のまま維持されるので、パース処理をモデルごとに書き直す必要はない。ただしモデルによってツール呼び出しや構造化出力のサポート状況が異なることがあるので、新しいモデルに切り替えるときはその機能が実際に動くか確認する。
- フォールバック配列は信頼性を高めるが、末尾に高価なモデルを置くと障害時にコストが跳ね上がることがある。フォールバックの順序は可用性だけでなく単価も考慮して配置する。
参考資料
현재 단락 (1/175)
複数の LLM を扱い始めると、すぐに同じ問題にぶつかる。OpenAI、Anthropic、Google、Meta のモデルを混ぜて使いたいのに、プロバイダごとに別々の SDK、別々の認証、別々の課金...