Skip to main content
すべてのLLMレスポンスには、そのリクエストが消費したトークンを報告するusageオブジェクトが含まれます。Sunraは、呼び出したendpointのセマンティクスに従って使用量を報告します。Messagesのレスポンスは Anthropic の契約に従い、Chat Completions または Responses のレスポンスは OpenAI の契約に従います。 これらの形状が異なるのは意図的なものです。Chat Completionsのレスポンスを読むOpenAI SDKはOpenAIのセマンティクスを前提とし、Messagesのレスポンスを読むAnthropic SDKはAnthropicのセマンティクスを前提とします。各endpointは、単一の共通形状に押し込められるのではなく、それぞれの仕様が約束する内容を尊重します。
/v1/messages/v1/responsesはどちらもinput_tokensというフィールド名を使用しますが、両者で意味は同じではありません。Messagesでは新規入力のみを指します。Responsesではキャッシュされたトークンを含むプロンプト全体を指します。

Messages

/v1/messagesでは、3つの入力バケットは相互排他的です。同じトークンが二重に数えられることはないため、プロンプトの合計はそれらの和になります。
integer
新規の入力トークンのみ。両方のキャッシュバケットを除きます。
integer
このリクエストによってキャッシュに書き込まれたトークン。
integer
キャッシュからこのリクエストに提供されたトークン。
integer
モデルが生成したトークン。
integer
3つの入力バケットとoutput_tokensの合計。非streamingのレスポンスに存在します。
存在しないバケットやnullのバケットはゼロとして扱われます。

実例

同じ19,000トークンのプレフィックスをclaude-opus-4-8に対して2回送信した場合。1回目のリクエストはキャッシュを書き込み、2回目はそれを読み取ります。
コールドリクエスト(キャッシュ書き込み)
ウォームリクエスト(キャッシュ読み取り)
input_tokensは両方のリクエストで8のままです。8が毎回の真に新しい入力だからです。19,349トークンのプレフィックスは、作成バケットから読み取りバケットへ移動します。どちらのリクエストも合計は同じ19,359トークンになりますが、コストは同じではありません。キャッシュ書き込みとキャッシュ読み取りはそれぞれ独自のトークン単価で課金されるため、別々のバケットとして報告されています。

Chat Completions と Responses

これらのendpointは、OpenAIのセマンティクスをそのまま報告します。プロンプト数はプロンプト全体であり、キャッシュされたトークンはその部分集合として別途報告されます。
/v1/chat/completions
prompt_tokenscached_tokensを足し合わせると二重計上になります。これらのendpointで新規入力を求めるには、次のように引き算します。
同じルールが、input_tokensinput_tokens_details.cached_tokensを持つ/v1/responsesにも適用されます。

sunra_usage_semanticsマーカー

Sunraが正規化したレスポンスには、usageの内部にマーカーが含まれます。
このマーカーはレスポンスについての約束であり、個々のイベントやフィールドについての約束ではありません。非streamingのレスポンスではルートのusageオブジェクトに現れ、streamingのレスポンスでは入力バケットを運ぶイベントであるmessage_startに現れます。この値とともに存在する場合、このページに記載された保証が成り立ちます。すなわち、3つの入力バケットは相互排他的であり、total_tokensは — 存在する場合 — それらの和にoutput_tokensを加えた値です。 マーカーが存在しないことも、また約束です。 Sunraが正規化するのは、実測したレスポンス形状のみです。それ以外はアップストリームのプロバイダーからそのまま転送され、マーカーは付きません。マーカーのないレスポンスは、そのバケットについてSunraが保証しないレスポンスです。 レスポンスがどの規約に従っているかを数値から推測するのではなく、マーカーに対してアサートしてください。形状の推測こそ、このフィールドが置き換えるために存在するものです。「バケットの合計がプロンプト数を超えているのだから相互排他的に違いない」といったヒューリスティックは複数の規約で成立してしまい、いずれレスポンスを読み違えます。
マーカーが付くのは/v1/messagesのレスポンスのみです。Chat CompletionsとResponsesはOpenAIの仕様に従っており、マーカーは付きません。 この値はバージョン管理されています。これらのフィールドの意味に破壊的変更が入る場合は新しい値で出荷されるため、anthropic.exclusive.v1との等価チェックが黙って別の契約を読み始めることはありません。

Streaming

streamingのMessagesリクエストでは、使用量は2つのイベントに分かれて届きます。message_startが入力側とマーカーを運びます。終端のmessage_deltaが運ぶのはoutput_tokensのみです。マーカーへのアサートはmessage_startで行い、そのうえで通常どおり2つのイベントをマージすれば — 後のイベントの使用量を先のイベントに上書きする — 上記に記載した値が得られます。 total_tokensはstreamingのレスポンスでは省略されます。入力側と出力側の両方を知っている単一のイベントは存在しないため、ストリームの途中で計算した合計はいずれも誤りになります。ストリームが完了してから、ご自身でバケットを合算してください。

以前の挙動からの移行

Sunraは以前、/v1/messagesにおいてアップストリームのusageオブジェクトをそのまま転送していました。一部のプロバイダーの前段にある変換レイヤーは、キャッシュ作成トークンをinput_tokens中に畳み込みます。そのため、Anthropicの契約に従って3つのバケットを合算した呼び出し側は、キャッシュ作成トークンを二重に数えていました。
  • 3つのバケットを合算している場合、Anthropicの契約が記述するとおりであり、現在は正しい結果になります。お客様側での変更は不要です。
  • 以前の挙動を補正していた場合input_tokensからcache_creation_input_tokensを自分で引いていた、あるいは畳み込みを何らかの形でリバースエンジニアリングしていた場合 — やめてください。その補正は、すでに除外済みのトークンを引くことになり、入力を過小に見積もります。
  • total_tokensを読んでいる場合、これは引き続き全体の数を報告します。新規入力、両方のキャッシュバケット、そして出力です。
デプロイ日ではなくマーカーで変更を分岐させてください。そうすれば、マーカー付きのレスポンスと付いていないレスポンスの両方に対して、同じコードパスが正しく動作します。