Tool runner (SDK)
Gunakan tool runner SDK untuk menangani loop agentik, pembungkusan error, dan keamanan tipe secara otomatis.
Tool runner menangani "agentic loop" (loop agentik), pembungkusan error, dan "type safety" (keamanan tipe) sehingga Anda tidak perlu melakukannya sendiri. Ketika Anda memerlukan persetujuan human-in-the-loop, logging kustom, atau eksekusi bersyarat, gunakan loop manual sebagai gantinya.
Alih-alih menangani pemanggilan alat, hasil alat, dan manajemen percakapan secara manual, tool runner secara otomatis:
- Menjalankan alat ketika Claude memanggilnya
- Menangani siklus permintaan/respons
- Mengelola status percakapan
- Menyediakan keamanan tipe dan validasi
Penggunaan dasar
Definisikan alat menggunakan helper SDK, lalu gunakan tool runner untuk menjalankannya.
Bergantung pada signature alat di SDK, sebuah alat mengembalikan hasilnya sebagai string atau sebagai blok konten (blok teks, gambar, atau dokumen), sehingga sebuah alat dapat mengembalikan hasil multimodal. String yang dikembalikan menjadi satu blok konten teks. Untuk mengembalikan data terstruktur, seperti objek JSON atau angka, enkode terlebih dahulu sebagai string.
Gunakan decorator @beta_tool untuk mendefinisikan alat dengan type hint dan docstring.
import json
from anthropic import Anthropic, beta_tool
client = Anthropic()
@beta_tool
def get_weather(location: str, unit: str = "fahrenheit") -> str:
"""Get the current weather in a given location.
Args:
location: The city and state, e.g. San Francisco, CA
unit: Temperature unit, either 'celsius' or 'fahrenheit'
"""
return json.dumps({"temperature": "20°C", "condition": "Sunny"})
@beta_tool
def calculate_sum(a: int, b: int) -> str:
"""Add two numbers together.
Args:
a: First number
b: Second number
"""
return str(a + b)
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
tools=[get_weather, calculate_sum],
messages=[
{
"role": "user",
"content": "What's the weather like in Paris? Also, what's 15 + 27?",
}
],
)
for message in runner:
print(message)Decorator @beta_tool memeriksa argumen fungsi dan docstring untuk menurunkan skema JSON bagi Anda.
Melakukan iterasi pada tool runner
Tool runner adalah iterable yang menghasilkan pesan dari Claude. Pada setiap iterasi, runner memeriksa apakah Claude meminta penggunaan alat. Jika ya, runner menjalankan alat tersebut dan mengirim hasilnya kembali ke Claude secara otomatis, lalu menghasilkan pesan berikutnya dari Claude untuk melanjutkan loop Anda.
Anda dapat mengakhiri loop pada iterasi mana pun dengan pernyataan break. Runner terus melakukan loop hingga Claude mengembalikan pesan tanpa penggunaan alat, atau hingga mencapai max_iterations jika Anda mengaturnya.
Jika Anda tidak memerlukan pesan perantara, Anda dapat memperoleh pesan akhir secara langsung:
Gunakan runner.until_done() untuk mendapatkan pesan akhir.
client = anthropic.Anthropic()
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
tools=[get_weather, calculate_sum],
messages=[
{
"role": "user",
"content": "What's the weather like in Paris? Also, what's 15 + 27?",
}
],
)
final_message = runner.until_done()
for block in final_message.content:
if block.type == "text":
print(block.text)Penggunaan lanjutan
Di dalam loop, Anda dapat membaca setiap pesan respons dan memodifikasi status runner sebelum panggilan API berikutnya. Setiap iterasi mengikuti siklus hidup berikut:
- Runner mengirim permintaan ke Messages API dengan statusnya saat ini.
- Runner menghasilkan pesan respons ke badan loop Anda.
- Badan loop Anda dijalankan. Anda dapat membaca pesan dan secara opsional memodifikasi status runner.
- Ketika badan loop Anda selesai, runner memeriksa apakah Anda memodifikasi riwayat pesannya.
- Jika Anda tidak memodifikasi riwayat pesan: Jika pesan berisi pemanggilan alat, runner menambahkan pesan asisten dan hasil alat, lalu melanjutkan. Jika tidak ada pemanggilan alat, loop berakhir.
- Jika Anda memodifikasi riwayat pesan: Runner melewati penambahan otomatisnya dan menggunakan status Anda tanpa perubahan. Lihat Mengambil alih riwayat pesan.
Mengambil alih riwayat pesan
Secara default, runner mengelola status percakapan untuk Anda: setelah setiap giliran pemanggilan alat, runner menambahkan pesan asisten dan hasil alat apa pun ke riwayat pesannya sendiri. Anda mengambil alih riwayat pesan ketika Anda ingin mencoba ulang suatu giliran (membuang respons dan mengirim ulang), menyisipkan pesan lanjutan, atau membangun hasil alat sendiri.
Anda mengambil alih dengan memodifikasi pesan runner dari dalam badan loop. Metode persisnya bergantung pada SDK. Lihat tab per bahasa berikut ini.
Ketika Anda mengambil alih untuk suatu iterasi, runner tidak menambahkan pesan asisten atau hasil alat dari giliran tersebut. Anda menjadi bertanggung jawab untuk menjaga percakapan tetap valid: tambahkan sendiri pesan asisten dan hasil alat (jika Anda ingin giliran tersebut dihitung), modifikasi status secara bersyarat agar loop tetap dapat berakhir ketika tidak ada pemanggilan alat, dan berikan max_iterations untuk membatasi loop. Ketujuh SDK mendukung max_iterations.
Gunakan generate_tool_call_response() untuk memeriksa atau menghitung hasil alat. Memanggil append_messages() di dalam loop memberi tahu runner bahwa Anda mengelola riwayat sendiri, jadi sertakan pesan asisten dan hasil alat dalam apa yang Anda tambahkan.
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
max_iterations=10,
tools=[get_weather],
messages=[{"role": "user", "content": "What's the weather in San Francisco?"}],
)
for message in runner:
tool_response = runner.generate_tool_call_response()
if tool_response is not None:
# append_messages() menandai state sebagai dimodifikasi, jadi runner melewati
# append otomatisnya untuk iterasi ini. Tambahkan sendiri pesan asisten dan
# tool result, beserta tindak lanjut apa pun.
runner.append_messages(
message,
tool_response,
{"role": "user", "content": "Please be concise."},
)
# Jika tidak ada pemanggilan alat, biarkan state tidak tersentuh agar loop keluar.Untuk mengubah parameter permintaan seperti max_tokens tanpa mengambil alih riwayat pesan, gunakan set_messages_params(). Runner tetap menambahkan pesan asisten dan hasil alat secara otomatis.
for message in runner:
runner.set_messages_params(lambda params: {**params, "max_tokens": 2048})Manajemen konteks otomatis
Untuk tugas agentik yang berjalan lama, tool runner TypeScript dan Ruby mendukung compaction (pemadatan) otomatis, yang menghasilkan ringkasan ketika penggunaan token melebihi ambang batas sehingga percakapan dapat berlanjut melampaui batas "context window" (jendela konteks). Kedua SDK telah mendeprekasi opsi sisi klien ini dan menggantinya dengan compaction sisi server, yang berfungsi dengan tool runner setiap SDK melalui parameter permintaan context_management. Python SDK (v1.0 dan yang lebih baru) serta tool runner Go, Java, C#, dan PHP tidak menyertakan compaction sisi klien.
Men-debug eksekusi alat
Ketika sebuah alat melempar exception, tool runner menangkapnya dan mengembalikan error tersebut ke Claude sebagai hasil alat dengan is_error: true. Hasil alat membawa pesan exception (di Python, tipe dan pesannya), bukan stack trace lengkap.
Apa yang dicatat oleh SDK bersifat spesifik per bahasa. Python SDK mencatat exception lengkap, termasuk stack trace-nya, melalui modul logging standar setiap kali sebuah alat memunculkan exception yang tidak ditangani. Python, TypeScript, dan Java SDK membaca variabel lingkungan ANTHROPIC_LOG untuk mengaktifkan logging SDK, yang mencakup detail permintaan dan respons:
# Log pada level info
export ANTHROPIC_LOG=info
# Log pada level debug untuk output yang lebih rinci
export ANTHROPIC_LOG=debugGo, Ruby, C#, dan PHP SDK tidak membaca ANTHROPIC_LOG. Di luar Python, tidak ada SDK yang mencatat alat yang gagal: untuk melihat mengapa sebuah alat gagal, tangkap dan catat exception di dalam fungsi alat sebelum mengembalikan atau melemparnya kembali.
Mencegat error alat
Secara default, error alat diteruskan kembali ke Claude, yang kemudian dapat merespons dengan tepat. Namun, Anda mungkin ingin mendeteksi error dan menanganinya secara berbeda, misalnya untuk menghentikan eksekusi lebih awal atau mengimplementasikan penanganan error kustom.
Di Python dan TypeScript SDK, gunakan metode respons alat (generate_tool_call_response() di Python, generateToolResponse() di TypeScript) untuk mencegat hasil alat dan memeriksa error sebelum dikirim ke Claude. SDK lainnya tidak mengekspos hook tersebut. Tab masing-masing menjelaskan alternatif terdekat:
client = anthropic.Anthropic()
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
tools=[my_tool],
messages=[{"role": "user", "content": "Run my_tool with the query 'hello'."}],
)
for message in runner:
tool_response = runner.generate_tool_call_response()
if tool_response is not None:
# tool_response adalah dict: {"role": "user", "content": [...]}
# Periksa apakah ada hasil alat yang mengandung error
for block in tool_response["content"]:
if block.get("is_error"):
# Opsi 1: Lempar exception untuk menghentikan loop
raise RuntimeError(f"Tool failed: {json.dumps(block['content'])}")
# Opsi 2: Catat log dan lanjutkan (biarkan Claude menanganinya)
# logger.error(f"Tool error: {json.dumps(block['content'])}")
# Proses pesan seperti biasa
print(message.content)Memodifikasi hasil alat
Anda dapat memodifikasi hasil alat sebelum dikirim kembali ke Claude. Ini berguna untuk menambahkan metadata seperti cache_control guna mengaktifkan caching prompt pada hasil alat, atau untuk mentransformasi output alat.
Di Python dan TypeScript SDK, gunakan metode respons alat untuk mendapatkan hasil alat, lalu modifikasi sebelum runner melanjutkan. Apakah Anda secara eksplisit menambahkan hasil yang dimodifikasi atau memutasinya di tempat bergantung pada SDK. Lihat komentar kode di setiap tab.
client = anthropic.Anthropic()
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
tools=[search_documents],
messages=[
{
"role": "user",
"content": "Search for information about the climate of San Francisco",
}
],
)
for message in runner:
tool_response = runner.generate_tool_call_response()
if tool_response is not None:
# tool_response adalah dict: {"role": "user", "content": [...]}
# Ubah hasil alat untuk menambahkan cache control
for block in tool_response["content"]:
if block["type"] == "tool_result":
# Tambahkan cache_control untuk meng-cache hasil alat ini
block["cache_control"] = {"type": "ephemeral"}
# Tambahkan respons yang telah diubah (ini mencegah penambahan otomatis respons asli)
runner.append_messages(message, tool_response)
print(message.content)Streaming
Aktifkan streaming untuk memproses respons setiap giliran secara bertahap. Setiap iterasi menghasilkan objek stream yang dapat Anda iterasi untuk mendapatkan event.
Atur stream=True dan gunakan get_final_message() untuk mendapatkan pesan yang terakumulasi.
client = anthropic.Anthropic()
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=1024,
tools=[calculate_sum],
messages=[{"role": "user", "content": "What is 15 + 27?"}],
stream=True,
)
# Saat streaming, runner mengembalikan BetaMessageStream
for message_stream in runner:
for event in message_stream:
print("event:", event)
print("message:", message_stream.get_final_message())
print(runner.until_done())Langkah selanjutnya
Terapkan kepatuhan JSON Schema pada input alat Claude dengan sampling yang dibatasi grammar.
Parse blok tool_use, format respons tool_result, dan tangani error dengan is_error.
Aktifkan, format, dan nonaktifkan pemanggilan alat paralel, dengan panduan riwayat pesan dan pemecahan masalah.
Tentukan skema alat, tulis deskripsi yang efektif, dan kontrol kapan Claude memanggil alat Anda.
Was this page helpful?