---
title: Gérer les refus en streaming
url: https://platform.claude.com/docs/fr/test-and-evaluate/strengthen-guardrails/handle-streaming-refusals
description: Détectez et gérez les raisons d'arrêt de type refus dans les réponses en streaming, et relancez les requêtes refusées sur un modèle de repli.
---

À partir des modèles Claude 4, les réponses en « streaming » (streaming) de l'API de Claude renvoient **`stop_reason`: `"refusal"`** lorsque les classificateurs de streaming interviennent pour gérer d'éventuelles violations de politique. Cette fonctionnalité de sécurité aide à maintenir la conformité du contenu pendant le streaming en temps réel.

<Tip>
  Cette page explique comment les refus apparaissent dans les réponses en streaming. Pour connaître chaque valeur de `stop_reason` et la manière de la gérer, consultez [Raisons d'arrêt et repli](https://platform.claude.com/docs/fr/build-with-claude/handling-stop-reasons). Pour relancer les requêtes refusées sur un autre modèle Claude, consultez [Refus et repli](https://platform.claude.com/docs/fr/build-with-claude/refusals-and-fallback).
</Tip>

## Format de réponse de l'API

Lorsque les classificateurs de streaming détectent un contenu qui enfreint les politiques d'Anthropic, l'API renvoie cette réponse :

```json
{
  "role": "assistant",
  "content": [
    {
      "type": "text",
      "text": "Hello.."
    }
  ],
  "stop_reason": "refusal",
  "stop_details": {
    "type": "refusal",
    "category": "cyber",
    "explanation": "This request was declined because it could enable cyber harm."
  }
}
```

Dans le flux d'événements, `stop_details` arrive sur l'événement `message_delta` en même temps que `stop_reason`.

<Note>
  Une réponse `refusal` provenant des classificateurs de streaming inclut un objet `stop_details` avec une `category` et une `explanation` lisible par un humain que vous pouvez présenter à l'utilisateur. Consultez [Refus et repli](https://platform.claude.com/docs/fr/build-with-claude/refusals-and-fallback#refusal-response) pour la forme complète de la réponse et les catégories disponibles.

  Lors d'un refus, l'objet `stop_details` est toujours présent, mais ses champs `category` et `explanation` peuvent être `null`, par exemple lorsque le refus ne correspond à aucune catégorie nommée. Effectuez votre branchement sur `stop_reason` ou `stop_details.type` plutôt que de supposer que `category` et `explanation` sont renseignés, et fournissez vos propres messages destinés à l'utilisateur lorsqu'ils sont `null`.
</Note>

## Réinitialiser le contexte après un refus

Lorsque vous recevez **`stop_reason`: `refusal`**, vous devez réinitialiser le contexte de la conversation avant de continuer. Vous pouvez supprimer ou reformuler le tour qui a déclenché le refus, ou effacer entièrement l'historique de la conversation. Tenter de continuer sans réinitialiser entraînera des refus répétés.

<Note>
  Les métriques d'utilisation sont toujours fournies dans la réponse, même lorsque la réponse est refusée. La facturation d'une requête refusée dépend du moment où le refus survient et de sa catégorie ; consultez [Facturation des refus](https://platform.claude.com/docs/fr/build-with-claude/refusals-and-fallback#how-refusals-are-billed).
</Note>

<Tip>
  Réinitialiser le contexte n'est pas le seul moyen de récupérer. Vous pouvez également relancer la requête refusée sur un autre modèle Claude, et la page [Refus et repli](https://platform.claude.com/docs/fr/build-with-claude/refusals-and-fallback) montre comment configurer cela avec le repli côté serveur, le middleware du SDK ou une relance manuelle.
</Tip>

## Guide d'implémentation

Voici comment détecter et gérer les refus en streaming dans votre application :

<CodeGroup>
  ```bash cURL
  response=$(curl -N https://api.anthropic.com/v1/messages \
    -H "anthropic-version: 2023-06-01" \
    -H "content-type: application/json" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -d '{
      "model": "claude-opus-5-5",
      "messages": [{"role": "user", "content": "Hello"}],
      "max_tokens": 1024,
      "stream": true
    }')

  if echo "$response" | jq -R -e 'select(startswith("data: "))
      | sub("^data: "; "") | fromjson
      | select(.delta.stop_reason == "refusal")' >/dev/null; then
    echo "Response refused - resetting conversation context"
    # Réinitialisez ici l'état de votre conversation.
  fi
  ```

  ```bash CLI
  response=$(ant messages create --stream --format jsonl \
    --model claude-opus-5-5 \
    --max-tokens 1024 \
    --message '{role: user, content: Hello}')

  if echo "$response" | jq -e 'select(.delta.stop_reason == "refusal")' >/dev/null; then
    echo "Response refused - resetting conversation context"
    # Réinitialisez ici l'état de votre conversation.
  fi
  ```

  ```python Python
  client = anthropic.Anthropic()
  messages = []


  def reset_conversation():
      """Reset conversation context after refusal"""
      global messages
      messages = []
      print("Conversation reset due to refusal")


  try:
      with client.messages.stream(
          max_tokens=1024,
          messages=messages + [{"role": "user", "content": "Hello"}],
          model="claude-opus-5-5",
      ) as stream:
          for event in stream:
              # Vérifier la présence d'un refus dans le delta du message.
              if event.type == "message_delta":
                  if event.delta.stop_reason == "refusal":
                      reset_conversation()
                      break
  except Exception as e:
      print(f"Error: {e}")
  ```

  ```typescript TypeScript
  const client = new Anthropic();
  let messages: Anthropic.MessageParam[] = [];

  function resetConversation() {
    // Réinitialiser le contexte de la conversation après un refus.
    messages = [];
    console.log("Conversation reset due to refusal");
  }

  try {
    const stream = await client.messages.stream({
      messages: [...messages, { role: "user", content: "Hello" }],
      model: "claude-opus-5-5",
      max_tokens: 1024
    });

    for await (const event of stream) {
      // Vérifier la présence d'un refus dans le delta du message.
      if (event.type === "message_delta" && event.delta.stop_reason === "refusal") {
        resetConversation();
        break;
      }
    }
  } catch (error) {
    console.error("Error:", error);
  }
  ```

  ```csharp C#
  List<Message> messages = new();
  AnthropicClient client = new();

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

  try
  {
      await foreach (var streamEvent in client.Messages.CreateStreaming(parameters))
      {
          if (
              streamEvent.TryPickDelta(out var deltaEvent)
              && deltaEvent.Delta.StopReason == StopReason.Refusal
          )
          {
              ResetConversation();
              break;
          }
      }
  }
  catch (Exception e)
  {
      Console.WriteLine($"Error: {e.Message}");
  }

  void ResetConversation()
  {
      messages.Clear();
      Console.WriteLine("Conversation reset due to refusal");
  }
  ```

  ```go Go
  var messages []anthropic.MessageParam

  func resetConversation() {
  	messages = []anthropic.MessageParam{}
  	fmt.Println("Conversation reset due to refusal")
  }
  // ...
  	client := anthropic.NewClient()

  	stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{
  		Model:     anthropic.ModelClaudeOpus5_5,
  		MaxTokens: 1024,
  		Messages: []anthropic.MessageParam{
  			anthropic.NewUserMessage(anthropic.NewTextBlock("Hello")),
  		},
  	})

  streamLoop:
  	for stream.Next() {
  		event := stream.Current()
  		switch eventVariant := event.AsAny().(type) {
  		case anthropic.MessageDeltaEvent:
  			if eventVariant.Delta.StopReason == anthropic.StopReasonRefusal {
  				resetConversation()
  				break streamLoop
  			}
  		}
  	}

  	if err := stream.Err(); err != nil {
  		log.Fatal(err)
  	}
  ```

  ```java Java
  import com.anthropic.core.http.StreamResponse;
  import com.anthropic.models.messages.RawMessageStreamEvent;
  import com.anthropic.models.messages.StopReason;
  // ...

  List<MessageParam> messages = new ArrayList<>();

  void main() {
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

      MessageCreateParams params = MessageCreateParams.builder()
          .model(Model.CLAUDE_OPUS_5_5)
          .maxTokens(1024L)
          .addUserMessage("Hello")
          .build();

      try (StreamResponse<RawMessageStreamEvent> stream = client.messages().createStreaming(params)) {
          stream.stream().forEach(event -> {
              event.messageDelta().ifPresent(deltaEvent -> {
                  deltaEvent.delta().stopReason().ifPresent(stopReason -> {
                      if (stopReason.equals(StopReason.REFUSAL)) {
                          resetConversation();
                      }
                  });
              });
          });
      } catch (Exception e) {
          System.err.println("Error: " + e.getMessage());
      }
  }

  void resetConversation() {
      messages.clear();
      IO.println("Conversation reset due to refusal");
  }
  ```

  ```php PHP
  $client = new Client();
  $messages = [];

  function resetConversation(&$messages) {
      $messages = [];
      echo "Conversation reset due to refusal\n";
  }

  try {
      $stream = $client->messages->createStream(
          maxTokens: 1024,
          messages: [
              ['role' => 'user', 'content' => 'Hello']
          ],
          model: 'claude-opus-5-5',
      );

      foreach ($stream as $event) {
          if ($event->type === 'message_delta' && $event->delta->stopReason === 'refusal') {
              resetConversation($messages);
              break;
          }
      }
  } catch (\Exception $e) {
      echo "Error: " . $e->getMessage() . "\n";
  }
  ```

  ```ruby Ruby
  client = Anthropic::Client.new
  messages = []

  def reset_conversation(messages)
    messages.clear
    puts "Conversation reset due to refusal"
  end

  begin
    stream = client.messages.stream(
      model: :"claude-opus-5-5",
      max_tokens: 1024,
      messages: [{ role: "user", content: "Hello" }]
    )

    stream.each do |event|
      if event.type == :message_delta && event.delta.stop_reason == :refusal
        reset_conversation(messages)
        break
      end
    end
  rescue => e
    puts "Error: #{e.message}"
  end
  ```
</CodeGroup>

## Types de refus actuels

L'API gère actuellement les refus de trois manières différentes :

| Type de refus                                         | Format de réponse            | Quand il se produit                                             |
| ----------------------------------------------------- | ---------------------------- | --------------------------------------------------------------- |
| Refus des classificateurs de streaming                | **`stop_reason`: `refusal`** | Pendant le streaming lorsque le contenu enfreint les politiques |
| Validation des entrées et du droit d'auteur par l'API | Codes d'erreur 400           | Lorsque l'entrée échoue aux contrôles de validation             |
| Refus générés par le modèle                           | Réponses textuelles standard | Lorsque le modèle lui-même refuse                               |

## Bonnes pratiques

* **Surveillez les refus :** incluez des vérifications de **`stop_reason`: `refusal`** dans votre gestion des erreurs.
* **Réinitialisez automatiquement :** implémentez une réinitialisation automatique du contexte lorsque des refus sont détectés.
* **Basculez vers un autre modèle :** configurez [le repli côté serveur ou le middleware du SDK](https://platform.claude.com/docs/fr/build-with-claude/refusals-and-fallback) afin que les requêtes refusées soient relancées sur un autre modèle Claude au lieu de présenter un refus à l'utilisateur. Claude Haiku 5.5 ne dispose pas de repli côté serveur ; configurez donc sa relance dans votre client.
* **Utilisez le crédit de repli lors des relances manuelles :** si vous construisez vous-même la relance, transmettez le jeton de [crédit de repli](https://platform.claude.com/docs/fr/build-with-claude/fallback-credit) du refus afin que la relance ne paie pas deux fois le coût de la mise en cache des prompts. Les refus de Claude Haiku 5.5 ne comportent aucun crédit de repli.
* **Fournissez des messages personnalisés :** créez des messages conviviaux pour une meilleure expérience utilisateur lorsque des refus se produisent.
* **Suivez les tendances de refus :** surveillez la fréquence des refus pour identifier d'éventuels problèmes avec vos prompts.

## Notes de migration

Si vous avez mis en place une gestion des refus lors du lancement initial de cette fonctionnalité, ou si vous l'ajoutez à une intégration existante, vérifiez les points suivants :

* **Les refus sont des réponses, pas des erreurs.** Un refus arrive sous la forme d'une réponse HTTP 200 réussie avec `stop_reason`: `"refusal"`, de sorte qu'une surveillance fondée uniquement sur les taux d'erreur ne le fera pas apparaître. Suivez les refus comme un signal à part entière.
* **Les refus incluent des détails structurés.** Sur chaque modèle, un refus inclut également un objet `stop_details` qui identifie la catégorie de politique à l'origine du refus. Consultez [Refus et repli](https://platform.claude.com/docs/fr/build-with-claude/refusals-and-fallback#refusal-response) pour la forme complète de la réponse.
* **Relancez sur un autre modèle.** Renvoyer une requête refusée au même modèle entraîne généralement un nouveau refus. Au lieu de simplement réinitialiser le contexte, relancez sur un modèle de repli avec [le repli côté serveur, le middleware du SDK ou une relance manuelle](https://platform.claude.com/docs/fr/build-with-claude/refusals-and-fallback), et utilisez le [crédit de repli](https://platform.claude.com/docs/fr/build-with-claude/fallback-credit) lorsque vous construisez vous-même la relance. Claude Haiku 5.5 ne dispose pas de repli côté serveur et ses refus ne comportent aucun crédit de repli ; configurez donc sa relance dans votre client.
* **Vérifiez les refus dans les résultats de lots.** Une requête refusée dans un [Message Batch](https://platform.claude.com/docs/fr/build-with-claude/batch-processing) est renvoyée comme un résultat réussi avec `stop_reason`: `"refusal"`, et non comme un résultat en erreur.
* **Centralisez la gestion sur `stop_reason`.** L'API continue de consolider la gestion des refus autour de `stop_reason`: `"refusal"`, effectuez donc votre branchement sur la raison d'arrêt plutôt que sur un comportement propre à un modèle.

## Étapes suivantes

<CardGroup cols={2}>
  <Card title="Refus et repli" icon="arrows-clockwise" href="https://platform.claude.com/docs/fr/build-with-claude/refusals-and-fallback">
    Relancez les requêtes refusées sur un autre modèle Claude, côté serveur ou dans votre client.
  </Card>

  <Card title="Raisons d'arrêt et repli" icon="code" href="https://platform.claude.com/docs/fr/build-with-claude/handling-stop-reasons">
    Chaque valeur de `stop_reason` et la manière de la gérer.
  </Card>

  <Card title="Messages en streaming" icon="lightning" href="https://platform.claude.com/docs/fr/build-with-claude/streaming">
    Diffusez les réponses en streaming et lisez `stop_reason` depuis les événements `message_delta` au fur et à mesure de leur arrivée.
  </Card>

  <Card title="Prise en charge multilingue" icon="text-aa" href="https://platform.claude.com/docs/fr/build-with-claude/multilingual-support">
    Servez des utilisateurs dans toutes les langues grâce aux capacités interlinguistiques de Claude.
  </Card>
</CardGroup>
