コンテンツにスキップ

プロトコル変換ガイド

RouteAPIは統合APIゲートウェイとして、異なるプロトコルフォーマット間の変換を内部で自動的に処理します。OpenAIプロトコルでClaudeモデルを呼び出したり、Claude MessagesプロトコルでGeminiモデルを呼び出したりする場合、RouteAPIはメッセージ構造、パラメータマッピング、レスポンスフォーマットの違いを処理するため、基盤となるプロトコルの詳細を気にする必要はありません。

プロトコルアダプターレイヤーとしてのRouteAPI

Section titled “プロトコルアダプターレイヤーとしてのRouteAPI”

RouteAPIは3つの主要なプロトコルエントリポイントをサポートしています:

  • OpenAI互換プロトコル: /v1/chat/completions、/v1/responses
  • Claude Messagesプロトコル: /v1/messages
  • Google Geminiプロトコル: /v1beta/models/{model}:generateContent

リクエストが到着すると、RouteAPIはパスに基づいてプロトコルタイプを識別し、モデルIDに基づいてターゲットアップストリームを決定し、その間で必要なフォーマット変換を実行します。

シナリオ変換説明
OpenAIプロトコル → OpenAIモデルなしパススルー
Claude Messages → Claudeモデルなしパススルー
OpenAIプロトコル → ClaudeモデルありOpenAI → Claude Messages
OpenAIプロトコル → GeminiモデルありOpenAI → Gemini contents
Claude Messages → OpenAIモデルありClaude Messages → OpenAI
Claude Messages → GeminiモデルありClaude Messages → Gemini

プロトコル変換はクライアントに対して透過的です。OpenAIフォーマットのリクエストを送信すると、基盤でClaudeまたはGeminiが呼び出されていても、OpenAIフォーマットのレスポンスを受け取ります。

ただし、変換には制限があります:

  • ターゲットプロトコルでサポートされていないパラメータは無視されるか、デフォルト値が使用されます。
  • 一部のプロトコル固有の機能(Claudeの拡張思考、プロンプトキャッシングなど)は、変換後に完全に表現できない場合があります。
  • 変換プロセスはわずかな遅延を導入します(通常10ms未満)。

ベストプラクティス: ターゲットモデルがネイティブにサポートするプロトコルを優先して使用することで、最も完全な機能サポートと最高のパフォーマンスが得られます。

OpenAIはsystem promptをmessages配列の最初のメッセージとして配置します:

{
"messages": [
{ "role": "system", "content": "あなたは厳密な技術アシスタントです。" },
{ "role": "user", "content": "APIゲートウェイとは何か説明してください" }
]
}

Claudeはsystem promptをトップレベルの独立したフィールドに配置します:

{
"system": "あなたは厳密な技術アシスタントです。",
"messages": [
{ "role": "user", "content": "APIゲートウェイとは何か説明してください" }
]
}

変換ルール:

  • OpenAI → Claude: 最初のrole: "system"メッセージを抽出し、systemフィールドに移動します。
  • Claude → OpenAI: systemフィールドの内容をrole: "system"メッセージに変換し、messages配列の先頭に挿入します。
OpenAIClaudeGemini説明
systemトップレベルsystemフィールドsystemInstructionシステムプロンプトの位置が異なる
useruseruserユーザーメッセージ、一致
assistantassistantmodelアシスタント/モデル応答、名前が異なる
tooluser内のtool_resultuser内のfunctionResponseツール結果の帰属が異なる

変換の注意点:

  • Claudeは同じロールの連続する2つのメッセージを受け付けないため、変換時にマージまたはプレースホルダーメッセージの挿入が必要です。
  • GeminiのmodelロールはOpenAIに変換する際にassistantにマッピングされます。
  • OpenAIのrole: "tool"はClaudeとGeminiの両方でuserメッセージにマージされます。

Geminiのメッセージ構造はcontentsと呼ばれ、各メッセージのロールはrole、コンテンツはparts配列にあります:

{
"contents": [
{
"role": "user",
"parts": [{ "text": "APIゲートウェイとは何か説明してください" }]
}
]
}

変換ルール:

  • OpenAI messages ↔ Gemini contents
  • OpenAI content ↔ Gemini parts
  • OpenAI assistant ↔ Gemini model
  • system promptはトップレベルsystemInstructionフィールドに変換

パラメータマッピングテーブル

Section titled “パラメータマッピングテーブル”
OpenAIClaudeGemini説明
temperaturetemperaturetemperatureClaude上限1、OpenAI上限2、Gemini上限2
top_ptop_ptopPnucleusサンプリング、すべてサポート
非サポートtop_ktopKOpenAIは非サポート、変換時に削除
max_tokens / max_completion_tokensmax_tokens(必須)maxOutputTokensClaudeは明示的な設定が必要
n非サポートcandidateCountClaudeは複数候補生成を非サポート
stopstop_sequencesstopSequencesフィールド名が異なるが意味は同じ

温度範囲の変換:

OpenAIリクエストのtemperatureが1を超え、ターゲットがClaudeの場合、RouteAPIは自動的に1に切り詰めて、アップストリームによる拒否を回避します。

OpenAIClaudeGemini説明
response_format非サポートresponseMimeTypeOpenAIはJSONモードとJSON Schemaをサポート
frequency_penalty非サポートfrequencyPenaltyClaudeはペナルティパラメータを非サポート
presence_penalty非サポートpresencePenaltyClaudeはペナルティパラメータを非サポート
streamstreamstreamすべてサポートだがイベントフォーマットは全く異なる
stream_options.include_usage常に返されるgenerateContentRequest.stream=true時に自動返却使用統計の返却方法が異なる

変換動作:

  • frequency_penaltyとpresence_penaltyはClaudeに転送される際に無視されます。
  • response_format: { type: "json_object" }はClaudeに転送される際にツール呼び出しでシミュレートされるか、systemプロンプトにJSON出力プロンプトが追加されます。
  • n > 1はClaudeに転送される際に1にリセットされます。Claudeは複数候補生成をサポートしていないためです。
OpenAIClaudeGemini説明
usermetadata.user_id非サポート不正使用検出用
seed非サポートseedClaudeは決定論的サンプリングを非サポート
logprobs / top_logprobs非サポート非サポートOpenAIモデルのみサポート
非サポートthinking非サポートClaude固有の拡張思考設定

ツール定義フォーマットの違い

Section titled “ツール定義フォーマットの違い”
{
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "指定された都市の現在の天気を取得",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string", "description": "都市名" }
},
"required": ["city"]
}
}
}
]
}
{
"tools": [
{
"name": "get_weather",
"description": "指定された都市の現在の天気を取得",
"input_schema": {
"type": "object",
"properties": {
"city": { "type": "string", "description": "都市名" }
},
"required": ["city"]
}
}
]
}
{
"tools": [
{
"functionDeclarations": [
{
"name": "get_weather",
"description": "指定された都市の現在の天気を取得",
"parameters": {
"type": "object",
"properties": {
"city": { "type": "string", "description": "都市名" }
},
"required": ["city"]
}
}
]
}
]
}
OpenAIClaudeGemini変換メモ
tools[].type: "function"このレベルなしこのレベルなし変換時にtypeラッパーを削除
tools[].functiontools[]にフラット化functionDeclarations[]に配置階層構造が異なる
function.parametersinput_schemaparametersClaudeはフィールド名が異なる
OpenAIClaudeGemini説明
"auto"{ "type": "auto" }"AUTO"モデルが自動決定
"none"{ "type": "none" }"NONE"ツール呼び出しを禁止
"required"{ "type": "any" }"ANY"ツールを必ず呼び出す
{ "type": "function", "function": { "name": "get_weather" } }{ "type": "tool", "name": "get_weather" }{ "functionCallingConfig": { "allowedFunctionNames": ["get_weather"] } }特定ツールを強制、構造が大きく異なる
{
"role": "tool",
"tool_call_id": "call_abc123",
"content": "東京、晴れ、23°C"
}
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",
"content": "東京、晴れ、23°C"
}
]
}
{
"role": "user",
"parts": [
{
"functionResponse": {
"name": "get_weather",
"response": { "result": "東京、晴れ、23°C" }
}
}
]
}

変換のポイント:

  • OpenAIのrole: "tool"はClaude/Geminiに変換する際にuserメッセージにマージされます。
  • ツール呼び出しIDのフィールド名が異なります: tool_call_id vs tool_use_id vs Geminiの関数名識別。
  • ClaudeとGeminiはすべてのツール結果を同じuserメッセージ内に要求しますが、OpenAIは複数のtoolメッセージに分けることを許可します。

マルチモーダルコンテンツ変換

Section titled “マルチモーダルコンテンツ変換”
{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {
"url": "https://example.com/image.jpg",
"detail": "high"
}
},
{ "type": "text", "text": "この画像を説明してください" }
]
}
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "url",
"url": "https://example.com/image.jpg"
}
},
{ "type": "text", "text": "この画像を説明してください" }
]
}
{
"role": "user",
"parts": [
{
"fileData": {
"mimeType": "image/jpeg",
"fileUri": "https://example.com/image.jpg"
}
},
{ "text": "この画像を説明してください" }
]
}
{
"type": "image_url",
"image_url": {
"url": "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
}
}
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/jpeg",
"data": "/9j/4AAQSkZJRg..."
}
}
{
"inlineData": {
"mimeType": "image/jpeg",
"data": "/9j/4AAQSkZJRg..."
}
}

変換ルール:

  • OpenAIのdata: URIは解析され、media_typeはURIプレフィックスから抽出され、純粋なbase64部分がターゲットプロトコルに渡されます。
  • Claudeは個別のmedia_typeフィールドを要求し、data: URIを受け付けません。
  • Geminiはbase64コンテンツを表すためにfileDataではなくinlineDataを使用します。
  • OpenAIのdetailパラメータ(low/high)は変換時に失われます。ClaudeとGeminiには対応する概念がありません。
パラメータ元のプロトコル変換不可先理由
top_kClaude, GeminiOpenAIOpenAIはtop-kサンプリングを非サポート
nOpenAI, GeminiClaudeClaudeは複数候補生成を非サポート
frequency_penalty / presence_penaltyOpenAI, GeminiClaudeClaudeにペナルティパラメータなし
logprobsOpenAIClaude, GeminiOpenAIモデルのみ対数確率を返す
thinkingClaudeOpenAI, GeminiClaude固有の拡張思考設定
cache_controlClaudeOpenAI, GeminiClaude固有のプロンプトキャッシング制御
reasoning_effortOpenAIClaude, GeminiOpenAI o1シリーズ固有パラメータ
response_format (JSON Schema)OpenAIClaude, Gemini完全なJSON Schema制約はOpenAIのみサポート

RouteAPIは以下の戦略を採用します:

  1. サイレント無視: サポートされていないパラメータは変換時に削除され、リクエストの成功には影響しません(例: detail、logprobs)。
  2. 自動調整: 範囲外の値は合法的な範囲に切り詰められます(例: temperature > 1はClaudeに転送される際に1に切り詰め)。
  3. 保守的な降格: 複雑な機能は簡単な方法でシミュレートされます(例: OpenAIのJSON SchemaはClaude上でツール呼び出しまたはプロンプト制約に降格)。
  4. リクエスト拒否: まれに、コアパラメータが変換できず、合理的なデフォルト値がない場合、400エラーを返します(例: Claudeプロトコルでmax_tokensが欠落)。

RouteAPIはレスポンスヘッダーとログで変換情報を提供します:

X-RouteAPI-Protocol-Conversion: openai-to-claude
X-RouteAPI-Dropped-Params: frequency_penalty,presence_penalty

変換が失敗またはパラメータが競合する場合、標準エラーレスポンスが返されます:

{
"error": {
"message": "Parameter 'max_tokens' is required for Claude models",
"type": "invalid_request_error",
"param": "max_tokens",
"code": "missing_required_parameter"
}
}
  1. ネイティブプロトコルを使用: 可能な限りモデルのネイティブプロトコルを使用して、変換による損失を回避します。
  2. プロトコル固有機能への依存を避ける: logprobs、thinkingなどの単一プロトコル固有機能に依存しないでください。そのプロトコルのモデルのみを使用する場合を除きます。
  3. レスポンスヘッダーを確認: X-RouteAPI-Dropped-Paramsヘッダーに注目して、どのパラメータが無視されたかを把握します。
  4. クロスプロトコル互換性をテスト: テスト環境で同じリクエストの異なるプロトコル/モデル組み合わせでの動作を検証します。
  5. モデルIDを記録: ログで実際に呼び出されたモデルIDとプロトコルタイプを記録して、違いのトラブルシューティングを容易にします。

レスポンスフォーマットの標準化

Section titled “レスポンスフォーマットの標準化”
プロトコルinputトークンフィールドoutputトークンフィールドtotalトークンフィールド
OpenAIprompt_tokenscompletion_tokenstotal_tokens
Claudeinput_tokensoutput_tokensなし(自分で計算)
GeminipromptTokenCountcandidatesTokenCounttotalTokenCount

変換ルール:

  • Claude → OpenAI: input_tokens → prompt_tokens、output_tokens → completion_tokens、total_tokens = input_tokens + output_tokensを計算。
  • Gemini → OpenAI: promptTokenCount → prompt_tokens、candidatesTokenCount → completion_tokens、totalTokenCount → total_tokens。
  • OpenAI → Claude: prompt_tokens → input_tokens、completion_tokens → output_tokens、total_tokensを削除。

Claudeのプロンプトキャッシングフィールドも保持されます:

{
"usage": {
"prompt_tokens": 120,
"completion_tokens": 45,
"total_tokens": 165,
"cache_creation_input_tokens": 80,
"cache_read_input_tokens": 40
}
}
OpenAIClaudeGemini意味
stopend_turnSTOP自然終了
lengthmax_tokensMAX_TOKENS長さ制限到達
tool_callstool_useSTOP(functionCall含む)ツール呼び出し要求
content_filter該当なしSAFETYコンテンツフィルターでブロック
stopstop_sequenceSTOP停止シーケンスに到達

変換ルール:

  • Claude end_turn → OpenAI stop
  • Claude max_tokens → OpenAI length
  • Claude tool_use → OpenAI tool_calls
  • Gemini STOPはfunctionCallの有無に基づいてstopまたはtool_callsにマッピング
  • Gemini SAFETY → OpenAI content_filter

すべてのプロトコルのエラーレスポンスはOpenAIフォーマットに変換されます(クライアントがOpenAIプロトコルを使用する場合):

{
"error": {
"message": "Invalid API key",
"type": "invalid_request_error",
"param": null,
"code": "invalid_api_key"
}
}

Claude元のエラー:

{
"type": "error",
"error": {
"type": "authentication_error",
"message": "invalid x-api-key"
}
}

OpenAIフォーマットに変換後、typeはinvalid_request_errorにマッピングされ、codeはinvalid_api_keyに設定されます。

例1: OpenAIリクエスト → Claudeフォーマット

Section titled “例1: OpenAIリクエスト → Claudeフォーマット”

元のOpenAIリクエスト:

{
"model": "claude-sonnet-4-5",
"messages": [
{
"role": "system",
"content": "あなたは厳密な技術アシスタントです。簡潔に回答してください。"
},
{
"role": "user",
"content": "APIゲートウェイとは何か説明してください"
}
],
"temperature": 0.7,
"max_tokens": 150,
"stream": false
}

変換後のClaudeリクエスト:

{
"model": "claude-sonnet-4-5",
"system": "あなたは厳密な技術アシスタントです。簡潔に回答してください。",
"messages": [
{
"role": "user",
"content": "APIゲートウェイとは何か説明してください"
}
],
"temperature": 0.7,
"max_tokens": 150,
"stream": false
}

主な変更点:

  • systemメッセージがmessages配列からトップレベルsystemフィールドに抽出されました。
  • messagesにはuserとassistantメッセージのみが含まれるようになりました。

例2: Claudeツール呼び出し → OpenAIフォーマット

Section titled “例2: Claudeツール呼び出し → OpenAIフォーマット”

Claudeツール呼び出しレスポンス:

{
"id": "msg_01XFDUDYJgAACzvnptvVoYEL",
"type": "message",
"role": "assistant",
"model": "claude-sonnet-4-5",
"content": [
{
"type": "text",
"text": "東京の天気を確認します。"
},
{
"type": "tool_use",
"id": "toolu_01A09q90qw90lq917835lq9",
"name": "get_weather",
"input": { "city": "東京" }
}
],
"stop_reason": "tool_use",
"usage": {
"input_tokens": 120,
"output_tokens": 45
}
}

OpenAIフォーマットに変換:

{
"id": "msg_01XFDUDYJgAACzvnptvVoYEL",
"object": "chat.completion",
"created": 1726567890,
"model": "claude-sonnet-4-5",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "東京の天気を確認します。",
"tool_calls": [
{
"id": "toolu_01A09q90qw90lq917835lq9",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"東京\"}"
}
}
]
},
"finish_reason": "tool_calls"
}
],
"usage": {
"prompt_tokens": 120,
"completion_tokens": 45,
"total_tokens": 165
}
}

主な変更点:

  • content配列を分割: textブロックをcontentフィールドに抽出、tool_useブロックをtool_calls配列に変換。
  • tool_use.inputオブジェクトをfunction.arguments JSON文字列にシリアライズ。
  • stop_reason: "tool_use" → finish_reason: "tool_calls"。
  • input_tokens → prompt_tokens、output_tokens → completion_tokens、total_tokensを追加。
  • OpenAIフォーマットのトップレベルフィールドを追加: object、created、choices配列。

例3: Geminiマルチモーダル → OpenAIフォーマット

Section titled “例3: Geminiマルチモーダル → OpenAIフォーマット”

Geminiレスポンス:

{
"candidates": [
{
"content": {
"parts": [
{
"text": "この画像は、ナビゲーションバー、コンテンツエリア、サイドバーを含む現代的なユーザーインターフェースを示しています。"
}
],
"role": "model"
},
"finishReason": "STOP",
"index": 0
}
],
"usageMetadata": {
"promptTokenCount": 258,
"candidatesTokenCount": 32,
"totalTokenCount": 290
}
}

OpenAIフォーマットに変換:

{
"id": "chatcmpl-gemini-abc123",
"object": "chat.completion",
"created": 1726567890,
"model": "gemini-2.0-flash-exp",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "この画像は、ナビゲーションバー、コンテンツエリア、サイドバーを含む現代的なユーザーインターフェースを示しています。"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 258,
"completion_tokens": 32,
"total_tokens": 290
}
}

主な変更点:

  • candidates[0].content.parts[0].text → choices[0].message.content。
  • role: "model" → role: "assistant"。
  • finishReason: "STOP" → finish_reason: "stop"(小文字に変換)。
  • usageMetadataフィールド名をOpenAIのusage構造にマッピング。

クライアントとモデルタイプに基づいてプロトコルを選択:

クライアントタイプターゲットモデル推奨プロトコル理由
OpenAI SDKOpenAIモデルOpenAIネイティブサポート、変換なし
Claude CodeClaudeモデルClaude Messagesネイティブサポート、変換なし
LangChain / LiteLLM任意のモデルOpenAIエコシステム互換性が最高
Anthropic SDKClaudeモデルClaude Messages拡張思考、プロンプトキャッシングにアクセス
カスタムクライアント任意のモデルニーズによるターゲットモデルのネイティブプロトコルを優先

2. プロトコル固有機能への依存を避ける

Section titled “2. プロトコル固有機能への依存を避ける”

ビジネスがモデル間の切り替えを必要とする場合、これらの機能の使用を避けてください:

  • OpenAI固有: logprobs、seed、完全なJSON Schema制約、reasoning_effort(o1シリーズ)
  • Claude固有: thinking、cache_control、mcp_servers
  • Gemini固有: grounding、codeExecution

汎用機能セット(すべてサポート):

  • 基本チャット会話(messages / contents)
  • ストリーミング出力(stream)
  • 温度制御(temperature、範囲の違いに注意)
  • ツール呼び出し(tools、フォーマットの違いに注意)
  • マルチモーダル入力(画像、フォーマットの違いに注意)
  • 停止シーケンス(stop / stop_sequences / stopSequences)

3. クロスプロトコル互換性をテスト

Section titled “3. クロスプロトコル互換性をテスト”

テスト環境で以下のシナリオを検証:

  1. 同じプロトコル、異なるモデル: OpenAIプロトコルがClaudeとGeminiモデルを正しく呼び出すことを確認。
  2. 異なるプロトコル、同じモデル: Claude MessagesとOpenAIプロトコルで同じClaudeモデルを呼び出した結果の一貫性を検証。
  3. ツール呼び出しラウンドトリップ: プロトコル間でのツール定義、呼び出し、結果渡しが正しいかテスト。
  4. 境界パラメータ: temperature: 1.5(OpenAI有効、Claude切り詰め必要)、n: 2(OpenAIサポート、Claude非サポート)などの境界ケースをテスト。
  5. エラー処理: アップストリームエラーがクライアントプロトコルフォーマットに正しく変換されるか検証。

プロトコル変換の問題をトラブルシューティングするために以下の情報を記録:

{
"request_id": "req_abc123",
"client_protocol": "openai",
"model_id": "claude-sonnet-4-5",
"upstream_protocol": "claude",
"conversion_required": true,
"dropped_params": ["frequency_penalty", "logprobs"],
"adjusted_params": {"temperature": {"original": 1.8, "adjusted": 1.0}},
"latency_ms": 856,
"conversion_overhead_ms": 8
}

主要メトリクス:

  • 変換成功率: プロトコル変換失敗による400エラーの割合。
  • 変換レイテンシ: プロトコル変換によって導入される追加レイテンシ(通常5-15ms)。
  • パラメータ削除率: 最も頻繁に削除されるパラメータ、ビジネスへの影響。
  • クロスプロトコルエラー率: OpenAI → Claude呼び出しのエラー率がOpenAI → OpenAIより高いか。

あるプロトコルから別のプロトコルに移行する場合:

  1. フェーズ1: デュアルライトテスト: 新プロトコル呼び出し結果は比較にのみ使用、ビジネスに影響なし。
  2. フェーズ2: 段階的切り替え: 小規模トラフィックを新プロトコルに切り替え、エラー率とレスポンス品質を監視。
  3. フェーズ3: 完全切り替え: 異常がないことを確認した後、すべてのトラフィックを切り替え。
  4. フェーズ4: 古いコードのクリーンアップ: 古いプロトコルのアダプターコードを削除。

各フェーズで検証が必要:

  • 機能の正確性(ツール呼び出し、マルチモーダル、ストリーミング出力)
  • レスポンス品質(異なるプロトコル/モデル組み合わせの出力の違い)
  • パフォーマンスメトリクス(レイテンシ、トークン使用量、コスト)
  • エラー処理(ネットワーク異常、レート制限、アップストリーム障害)

プロトコル変換により、クライアントとモデルを柔軟に選択できますが、ベストプラクティスはターゲットモデルのネイティブプロトコルを優先して使用することです。クロスプロトコル呼び出しが必要な場合は、テスト環境で十分に検証し、本番環境で変換関連のエラーとパフォーマンスメトリクスを監視してください。