---
title: Lidar com recusas em streaming
url: https://platform.claude.com/docs/pt-BR/test-and-evaluate/strengthen-guardrails/handle-streaming-refusals
description: Detecte e trate motivos de parada de recusa em respostas de streaming, e tente novamente solicitações recusadas em um modelo de fallback.
---

A partir dos modelos Claude 4, as respostas de streaming da API do Claude retornam **`stop_reason`: `"refusal"`** quando classificadores de streaming intervêm para lidar com possíveis violações de política. Esse recurso de segurança ajuda a manter a conformidade do conteúdo durante o streaming em tempo real.

<Tip>
  Esta página aborda como as recusas aparecem em respostas de streaming. Para cada valor de `stop_reason` e como tratá-lo, consulte [Motivos de parada e fallback](https://platform.claude.com/docs/pt-BR/build-with-claude/handling-stop-reasons). Para tentar novamente solicitações recusadas em outro modelo Claude, consulte [Recusas e fallback](https://platform.claude.com/docs/pt-BR/build-with-claude/refusals-and-fallback).
</Tip>

## Formato de resposta da API

Quando os classificadores de streaming detectam conteúdo que viola as políticas da Anthropic, a API retorna esta resposta:

```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."
  }
}
```

No fluxo de eventos, `stop_details` chega no evento `message_delta` junto com `stop_reason`.

<Note>
  Uma resposta `refusal` dos classificadores de streaming inclui um objeto `stop_details` com uma `category` e uma `explanation` legível por humanos que você pode exibir ao usuário. Consulte [Recusas e fallback](https://platform.claude.com/docs/pt-BR/build-with-claude/refusals-and-fallback#refusal-response) para ver o formato completo da resposta e as categorias disponíveis.

  Em uma recusa, o objeto `stop_details` está sempre presente, mas seus campos `category` e `explanation` podem ser `null`, por exemplo, quando a recusa não corresponde a nenhuma categoria nomeada. Faça a ramificação com base em `stop_reason` ou `stop_details.type` em vez de presumir que `category` e `explanation` estão preenchidos, e forneça suas próprias mensagens voltadas ao usuário quando eles forem `null`.
</Note>

## Redefinir o contexto após uma recusa

Quando você recebe **`stop_reason`: `refusal`**, deve redefinir o contexto da conversa antes de continuar. Você pode remover ou reformular o turno que acionou a recusa, ou limpar completamente o histórico da conversa. Tentar continuar sem redefinir resultará em recusas contínuas.

<Note>
  As métricas de uso ainda são fornecidas na resposta, mesmo quando a resposta é recusada. Se uma solicitação recusada é cobrada ou não depende de quando a recusa chega e de sua categoria; consulte [Como as recusas são cobradas](https://platform.claude.com/docs/pt-BR/build-with-claude/refusals-and-fallback#how-refusals-are-billed).
</Note>

<Tip>
  Redefinir o contexto não é a única forma de se recuperar. Você também pode tentar novamente a solicitação recusada em um modelo Claude diferente, e a página [Recusas e fallback](https://platform.claude.com/docs/pt-BR/build-with-claude/refusals-and-fallback) mostra como configurar isso com fallback no lado do servidor, o middleware do SDK ou uma nova tentativa manual.
</Tip>

## Guia de implementação

Veja como detectar e tratar recusas em streaming na sua aplicação:

<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"
    # Redefina o estado da sua conversa aqui
  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"
    # Redefina o estado da sua conversa aqui
  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:
              # Verifica se há recusa no delta da mensagem
              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() {
    // Redefine o contexto da conversa após uma recusa
    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) {
      // Verifica se há recusa no delta da mensagem
      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>

## Tipos de recusa atuais

Atualmente, a API trata recusas de três maneiras diferentes:

| Tipo de recusa                                     | Formato da resposta          | Quando ocorre                                          |
| -------------------------------------------------- | ---------------------------- | ------------------------------------------------------ |
| Recusas de classificadores de streaming            | **`stop_reason`: `refusal`** | Durante o streaming, quando o conteúdo viola políticas |
| Validação de entrada e de direitos autorais da API | Códigos de erro 400          | Quando a entrada falha nas verificações de validação   |
| Recusas geradas pelo modelo                        | Respostas de texto padrão    | Quando o próprio modelo recusa                         |

## Melhores práticas

* **Monitore recusas:** Inclua verificações de **`stop_reason`: `refusal`** no seu tratamento de erros
* **Redefina automaticamente:** Implemente a redefinição automática de contexto quando recusas forem detectadas
* **Recorra a outro modelo:** Configure o [fallback no lado do servidor ou o middleware do SDK](https://platform.claude.com/docs/pt-BR/build-with-claude/refusals-and-fallback) para que solicitações recusadas sejam tentadas novamente em outro modelo Claude em vez de exibir uma recusa ao usuário. O Claude Haiku 5.5 não tem fallback no lado do servidor, então configure a nova tentativa dele no seu cliente
* **Resgate o crédito de fallback em novas tentativas manuais:** Se você mesmo construir a nova tentativa, passe o token de [crédito de fallback](https://platform.claude.com/docs/pt-BR/build-with-claude/fallback-credit) da recusa para que a nova tentativa não pague duas vezes o custo do cache de prompt. As recusas do Claude Haiku 5.5 não incluem crédito de fallback
* **Forneça mensagens personalizadas:** Crie mensagens amigáveis ao usuário para uma melhor UX quando ocorrerem recusas
* **Acompanhe padrões de recusa:** Monitore a frequência de recusas para identificar possíveis problemas com seus prompts

## Notas de migração

Se você construiu o tratamento de recusas quando esse recurso foi lançado pela primeira vez, ou está adicionando-o a uma integração existente, verifique o seguinte:

* **Recusas são respostas, não erros.** Uma recusa chega como uma resposta HTTP 200 bem-sucedida com `stop_reason`: `"refusal"`, portanto um monitoramento baseado apenas em taxas de erro não a detectará. Acompanhe as recusas como um sinal próprio.
* **Recusas incluem detalhes estruturados.** Em todos os modelos, uma recusa também inclui um objeto `stop_details` que identifica a categoria de política por trás da recusa. Consulte [Recusas e fallback](https://platform.claude.com/docs/pt-BR/build-with-claude/refusals-and-fallback#refusal-response) para ver o formato completo da resposta.
* **Tente novamente em um modelo diferente.** Reenviar uma solicitação recusada ao mesmo modelo geralmente resulta em outra recusa. Em vez de apenas redefinir o contexto, tente novamente em um modelo de fallback com [fallback no lado do servidor, o middleware do SDK ou uma nova tentativa manual](https://platform.claude.com/docs/pt-BR/build-with-claude/refusals-and-fallback), e resgate o [crédito de fallback](https://platform.claude.com/docs/pt-BR/build-with-claude/fallback-credit) quando você mesmo construir a nova tentativa. O Claude Haiku 5.5 não tem fallback no lado do servidor, e suas recusas não incluem crédito de fallback, então configure a nova tentativa dele no seu cliente.
* **Verifique recusas nos resultados de lotes.** Uma solicitação recusada em um [Message Batch](https://platform.claude.com/docs/pt-BR/build-with-claude/batch-processing) é retornada como um resultado bem-sucedido com `stop_reason`: `"refusal"`, não como um resultado com erro.
* **Centralize o tratamento em `stop_reason`.** A API continua a consolidar o tratamento de recusas em torno de `stop_reason`: `"refusal"`, portanto faça a ramificação com base no motivo de parada em vez de em comportamentos específicos de modelo.

## Próximos passos

<CardGroup cols={2}>
  <Card title="Recusas e fallback" icon="arrows-clockwise" href="https://platform.claude.com/docs/pt-BR/build-with-claude/refusals-and-fallback">
    Tente novamente solicitações recusadas em outro modelo Claude, no lado do servidor ou no seu cliente.
  </Card>

  <Card title="Motivos de parada e fallback" icon="code" href="https://platform.claude.com/docs/pt-BR/build-with-claude/handling-stop-reasons">
    Cada valor de `stop_reason` e como tratá-lo.
  </Card>

  <Card title="Streaming de mensagens" icon="lightning" href="https://platform.claude.com/docs/pt-BR/build-with-claude/streaming">
    Faça streaming de respostas e leia `stop_reason` dos eventos `message_delta` à medida que chegam.
  </Card>

  <Card title="Suporte multilíngue" icon="text-aa" href="https://platform.claude.com/docs/pt-BR/build-with-claude/multilingual-support">
    Atenda usuários em vários idiomas com as capacidades multilíngues do Claude.
  </Card>
</CardGroup>
