Saat Anda membuat permintaan ke Messages API, respons Claude menyertakan field stop_reason yang menunjukkan mengapa model berhenti menghasilkan responsnya. Memahami nilai-nilai ini sangat penting untuk membangun aplikasi yang tangguh yang menangani berbagai jenis respons dengan tepat.
Untuk detail tentang stop_reason dalam respons API, lihat referensi Messages API.
Field stop_reason adalah bagian dari setiap respons Messages API yang berhasil. Tidak seperti error, yang menunjukkan kegagalan dalam memproses permintaan Anda, stop_reason memberi tahu Anda mengapa Claude menyelesaikan pembuatan responsnya.
{
"id": "msg_01234",
"type": "message",
"role": "assistant",
"content": [
{
"type": "text",
"text": "Here's the answer to your question..."
}
],
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 100,
"output_tokens": 50
}
}Stop reason yang paling umum. Menunjukkan bahwa Claude menyelesaikan responsnya secara alami.
from anthropic import Anthropic
client = Anthropic()
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello!"}],
)
if response.stop_reason == "end_turn":
# Proses respons lengkap
print(response.content[0].text)Terkadang Claude mengembalikan respons kosong (tepat 2-3 token tanpa konten) dengan stop_reason: "end_turn". Ini biasanya terjadi ketika Claude menafsirkan bahwa giliran asisten sudah selesai, terutama setelah hasil alat.
Penyebab umum:
Cara mencegah respons kosong:
# SALAH: Menambahkan teks langsung setelah tool_result
messages = [
{"role": "user", "content": "Calculate the sum of 1234 and 5678"},
{
"role": "assistant",
"content": [
{
"type": "tool_use",
"id": "toolu_123",
"name": "calculator",
"input": {"operation": "add", "a": 1234, "b": 5678},
}
],
},
{
"role": "user",
"content": [
{"type": "tool_result", "tool_use_id": "toolu_123", "content": "6912"},
{
"type": "text",
"text": "Here's the result", # Don't add text after tool_result
},
],
},
]
# BENAR: Kirim hasil alat secara langsung tanpa teks tambahan
messages = [
{"role": "user", "content": "Calculate the sum of 1234 and 5678"},
{
"role": "assistant",
"content": [
{
"type": "tool_use",
"id": "toolu_123",
"name": "calculator",
"input": {"operation": "add", "a": 1234, "b": 5678},
}
],
},
{
"role": "user",
"content": [
{"type": "tool_result", "tool_use_id": "toolu_123", "content": "6912"}
],
}, # Just the tool_result, no additional text
]
# Jika Anda masih mendapatkan respons kosong setelah memperbaiki struktur pesan:
def handle_empty_response(client, messages):
response = client.messages.create(
model="claude-opus-4-8", max_tokens=1024, messages=messages
)
# Periksa apakah respons kosong
if response.stop_reason == "end_turn" and not response.content:
# SALAH: Jangan hanya mencoba ulang dengan respons kosong tersebut
# Ini tidak akan berhasil karena Claude sudah memutuskan bahwa ia selesai
# BENAR: Tambahkan prompt lanjutan dalam pesan user yang BARU
messages.append({"role": "user", "content": "Please continue"})
response = client.messages.create(
model="claude-opus-4-8", max_tokens=1024, messages=messages
)
return responsePraktik terbaik:
Claude berhenti karena mencapai batas max_tokens yang ditentukan dalam permintaan Anda.
# Permintaan dengan token terbatas
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=10,
messages=[{"role": "user", "content": "Explain quantum physics"}],
)
if response.stop_reason == "max_tokens":
# Respons terpotong
print("Response was cut off at token limit")
# Pertimbangkan untuk membuat permintaan lain untuk melanjutkanJika respons Claude terpotong karena mencapai batas max_tokens, dan respons yang terpotong tersebut berisi blok tool use yang tidak lengkap, Anda perlu mencoba ulang permintaan dengan nilai max_tokens yang lebih tinggi untuk mendapatkan tool use yang lengkap.
# Periksa apakah respons terpotong selama penggunaan alat
if response.stop_reason == "max_tokens":
# Periksa apakah blok konten terakhir adalah tool_use yang tidak lengkap
last_block = response.content[-1]
if last_block.type == "tool_use":
# Kirim permintaan dengan max_tokens yang lebih tinggi
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=4096, # Increased limit
messages=messages,
tools=tools,
)Claude menemukan salah satu stop sequence kustom Anda.
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
stop_sequences=["END", "STOP"],
messages=[{"role": "user", "content": "Generate text until you say END"}],
)
if response.stop_reason == "stop_sequence":
print(f"Stopped at sequence: {response.stop_sequence}")Claude memanggil sebuah alat dan mengharapkan Anda untuk mengeksekusinya.
Untuk sebagian besar implementasi penggunaan alat, gunakan tool runner, yang secara otomatis menangani eksekusi alat, pemformatan hasil, dan manajemen percakapan.
from anthropic import Anthropic
client = Anthropic()
weather_tool = {
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "City and state"},
},
"required": ["location"],
},
}
def execute_tool(name, tool_input):
"""Execute a tool and return the result."""
return f"Weather in {tool_input.get('location', 'unknown')}: 72°F"
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
tools=[weather_tool],
messages=[{"role": "user", "content": "What's the weather?"}],
)
if response.stop_reason == "tool_use":
# Ekstrak dan jalankan alat
for content in response.content:
if content.type == "tool_use":
result = execute_tool(content.name, content.input)
# Kembalikan hasil ke Claude untuk respons akhirDikembalikan ketika loop sampling sisi server mencapai batas iterasinya saat mengeksekusi server tools seperti web search atau web fetch. Batas default adalah 10 iterasi per permintaan.
Ketika ini terjadi, respons mungkin berisi blok server_tool_use tanpa server_tool_result yang sesuai. Untuk membiarkan Claude menyelesaikan pemrosesan, lanjutkan percakapan dengan mengirim kembali respons apa adanya.
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
tools=[{"type": "web_search_20250305", "name": "web_search"}],
messages=[{"role": "user", "content": "Search for latest AI news"}],
)
if response.stop_reason == "pause_turn":
# Lanjutkan percakapan dengan mengirim kembali respons tersebut
messages = [
{"role": "user", "content": original_query},
{"role": "assistant", "content": response.content},
]
continuation = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
messages=messages,
tools=[{"type": "web_search_20250305", "name": "web_search"}],
)Aplikasi Anda harus menangani pause_turn dalam setiap loop agen yang menggunakan server tools. Cukup tambahkan respons asisten ke array messages Anda dan buat permintaan API lain untuk membiarkan Claude melanjutkan.
Claude menolak untuk menghasilkan respons. Pada Claude Fable 5, pengklasifikasi keamanan mengembalikan stop reason ini sebagai respons HTTP 200 normal, bukan error.
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
messages=[{"role": "user", "content": "[Unsafe request]"}],
)
if response.stop_reason == "refusal":
# Claude menolak untuk merespons
print("Claude was unable to process this request")
# Pertimbangkan untuk menyusun ulang atau memodifikasi permintaanJika Anda sering menemukan stop reason refusal saat menggunakan Claude Sonnet 4.5 atau Opus 4.1 (tidak digunakan lagi), Anda dapat mencoba memperbarui panggilan API Anda untuk menggunakan Haiku 4.5 (claude-haiku-4-5-20251001), yang memiliki batasan penggunaan yang berbeda. Pelajari lebih lanjut tentang memahami filter keamanan API Sonnet 4.5.
Pada penolakan, objek stop_details mengidentifikasi kategori kebijakan yang memicunya. Kategori-kategori tersebut dan bentuk lengkap respons penolakan dibahas di Penolakan dan fallback. stop_details bernilai null untuk semua stop reason selain refusal.
Permintaan yang ditolak pada Claude Fable 5 biasanya dapat dilayani dengan mencoba ulang pada model Claude lain, dan Penolakan dan fallback menunjukkan cara menyiapkan percobaan ulang tersebut, baik di sisi server maupun di klien Anda. Kredit fallback membahas cara menghindari pembayaran biaya cache prompt dua kali ketika Anda membangun percobaan ulang sendiri.
Claude berhenti karena mencapai batas jendela konteks model. Ini memungkinkan Anda meminta token maksimum yang mungkin tanpa mengetahui ukuran input yang tepat.
# Permintaan dengan token maksimum untuk mendapatkan sebanyak mungkin
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=20000, # Python SDK requires streaming for max_tokens above ~21k (Opus 4.8 supports 128k with streaming)
messages=[
{"role": "user", "content": "Large input that uses most of context window..."}
],
)
if response.stop_reason == "model_context_window_exceeded":
# Respons mencapai batas jendela konteks sebelum max_tokens
print("Response reached model's context window limit")
# Respons tetap valid tetapi dibatasi oleh jendela konteksStop reason ini tersedia secara default di Sonnet 4.5 dan model yang lebih baru. Untuk model sebelumnya, gunakan beta header model-context-window-exceeded-2025-08-26 untuk mengaktifkan perilaku ini.
Biasakan untuk memeriksa stop_reason dalam logika penanganan respons Anda:
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 == "model_context_window_exceeded":
return handle_context_limit(response)
elif response.stop_reason == "pause_turn":
return handle_pause(response)
elif response.stop_reason == "refusal":
return handle_refusal(response)
else:
# Tangani end_turn dan kasus lainnya
return response.content[0].textKetika respons terpotong karena batas token atau jendela konteks:
def handle_truncated_response(response):
if response.stop_reason in ["max_tokens", "model_context_window_exceeded"]:
# Opsi 1: Peringatkan pengguna tentang batas spesifik tersebut
if response.stop_reason == "max_tokens":
message = "[Response truncated due to max_tokens limit]"
else:
message = "[Response truncated due to context window limit]"
return f"{response.content[0].text}\n\n{message}"
# Opsi 2: Lanjutkan proses generasi
messages = [
{"role": "user", "content": original_prompt},
{"role": "assistant", "content": response.content[0].text},
]
continuation = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
messages=messages + [{"role": "user", "content": "Please continue"}],
)
return response.content[0].text + continuation.content[0].textSaat menggunakan server tools, API mungkin mengembalikan pause_turn jika loop sampling sisi server mencapai batas iterasinya (default 10). Tangani ini dengan melanjutkan percakapan:
def handle_server_tool_conversation(client, user_query, tools, max_continuations=5):
"""
Handle server tool conversations that may require multiple continuations.
The server runs a sampling loop when executing server tools. If the loop
reaches its iteration limit, the API returns pause_turn. Continue the
conversation by sending the response back to let Claude finish.
"""
messages = [{"role": "user", "content": user_query}]
for _ in range(max_continuations):
response = client.messages.create(
model="claude-opus-4-8", max_tokens=1024, messages=messages, tools=tools
)
if response.stop_reason != "pause_turn":
# Claude selesai memproses - kembalikan respons akhir
return response
# pause_turn: ganti seluruh daftar pesan untuk mempertahankan peran yang bergantian
messages = [
{"role": "user", "content": user_query},
{"role": "assistant", "content": response.content},
]
# Mencapai batas maksimum kelanjutan - kembalikan respons terakhir
return responsePenting untuk membedakan antara nilai stop_reason dan error yang sebenarnya:
import anthropic
from anthropic import Anthropic
client = Anthropic()
try:
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello!"}],
)
# Tangani respons yang berhasil dengan stop_reason
if response.stop_reason == "max_tokens":
print("Response was truncated")
except anthropic.APIStatusError as e:
# Tangani error yang sebenarnya
if e.status_code == 429:
print("Rate limit exceeded")
elif e.status_code == 500:
print("Server error")Saat menggunakan streaming, stop_reason adalah:
null dalam event message_start awalmessage_deltafrom anthropic import Anthropic
client = Anthropic()
with client.messages.stream(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello!"}],
) as stream:
for event in stream:
if event.type == "message_delta":
stop_reason = event.delta.stop_reason
if stop_reason:
print(f"Stream ended with: {stop_reason}")Lebih sederhana dengan tool runner: Contoh berikut menunjukkan penanganan alat secara manual. Untuk sebagian besar kasus penggunaan, tool runner secara otomatis menangani eksekusi alat dengan kode yang jauh lebih sedikit.
def complete_tool_workflow(client, user_query, tools):
messages = [{"role": "user", "content": user_query}]
while True:
response = client.messages.create(
model="claude-opus-4-8", max_tokens=1024, messages=messages, tools=tools
)
if response.stop_reason == "tool_use":
# Jalankan alat dan lanjutkan
tool_results = execute_tools(response.content)
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
else:
# Respons akhir
return responsedef 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-opus-4-8", messages=messages, max_tokens=4096
)
full_response += response.content[0].text
if response.stop_reason != "max_tokens":
break
# Lanjutkan dari titik terakhir berhenti
messages = [
{"role": "user", "content": prompt},
{"role": "assistant", "content": full_response},
{"role": "user", "content": "Please continue from where you left off."},
]
return full_responseDengan stop reason model_context_window_exceeded, Anda dapat meminta token maksimum yang mungkin tanpa menghitung ukuran input:
def get_max_possible_tokens(client, prompt):
"""
Get as many tokens as possible within the model's context window
without needing to calculate input token count
"""
response = client.messages.create(
model="claude-opus-4-8",
messages=[{"role": "user", "content": prompt}],
max_tokens=20000, # Python SDK requires streaming for max_tokens above ~21k
)
if response.stop_reason == "model_context_window_exceeded":
# Mendapatkan token maksimum yang mungkin berdasarkan ukuran input
print(
f"Generated {response.usage.output_tokens} tokens (context limit reached)"
)
elif response.stop_reason == "max_tokens":
# Mendapatkan persis jumlah token yang diminta
print(f"Generated {response.usage.output_tokens} tokens (max_tokens reached)")
else:
# Penyelesaian alami
print(f"Generated {response.usage.output_tokens} tokens (natural completion)")
return response.content[0].textDengan menangani nilai stop_reason dengan benar, Anda dapat membangun aplikasi yang lebih tangguh yang menangani berbagai skenario respons dengan baik dan memberikan pengalaman pengguna yang lebih baik.
Was this page helpful?