> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sunra.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Token 用量

每個 LLM 回應都帶有一個 `usage` 物件，回報該請求消耗的 token。Sunra 會依照您所呼叫 endpoint 的語意來回報用量：Messages 回應遵循 Anthropic 的約定，Chat Completions 或 Responses 回應則遵循 OpenAI 的約定。

這些結構的差異是刻意為之。讀取 Chat Completions 回應的 OpenAI SDK 會假定 OpenAI 語意，而讀取 Messages 回應的 Anthropic SDK 會假定 Anthropic 語意。每個 endpoint 都遵守其自身規格所承諾的內容，而不是被強行套進單一共用結構。

| Endpoint               | 提示計數欄位          | 快取的 token 是否計入其中？                              |
| ---------------------- | --------------- | ---------------------------------------------- |
| `/v1/messages`         | `input_tokens`  | 否 — 三個輸入桶互斥                                    |
| `/v1/chat/completions` | `prompt_tokens` | 是 — 快取的 token 是其子集，細節見 `prompt_tokens_details` |
| `/v1/responses`        | `input_tokens`  | 是 — 快取的 token 是其子集，細節見 `input_tokens_details`  |

<Warning>
  `/v1/messages` 和 `/v1/responses` 都使用 `input_tokens` 這個欄位名稱，但它在兩者上的含義並不相同。在 Messages 上，它僅代表全新的輸入。在 Responses 上，它代表整個提示，包含快取的 token。
</Warning>

## Messages

在 `/v1/messages` 上，三個輸入桶是**互斥**的。沒有任何 token 會被計算兩次，因此提示總量就是它們的總和：

```
total prompt = input_tokens + cache_creation_input_tokens + cache_read_input_tokens
```

<ResponseField name="input_tokens" type="integer">
  僅為全新的輸入 token。不包含兩個快取桶。
</ResponseField>

<ResponseField name="cache_creation_input_tokens" type="integer">
  本次請求寫入快取的 token。
</ResponseField>

<ResponseField name="cache_read_input_tokens" type="integer">
  從快取提供給本次請求的 token。
</ResponseField>

<ResponseField name="output_tokens" type="integer">
  模型生成的 token。
</ResponseField>

<ResponseField name="total_tokens" type="integer">
  三個輸入桶加上 `output_tokens`。存在於非 streaming 回應中。
</ResponseField>

缺席或為 `null` 的桶視為零。

### 實例演算

對 `claude-opus-4-8` 送出同一段 19,000 個 token 的前綴兩次。第一次請求寫入快取，第二次請求讀取快取。

```json 冷請求（寫入快取） theme={null}
{
  "usage": {
    "input_tokens": 8,
    "cache_creation_input_tokens": 19349,
    "cache_read_input_tokens": 0,
    "output_tokens": 2,
    "total_tokens": 19359,
    "sunra_usage_semantics": "anthropic.exclusive.v1"
  }
}
```

```json 暖請求（讀取快取） theme={null}
{
  "usage": {
    "input_tokens": 8,
    "cache_creation_input_tokens": 0,
    "cache_read_input_tokens": 19349,
    "output_tokens": 2,
    "total_tokens": 19359,
    "sunra_usage_semantics": "anthropic.exclusive.v1"
  }
}
```

兩次請求的 `input_tokens` 都維持在 8，因為每次真正新增的輸入就是這 8 個 token。那段 19,349 個 token 的前綴從建立桶移到了讀取桶。兩次請求的總和都是同樣的 19,359 個 token，但花費並不相同：快取寫入和快取讀取各有自己的每 token 費率，這正是它們被分開回報為不同桶的原因。

## Chat Completions 與 Responses

這些 endpoint 回報的是原封不動的 OpenAI 語意。提示計數是**整個**提示，而快取的 token 是其中的**子集**，另外單獨回報。

```json /v1/chat/completions theme={null}
{
  "usage": {
    "prompt_tokens": 19357,
    "completion_tokens": 2,
    "total_tokens": 19359,
    "prompt_tokens_details": {
      "cached_tokens": 19349
    }
  }
}
```

把 `prompt_tokens` 和 `cached_tokens` 相加會重複計算。若要在這些 endpoint 上取得全新的輸入，請相減：

```
fresh input = prompt_tokens - prompt_tokens_details.cached_tokens
```

同樣的規則適用於 `/v1/responses` 的 `input_tokens` 和 `input_tokens_details.cached_tokens`。

## `sunra_usage_semantics` 標記

經過 Sunra 正規化的回應會在 `usage` 內帶有一個標記：

```json theme={null}
"sunra_usage_semantics": "anthropic.exclusive.v1"
```

這個標記是一項關於**回應**的承諾，而不是關於任何單一事件或欄位的承諾。在非 streaming 的回應中，它位於根層的 `usage` 物件內；在 streaming 的回應中，它出現在帶有輸入桶的那個事件 `message_start` 上。當它以此值出現時，本頁面上的保證即成立：三個輸入桶互斥，而 `total_tokens`（在存在時）等於它們的總和加上 `output_tokens`。

**它的缺席同樣是一項承諾。** Sunra 只會正規化它已實測過的回應結構。其他一律原封不動地從上游供應商轉發，且不加標記；不帶標記的回應，就是 Sunra 不為其各個桶背書的回應。

請對標記做斷言，而不要藉由檢視數字來猜測某個回應遵循哪一套慣例。這個欄位存在的目的就是取代結構嗅探——像是「這些桶一定互斥，因為它們的總和大於提示計數」這類啟發式判斷，會有不只一套慣例能滿足它，最終必定會把某個回應讀錯。

```python theme={null}
usage = response["usage"]

if usage.get("sunra_usage_semantics") == "anthropic.exclusive.v1":
    total_prompt = (
        usage["input_tokens"]
        + usage.get("cache_creation_input_tokens", 0)
        + usage.get("cache_read_input_tokens", 0)
    )
else:
    # Not normalized by Sunra. Treat the upstream shape as unverified
    # and consult that provider's own documentation.
    total_prompt = None
```

只有 `/v1/messages` 的回應才會帶有這個標記。Chat Completions 和 Responses 遵循 OpenAI 規格，不會被加上標記。

這個值帶有版本。若這些欄位的含義發生破壞性變更，將以新的值發布，因此對 `anthropic.exclusive.v1` 做等值檢查，不會在無聲無息中開始讀取另一套約定。

## Streaming

在 streaming 的 Messages 請求中，用量會分散在兩個事件中送達。`message_start` 帶有輸入端與標記。結尾的 `message_delta` 只帶有 `output_tokens`。請對 `message_start` 中的標記做斷言，然後以慣常的方式合併這兩個事件——將較晚事件的用量覆蓋在較早事件之上——就會得出上述記載的值。

streaming 回應會省略 `total_tokens`。沒有任何單一事件同時知道輸入端和輸出端，因此在 streaming 途中計算出的任何總數都會是錯的。請在 streaming 結束後自行將各個桶相加。

## 從先前的行為遷移

Sunra 先前在 `/v1/messages` 上會原樣轉發上游的 `usage` 物件。某些供應商前面的翻譯層會把快取建立的 token 折疊**進** `input_tokens`，因此遵循 Anthropic 約定並把三個桶相加的呼叫方，會把快取建立的 token 計算兩次。

* **若您把三個桶相加**，如同 Anthropic 約定所描述的那樣，您現在是正確的。您這邊不需要任何改動。
* **若您曾為舊行為做過補償**——自行從 `input_tokens` 中減去 `cache_creation_input_tokens`，或以其他方式反推那個折疊——**請停止**。該修正現在會減掉早已被排除在外的 token，並會低估您的輸入量。
* **若您讀取 `total_tokens`**，它會繼續回報完整的計數：全新輸入、兩個快取桶，以及輸出。

請以標記而非部署日期作為這項變更的判斷閘門，如此同一條程式碼路徑對有標記和無標記的回應都會是正確的。
