Tool Use Overview
Tool use adalah fondasi semua agent. LLM tidak mengeksekusi apa pun — ia hanya meminta kamu menjalankan fungsi.
Intisari
- LLM tidak menjalankan kode. Ia mengembalikan blok
tool_useberisi nama fungsi dan argumennya; kamu yang mengeksekusi. - Loop-nya: kirim tools → model minta → kamu jalankan → kirim
tool_result→ ulangi sampaiend_turn. - Definisi tool = nama + deskripsi + JSON Schema. Persis output
model_json_schema()dari Fase 2. tool_resultharus punyatool_use_idyang cocok, dan semua hasil dikirim dalam satu pesan user.- SDK punya
tool_runneryang mengurus loop-nya. Pahami loop manualnya dulu, baru pakai abstraksinya.
Model mental
KAMU MODEL
│ │
│ ── messages + tools ──────> │
│ │ "aku butuh cari_tiket(status='open')"
│ <── stop_reason: tool_use ── │
│ │
[jalankan fungsinya] │
│ │
│ ── tool_result ───────────> │
│ │ "ada 12 tiket open, yaitu..."
│ <── stop_reason: end_turn ── │
Ini seluruh rahasia "agent AI". Model tidak punya akses ke database, internet, atau filesystem-mu. Ia hanya bisa memintamu memanggil fungsi dan membaca hasilnya. Semua keputusan tentang apa yang boleh dan tidak boleh dijalankan tetap ada di kodemu.
Mendefinisikan tool
tools = [
{
"name": "cari_tiket",
"description": (
"Cari tiket support berdasarkan status. "
"Gunakan saat pengguna bertanya tentang tiket yang sedang berjalan, "
"belum selesai, atau sudah ditutup."
),
"input_schema": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["open", "closed", "pending"],
"description": "Status tiket yang dicari",
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"description": "Jumlah maksimal hasil. Default 10.",
},
},
"required": ["status"],
},
}
]
input_schema itu JSON Schema. Yaitu format yang persis dihasilkan
Model.model_json_schema() dari Pydantic. Inilah alasan Fase 2 tidak bisa dilewati —
tanpa memahami JSON Schema, bagian ini hanya jadi salinan kode.
Deskripsi adalah prompt engineering
Deskripsi tool menentukan seberapa tepat model memanggilnya. Yang perlu ada di dalamnya:
- Apa yang dilakukan tool
- Kapan ia layak dipakai
- Kapan tidak layak dipakai
- Format tiap argumen, dengan contoh kalau perlu
Kesalahan yang paling umum bukan deskripsi yang terlalu panjang, tapi terlalu pendek. Tiga sampai empat kalimat adalah minimum yang wajar untuk tool nontrivial.
Loop manual — pahami ini dulu
import anthropic
client = anthropic.Anthropic()
messages = [{"role": "user", "content": "Ada berapa tiket yang masih open?"}]
while True:
response = client.messages.create(
model="claude-opus-5",
max_tokens=16000,
tools=tools,
messages=messages,
)
if response.stop_reason == "end_turn":
break
# 1. Simpan balasan model APA ADANYA (termasuk blok tool_use)
messages.append({"role": "assistant", "content": response.content})
# 2. Jalankan tiap tool yang diminta
hasil = []
for block in response.content:
if block.type != "tool_use":
continue
try:
keluaran = jalankan_tool(block.name, block.input)
hasil.append({
"type": "tool_result",
"tool_use_id": block.id, # ← WAJIB cocok
"content": str(keluaran),
})
except Exception as e:
hasil.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": f"Error: {e}",
"is_error": True,
})
# 3. SEMUA hasil dikirim dalam SATU pesan user
messages.append({"role": "user", "content": hasil})
jawaban = next(b.text for b in response.content if b.type == "text")
Tiga aturan yang mudah dilanggar:
1. Simpan response.content utuh, jangan hanya teksnya — blok tool_use
harus ikut.
2. Tiap tool_result wajib punya tool_use_id yang cocok, atau API menolak.
3. Kalau model minta tiga tool sekaligus, ketiga hasilnya dikirim dalam satu pesan
user. Memecahnya jadi beberapa pesan akan membuat model berhenti memanggil tool
secara paralel.
Menangani error tool
{
"type": "tool_result",
"tool_use_id": block.id,
"content": "Error: kota 'xyz' tidak ditemukan. Berikan nama kota yang valid.",
"is_error": True,
}
Kembalikan pesan error yang informatif, bukan sekadar melempar exception. Model akan membacanya dan bisa mencoba pendekatan lain — misalnya bertanya balik ke pengguna atau memperbaiki argumennya.
Tool runner — abstraksinya
from anthropic import beta_tool
import anthropic
client = anthropic.Anthropic()
@beta_tool
def cari_tiket(status: str, limit: int = 10) -> str:
"""Cari tiket support berdasarkan status.
Args:
status: Status tiket, misal "open" atau "closed".
limit: Jumlah maksimal hasil yang dikembalikan.
"""
return db.query(status=status, limit=limit)
runner = client.beta.messages.tool_runner(
model="claude-opus-5",
max_tokens=16000,
tools=[cari_tiket],
messages=[{"role": "user", "content": "Ada berapa tiket yang masih open?"}],
)
for message in runner:
print(message)
Skema tool dibuat otomatis dari type hint dan docstring. status: str jadi
{"type": "string"}, dan blok Args: di docstring jadi
description tiap properti. Sekarang jelas kenapa Fase 1 (docstring) dan
Fase 2 (type hint) bukan formalitas.
Tool runner tetap memberi kendali
Anggapan umum bahwa "tool runner itu kotak hitam" keliru. Tiap iterasi memberimu pesan sebelum tool dijalankan:
- Persetujuan manusia — gerbangi di dalam fungsi tool-nya, atau periksa pesan dan intervensi sebelum eksekusi
- Logging & intersepsi — periksa hasil tool sebelum dikirim balik
- Modifikasi hasil — misalnya menambahkan
cache_control - Batas iterasi —
max_iterationssupaya loop tidak liar
Loop manual baru benar-benar perlu kalau kamu butuh bentuk kendali yang tidak disediakan hook-nya.
tool_choice
tool_choice={"type": "auto"} # model memutuskan (default)
tool_choice={"type": "any"} # wajib pakai salah satu tool
tool_choice={"type": "tool", "name": "cari"} # wajib pakai tool tertentu
tool_choice={"type": "none"} # dilarang pakai tool
Pemanggilan paralel
Model bisa meminta beberapa tool sekaligus dalam satu balasan. Jalankan bersamaan (lihat Fase 3), lalu kirim semua hasilnya dalam satu pesan:
import asyncio
panggilan = [b for b in response.content if b.type == "tool_use"]
keluaran = await asyncio.gather(*(jalankan_async(b.name, b.input) for b in panggilan))
hasil = [
{"type": "tool_result", "tool_use_id": b.id, "content": str(o)}
for b, o in zip(panggilan, keluaran)
]
messages.append({"role": "user", "content": hasil})
Merancang permukaan tool
| Prinsip | Alasan |
|---|---|
| Sedikit tool dengan batas jelas | Terlalu banyak tool membingungkan model |
| Deskripsi rinci | Faktor terbesar yang menentukan akurasi pemanggilan |
Argumen bertipe ketat (enum) | Menutup ruang nilai yang salah |
| Hasil ringkas, bukan dump mentah | Hasil tool ikut masuk konteks dan dibayar |
| Aksi berbahaya jadi tool tersendiri | Bisa digerbangi persetujuan manusia |
| Validasi argumen dengan Pydantic | Skema itu panduan, bukan jaminan |
Selalu validasi argumen tool sebelum memakainya. Model bisa mengirim argumen yang
lolos skema tapi tidak masuk akal secara bisnis. Model.model_validate(block.input)
adalah baris pertama di setiap implementasi tool yang baik.
Tool sisi server
Beberapa tool dijalankan di infrastruktur Anthropic — kamu cukup mendeklarasikannya:
tools=[
{"type": "web_search_20260209", "name": "web_search"},
{"type": "web_fetch_20260209", "name": "web_fetch"},
{"type": "code_execution_20260120", "name": "code_execution"},
]
Hasilnya datang sebagai content block di respons yang sama — tidak ada loop tool_result untuk yang ini.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.