Claude Code LLM gatewayのプロトコル — 送信リクエストの中身
Claude CodeがLLMゲートウェイに送るヘッダー・ストリーミング要件・機能パススルーの仕様と、転送を誤ったときに何が壊れるかをまとめます。
Claude Code LLM gatewayのプロトコルとは何を指すか
Claude CodeはANTHROPIC_BASE_URLに指定したLLMゲートウェイへ、特定のエンドポイント・ヘッダー・ボディフィールドの組み合わせでリクエストを送ります。このリクエストの中身そのものが公式ドキュメント「Claude Code gateway compatibility guide」の主題で、社内でLLMゲートウェイ製品を運用する担当者や、独自のゲートウェイを実装する開発者向けに書かれています。本記事はこのプロトコル全体の実装仕様を扱い、どちらのゲートウェイ製品を選ぶかはClaude Code LLM gatewayとは、モデルディスカバリ単体の挙動は後述のリンク先に譲ります。
紛らわしい点として、Anthropic製の自己ホスト型ゲートウェイ「Claude apps gateway」はGET /protocolという別のエンドポイントリファレンスを自前で持っています。これはサインイン・推論・managed settings・モデルディスカバリ・テレメトリを含むそのゲートウェイ固有のAPI一覧で、本記事が扱う「Claude Codeが送るリクエストの仕様」とは別のドキュメントです。Claude apps gatewayを使うだけなら本記事の詳細を意識する必要はなく、社内で別製品のゲートウェイを運用・実装する場合にこそ必要になる仕様です。
3つのAPI形式とエンドポイント
ゲートウェイはClaude Codeクライアント向けに、次の3形式のうち少なくとも1つを実装する必要があります。クライアント側はどの形式を使うかを環境変数で選びます。
| 形式 | 選択する環境変数 | 主なエンドポイント |
|---|---|---|
| Anthropic Messages | 選択する環境変数ANTHROPIC_BASE_URL | 主なエンドポイント/v1/messages、/v1/messages/count_tokens(任意) |
| Amazon Bedrock InvokeModel | 選択する環境変数ANTHROPIC_BEDROCK_BASE_URL + CLAUDE_CODE_USE_BEDROCK=1 | 主なエンドポイント/model/{model}/invoke、/model/{model}/invoke-with-response-stream、/model/{model}/count-tokens(任意) |
| Google Cloud's Agent Platform rawPredict | 選択する環境変数ANTHROPIC_VERTEX_BASE_URL + CLAUDE_CODE_USE_VERTEX=1 | 主なエンドポイント:rawPredict、:streamRawPredict、count-tokens:rawPredict(任意) |
Microsoft FoundryとClaude Platform on AWSは、それぞれ専用の環境変数(ANTHROPIC_FOUNDRY_BASE_URL・ANTHROPIC_AWS_BASE_URL)でルーティングされますが、実装するのはAnthropic Messages形式です。ただしClaude Platform on AWS向けのゲートウェイは、そのプラットフォームが全リクエストで要求するanthropic-workspace-idヘッダーも転送する必要があります。
トークンカウント系のエンドポイントだけは省略可能です。無い場合、Claude Codeは推論エンドポイント経由でコンテキスト使用量を数える処理にフォールバックします。
Anthropic Messages形式の推論リクエストは実際には/v1/messages?beta=trueというクエリパラメータ付きのURLに飛びます。ゲートウェイをフルURLの完全一致でルーティングすると、この?beta=trueが付いた瞬間にマッチしなくなるため、実装時はパス(/v1/messages)側でマッチさせる必要があります。対応API形式とサブスクリプションの関係はClaude CodeのLLMゲートウェイ互換性で扱っています。
リクエストヘッダーの転送要否
Claude CodeがAPIリクエストに付けるヘッダーのうち、そのままアップストリームへ転送すべきものと、ゲートウェイ側で消費してよい(転送必須ではない)ものが分かれています。
| ヘッダー | 扱い | 説明 |
|---|---|---|
anthropic-version | 扱い転送必須 | 説明現在の値は2023-06-01 |
anthropic-beta | 扱い転送必須 | 説明カンマ区切りの機能フラグ。個別の値を許可リスト化せず、そのまま丸ごと転送する(Claude Codeのリリースごとに値が増減するため) |
Authorization / x-api-key | 扱い消費してよい | 説明開発者のゲートウェイ資格情報 |
x-claude-code-session-id | 扱い消費してよい | 説明セッション単位でリクエストを集約するための識別子 |
x-claude-code-agent-id | 扱い消費してよい | 説明サブエージェントが発行したリクエストにのみ付く識別子。並列エージェントへのコスト帰属に使える |
x-claude-code-parent-agent-id | 扱い消費してよい | 説明ネストしたエージェントの親を示す識別子 |
anthropic-betaは個別の値をホワイトリスト化してはいけません。Claude Codeのバージョンが上がるたびに新しい値が追加されるため、観測済みの値だけを許可するゲートウェイは、次に追加される機能のヘッダーをエラーを出さずに落とし、その機能をリリース直後から壊します。例としてcontext-management-2025-06-27のようなanthropic-beta値は今後も増え続ける前提で、ヘッダーは丸ごと転送するのが正しい実装です。
ストリーミングを止めないための要件
Claude Codeはレスポンスを届いた順に読むストリーミングクライアントです。ゲートウェイが完全なレスポンスをバッファしてから中継すると、Claude Code側の表示が止まります。
ANTHROPIC_BASE_URLやANTHROPIC_AWS_BASE_URL経由の接続では、Claude Codeはゲートウェイが中継する全バイト(SSEのpingイベントやコメント行を含む)を数えており、データが300秒流れないとストリームを打ち切ります。アップストリームからのpingは長い思考の間の唯一のトラフィックなので、ゲートウェイがこれを取り除いたりバッファしたりすると、その無通信の区間でストリームが打ち切られてしまいます。Amazon Bedrockのバイナリイベントストリームのようにpingを一切送らない上流を中継する場合は、無通信の区間でゲートウェイ自身がpingイベントを発行する必要があります。
Amazon Bedrock形式のクライアントを扱う場合は、InvokeModelWithResponseStreamのレスポンスボディとContent-Type: application/vnd.amazon.eventstreamヘッダーを無変更で中継し、Server-Sent Eventsへ変換してはいけません。
ANTHROPIC_BEDROCK_BASE_URL・ANTHROPIC_VERTEX_BASE_URL・ANTHROPIC_FOUNDRY_BASE_URL経由の接続はこのバイト単位の監視の対象外です。代わりに5分のアイドルタイムアウトが働きますが、ANTHROPIC_BEDROCK_BASE_URL経由に限ってはCLAUDE_ENABLE_BYTE_WATCHDOG_BEDROCKを設定するとバイト単位の監視を追加できます。
システムプロンプトのアトリビューションブロックとキャッシュ
Claude Codeはシステムプロンプトの先頭に、クライアントバージョンと会話由来のフィンガープリントを含む短いアトリビューションブロックを付加します。api.anthropic.comはこのブロックがsystem配列の先頭ブロックとして無変更で届いた場合にのみ処理前に取り除くため、ファーストパーティのプロンプトキャッシュには影響しません。それ以外のアップストリームは、このブロックをプロンプトの一部としてそのまま受け取ります。
この取り除き処理は位置に依存します。system配列を受け取ったとおりの順序・形のまま、ブロックを先頭に保ったまま転送する必要があります。別のシステムブロックを前に追加する、配列の順序を変える、単一の文字列に変換する、といった操作はすべてこの取り除き処理を無効にします。その結果、ブロックがモデルとプロンプトキャッシュキーの両方に影響してしまいます。ゲートウェイ側でシステムコンテンツを作り替える必要がある場合は、CLAUDE_CODE_ATTRIBUTION_HEADER=0を設定してClaude Code側でブロックの付加自体を止めるのが正しい対処です。
機能パススルー — ヘッダーを落とすと何が壊れるか
capability(機能)を追加するボディフィールドは、それぞれ対応するanthropic-betaヘッダーとペアで送られます。ヘッダーだけを落としてボディを通す、あるいはAnthropic形式のボディを別スキーマの上流にそのまま転送するようなゲートウェイは、ハードな400エラーを発生させます。ヘッダーとボディの両方が揃って欠けているときだけ、機能はエラーを出さずに無効化されます。
| 機能 | 壊れたときの症状 | 対処 |
|---|---|---|
適応的推論(Adaptive reasoning、thinking: {"type": "adaptive"}) | 壊れたときの症状アップストリームのモデルがこのフィールドを受け付けない場合400 | 対処アップストリームをアップグレードするか、Opus 4.6/Sonnet 4.6ではCLAUDE_CODE_DISABLE_ADAPTIVE_THINKING=1 |
| コンテキスト管理(Context management) | 壊れたときの症状Extra inputs are not permittedを伴う400。Anthropic形式を受けてAmazon Bedrockへ転送するゲートウェイで起きやすい | 対処ヘッダーとボディ両方を転送するかCLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1 |
| 拡張コンテキスト(Extended context)/ 交互思考(Interleaved thinking) | 壊れたときの症状ヘッダーが落ちると気づかないうちに機能が使えなくなる(エラーは出ない) | 対処anthropic-betaをそのまま転送する |
ツールスキーマのbetaフィールド(strict・defer_loading等) | 壊れたときの症状ヘッダーなしでボディだけ通ると、未知のツールスキーマフィールドを名指しした400 | 対処両方を転送するかCLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1 |
エフォート指定 / 構造化出力(Structured outputs、output_config) | 壊れたときの症状Amazon Bedrock・Google Cloud's Agent Platform上流でoutput_configを名指しした400 | 対処フィールドと対応ヘッダーを一緒に転送する |
プロンプトキャッシュ(Prompt caching、cache_control) | 壊れたときの症状エラーは出ず、毎ターン非キャッシュ扱いで課金される(usageのキャッシュ活動がほぼ無い状態で発覚) | 対処cache_controlをどこに付いていても無変更で転送する |
CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1は、context managementやツールのbetaフィールドを含む先行機能の送信を全プロバイダで止めますが、adaptive reasoningには効きません(betaではなくモデル単位で選択されるため)。サブスクリプション認証に必要なOAuth capabilityも、この変数では抑制されません。
モデルディスカバリの仕組み
本記事ではプロトコル実装に必要な範囲だけを扱います。有効化条件の詳細・フィルタ条件・キャッシュの挙動・ピッカー統合はLLMゲートウェイのモデルディスカバリはどう動くかにまとめています。
ANTHROPIC_BASE_URLがAnthropic Messages形式を実装したゲートウェイを指しているとき、Claude Codeは起動時にゲートウェイの/v1/modelsを呼び、返ってきたモデルを/modelピッカーに追加できます。この機能は既定でオフです。共有のAPIキーを使うゲートウェイがキーの届く全モデルを全ユーザーに見せてしまわないよう、開発者が明示的にCLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1を設定して有効化します。
export ANTHROPIC_BASE_URL="https://gateway.example.com"
export CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1ゲートウェイ実装者が最低限守るべき点は、/v1/modelsが設定したベースURLで直接応答することです。リクエストは3秒タイムアウトで、リダイレクトはすべて失敗扱いになります(資格情報がリダイレクト先に漏れないようにするため)。レスポンスはdata配列でidを返す形式です。
{
"data": [
{ "id": "claude-sonnet-4-6", "display_name": "Claude Sonnet 4.6" },
{ "id": "claude-opus-4-8" }
]
}エラーの自動リトライが前提にしていること
アップストリームがthinkingフィールドやthinking signature、会話途中のrole: "system"メッセージ、それらに付いたcache_controlマーカーを拒否すると、Claude Codeはリクエストをリトライしてその機能を会話の残り全体で無効化します。この自動リトライはアップストリームのエラー文言に基づいてマッチするため、ゲートウェイがエラーレスポンスのボディを書き換えずに転送することが前提です。独自のエンベロープでエラーを包むゲートウェイは、ステータスコードを保っていてもこのリトライ経路を壊します。ただしエンベロープのメッセージにcapability_rejected:のような安定したトークンを含めれば、その限りではありません。一方、context managementやツールスキーマフィールドの拒否によるエラーはリトライされず、そのまま開発者に届きます。
まとめ
Claude Codeが送るリクエストは、3つのAPI形式・anthropic-*ヘッダーの丸ごと転送・SSEpingを落とさないストリーミング・アトリビューションブロックの位置保持という4点が守られて初めて成立します。ヘッダーとボディフィールドはペアで送られる機能が多く、片方だけを落とすと400エラーか、エラーが出ないままキャッシュが効かなくなる状態という2種類の壊れ方をします。モデルディスカバリは既定オフの任意機能で、具体的な挙動はモデルディスカバリの記事で扱っています。自前でゲートウェイを実装・運用する場合は、この仕様書を観測済みの値だけに固定せず、常に「開いたリスト」として転送する実装にしておくと、Claude Codeの新しいリリースでも機能が壊れにくくなります。具体的な接続手順はClaude CodeをLLMゲートウェイに接続する方法、組織展開の手順はClaude CodeのLLMゲートウェイをロールアウトする手順を参照してください。