---
title: 拒絕與備援
url: https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback
description: Claude Fable 模型、Claude Opus 模型、Claude Sonnet 5.5 和 Claude Haiku 5.5 如何回傳分類器拒絕，以及如何在備援模型上重試被拒絕的請求。
---

Claude Fable 5.1、Claude Fable 5、Claude Opus 5.5、Claude Opus 5、Claude Sonnet 5.5 和 Claude Haiku 5.5 包含可能拒絕請求的「safety classifier」（安全分類器）。發生這種情況時，您會收到一個正常的回應，而不是錯誤，其中帶有 `stop_reason: "refusal"`。其 `stop_details.category` 會指出政策領域（請參閱[拒絕的樣貌](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#refusal-response)）。您通常仍可透過將相同請求傳送至另一個 Claude 模型來取得答案。本頁說明如何辨識拒絕，以及如何設定該重試。

當您以上述任一模型進行開發，並希望被拒絕的請求能自動轉交給另一個模型時，請閱讀本頁。若您已在回應中看到 `"refusal"` 並想知道下一步該怎麼做，本頁同樣適用。

相關頁面：

* [停止原因與備援](https://platform.claude.com/docs/zh-TW/build-with-claude/handling-stop-reasons)：`stop_reason` 值的完整清單。
* [備援抵免](https://platform.claude.com/docs/zh-TW/build-with-claude/fallback-credit)：當您自行建構重試時，如何避免重複支付提示快取成本。
* [SDK 中介軟體](https://platform.claude.com/docs/zh-TW/cli-sdks-libraries/middleware)：封裝上述所有功能的 SDK 輔助工具。
* [備援與計費 cookbook](https://platform.claude.com/cookbook/fable-5-fallback-billing-guide)：一個完整的端對端範例。

最簡單的設定（在 Claude API 上為 beta 版）：將 `fallbacks` 設為 `"default"`，API 便會在 Anthropic 針對該拒絕類別所建議的備援模型上重試被拒絕的請求。對於沒有建議備援模型的類別，拒絕將維持不變。Claude Haiku 5.5 沒有伺服器端備援，因此請改用[搭配 SDK 中介軟體的用戶端備援](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#client-side-fallback)或[自行撰寫重試](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#manual-retry)。

<CodeGroup>
  ```bash cURL
  curl --fail-with-body -sS https://api.anthropic.com/v1/messages \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: server-side-fallback-2026-07-01" \
    -H "content-type: application/json" \
    -d '{
      "model": "claude-fable-5",
      "max_tokens": 1024,
      "fallbacks": "default",
      "messages": [{"role": "user", "content": "Hello, Claude"}]
    }'
  ```

  ```bash CLI
  ant beta:messages create \
    --model claude-fable-5 \
    --max-tokens 1024 \
    --message '{"role":"user","content":"Hello, Claude"}' \
    --fallbacks default \
    --beta server-side-fallback-2026-07-01
  ```

  ```python Python
  client = Anthropic()

  response = client.beta.messages.create(
      model="claude-fable-5",
      max_tokens=1024,
      messages=[{"role": "user", "content": "Hello, Claude"}],
      fallbacks="default",
      betas=["server-side-fallback-2026-07-01"],
  )
  print(response.model)
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  const response = await client.beta.messages.create({
    model: "claude-fable-5",
    max_tokens: 1024,
    messages: [{ role: "user", content: "Hello, Claude" }],
    fallbacks: "default",
    betas: ["server-side-fallback-2026-07-01"]
  });
  console.log(response.model);
  ```

  ```csharp C#
  AnthropicClient client = new();

  BetaMessage response = await client.Beta.Messages.Create(
      new()
      {
          Model = Messages::Model.ClaudeFable5,
          MaxTokens = 1024,
          Messages = [new() { Content = "Hello, Claude", Role = Role.User }],
          Fallbacks = new Default(),
          Betas = [AnthropicBeta.ServerSideFallback2026_07_01],
      }
  );

  Console.WriteLine(response.Model.Raw());
  ```

  ```go Go
  client := anthropic.NewClient()

  response, err := client.Beta.Messages.New(context.Background(), anthropic.BetaMessageNewParams{
  	Model:     anthropic.ModelClaudeFable5,
  	MaxTokens: 1024,
  	Messages: []anthropic.BetaMessageParam{
  		anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("Hello, Claude")),
  	},
  	Fallbacks: anthropic.BetaFallbacksParamOfDefault(),
  	Betas:     []anthropic.AnthropicBeta{anthropic.AnthropicBetaServerSideFallback2026_07_01},
  })
  if err != nil {
  	panic(err)
  }

  fmt.Println(response.Model)
  ```

  ```java Java
  AnthropicClient client = AnthropicOkHttpClient.fromEnv();

  BetaMessage response = client.beta().messages().create(MessageCreateParams.builder()
      .model(Model.CLAUDE_FABLE_5)
      .maxTokens(1024L)
      .addUserMessage("Hello, Claude")
      .fallbacksDefault()
      .addBeta(AnthropicBeta.SERVER_SIDE_FALLBACK_2026_07_01)
      .build());

  IO.println(response.model().asString());
  ```

  ```php PHP
  $client = new Client();

  $response = $client->beta->messages->create(
      model: 'claude-fable-5',
      maxTokens: 1024,
      messages: [['role' => 'user', 'content' => 'Hello, Claude']],
      fallbacks: 'default',
      betas: ['server-side-fallback-2026-07-01'],
  );

  echo $response->model, PHP_EOL;
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  response = client.beta.messages.create(
    model: "claude-fable-5",
    max_tokens: 1024,
    messages: [{role: "user", content: "Hello, Claude"}],
    fallbacks: :default,
    betas: ["server-side-fallback-2026-07-01"]
  )

  puts response.model
  ```
</CodeGroup>

以下各節說明拒絕回應包含哪些內容、何時使用伺服器端或用戶端備援，以及各自的計費方式。

## 拒絕的樣貌

拒絕是一個成功的 HTTP 200 回應，帶有 `stop_reason: "refusal"`：

```json
{
  "id": "msg_01XFUDYJgAACzvnptvVoYEL",
  "type": "message",
  "role": "assistant",
  "model": "claude-fable-5",
  "content": [],
  "stop_reason": "refusal",
  "stop_details": {
    "type": "refusal",
    "category": "cyber",
    "explanation": "This request was declined because it could enable cyber harm."
  },
  "usage": {
    "input_tokens": 412,
    "output_tokens": 0
  }
}
```

`stop_details` 物件說明拒絕的原因：

* **`category`：** 指出觸發分類器的政策領域。
* **`explanation`：** 人類可讀的描述。此文字並不穩定，因此請直接顯示而非解析它。
* **`recommended_model`：** 僅出現在設定了 `fallbacks` 的請求上（[伺服器端備援](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#server-side-fallback)，beta）。當 API 略過備援嘗試時（例如備援模型受到速率限制），它會指出可直接重試的模型，否則為 `null`。這是一個提示，而非保證。
* 當拒絕無法對應到具名類別時，`category` 與 `explanation` 皆為 `null`。該 `null` 是正常且永久的值，而非佔位符。
* 對於 `refusal` 以外的所有停止原因，`stop_details` 本身為 `null`。

| `category`               | 含義                                                                                                                                                                                                                                                   | 在產生任何輸出前即計費 |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| `"cyber"`                | 該請求可能促成網路危害，例如惡意軟體或漏洞利用程式開發。良性的網路安全工作也可能觸發此類別。                                                                                                                                                                                                       | 否           |
| `"bio"`                  | 該請求可能促成生物危害，例如危險的實驗室方法。有益的生命科學工作也可能觸發此類別。                                                                                                                                                                                                            | 是           |
| `"frontier_llm"`         | 該請求可能協助開發競爭性 AI 模型，這在 [Anthropic 的商業條款](https://www.anthropic.com/legal/commercial-terms)下受到限制。良性的機器學習工作也可能觸發此類別。                                                                                                                                    | 是           |
| `"reasoning_extraction"` | 該請求要求模型在回應文字中重現其內部推理。若要改以結構化形式取得推理，請使用[自適應思考](https://platform.claude.com/docs/zh-TW/build-with-claude/thinking)。請參閱[將推理保留在思考區塊中](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#keep-reasoning-in-thinking-blocks)。 | 是           |
| `"general_harms"`        | 該請求屬於上述四個具名類別以外的使用政策領域。良性工作也可能觸發此類別。                                                                                                                                                                                                                 | 否           |

拒絕可能在任何輸出之前到達，也可能在部分輸出後於串流中途到達。無論哪種情況，請將任何部分輸出視為不完整並捨棄。

### 將推理保留在思考區塊中

`reasoning_extraction` 拒絕通常來自要求模型將其思考或推理放入輸出中的提示，無論是逐字或以固定格式。常見範例：

* 模型在回答前填寫的 `<thinking>`、`<reasoning>` 或草稿區段
* JSON 輸出或工具輸入中的 `reasoning`、`thinking` 或 `trace` 欄位
* 模型的私人筆記，或其推理的持續記錄
* 要求逐字或完整呈現的推理

這類措辭可能出現在系統提示、技能或工具描述中，因此也請檢查這些地方。

您仍然可以要求 Claude 解釋其答案。請要求簡短的解釋、結果背後的證據，或其所採取行動的摘要。若要查看模型如何推理，請設定 `display: "summarized"` 並閱讀 [`thinking` 區塊](https://platform.claude.com/docs/zh-TW/build-with-claude/thinking#summarized-thinking)。此類別沒有建議的備援模型，因此請修改提示，而不是重試請求。如果改寫後的請求仍被拒絕，請[聯絡支援團隊](https://support.claude.com/en/articles/9015913-how-to-get-support)並附上[請求 ID](https://platform.claude.com/docs/zh-TW/api/errors#request-id)。

## 拒絕的計費方式

這些計費規則適用於所有平台：Claude API、Amazon Bedrock、Claude Platform on AWS、Google Cloud 和 Microsoft Foundry。

**產生任何輸出前的拒絕：** 為了阻止大規模規避 Anthropic 防護措施的企圖，在任何輸出之前到達的拒絕，若其 `stop_details.category` 為 `"bio"`、`"frontier_llm"` 或 `"reasoning_extraction"`，就會計費。截至 2026 年 9 月，這些是 Anthropic 測得「false positive」（誤判）數量較低的類別。這些拒絕的計費方式與其他請求相同，依執行該請求之模型的費率計算。在任何輸出之前到達、但屬於其他類別或類別為 `null` 的拒絕則不計費。無論哪種情況，`content` 皆為空，token 計數會出現在 `usage` 中。該請求仍會計入您的速率限制。

**串流中途的拒絕：** 串流中途的拒絕會以正常費率計收輸入 token 以及已串流的輸出。

**備援：** 當您使用備援時，若觸發備援的拒絕是在串流中途出現，或屬於計費類別之一，則除了備援請求之外，該拒絕也會計費。[備援抵免](https://platform.claude.com/docs/zh-TW/build-with-claude/fallback-credit)會補償備援請求的提示快取未命中，因此您無需為快取對話支付兩次費用。Claude Haiku 5.5 的拒絕不附帶備援抵免，因此在其之後的備援需支付寫入備援模型提示快取的全額成本。關於伺服器端備援如何回報每次嘗試，請參閱[計費與速率限制](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#billing-and-rate-limits)。

隨著 Anthropic 持續測量並改善其防護措施的誤判率，計費類別可能會有所變動。[拒絕類別表](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#refusal-response)中的**在產生任何輸出前即計費**欄位列出了計費類別。

## 選擇備援方式

有三種方式可在另一個模型上重試被拒絕的請求。合適的方式取決於您的執行環境以及您需要多少控制權。

| 您的情況                  | 使用                                                                                                                                                                                    | 原因                  |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
| Claude API，最簡單的設定     | [伺服器端備援](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#server-side-fallback)                                                                         | 一個請求，一個回應。API 處理重試。 |
| 任何平台，使用 Anthropic SDK | [SDK 中介軟體](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#client-side-fallback)                                                                       | 在用戶端設定一次。重試自動進行。    |
| 原始 HTTP 或自訂重試邏輯       | [手動重試](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#manual-retry)搭配[備援抵免](https://platform.claude.com/docs/zh-TW/build-with-claude/fallback-credit) | 完全控制。備援抵免可降低成本。     |

伺服器端備援和 SDK 中介軟體會為您套用備援抵免。只有在您自行建構重試時，才需要參閱[備援抵免](https://platform.claude.com/docs/zh-TW/build-with-claude/fallback-credit)頁面。Claude Haiku 5.5 既沒有伺服器端備援也沒有備援抵免，因此請使用 SDK 中介軟體或手動重試。

## 伺服器端備援

伺服器端備援（server-side fallback）在單一 API 呼叫內重試被拒絕的請求。在預設模式下，當主要模型拒絕且該拒絕類別有建議的備援時，API 會在 Anthropic 針對該類別建議的模型上執行相同請求。您也可以改為[自行指定最多三個備援模型](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#naming-your-own-fallback-models)。無論哪種方式，您都會收到一個指出回答模型的回應，因此您的使用者在一次往返中即可獲得答案。

<Note>
  伺服器端備援在 Claude API 上為 beta 版。[Message Batches API](https://platform.claude.com/docs/zh-TW/build-with-claude/batch-processing) 不支援 `fallbacks` 參數（包含此參數的批次項目會以錯誤結果傳回），且此參數不適用於 Amazon Bedrock、Google Cloud 或 Microsoft Foundry。在這些平台上，請改用[搭配 SDK 中介軟體的用戶端備援](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#client-side-fallback)。Claude Haiku 5.5 沒有伺服器端備援：使用 `fallbacks: "default"` 時，被拒絕的請求會維持被拒絕，而備援模型清單則會傳回 400 錯誤。
</Note>

### 發出請求

將 `fallbacks` 參數設為字串 `"default"`，並傳送 `server-side-fallback-2026-07-01` beta 標頭。API 隨後會套用所請求模型的伺服器定義預設路由，該路由會根據分類器回報的拒絕類別選擇建議的備援模型，因此被拒絕的請求可獲得服務，而您無需在建議變更時維護模型清單。

預設路由絕不會因您未選擇的模型而引發預先的[過大圖片拒絕](https://platform.claude.com/docs/zh-TW/build-with-claude/vision-coordinates#oversized-image-error)：若某個路由模型會縮放標記為 `"oversized_image": "error"` 的圖片，該模型會從路由中移除，因此已標記的圖片絕不會以縮放後的形式提供。

<CodeGroup>
  ```bash cURL
  curl --fail-with-body -sS https://api.anthropic.com/v1/messages \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: server-side-fallback-2026-07-01" \
    -H "content-type: application/json" \
    -d '{
      "model": "claude-fable-5",
      "max_tokens": 1024,
      "fallbacks": "default",
      "messages": [{"role": "user", "content": "Hello, Claude"}]
    }' |
    jq -c '{
      stop_reason,
      model,
      # usage.iterations 中出現 fallback_message 項目表示已執行備援模型；
      # 請搭配 stop_reason 確認回應是否由備援模型提供。
      served_by_fallback: (
        any(.usage.iterations[]?; .type == "fallback_message")
        and .stop_reason != "refusal"
      )
    }'
  ```

  ```bash CLI
  ant beta:messages create \
    --model claude-fable-5 \
    --max-tokens 1024 \
    --message '{"role":"user","content":"Hello, Claude"}' \
    --fallbacks default \
    --beta server-side-fallback-2026-07-01 \
    --format json |
    jq -c '{
      stop_reason,
      model,
      # usage.iterations 中出現 fallback_message 項目表示已執行備援模型；
      # 請搭配 stop_reason 確認回應是否由備援模型提供。
      served_by_fallback: (
        any(.usage.iterations[]?; .type == "fallback_message")
        and .stop_reason != "refusal"
      )
    }'
  ```

  ```python Python
  client = Anthropic()

  response = client.beta.messages.create(
      model="claude-fable-5",
      max_tokens=1024,
      messages=[{"role": "user", "content": "Hello, Claude"}],
      fallbacks="default",
      betas=["server-side-fallback-2026-07-01"],
  )

  # usage.iterations 中出現 fallback_message 項目表示已執行備援模型；
  # 請搭配 stop_reason 確認該回應是否由備援模型提供。
  fallback_ran = any(
      iteration.type == "fallback_message"
      for iteration in response.usage.iterations or []
  )
  served_by_fallback = fallback_ran and response.stop_reason != "refusal"

  print(
      json.dumps(
          {
              "stop_reason": response.stop_reason,
              "model": response.model,
              "served_by_fallback": served_by_fallback,
          }
      )
  )
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  const response = await client.beta.messages.create({
    model: "claude-fable-5",
    max_tokens: 1024,
    messages: [{ role: "user", content: "Hello, Claude" }],
    fallbacks: "default",
    betas: ["server-side-fallback-2026-07-01"]
  });

  // usage.iterations 中出現 fallback_message 項目表示已執行備援模型；
  // 請搭配 stop_reason 確認回應是否由備援模型提供。
  const { stop_reason, model, usage } = response;
  const servedByFallback =
    (usage.iterations ?? []).some((entry) => entry.type === "fallback_message") &&
    stop_reason !== "refusal";

  console.log(
    JSON.stringify({
      stop_reason,
      model,
      served_by_fallback: servedByFallback
    })
  );
  ```

  ```csharp C#
  AnthropicClient client = new();

  var response = await client.Beta.Messages.Create(
      new()
      {
          Model = Messages::Model.ClaudeFable5,
          MaxTokens = 1024,
          Messages =
          [
              new() { Content = "Hello, Claude", Role = Role.User },
          ],
          Fallbacks = new Default(),
          Betas = [AnthropicBeta.ServerSideFallback2026_07_01],
      }
  );

  // usage.iterations 中出現 fallback_message 項目表示已執行備援模型；
  // 請搭配 stop_reason 確認回應是否由備援模型提供。
  bool fallbackRan = (response.Usage.Iterations ?? []).Any(iteration =>
      iteration.TryPickBetaFallbackMessageIterationUsage(out _)
  );
  bool servedByFallback =
      fallbackRan && response.StopReason?.Value() != BetaStopReason.Refusal;

  Console.WriteLine(
      JsonSerializer.Serialize(
          new
          {
              stop_reason = response.StopReason?.Raw(),
              model = response.Model.Raw(),
              served_by_fallback = servedByFallback,
          }
      )
  );
  ```

  ```go Go
  client := anthropic.NewClient()

  response, err := client.Beta.Messages.New(context.Background(), anthropic.BetaMessageNewParams{
  	Model:     anthropic.ModelClaudeFable5,
  	MaxTokens: 1024,
  	Messages: []anthropic.BetaMessageParam{
  		anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("Hello, Claude")),
  	},
  	Fallbacks: anthropic.BetaFallbacksParamOfDefault(),
  	Betas:     []anthropic.AnthropicBeta{anthropic.AnthropicBetaServerSideFallback2026_07_01},
  })
  if err != nil {
  	panic(err)
  }

  // usage.iterations 中出現 fallback_message 項目表示已執行備援模型；
  // 請搭配 stop_reason 確認回應是否由備援模型提供。
  fallbackRan := slices.ContainsFunc(
  	response.Usage.Iterations,
  	func(iteration anthropic.BetaIterationsUsageItemUnion) bool {
  		_, isFallback := iteration.AsAny().(anthropic.BetaFallbackMessageIterationUsage)
  		return isFallback
  	},
  )
  servedByFallback := fallbackRan && response.StopReason != anthropic.BetaStopReasonRefusal

  summary, err := json.Marshal(struct {
  	StopReason       anthropic.BetaStopReason `json:"stop_reason"`
  	Model            anthropic.Model          `json:"model"`
  	ServedByFallback bool                     `json:"served_by_fallback"`
  }{response.StopReason, response.Model, servedByFallback})
  if err != nil {
  	panic(err)
  }
  fmt.Println(string(summary))
  ```

  ```java Java
  AnthropicClient client = AnthropicOkHttpClient.fromEnv();

  BetaMessage response = client.beta().messages().create(
      MessageCreateParams.builder()
          .model(Model.CLAUDE_FABLE_5)
          .maxTokens(1024L)
          .addUserMessage("Hello, Claude")
          .fallbacksDefault()
          .addBeta(AnthropicBeta.SERVER_SIDE_FALLBACK_2026_07_01)
          .build()
  );

  // 出現 fallback_message 用量項目表示回應是由備援模型產生；
  // 而 refusal 停止原因則表示沒有任何模型提供該回應。
  List<BetaUsage.Iteration> iterations =
      response.usage().iterations().orElse(List.of());
  boolean servedByFallback =
      iterations.stream().anyMatch(BetaUsage.Iteration::isFallbackMessage)
          && response.stopReason().filter(BetaStopReason.REFUSAL::equals).isEmpty();

  IO.println("""
      {"stop_reason":"%s","model":"%s","served_by_fallback":%b}\
      """.formatted(
          response.stopReason().map(BetaStopReason::asString).orElse("null"),
          response.model().asString(),
          servedByFallback));
  ```

  ```php PHP
  $client = new Client();

  $response = $client->beta->messages->create(
      maxTokens: 1024,
      messages: [['role' => 'user', 'content' => 'Hello, Claude']],
      model: 'claude-fable-5',
      fallbacks: 'default',
      betas: ['server-side-fallback-2026-07-01'],
  );

  // usage.iterations 中出現 fallback_message 項目表示已執行備援模型；
  // 請搭配 stop_reason 確認該回應是否由備援模型提供。
  $iterations = $response->usage->iterations ?? [];
  $servedByFallback = array_any($iterations, fn($entry) => $entry->type === 'fallback_message')
      && $response->stopReason !== 'refusal';

  echo json_encode([
      'stop_reason' => $response->stopReason,
      'model' => $response->model,
      'served_by_fallback' => $servedByFallback,
  ]), PHP_EOL;
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  response = client.beta.messages.create(
    model: "claude-fable-5",
    max_tokens: 1024,
    messages: [{role: "user", content: "Hello, Claude"}],
    fallbacks: :default,
    betas: ["server-side-fallback-2026-07-01"]
  )

  # usage.iterations 中出現 fallback_message 項目表示已執行備援模型；
  # 請搭配 stop_reason 確認回應是否由備援模型提供。
  iterations = response.usage.iterations || []
  served_by_fallback = iterations.any? { it.type == :fallback_message } &&
    response.stop_reason != :refusal

  stop_reason = response.stop_reason
  model = response.model
  puts JSON.generate({stop_reason:, model:, served_by_fallback:})
  ```
</CodeGroup>

Anthropic 依據模型的能力，為每個模型及每個政策類別個別設定防護措施：視類別而定，被標記的請求可能備援至能力較低的模型，或被拒絕。`"default"` 模式為您編碼了這些依模型、依類別的建議，因此被拒絕的請求會在 Anthropic 針對該類別建議的模型上重試。無論哪種方式，備援都是可見的：回應會指出提供服務的模型，而 `fallback` 內容區塊會標記交接點。

路由在伺服器端套用，且不會在 [Models API](https://platform.claude.com/docs/zh-TW/api/models/list) 上依模型公布。若要查看哪個模型服務了被拒絕的請求，請檢查回應的頂層 `model` 欄位，並在 `usage.iterations` 中尋找 `fallback_message` 項目，如本頁範例所示。

只有安全分類器的拒絕會觸發備援。所請求模型上的速率限制、過載或伺服器錯誤會原樣回傳給您。

<Note>
  beta 標頭必須精確帶有日期 `2026-07-01`（同時支援 `"default"` 與明確清單形式）或 `2026-06-01`（僅接受明確清單形式）。在任何其他 `server-side-fallback-*` 值下，`fallbacks` 參數會以 400 錯誤被拒絕。若您是依據此功能的早期預覽版進行開發，請將 beta 標頭以及請求與回應的結構一併更新為本頁所示的版本。
</Note>

### 自行指定備援模型

除了預設路由之外，您也可以將 `fallbacks` 設為最多三個模型的清單。當所請求的模型拒絕時，API 會在相同請求上執行鏈中的下一個模型。當您想精確控制由哪些模型服務被拒絕的請求時（例如固定使用您的應用程式已驗證合格的模型），請使用此形式。

具名的備援模型會計入[過大圖片檢查](https://platform.claude.com/docs/zh-TW/build-with-claude/vision-coordinates#oversized-image-error)：若請求的圖片區塊設定了 `"oversized_image": "error"`，則會預先針對所請求的模型及每個具名備援進行檢查，只要其中任一模型會縮放該圖片，請求即被拒絕，且拒絕所回報的縮放目標適用於所有這些模型。

醒目標示的行是與預設路由請求唯一的差異。

<CodeGroup>
  ```bash cURL
  curl --fail-with-body -sS https://api.anthropic.com/v1/messages \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: server-side-fallback-2026-07-01" \
    -H "content-type: application/json" \
    -d '{
      "model": "claude-fable-5",
      "max_tokens": 1024,
      "fallbacks": [{"model": "claude-opus-4-8"}],
      "messages": [{"role": "user", "content": "Hello, Claude"}]
    }'
  ```

  ```bash CLI
  ant beta:messages create \
    --model claude-fable-5 \
    --max-tokens 1024 \
    --message '{"role":"user","content":"Hello, Claude"}' \
    --fallbacks '[{"model":"claude-opus-4-8"}]' \
    --beta server-side-fallback-2026-07-01
  ```

  ```python Python
  client = Anthropic()

  response = client.beta.messages.create(
      model="claude-fable-5",
      max_tokens=1024,
      messages=[{"role": "user", "content": "Hello, Claude"}],
      fallbacks=[{"model": "claude-opus-4-8"}],
      betas=["server-side-fallback-2026-07-01"],
  )
  print(response.model)
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  const response = await client.beta.messages.create({
    model: "claude-fable-5",
    max_tokens: 1024,
    messages: [{ role: "user", content: "Hello, Claude" }],
    fallbacks: [{ model: "claude-opus-4-8" }],
    betas: ["server-side-fallback-2026-07-01"]
  });
  console.log(response.model);
  ```

  ```csharp C#
  AnthropicClient client = new();

  BetaMessage response = await client.Beta.Messages.Create(
      new()
      {
          Model = Messages::Model.ClaudeFable5,
          MaxTokens = 1024,
          Messages = [new() { Content = "Hello, Claude", Role = Role.User }],
          Fallbacks = new([new(Messages::Model.ClaudeOpus4_8)]),
          Betas = [AnthropicBeta.ServerSideFallback2026_07_01],
      }
  );

  Console.WriteLine(response.Model.Raw());
  ```

  ```go Go
  client := anthropic.NewClient()

  response, err := client.Beta.Messages.New(context.Background(), anthropic.BetaMessageNewParams{
  	Model:     anthropic.ModelClaudeFable5,
  	MaxTokens: 1024,
  	Messages: []anthropic.BetaMessageParam{
  		anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("Hello, Claude")),
  	},
  	Fallbacks: anthropic.BetaFallbacksParamUnion{
  		OfBetaFallbackArray: []anthropic.BetaFallbackParam{{Model: anthropic.ModelClaudeOpus4_8}},
  	},
  	Betas: []anthropic.AnthropicBeta{anthropic.AnthropicBetaServerSideFallback2026_07_01},
  })
  if err != nil {
  	panic(err)
  }

  fmt.Println(response.Model)
  ```

  ```java Java
  AnthropicClient client = AnthropicOkHttpClient.fromEnv();

  BetaMessage response = client.beta().messages().create(MessageCreateParams.builder()
      .model(Model.CLAUDE_FABLE_5)
      .maxTokens(1024L)
      .addUserMessage("Hello, Claude")
      .fallbacksOfFallbackParams(List.of(BetaFallbackParam.builder()
          .model(Model.CLAUDE_OPUS_4_8)
          .build()))
      .addBeta(AnthropicBeta.SERVER_SIDE_FALLBACK_2026_07_01)
      .build());

  IO.println(response.model().asString());
  ```

  ```php PHP
  $client = new Client();

  $response = $client->beta->messages->create(
      model: 'claude-fable-5',
      maxTokens: 1024,
      messages: [['role' => 'user', 'content' => 'Hello, Claude']],
      fallbacks: [['model' => 'claude-opus-4-8']],
      betas: ['server-side-fallback-2026-07-01'],
  );

  echo $response->model, PHP_EOL;
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  response = client.beta.messages.create(
    model: "claude-fable-5",
    max_tokens: 1024,
    messages: [{role: "user", content: "Hello, Claude"}],
    fallbacks: [{model: "claude-opus-4-8"}],
    betas: ["server-side-fallback-2026-07-01"]
  )

  puts response.model
  ```
</CodeGroup>

`fallbacks` 清單適用以下幾項規則：

* 項目會依序嘗試。每個項目都必須與其他項目及所請求的模型不同。
* 每個項目都必須是所請求模型允許的目標之一。設定 beta 標頭後，該清單會以 `allowed_fallback_models` 的形式公開在 [Models API](https://platform.claude.com/docs/zh-TW/api/models/list) 中該模型的項目上。
* 每個項目會指定一個 `model`，並可僅針對該次嘗試覆寫 `max_tokens`、`thinking`、`output_config` 和 `speed`。
* 該請求必須作為直接請求對每個指定的模型都有效。如果備援模型不支援請求所使用的功能，API 會預先拒絕該請求。在 `2026-07-01` 標頭下，`thinking: {"type": "between_tools"}` 是例外：當 Claude Sonnet 5.5 請求備援至 Claude Sonnet 5 時，備援嘗試會以 `thinking: {"type": "disabled"}` 和 `display: "omitted"` 執行。在 `2026-06-01` 下，請在 Claude Sonnet 5 項目上設定 `thinking`，否則請求會被預先拒絕。
* 與預設模式相同，只有安全分類器的拒絕才會觸發備援。所請求模型上的速率限制、過載或伺服器錯誤會原樣傳回給您。
* 如果備援模型受到速率限制或過載，則不會進行備援嘗試，而是改為傳回前一個拒絕。此時該拒絕的 `stop_details.recommended_model` 會指出一個可直接重試的模型。請依據您預期的拒絕量來規劃備援模型的速率限制，否則在高負載下備援會退化為拒絕。

兩種模式下的回應結構相同：服務該輪次的模型出現在頂層 `model` 欄位，`fallback` 內容區塊標記交接點，而 `usage.iterations` 記錄每次嘗試。

### 回應包含的內容

回應看起來與任何其他訊息相同，但有兩項新增：

* 頂層 `model` 欄位回報產生所回傳訊息的模型，無論是所請求的模型還是備援模型。

* `fallback` 內容區塊標記 `content` 中一個模型的輸出交接給下一個模型的每個位置：`{"type": "fallback", "from": {"model": ...}, "to": {"model": ...}}`。

  * 當拒絕的那一跳是所請求的模型時，`from.model` 會回顯您傳送的模型字串。
  * `to.model` 永遠是接續模型的已解析 ID。

在任何輸出之前發生拒絕時，`fallback` 區塊是第一個內容區塊。例如，當預設路由針對該拒絕類別選擇 Claude Opus 4.8 時：

```json
{
  "id": "msg_01XFUDYJgAACzvnptvVoYEL",
  "type": "message",
  "role": "assistant",
  "model": "claude-opus-4-8",
  "content": [
    {
      "type": "fallback",
      "from": { "model": "claude-fable-5" },
      "to": { "model": "claude-opus-4-8" }
    },
    { "type": "text", "text": "Hi! How can I help you today?" }
  ],
  "stop_reason": "end_turn",
  "stop_details": null,
  "usage": {
    "input_tokens": 412,
    "output_tokens": 264,
    "cache_read_input_tokens": 0,
    "cache_creation_input_tokens": 0,
    "iterations": [
      {
        "type": "message",
        "model": "claude-fable-5",
        "input_tokens": 535,
        "output_tokens": 0,
        "cache_read_input_tokens": 0,
        "cache_creation_input_tokens": 0
      },
      {
        "type": "fallback_message",
        "model": "claude-opus-4-8",
        "input_tokens": 412,
        "output_tokens": 264,
        "cache_read_input_tokens": 0,
        "cache_creation_input_tokens": 0
      }
    ]
  }
}
```

`usage.iterations` 陣列記錄每次嘗試。拒絕的模型以一般的 `message` 項目出現，而服務該輪次的模型以 `fallback_message` 項目出現。若鏈中每個模型都拒絕，回應即為最後一個模型的拒絕，每個較早的跳點各有一個 `message` 項目，最後一個則為 `fallback_message` 項目。

[黏性路由](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#sticky-routing)可將後續輪次直接傳送至備援模型。這樣的輪次不帶 `fallback` 內容區塊，因為該輪次沒有模型拒絕。請透過 `usage.iterations` 中的 `fallback_message` 項目、所請求模型沒有 `message` 項目，以及回應的 `model` 欄位來辨識它。

### 延續對話

在下一輪次，請將助理內容依您收到的原樣傳回。在輸出中途備援之後，`content` 可能包含拒絕模型在交接前產生的區塊類型。下表說明當您回顯該輪次時，哪些應保留、哪些應捨棄。

| 區塊類型                                                                    | 在下一輪次                                                            |
| ----------------------------------------------------------------------- | ---------------------------------------------------------------- |
| `fallback`                                                              | 精確保留在其出現的位置。API 使用其位置來驗證其周圍的思考區塊，因此若該區塊被省略或移動，回顯邊界兩側思考區塊的請求會被拒絕。 |
| `text`                                                                  | 保留。                                                              |
| 最後一個 `fallback` 區塊之後的任何區塊                                               | 保留。                                                              |
| 最後一個 `fallback` 區塊之前的 `thinking`、`redacted_thinking` 或 `connector_text` | 捨棄。                                                              |
| 最後一個 `fallback` 區塊之前的用戶端 `tool_use`                                     | 捨棄。                                                              |
| 最後一個 `fallback` 區塊之前的 `server_tool_use`                                 | 與其結果配對時保留。沒有對應結果時捨棄。                                             |

<Note>
  `connector_text` 區塊承載某些使用工具的回應在工具呼叫之間所包含的敘述文字。
</Note>

### 串流

在串流（streaming）請求上，重試在同一個串流上進行，且您已收到的任何內容都不會失效。您看到的內容取決於拒絕發生的時間點。

**當拒絕發生在任何輸出之前：**

* `message_start` 指出備援模型，且 `fallback` 區塊是第一個內容區塊。
* 由於 `message_start` 會等待備援嘗試開始，首位元組時間包含被拒絕的嘗試。

**當拒絕發生在輸出中途：**

* 開啟中的內容區塊會關閉，而 `fallback` 區塊（一對沒有 delta 的一般 `content_block_start` 與 `content_block_stop`）標記邊界。
* 備援模型從部分輸出接續。只有部分輸出的 `text` 區塊會作為上下文傳遞給備援模型。其他區塊類型保留在 `content` 中。
* `message_start` 已指出所請求的模型，因此請從 `fallback` 區塊的 `to.model` 以及最終 `message_delta` 的 `usage.iterations` 中的 `fallback_message` 項目讀取服務模型。

### 非串流回應

在非串流請求上，輸出中途的拒絕行為不同：回應會省略被拒絕模型的部分輸出，而備援模型從頭回答。結果看起來像是在任何輸出之前的拒絕，`fallback` 區塊位於最前。被拒絕的嘗試及其輸出 token 仍會出現在 `usage.iterations` 中。

<Note>
  **工具使用期間的拒絕：** 已完成的工具工作不會阻擋備援。當拒絕在伺服器工具（例如網頁搜尋或程式碼執行）於請求內執行完畢後觸發時，備援嘗試會繼續進行：已完成的工具結果會延續，且備援模型可繼續呼叫伺服器工具。唯一不會重試的情況是：串流拒絕在任何類型的工具使用區塊（用戶端工具、伺服器工具或 MCP 工具呼叫）仍在串流上開啟時觸發：該拒絕會直接回傳，且若設定了 `fallback-credit-2026-07-01` 標頭，它仍會帶有可透過接續部分回應來兌換的抵免 token。非串流請求不受影響；API 會清除部分工作並在回應前重試。
</Note>

### 計費與速率限制

每次嘗試都遵循[拒絕的計費方式](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#how-refusals-are-billed)中的規則，並依執行該嘗試之模型的費率計算。在產生任何輸出之前即拒絕的嘗試，只有在其拒絕類別屬於計費類別時才會計費，且無論如何，其 token 都會回報於其 `usage.iterations` 項目上。每個產生了輸出的嘗試（包括在回應中途拒絕的嘗試）都會分別計費。`usage.iterations` 陣列是您被計費內容的逐次嘗試記錄。頂層 `usage` 計數僅描述產生所回傳訊息的那次嘗試。來自不同模型的 token 絕不會加總到同一個欄位中。

每次執行的嘗試（包括拒絕的嘗試）都會計入其自身模型的速率限制。

### 黏性路由

對話備援之後，API 會記錄由哪個模型服務。該對話後續包含 `fallbacks` 的請求會直接送往該備援模型，而不執行所請求的模型。這可避免在每一輪次為可預期會再次被拒絕的嘗試付費。

路由決策的幾項特性：

* 保留約 1 小時，且範圍限於您的組織。
* 以對話前綴的內容雜湊加上服務它的模型來儲存。訊息內容本身不會被儲存。
* 屬於盡力而為，因此您的程式碼必須能處理所請求的模型在任何時候被再次嘗試的情況。

黏性路由（sticky routing）同時適用於串流與非串流請求。在串流請求上，路由決策在串流開啟前做出，因此 `message_start` 事件的 `model` 欄位已帶有備援模型的 ID。

## 搭配 SDK 中介軟體的用戶端備援

SDK 包含一個拒絕備援中介軟體。您只需在用戶端上以您的備援模型清單設定一次。之後透過 `client.beta.messages` (csharp, go: `client.Beta.Messages`; java: `client.beta().messages()`; php: `$client->beta->messages`) 的呼叫便會在任何平台上自動重試被拒絕的請求。中介軟體也會在其處理的每個請求上傳送 `fallback-credit-2026-07-01` beta 標頭，因此重試會重新計價，無需逐一設定請求。Claude Haiku 5.5 的拒絕不附帶備援抵免，因此在其之後的重試需支付寫入備援模型提示快取的全額成本。

### 設定方式

將 `BetaRefusalFallbackMiddleware` (typescript: `betaRefusalFallbackMiddleware`; go: `betafallback.BetaRefusalFallbackMiddleware`; csharp: `BetaRefusalFallbackHandler`; java: `BetaRefusalFallbackInterceptor`; php: `RefusalFallbackMiddleware`) 傳遞給用戶端建構函式，並在一個對話的各請求之間共用一個 `BetaFallbackState` 實例。

<CodeGroup exclude="shell">
  <CodeGroupItem language="cURL">
    拒絕備援中介軟體是 Claude SDK 的一部分，因此 cURL 請求無法使用它。若要在單一請求內進行備援，請使用[伺服器端備援](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#server-side-fallback)。若要自行撰寫重試，請參閱[備援抵免](https://platform.claude.com/docs/zh-TW/build-with-claude/fallback-credit)。
  </CodeGroupItem>

  <CodeGroupItem language="CLI">
    `ant` CLI 不包含拒絕備援中介軟體。若要在單一請求內進行備援，請使用[伺服器端備援](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#server-side-fallback)。若要自行撰寫重試，請參閱[備援抵免](https://platform.claude.com/docs/zh-TW/build-with-claude/fallback-credit)。
  </CodeGroupItem>

  ```python Python
  from anthropic import Anthropic, BetaFallbackState, BetaRefusalFallbackMiddleware

  # 遇到拒絕時，中介軟體會改用所列的備援模型重試，並且
  # 自動在其處理的每個請求上傳送 fallback-credit beta 標頭。
  client = Anthropic(
      middleware=[BetaRefusalFallbackMiddleware([{"model": "claude-opus-4-8"}])],
  )

  state = BetaFallbackState()  # pins follow-ups to the model that accepted

  # 串流：遇到拒絕時，中介軟體會改用備援模型重試，並且
  # 將其事件接續到已開啟的串流上。
  with (
      state,
      client.beta.messages.stream(
          max_tokens=1024,
          model="claude-fable-5",
          messages=[{"role": "user", "content": "Hello, Claude"}],
      ) as stream,
  ):
      for text in stream.text_stream:
          print(text, end="", flush=True)
      final_message = stream.get_final_message()
  print(f"\nserved by: {final_message.model}")

  # 非串流：重複使用該狀態可讓對話保持固定。
  with state:
      message = client.beta.messages.create(
          max_tokens=1024,
          model="claude-fable-5",
          messages=[{"role": "user", "content": "Hello, Claude"}],
      )
  print(f"served by: {message.model}")
  ```

  ```typescript TypeScript
  import { BetaFallbackState, betaRefusalFallbackMiddleware } from "@anthropic-ai/sdk";

  // 遇到拒絕時，中介軟體會改用所列的備援模型重試，並且
  // 在其處理的每個請求上自動傳送 fallback-credit beta 標頭。
  const client = new Anthropic({
    middleware: [betaRefusalFallbackMiddleware([{ model: "claude-opus-4-8" }])]
  });

  // 在整個對話中共用同一個狀態，讓後續請求持續
  // 固定在已接受的模型上。
  const fallbackState = new BetaFallbackState();

  // 串流：遇到拒絕時，中介軟體會改用備援模型重試，並且
  // 將其事件接合到已開啟的串流上。
  const stream = client.beta.messages
    .stream(
      {
        max_tokens: 1024,
        model: "claude-fable-5",
        messages: [{ role: "user", content: "Hello, Claude" }]
      },
      { fallbackState }
    )
    .on("text", (text) => process.stdout.write(text));

  const finalMessage = await stream.finalMessage();
  console.log("\nserved by:", finalMessage.model);

  // 非串流：重複使用該狀態可讓對話保持固定。
  const message = await client.beta.messages.create(
    {
      max_tokens: 1024,
      model: "claude-fable-5",
      messages: [{ role: "user", content: "Hello, Claude" }]
    },
    { fallbackState }
  );
  console.log("served by:", message.model);
  ```

  ```csharp C#
  using Anthropic;
  using Anthropic.Helpers;
  using Anthropic.Models.Beta.Messages;
  using Messages = Anthropic.Models.Messages;

  // 遇到拒絕時，處理程式會改用所列的備援模型重試，並且
  // 會在其處理的每個請求上自動傳送 fallback-credit beta 標頭。
  AnthropicClient client = new()
  {
      Handlers =
      [
          new BetaRefusalFallbackHandler { Fallbacks = [new(Messages::Model.ClaudeOpus4_8)] },
      ],
  };

  // 將共用此狀態的後續請求固定至已接受的模型。
  BetaFallbackState fallbackState = BetaFallbackState.Create();

  MessageCreateParams parameters = new()
  {
      Model = Messages::Model.ClaudeFable5,
      MaxTokens = 1024,
      Messages = [new() { Content = "Hello, Claude", Role = Role.User }],
  };

  // 串流：若串流以拒絕結束，處理程式會將備援
  // 模型的事件接續到仍開啟的串流上。
  BetaMessageContentAggregator aggregator = new();
  using (fallbackState.Use())
  {
      var responseUpdates = client.Beta.Messages.CreateStreaming(parameters);
      await foreach (BetaRawMessageStreamEvent rawEvent in responseUpdates.CollectAsync(aggregator))
      {
          if (
              rawEvent.TryPickContentBlockDelta(out var deltaEvent)
              && deltaEvent.Delta.TryPickText(out var textDelta)
          )
          {
              Console.Write(textDelta.Text);
          }
      }
  }
  BetaMessage streamedMessage = aggregator.Message();
  Console.WriteLine($"\nserved by: {streamedMessage.Model.Raw()}");

  // 非串流：重複使用該狀態可讓對話持續固定在已接受的模型上。
  using (fallbackState.Use())
  {
      BetaMessage message = await client.Beta.Messages.Create(parameters);
      Console.WriteLine($"served by: {message.Model.Raw()}");
  }
  ```

  ```go Go
  import (
  // ...
  	"github.com/anthropics/anthropic-sdk-go/lib/betafallback"
  // ...
  )

  func main() {
  	ctx := context.Background()

  	// 此中介軟體會在請求遭拒時，依序於各個備援模型上重試，
  	// 並自動將請求加入 fallback-credit beta。
  	client := anthropic.NewClient(
  		option.WithMiddleware(betafallback.BetaRefusalFallbackMiddleware(
  			[]anthropic.BetaFallbackParam{{Model: anthropic.ModelClaudeOpus4_8}},
  		)),
  	)

  	// 每個對話一個狀態：共用該狀態的請求會固定使用
  	// 已接受的模型，因此後續請求不會再詢問曾拒絕的模型。
  	state := &betafallback.BetaFallbackState{}
  	conversation := betafallback.WithBetaFallbackState(state)

  	params := anthropic.BetaMessageNewParams{
  		MaxTokens: 1024,
  		Model:     anthropic.ModelClaudeFable5,
  		Messages: []anthropic.BetaMessageParam{
  			anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("Hello, Claude")),
  		},
  	}

  	// 串流：遭拒時中介軟體會就地重試，將備援模型的事件
  	// 接續至已開啟的串流上，形成一則連續的訊息。
  	stream := client.Beta.Messages.NewStreaming(ctx, params, conversation)
  	defer stream.Close()
  	var streamed anthropic.BetaMessage
  	for stream.Next() {
  		event := stream.Current()
  		if err := streamed.Accumulate(event); err != nil {
  			panic(err)
  		}
  		switch eventVariant := event.AsAny().(type) {
  		case anthropic.BetaRawContentBlockDeltaEvent:
  			if textDelta, ok := eventVariant.Delta.AsAny().(anthropic.BetaTextDelta); ok {
  				fmt.Print(textDelta.Text)
  			}
  		}
  	}
  	if err := stream.Err(); err != nil {
  		panic(err)
  	}
  	fmt.Println("\nserved by:", streamed.Model)

  	// 非串流：共用狀態會將此後續請求固定至
  	// 先前處理串流回合的模型。
  	message, err := client.Beta.Messages.New(ctx, params, conversation)
  	if err != nil {
  		panic(err)
  	}
  	fmt.Println("served by:", message.Model)
  }
  ```

  ```java Java
  import com.anthropic.client.AnthropicClient;
  import com.anthropic.client.okhttp.AnthropicOkHttpClient;
  import com.anthropic.core.RequestOptions;
  import com.anthropic.core.http.StreamResponse;
  import com.anthropic.helpers.BetaFallbackState;
  import com.anthropic.helpers.BetaMessageAccumulator;
  import com.anthropic.helpers.BetaRefusalFallbackInterceptor;
  import com.anthropic.models.beta.messages.BetaMessage;
  import com.anthropic.models.beta.messages.BetaRawMessageStreamEvent;
  import com.anthropic.models.beta.messages.MessageCreateParams;
  import com.anthropic.models.messages.Model;

  void main() {
      // 此攔截器會在備援模型上重試遭拒絕的請求。它會自動
      // 為其處理的每個請求加上 fallback-credit beta 標頭。
      AnthropicClient client = AnthropicOkHttpClient.builder()
          .fromEnv()
          .addInterceptor(BetaRefusalFallbackInterceptor.builder()
              .addFallback(Model.CLAUDE_OPUS_4_8)
              .build())
          .build();

      // 在各請求間共用同一狀態，使後續請求固定於已接受的模型。
      BetaFallbackState state = BetaFallbackState.create();

      MessageCreateParams params = MessageCreateParams.builder()
          .model(Model.CLAUDE_FABLE_5)
          .maxTokens(1024)
          .addUserMessage("Hello, Claude")
          .build();

      // 串流：遭拒絕時，備援模型的事件會接續至已開啟的串流上。
      BetaMessageAccumulator accumulator = BetaMessageAccumulator.create();
      try (StreamResponse<BetaRawMessageStreamEvent> streamResponse = client.beta()
              .messages()
              .createStreaming(params, RequestOptions.builder().fallbackState(state).build())) {
          streamResponse.stream()
              .peek(accumulator::accumulate)
              .forEach(event -> event.contentBlockDelta()
                  .flatMap(deltaEvent -> deltaEvent.delta().text())
                  .ifPresent(textDelta -> IO.print(textDelta.text())));
      }
      IO.println("\nserved by: " + accumulator.message().model().asString());

      // 非串流：重複使用同一狀態可讓對話保持固定。
      BetaMessage message = client.beta()
          .messages()
          .create(params, RequestOptions.builder().fallbackState(state).build());
      IO.println("served by: " + message.model().asString());
  }
  ```

  ```php PHP
  use Anthropic\Beta\Messages\BetaRawContentBlockDeltaEvent;
  use Anthropic\Beta\Messages\BetaTextDelta;
  use Anthropic\Client;
  use Anthropic\Lib\Middleware\BetaFallbackState;
  use Anthropic\Lib\Middleware\RefusalFallbackMiddleware;
  use Anthropic\Lib\Streaming\MessageAccumulator;

  // 只需設定一次備援鏈。遇到拒絕時，中介軟體會沿著備援鏈重試
  // 該請求，並自動為您傳送 fallback-credit beta 標頭。
  $client = new Client(
      requestOptions: [
          'middleware' => [new RefusalFallbackMiddleware([['model' => 'claude-opus-4-8']])],
      ],
  );

  // 在整個對話中共用同一個狀態，讓後續請求持續固定
  // 在已接受請求的模型上。
  $state = new BetaFallbackState();

  // 串流：遇到拒絕時，中介軟體會將備援模型的事件接合
  // 到仍開啟的串流上。累加器的模型即為實際提供服務的模型。
  $stream = $client->beta->messages->createStream(
      model: 'claude-fable-5',
      maxTokens: 1024,
      messages: [['role' => 'user', 'content' => 'Hello, Claude']],
      requestOptions: ['fallbackState' => $state],
  );
  $accumulator = MessageAccumulator::forBetaMessages();
  foreach ($stream as $event) {
      $accumulator->accumulate($event);
      if ($event instanceof BetaRawContentBlockDeltaEvent
          && $event->delta instanceof BetaTextDelta) {
          echo $event->delta->text;
      }
  }
  echo "\nserved by: {$accumulator->message()->model}\n";

  // 非串流：使用相同的中介軟體。重複使用該狀態可讓對話
  // 持續固定在已接受請求的模型上。
  $message = $client->beta->messages->create(
      model: 'claude-fable-5',
      maxTokens: 1024,
      messages: [['role' => 'user', 'content' => 'Hello, Claude']],
      requestOptions: ['fallbackState' => $state],
  );
  echo "served by: {$message->model}\n";
  ```

  ```ruby Ruby
  # 遇到拒絕時，中介軟體會沿著備援鏈重試該請求。
  # 它會在處理的每個請求上傳送 fallback-credit beta 標頭。
  client = Anthropic::Client.new(
    middleware: [Anthropic::BetaRefusalFallbackMiddleware.new([{model: "claude-opus-4-8"}])]
  )

  # 在整個對話中共用同一個狀態，讓後續請求持續
  # 固定在已接受的模型上。
  state = Anthropic::BetaFallbackState.new

  # 串流：遇到拒絕時，中介軟體會將備援模型的
  # 事件接合到仍開啟的串流上。
  stream = client.beta.messages.stream(
    model: "claude-fable-5",
    max_tokens: 1024,
    messages: [{role: "user", content: "Hello, Claude"}],
    request_options: {fallback_state: state}
  )
  stream.text.each { print it }
  puts "\nserved by: #{stream.accumulated_message.model}"

  # 非串流：重複使用該狀態可讓對話持續固定在已接受的模型上。
  message = client.beta.messages.create(
    model: "claude-fable-5",
    max_tokens: 1024,
    messages: [{role: "user", content: "Hello, Claude"}],
    request_options: {fallback_state: state}
  )
  puts "served by: #{message.model}"
  ```
</CodeGroup>

### 行為方式

* 重試會依序走訪您的備援清單。若某個備援模型本身也拒絕，請求會傳遞給下一個項目。
* 當清單中的每個模型都拒絕時，中介軟體會傳回最終的拒絕（最後一個模型的拒絕回應），而不會引發錯誤。
* 來自 Claude Fable 5.1、Claude Opus 5.5、Claude Sonnet 5.5、Claude Haiku 5.5 或 Claude Fable 5 的思考區塊會原封不動地傳遞。每次重試都會重新傳送您原始的請求主體，而中介軟體在後續請求中從對話歷史移除的唯一區塊，是它自己新增的 `fallback` 邊界區塊。備援模型無法讀取 Claude Fable 5.1 區塊，因為只有 [Claude Fable 5.1 和 Claude Mythos 5.1 能讀取](https://platform.claude.com/docs/zh-TW/build-with-claude/thinking#preserved-for-model)，因此 API 會捨棄它們。對於 Claude Fable 5.1 和 Claude Mythos 5.1 以外的所有備援模型，API 也會捨棄 Claude Opus 5.5 區塊（請參閱[在對話中途切換模型](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#switching-models)）。對於 Claude API 和 Google Cloud 上的 Claude Opus 5.5 以外的所有備援模型，它也會捨棄 Claude Sonnet 5.5 區塊。Claude Opus 5.5 和 Claude Sonnet 5.5 在 Claude API 和 Google Cloud 上能讀取 Claude Haiku 5.5 區塊，而對於無法讀取它們的備援模型，API 會將其捨棄。
* 透過中介軟體處理的回應會在每個模型邊界包含一個 `fallback` 內容區塊，與伺服器端備援回應相同。中介軟體會在後續請求中為您管理這些區塊。
* 接受請求的模型會記錄在 `BetaFallbackState` 中，因此共用該狀態的後續請求會固定使用該模型，而不會再次詢問曾拒絕的模型。

<Note>
  中介軟體與伺服器端 `fallbacks` 參數執行相同的工作。請設定其中之一，切勿在同一請求上同時使用兩者。若要從安裝了中介軟體的應用程式傳送伺服器端 `fallbacks` 請求，請使用不含中介軟體的獨立用戶端實例。
</Note>

## 自行撰寫重試

透過原始 HTTP 或自訂重試邏輯，實作中介軟體所封裝的模式：

<Steps>
  <Step title="偵測拒絕">
    檢查回應中是否有 `stop_reason: "refusal"`。
  </Step>

  <Step title="在備援模型上重新傳送">
    傳送相同的請求，並將 `model` 設為備援模型，例如 Claude Opus 4.8。如果被拒絕的請求傳送了 `thinking: {"type": "between_tools"}`，請先變更 `thinking`：只有 Claude Sonnet 5.5 接受該值，因此請省略 `thinking` 或設定備援模型接受的值。在 `2026-07-01` 標頭下，[伺服器端備援](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#server-side-fallback)在備援至 Claude Sonnet 5 時會為您進行此變更。另一個模型通常可以為 Claude Fable 5.1 或 Claude Fable 5 拒絕的請求提供服務。您如何處理對話歷史記錄，取決於您是否兌換[備援抵免](https://platform.claude.com/docs/zh-TW/build-with-claude/fallback-credit)：

    * **不兌換額度：** 您可以保留先前的 `thinking` 和 `redacted_thinking` 區塊，或將其移除以節省輸入 token。無論哪種方式，備援模型通常都無法使用它們：只有 Claude Fable 5.1 和 Claude Mythos 5.1 能[讀取 Claude Fable 5.1 區塊](https://platform.claude.com/docs/zh-TW/build-with-claude/thinking#preserved-for-model)，而只有這兩個模型、Claude Fable 5 和 Claude Mythos 5 能讀取 Claude Fable 5 區塊，因此對於任何其他備援模型，API 會將其捨棄。對於 Claude Fable 5.1 和 Claude Mythos 5.1 以外的所有備援模型，API 也會捨棄 Claude Opus 5.5 區塊（請參閱[在對話中途切換模型](https://platform.claude.com/docs/zh-TW/build-with-claude/preserved-thinking#switching-models)）。對於 Claude API 和 Google Cloud 上的 Claude Opus 5.5 以外的所有備援模型，它也會捨棄 Claude Sonnet 5.5 區塊。Claude Haiku 5.5 拒絕後的重試一律屬於此情況。Claude Opus 5.5 和 Claude Sonnet 5.5 在 Claude API 和 Google Cloud 上能讀取 Claude Haiku 5.5 區塊，因此當您在這些平台上備援至其中任一模型時，請保留這些區塊。對於無法讀取它們的備援模型，API 會將其捨棄且不計費。
    * **兌換額度：** 請原封不動地傳送主體，因為兌換需要完全相符。兌換時，伺服器會處理先前模型的思考區塊，因此請勿移除它們（請參閱[必須與被拒絕請求相符的欄位](https://platform.claude.com/docs/zh-TW/build-with-claude/fallback-credit#reference)）。
  </Step>

  <Step title="持續使用備援模型">
    對於多輪對話，請在後續輪次中持續使用備援模型，而不要切換回原模型。
  </Step>
</Steps>

手動重試會從頭寫入備援模型的提示快取，這比讀取現有快取的成本更高。[備援抵免](https://platform.claude.com/docs/zh-TW/build-with-claude/fallback-credit)會退還該成本；請在您自行建構的每次重試中兌換它。Claude Haiku 5.5 的拒絕不附帶備援抵免，因此在其之後的重試需支付寫入備援模型提示快取的全額成本。

## Message Batches 中的拒絕

[Message Batch](https://platform.claude.com/docs/zh-TW/build-with-claude/batch-processing) 中被拒絕的請求會以 `result.type: "succeeded"` 搭配 `stop_reason: "refusal"` 回傳。批次結果帶有與同步回應相同的 `stop_details` 物件，因此您可以透過 `stop_reason` 或 `stop_details.type` 偵測拒絕。一項差異：批次拒絕不會產生備援抵免，因此批次結果上的 `stop_details` 絕不會包含 `fallback_credit_token`。

伺服器端備援不適用於批次（包含 `fallbacks` 的批次請求會產生逐項目的錯誤結果）。若要重試被拒絕的批次項目：

1. 從結果中收集被拒絕的項目。
2. 保留多輪歷史中的思考區塊，或將其移除以節省輸入 token。對於無法讀取它們的備援模型，API 會將其捨棄且不計費，與[手動重試](https://platform.claude.com/docs/zh-TW/build-with-claude/refusals-and-fallback#manual-retry)相同。
3. 如果被拒絕的項目傳送了 `thinking: {"type": "between_tools"}`，請省略 `thinking` 或設定備援模型接受的值。只有 Claude Sonnet 5.5 接受 `between_tools`。
4. 在備援模型上以新批次或直接請求的方式重新提交它們。

## 常見陷阱

* **在不同的模型上重試。** 將被拒絕的請求重新傳送至同一模型通常會再次被拒絕。請將重試指向備援模型。
* **依請求而非依輪次或依工作階段規劃重試預算。** 單一輪次可能產生多次拒絕，例如一個代理加上其子代理。
* **在每條請求路徑上設定備援。** 重試處理程式、錯誤復原分支與背景工作程式都需要它。在沒有備援的情況下重新發出請求的處理程式，恰恰會在最可能需要保護的請求上失去保護。
* **為子代理呼叫提供各自的備援。** `fallbacks` 參數不會傳播到從工具執行內部發出的模型呼叫。
* **讓備援成為請求的屬性，而非環境狀態的屬性。** 共用旗標、快取的設定值或全域開關可能會失去同步，並悄悄地讓請求失去保護。當您無法確認備援已啟用時，請設定它，而非假設它已開啟。
* **將拒絕作為獨立訊號進行監測。** 拒絕是 HTTP 200，因此建立在錯誤率或 5xx 回應上的監控永遠看不到它。請為每次拒絕發出一個事件，並為每個由備援服務的回應發出一個事件（`usage.iterations` 中的 `fallback_message` 項目標記後者），然後針對兩個計數之間的差距發出警示。
* **依 `stop_reason` 或 `stop_details.type` 分支，而非依 `content` 或內部的 `stop_details` 欄位。** `stop_details` 物件在拒絕時永遠存在，但其 `category` 與 `explanation` 欄位可能為 `null`。請直接檢查 `stop_reason` 是否等於 `"refusal"`。

## 後續步驟

<CardGroup>
  <Card title="備援抵免" icon="scales" href="https://platform.claude.com/docs/zh-TW/build-with-claude/fallback-credit">
    當您自行建構重試時，避免重複支付提示快取成本。
  </Card>

  <Card title="停止原因與備援" icon="code" href="https://platform.claude.com/docs/zh-TW/build-with-claude/handling-stop-reasons">
    每個 `stop_reason` 值及其處理方式。
  </Card>

  <Card title="SDK 中介軟體" icon="settings" href="https://platform.claude.com/docs/zh-TW/cli-sdks-libraries/middleware">
    SDK 中介軟體的運作方式，包括拒絕備援輔助工具。
  </Card>

  <Card title="遷移指南" icon="arrow-right" href="https://platform.claude.com/docs/zh-TW/models/fable-5-1/migration-guide">
    將現有應用程式遷移至 Claude Fable 5.1。
  </Card>
</CardGroup>
