Claude Messages プロトコル
Claude Messages は Anthropic のネイティブ会話プロトコルです。クライアントが既に Anthropic 仕様に従って開発されている場合、Base URL と API Key を RouteAPI に置き換えるだけで、リクエスト構造を変更することなく直接使用できます。
プロトコル概要
Section titled “プロトコル概要”Claude Messages は messages 配列で複数ターンの会話を表現し、独立した system フィールドでシステムプロンプトを表現し、max_tokens の明示的な宣言を要求します。OpenAI 互換フォーマットと比較して、コンテンツブロック構造がより統一されています。テキスト、画像、ツール呼び出し、ツール結果はすべて同じ配列内の異なる type です。
適用シナリオ:
| シナリオ | 説明 |
|---|---|
| Claude Code | Anthropic 公式コーディングエージェント、/v1/messages のみ認識 |
| Anthropic SDK | anthropic Python / TypeScript SDK、base_url を変更するだけ |
| ネイティブメッセージフォーマットクライアント | content block 構造で既にプロンプトを組織しているアプリケーション |
| 拡張思考とプロンプトキャッシング | thinking、cache_control などの Claude 特有の機能に依存 |
クライアントが OpenAI プロトコルのみをサポートしている場合は、Chat Completions を使用してください。RouteAPI は内部で必要なフォーマット適応を完了しますが、クライアントがネイティブにサポートするプロトコルを優先選択することで、互換性が最も良くなります。
エンドポイント詳細
Section titled “エンドポイント詳細”POST /v1/messages完全なアドレス:
https://api.routeapi.ai/v1/messagesリクエストヘッダーは 2 つの認証方法をサポートし、両方とも同じ RouteAPI Token を使用します:
Authorization: Bearer sk-your-routeapi-tokenContent-Type: application/jsonx-api-key: sk-your-routeapi-tokenanthropic-version: 2023-06-01Content-Type: application/jsonx-api-key は Anthropic SDK のデフォルトの書き方です。RouteAPI は /v1/messages パス上で自動的にそれを Token として認識するため、公式 SDK は追加の設定を必要としません。anthropic-version はそのまま上流に透過され、公式 SDK が自動的に付加します。
リクエストフォーマット
Section titled “リクエストフォーマット”| フィールド | タイプ | 必須 | 説明 |
|---|---|---|---|
model | string | はい | モデル ID、現在のアカウントで利用可能なモデルである必要があります |
messages | array | はい | 会話メッセージリスト、少なくとも 1 つ、role は交互に出現する必要があります |
max_tokens | integer | はい | 最大出力トークン数、Claude プロトコルで強制的に要求されます |
system | string/array | いいえ | システムプロンプト、独立したフィールド、messages には入れません |
temperature | number | いいえ | サンプリング温度、値は 0 から 1 |
top_p | number | いいえ | nucleus sampling パラメータ |
top_k | integer | いいえ | 確率が最も高い K 個のトークンからのみサンプリング |
stream | boolean | いいえ | SSE ストリーミング出力を使用するかどうか |
stop_sequences | array | いいえ | カスタム停止シーケンス |
tools | array | いいえ | ツール定義リスト |
tool_choice | object | いいえ | ツール選択戦略 |
thinking | object | いいえ | 拡張思考設定、モデルがサポートしているかどうかに依存 |
metadata | object | いいえ | リクエストメタ情報、Claude 特有 |
max_tokens は必須パラメータ
Section titled “max_tokens は必須パラメータ”これは OpenAI から移行する際に最も陥りやすい罠です。OpenAI の max_tokens は省略時にモデルのデフォルト上限を使用しますが、Claude プロトコルにはデフォルト値がなく、欠落している場合は上流が直接 invalid_request_error を返します。
{ "model": "claude-sonnet-4-5", "max_tokens": 1024, "messages": [{ "role": "user", "content": "こんにちは" }]}max_tokens は出力上限であり、入力トークンは含まれず、正確な長さの約束でもありません。モデルは早期に終了する可能性があり(stop_reason: "end_turn")、ちょうど切り捨てられる可能性もあります(stop_reason: "max_tokens")。本番環境では、ビジネスで期待される応答の長さに基づいて設定し、ある程度の余裕を残し、同時に stop_reason をチェックして切り捨てられたかどうかを判断することをお勧めします。
system は独立したフィールド
Section titled “system は独立したフィールド”Claude プロトコルは role: "system" のメッセージを受け入れません。システムプロンプトはリクエストのトップレベルの system フィールドに配置する必要があり、messages 配列には user と assistant のみを含めることができます。
正しい書き方:
{ "model": "claude-sonnet-4-5", "max_tokens": 1024, "system": "あなたは厳密な技術アシスタントです。回答は簡潔に保ってください。", "messages": [{ "role": "user", "content": "API ゲートウェイとは何かを説明してください" }]}誤った書き方(Claude プロトコルは拒否します):
{ "messages": [ { "role": "system", "content": "あなたは厳密な技術アシスタントです。" }, { "role": "user", "content": "API ゲートウェイとは何かを説明してください" } ]}system は配列形式もサポートしており、異なる段落に個別にプロンプトキャッシュを設定するために使用されます:
{ "system": [ { "type": "text", "text": "あなたはコードレビューアシスタントです。" }, { "type": "text", "text": "以下はプロジェクトのコーディング規約の全文です……", "cache_control": { "type": "ephemeral" } } ]}metadata
Section titled “metadata”metadata はリクエストのメタ情報を運ぶために使用され、現在は user_id フィールドのみがあり、上流の不正使用検出に使用されます。メールアドレスや電話番号など、個人を特定できる情報をここに入れないでください。ハッシュ値または内部 ID を渡すことをお勧めします。
{ "metadata": { "user_id": "a3f1c2d4e5b6" }}メッセージ構造
Section titled “メッセージ構造”messages 配列内の各メッセージには role と content の 2 つのフィールドが含まれています。role は user または assistant のみで、交互に出現する必要があり、最初は user である必要があります。
content は 2 つの形式をサポートしています。文字列は単一テキストの省略形です:
{ "role": "user", "content": "RouteAPI を一文で紹介してください" }配列形式はコンテンツブロックで構成され、各ブロックは type で区別されます:
| type | 出現位置 | 説明 |
|---|---|---|
text | user / assistant | プレーンテキストコンテンツ |
image | user | 画像入力、base64 と URL をサポート |
document | user | ドキュメント入力、モデルがサポートしているかどうかに依存 |
tool_use | assistant | モデルがツール呼び出しを要求 |
tool_result | user | クライアントから返されたツール実行結果 |
thinking | assistant | 拡張思考コンテンツブロック |
マルチモーダルコンテンツ
Section titled “マルチモーダルコンテンツ”画像は source フィールドを通じて渡されます。base64 方式では media_type も同時に提供する必要があります:
{ "role": "user", "content": [ { "type": "image", "source": { "type": "base64", "media_type": "image/jpeg", "data": "/9j/4AAQSkZJRgABAQAAAQ..." } }, { "type": "text", "text": "この画像にはどのようなコントロールがありますか?" } ]}URL 方式はより簡潔ですが、画像アドレスが上流からアクセス可能である必要があります:
{ "role": "user", "content": [ { "type": "image", "source": { "type": "url", "url": "https://example.com/screenshot.png" } }, { "type": "text", "text": "このインターフェースのレイアウトを説明してください" } ]}テキストブロックを画像ブロックの後に配置すると、通常より良い効果が得られます。1 回のリクエストで複数の画像を配置できますが、入力トークンが大幅に増加するため、最初にサイズを圧縮することをお勧めします。
ツール呼び出し
Section titled “ツール呼び出し”tools 定義フォーマット
Section titled “tools 定義フォーマット”Claude のツール定義はフラットな構造で、パラメータ schema フィールドは input_schema と呼ばれます:
{ "tools": [ { "name": "get_weather", "description": "指定された都市の現在の天気を照会します。都市名は中国語のフルネームを使用します。", "input_schema": { "type": "object", "properties": { "city": { "type": "string", "description": "都市名、例: 東京" }, "unit": { "type": "string", "enum": ["celsius", "fahrenheit"] } }, "required": ["city"] } } ]}OpenAI のネストされた構造と比較して、違いは Claude には外側の type: "function" ラッパーがなく、function ネストレイヤーもなく、parameters が input_schema に名前変更されていることです:
{ "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "指定された都市の現在の天気を照会します。", "parameters": { "type": "object", "properties": {} } } } ]}description の品質は、モデルがツールを正しく選択するかどうかを直接決定するため、用途、パラメータフォーマット、境界条件を明確に記述することをお勧めします。
tool_choice オプション
Section titled “tool_choice オプション”| 書き方 | 動作 |
|---|---|
{ "type": "auto" } | モデルがツールを呼び出すかどうかを自分で決定、デフォルト値 |
{ "type": "any" } | ツールを呼び出す必要があるが、モデルがどれを呼び出すかを選択 |
{ "type": "tool", "name": "get_weather" } | 指定されたツールを強制的に呼び出し |
{ "type": "none" } | ツール呼び出しを禁止 |
"disable_parallel_tool_use": true を追加すると、モデルが一度に 1 つのツール呼び出しのみを開始するように制限できます。
ツール結果の受け渡し
Section titled “ツール結果の受け渡し”ツール呼び出しは完全な会話のやり取りです。モデルが tool_use ブロックを返した後、元の assistant メッセージと実行結果を一緒に返す必要があります。
ステップ 1、モデルがツール呼び出しリクエストを返します:
{ "role": "assistant", "content": [ { "type": "text", "text": "東京の天気を調べてみます。" }, { "type": "tool_use", "id": "toolu_01A09q90qw90lq917835lq9", "name": "get_weather", "input": { "city": "東京", "unit": "celsius" } } ]}ステップ 2、この assistant メッセージをそのまま messages に追加し、次に結果を運ぶ user メッセージを追加します。tool_use_id は前のステップの id と完全に一致する必要があります:
{ "role": "user", "content": [ { "type": "tool_result", "tool_use_id": "toolu_01A09q90qw90lq917835lq9", "content": "東京、晴れ、気温 23 摂氏度、湿度 45%。" } ]}ツール実行が失敗した場合は is_error マーカーを使用して、モデルに戦略を変更する必要があることを知らせ、再試行しないようにします:
{ "type": "tool_result", "tool_use_id": "toolu_01A09q90qw90lq917835lq9", "content": "天気サービスがタイムアウトし、データを取得できませんでした。", "is_error": true}tool_result は user ロールに属し、Claude プロトコルには OpenAI のような独立した role: "tool" はありません。モデルが一度に複数の tool_use ブロックを返した場合、対応するすべての tool_result は同じ user メッセージの content 配列に配置する必要があります。
応答フォーマット
Section titled “応答フォーマット”{ "id": "msg_01XFDUDYJgAACzvnptvVoYEL", "type": "message", "role": "assistant", "model": "claude-sonnet-4-5", "content": [ { "type": "text", "text": "RouteAPI は複数の AI モデルプロバイダーを統一的に管理する API ゲートウェイです。" } ], "stop_reason": "end_turn", "stop_sequence": null, "usage": { "input_tokens": 24, "output_tokens": 18 }}content は常に配列であり、1 つのテキストセグメントのみの場合でも同様です。クライアントは content[0] がテキストブロックであると仮定しないでください。モデルが拡張思考を有効にするか、ツール呼び出しを開始すると、最初のブロックは thinking または tool_use になる可能性があります。
stop_reason の値:
| 値 | 意味 |
|---|---|
end_turn | モデルが自然に応答を終了 |
max_tokens | max_tokens 上限に達して切り捨て |
stop_sequence | stop_sequences 内のシーケンスにヒット |
tool_use | モデルがツール呼び出しを要求、結果を待機中 |
ストリーミング応答
Section titled “ストリーミング応答”stream: true を設定すると SSE が返されます。Claude のストリーミングフォーマットは OpenAI とかなり異なります。各イベントには明確な event: タイプ名があり、終了マーカーは message_stop イベントであり、data: [DONE] ではありません。
event: message_startdata: {"type":"message_start","message":{"id":"msg_01XFD","type":"message","role":"assistant","content":[],"model":"claude-sonnet-4-5","usage":{"input_tokens":24,"output_tokens":1}}}
event: content_block_startdata: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
event: content_block_deltadata: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"RouteAPI"}}
event: content_block_deltadata: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" は"}}
event: content_block_stopdata: {"type":"content_block_stop","index":0}
event: message_deltadata: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":18}}
event: message_stopdata: {"type":"message_stop"}イベントタイプの説明:
| イベント | 説明 |
|---|---|
message_start | メッセージ開始、初期 usage を運ぶ(この時点で output_tokens は不正確) |
content_block_start | コンテンツブロックが開始、index が位置を識別 |
content_block_delta | 増分コンテンツ、テキストは text_delta、ツールパラメータは input_json_delta |
content_block_stop | 現在のコンテンツブロックが終了 |
message_delta | メッセージレベルの増分、最終的な stop_reason と累積 output_tokens を運ぶ |
message_stop | 応答全体が終了 |
ping | ハートビートイベント、無視可能 |
error | ストリーム途中でエラー |
ツール呼び出しのパラメータは JSON 文字列を断片的に返すため、すべての input_json_delta の partial_json を連結して完全にした後に解析する必要があります:
event: content_block_deltadata: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"{\"city\":"}}
event: content_block_deltadata: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"\"東京\"}"}}index でグループ化して累積し、連結プロセス中に中間状態を解析しようとしないでください。
usage フィールド
Section titled “usage フィールド”| フィールド | 説明 |
|---|---|
input_tokens | 入力トークン数、キャッシュヒット部分を含まない |
output_tokens | 出力トークン数 |
cache_creation_input_tokens | プロンプトキャッシュに書き込まれたトークン数 |
cache_read_input_tokens | プロンプトキャッシュから読み取られたトークン数 |
server_tool_use | サーバーサイドツール使用量、例: web_search_requests |
ストリーミング応答では、output_tokens は message_delta イベント内の値を基準にする必要があります。message_start 内のものは初期プレースホルダーです。課金基準はコンソールログに基づいており、実際にサポートされるフィールドは選択したモデルによって異なります。
OpenAI フォーマットとの比較
Section titled “OpenAI フォーマットとの比較”パラメータマッピングテーブル
Section titled “パラメータマッピングテーブル”| Claude Messages | OpenAI Chat Completions | 差異説明 |
|---|---|---|
model | model | 一致 |
system(トップレベルフィールド) | messages[0] の role: "system" | 位置が異なる、Claude は system メッセージを受け入れない |
messages | messages | Claude は user / assistant の交互のみを許可 |
max_tokens | max_tokens / max_completion_tokens | Claude は必須、OpenAI はオプション |
stop_sequences | stop | 名前が異なる |
temperature | temperature | Claude の上限は 1、OpenAI の上限は 2 |
top_k | 対応なし | OpenAI はサポートしていない |
tools[].input_schema | tools[].function.parameters | 階層とフィールド名が両方異なる |
tool_choice: {"type":"any"} | tool_choice: "required" | 書き方が異なる |
metadata.user_id | user | 位置が異なる |
thinking | reasoning_effort | 制御方法が異なる |
| 対応なし | n | Claude は一度に複数の候補を生成することをサポートしていない |
| 対応なし | frequency_penalty / presence_penalty | Claude はサポートしていない |
| 対応なし | response_format | Claude はツールまたはプロンプトを使用して出力構造を制約 |
応答構造の差異:
| 項目 | Claude Messages | OpenAI Chat Completions |
|---|---|---|
| トップレベルコンテンツ | content 配列 | choices[0].message |
| テキスト位置 | content[0].text | choices[0].message.content |
| 終了理由 | stop_reason | finish_reason |
| ツール呼び出し | content 内の tool_use ブロック | message.tool_calls |
| ツール結果ロール | user メッセージ内の tool_result ブロック | 独立した role: "tool" |
| 入力使用量 | usage.input_tokens | usage.prompt_tokens |
| 出力使用量 | usage.output_tokens | usage.completion_tokens |
| 合計フィールド | なし、手動で加算する必要がある | usage.total_tokens |
| ストリーミング終了 | message_stop イベント | data: [DONE] |
移行の注意事項
Section titled “移行の注意事項”OpenAI から Claude Messages に移行する際は、次の順序で確認してください:
- system メッセージを
messages配列からトップレベルsystemフィールドに移動します。 max_tokensを追加します。これは必須項目です。messagesの最初がuserであることを確認し、ロールが厳密に交互であり、連続する同じロールのメッセージがないことを確認します。- ツール定義から
typeとfunctionラッパーレイヤーを削除し、parametersをinput_schemaに名前変更します。 - ツール結果を
role: "tool"からuserメッセージ内のtool_resultブロックに変更し、tool_use_idを揃えます。 temperatureが元々1より大きい場合は、Claude の値の範囲内に下げる必要があります。- 応答解析を
content配列を反復処理し、typeでディスパッチするように変更し、固定インデックスを仮定しないでください。 - ストリーミング解析を
event:タイプでディスパッチするように変更し、終了条件をmessage_stopに置き換えます。
改造コストが高い場合は、OpenAI プロトコルを使用して Claude シリーズモデルを呼び出し続けることもでき、RouteAPI がフォーマット変換を完了します。トレードオフは、Claude 特有の機能の一部(拡張思考の完全な制御、細粒度のプロンプトキャッシング)が OpenAI フォーマットでは完全に表現できないことです。
基本的な会話
Section titled “基本的な会話”curl:
curl https://api.routeapi.ai/v1/messages \ -H "x-api-key: $ROUTEAPI_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-5", "max_tokens": 1024, "system": "あなたは厳密な技術アシスタントです。回答は簡潔に保ってください。", "messages": [ { "role": "user", "content": "RouteAPI を一文で紹介してください" } ] }'Anthropic Python SDK、base_url を変更するだけ:
import osfrom anthropic import Anthropic
client = Anthropic( api_key=os.environ["ROUTEAPI_KEY"], base_url="https://api.routeapi.ai",)
message = client.messages.create( model="claude-sonnet-4-5", max_tokens=1024, system="あなたは厳密な技術アシスタントです。回答は簡潔に保ってください。", messages=[ {"role": "user", "content": "RouteAPI を一文で紹介してください"}, ],)
print(message.content[0].text)print(message.usage.input_tokens, message.usage.output_tokens)base_url はドメインまで入力すれば良く、SDK が自動的に /v1/messages を追加します。ストリーミング呼び出しには client.messages.stream() を使用します:
with client.messages.stream( model="claude-sonnet-4-5", max_tokens=1024, messages=[{"role": "user", "content": "API ゲートウェイとは何かを段階的に説明してください"}],) as stream: for text in stream.text_stream: print(text, end="", flush=True)
final = stream.get_final_message() print() print(final.stop_reason, final.usage.output_tokens)curl、base64 を使用:
curl https://api.routeapi.ai/v1/messages \ -H "x-api-key: $ROUTEAPI_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-5", "max_tokens": 1024, "messages": [ { "role": "user", "content": [ { "type": "image", "source": { "type": "base64", "media_type": "image/jpeg", "data": "'"$(base64 -w 0 screenshot.jpg)"'" } }, { "type": "text", "text": "この画像にはどのような UI コントロールがありますか?" } ] } ] }'Python SDK:
import base64import osfrom anthropic import Anthropic
client = Anthropic( api_key=os.environ["ROUTEAPI_KEY"], base_url="https://api.routeapi.ai",)
with open("screenshot.jpg", "rb") as f: image_data = base64.standard_b64encode(f.read()).decode("utf-8")
message = client.messages.create( model="claude-sonnet-4-5", max_tokens=1024, messages=[ { "role": "user", "content": [ { "type": "image", "source": { "type": "base64", "media_type": "image/jpeg", "data": image_data, }, }, {"type": "text", "text": "この画像にはどのような UI コントロールがありますか?"}, ], } ],)
print(message.content[0].text)ツール呼び出し
Section titled “ツール呼び出し”結果の受け渡しを含む完全な 2 ラウンドトリップ:
import jsonimport osfrom anthropic import Anthropic
client = Anthropic( api_key=os.environ["ROUTEAPI_KEY"], base_url="https://api.routeapi.ai",)
tools = [ { "name": "get_weather", "description": "指定された都市の現在の天気を照会します。都市名は中国語のフルネームを使用します。", "input_schema": { "type": "object", "properties": { "city": {"type": "string", "description": "都市名、例: 東京"}, "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}, }, "required": ["city"], }, }]
def get_weather(city: str, unit: str = "celsius") -> str: # ここを実際の天気サービス呼び出しに置き換えます return f"{city}、晴れ、気温 23 摂氏度、湿度 45%。"
messages = [{"role": "user", "content": "東京の天気はどうですか?"}]
response = client.messages.create( model="claude-sonnet-4-5", max_tokens=1024, tools=tools, messages=messages,)
# stop_reason が tool_use の場合のみツールを実行して返す必要がありますif response.stop_reason == "tool_use": # 元の assistant メッセージをそのまま追加する必要があります。そうしないと tool_use_id が揃いません messages.append({"role": "assistant", "content": response.content})
tool_results = [] for block in response.content: if block.type != "tool_use": continue try: result = get_weather(**block.input) is_error = False except Exception as exc: result = f"ツール実行失敗: {exc}" is_error = True tool_results.append( { "type": "tool_result", "tool_use_id": block.id, "content": result, "is_error": is_error, } )
# 同じラウンドのすべてのツール結果を 1 つの user メッセージに入れます messages.append({"role": "user", "content": tool_results})
response = client.messages.create( model="claude-sonnet-4-5", max_tokens=1024, tools=tools, messages=messages, )
print(response.content[0].text)対応する curl 第 2 ラウンドリクエスト:
curl https://api.routeapi.ai/v1/messages \ -H "x-api-key: $ROUTEAPI_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-5", "max_tokens": 1024, "tools": [ { "name": "get_weather", "description": "指定された都市の現在の天気を照会します。", "input_schema": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } ], "messages": [ { "role": "user", "content": "東京の天気はどうですか?" }, { "role": "assistant", "content": [ { "type": "tool_use", "id": "toolu_01A09q90qw90lq917835lq9", "name": "get_weather", "input": { "city": "東京" } } ] }, { "role": "user", "content": [ { "type": "tool_result", "tool_use_id": "toolu_01A09q90qw90lq917835lq9", "content": "東京、晴れ、気温 23 摂氏度、湿度 45%。" } ] } ] }'互換性の注意
Section titled “互換性の注意”- パラメータの実際のサポートレベルは、選択したモデルと上流サービスの機能に依存します。
thinking、cache_control、mcp_serversなどのオプション機能は、まずテスト環境で検証することをお勧めします。 - 明示的に
0またはfalseを渡すオプションパラメータは、ユーザーの明示的な設定と見なされ、デフォルト値として破棄されません。 - 本番環境では、モデル ID を固定することをお勧めします。一時的なエイリアスや表示名に依存しないでください。
- 各リクエストの request ID、モデル ID、ステータスコード、トークン使用量を記録して、レイテンシとコストの異常をトラブルシューティングしやすくします。
- エラー応答は Claude の
{"type": "error", "error": {...}}構造に従います。詳細は エラー処理 を参照してください。