Quando effettui una richiesta all’API Messages, la risposta di Claude include un campo stop_reason che indica perché il modello ha smesso di generare la sua risposta. Comprendere questi valori è fondamentale per costruire applicazioni robuste che gestiscano in modo appropriato diversi tipi di risposta.

Per i dettagli su stop_reason nella risposta API, consulta il riferimento dell’API Messages.

Che cos’è stop_reason?

Il campo stop_reason fa parte di ogni risposta dell’API Messages andata a buon fine. A differenza degli errori, che indicano fallimenti nell’elaborazione della tua richiesta, stop_reason ti dice perché Claude ha completato con successo la generazione della sua risposta.

Esempio di risposta
{
  "id": "msg_01234",
  "type": "message",
  "role": "assistant",
  "content": [
    {
      "type": "text",
      "text": "Ecco la risposta alla tua domanda..."
    }
  ],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": {
    "input_tokens": 100,
    "output_tokens": 50
  }
}

Valori di stop reason

end_turn

La ragione di interruzione più comune. Indica che Claude ha terminato naturalmente la sua risposta.

if response.stop_reason == "end_turn":
    # Elabora la risposta completa
    print(response.content[0].text)

max_tokens

Claude si è fermato perché ha raggiunto il limite max_tokens specificato nella tua richiesta.

# Richiesta con token limitati
response = client.messages.create(
    model="claude-3-7-sonnet-20250219",
    max_tokens=10,
    messages=[{"role": "user", "content": "Spiega la fisica quantistica"}]
)

if response.stop_reason == "max_tokens":
    # La risposta è stata troncata
    print("La risposta è stata interrotta al limite di token")
    # Considera di fare un'altra richiesta per continuare

stop_sequence

Claude ha incontrato una delle tue sequenze di interruzione personalizzate.

response = client.messages.create(
    model="claude-3-7-sonnet-20250219",
    max_tokens=1024,
    stop_sequences=["END", "STOP"],
    messages=[{"role": "user", "content": "Genera testo finché non dici END"}]
)

if response.stop_reason == "stop_sequence":
    print(f"Fermato alla sequenza: {response.stop_sequence}")

tool_use

Claude sta chiamando uno strumento e si aspetta che tu lo esegua.

response = client.messages.create(
    model="claude-3-7-sonnet-20250219",
    max_tokens=1024,
    tools=[weather_tool],
    messages=[{"role": "user", "content": "Com'è il tempo?"}]
)

if response.stop_reason == "tool_use":
    # Estrai ed esegui lo strumento
    for content in response.content:
        if content.type == "tool_use":
            result = execute_tool(content.name, content.input)
            # Restituisci il risultato a Claude per la risposta finale

pause_turn

Utilizzato con strumenti server come la ricerca web quando Claude deve mettere in pausa un’operazione di lunga durata.

response = client.messages.create(
    model="claude-3-7-sonnet-20250219",
    max_tokens=1024,
    tools=[{"type": "web_search_20250305", "name": "web_search"}],
    messages=[{"role": "user", "content": "Cerca le ultime notizie sull'IA"}]
)

if response.stop_reason == "pause_turn":
    # Continua la conversazione
    messages = [
        {"role": "user", "content": original_query},
        {"role": "assistant", "content": response.content}
    ]
    continuation = client.messages.create(
        model="claude-3-7-sonnet-20250219",
        messages=messages,
        tools=[{"type": "web_search_20250305", "name": "web_search"}]
    )

Best practice per gestire le ragioni di interruzione

1. Controlla sempre stop_reason

Prendi l’abitudine di controllare stop_reason nella tua logica di gestione delle risposte:

def handle_response(response):
    if response.stop_reason == "tool_use":
        return handle_tool_use(response)
    elif response.stop_reason == "max_tokens":
        return handle_truncation(response)
    elif response.stop_reason == "pause_turn":
        return handle_pause(response)
    else:
        # Gestisci end_turn e altri casi
        return response.content[0].text

2. Gestisci max_tokens con eleganza

Quando una risposta viene troncata a causa dei limiti di token:

def handle_truncated_response(response):
    if response.stop_reason == "max_tokens":
        # Opzione 1: Avvisa l'utente
        return f"{response.content[0].text}\n\n[Risposta troncata a causa della lunghezza]"
        
        # Opzione 2: Continua la generazione
        messages = [
            {"role": "user", "content": original_prompt},
            {"role": "assistant", "content": response.content[0].text}
        ]
        continuation = client.messages.create(
            model="claude-3-7-sonnet-20250219",
            max_tokens=1024,
            messages=messages + [{"role": "user", "content": "Per favore continua"}]
        )
        return response.content[0].text + continuation.content[0].text

3. Implementa la logica di ripetizione per pause_turn

Per strumenti server che potrebbero andare in pausa:

def handle_paused_conversation(initial_response, max_retries=3):
    response = initial_response
    messages = [{"role": "user", "content": original_query}]
    
    for attempt in range(max_retries):
        if response.stop_reason != "pause_turn":
            break
            
        messages.append({"role": "assistant", "content": response.content})
        response = client.messages.create(
            model="claude-3-7-sonnet-20250219",
            messages=messages,
            tools=original_tools
        )
    
    return response

Ragioni di interruzione vs. errori

È importante distinguere tra i valori di stop_reason e gli errori effettivi:

Ragioni di interruzione (risposte riuscite)

  • Parte del corpo della risposta
  • Indicano perché la generazione si è fermata normalmente
  • La risposta contiene contenuto valido

Errori (richieste fallite)

  • Codici di stato HTTP 4xx o 5xx
  • Indicano fallimenti nell’elaborazione della richiesta
  • La risposta contiene dettagli sull’errore
try:
    response = client.messages.create(...)
    
    # Gestisci la risposta riuscita con stop_reason
    if response.stop_reason == "max_tokens":
        print("La risposta è stata troncata")
    
except anthropic.APIError as e:
    # Gestisci gli errori effettivi
    if e.status_code == 429:
        print("Limite di frequenza superato")
    elif e.status_code == 500:
        print("Errore del server")

Considerazioni sullo streaming

Quando si utilizza lo streaming, stop_reason è:

  • null nell’evento iniziale message_start
  • Fornito nell’evento message_delta
  • Non nullo in tutti gli altri eventi
with client.messages.stream(...) as stream:
    for event in stream:
        if event.type == "message_delta":
            stop_reason = event.delta.stop_reason
            if stop_reason:
                print(f"Stream terminato con: {stop_reason}")

Pattern comuni

Gestione dei flussi di lavoro degli strumenti

def complete_tool_workflow(client, user_query, tools):
    messages = [{"role": "user", "content": user_query}]
    
    while True:
        response = client.messages.create(
            model="claude-3-7-sonnet-20250219",
            messages=messages,
            tools=tools
        )
        
        if response.stop_reason == "tool_use":
            # Esegui gli strumenti e continua
            tool_results = execute_tools(response.content)
            messages.append({"role": "assistant", "content": response.content})
            messages.append({"role": "user", "content": tool_results})
        else:
            # Risposta finale
            return response

Garantire risposte complete

def get_complete_response(client, prompt, max_attempts=3):
    messages = [{"role": "user", "content": prompt}]
    full_response = ""
    
    for _ in range(max_attempts):
        response = client.messages.create(
            model="claude-3-7-sonnet-20250219",
            messages=messages,
            max_tokens=4096
        )
        
        full_response += response.content[0].text
        
        if response.stop_reason != "max_tokens":
            break
            
        # Continua da dove si era interrotto
        messages = [
            {"role": "user", "content": prompt},
            {"role": "assistant", "content": full_response},
            {"role": "user", "content": "Per favore continua da dove ti sei fermato."}
        ]
    
    return full_response

Gestendo correttamente i valori di stop_reason, puoi costruire applicazioni più robuste che gestiscono con eleganza diversi scenari di risposta e forniscono esperienze utente migliori.