Tool use di Bedrock
Model tidak pernah memanggil tool sendiri. Ia meminta, dan kodemu yang menjalankan — kecuali kamu memilih mode server-side. Memahami loop ini adalah kunci seluruh Fase 5.
Intisari
- Kamu mengirim definisi tool; model memutuskan kapan tool dibutuhkan.
- Tiga mode: client-side (kodemu yang menjalankan), server-side (Bedrock yang menjalankan lewat Lambda/Gateway), dan mode khas Claude.
stopReason == "tool_use"adalah penanda bahwa model meminta tool.- Hasil tool dikirim balik sebagai pesan
userberisi bloktoolResult— dan loop berlanjut. - Deskripsi tool adalah prompt. Deskripsi yang buruk menghasilkan pemanggilan tool yang buruk.
Tiga mode
| Mode | Siapa menjalankan tool | Kapan dipakai |
|---|---|---|
| Client-side | Kode aplikasimu, setelah model meminta | Mayoritas kasus. Tersedia di Converse dan InvokeModel. |
| Server-side | Bedrock sendiri, lewat Lambda atau AgentCore Gateway yang kamu daftarkan | Eksekusi tool terpusat dan aman, tanpa orkestrasi di aplikasimu |
| Khas Claude | Kodemu, dengan tipe tool bawaan Anthropic | Computer use, eksekusi kode, penyuntingan berkas, memori persisten |
Materi ini fokus pada client-side, karena di situlah loop-nya terlihat jelas — dan pemahaman itu terpakai di semua mode lain.
Mendefinisikan tool
TOOLS = {
"tools": [{
"toolSpec": {
"name": "cari_dokumen",
"description": (
"Cari dokumen kebijakan internal perusahaan. "
"Gunakan ini setiap kali pengguna bertanya tentang aturan, prosedur, "
"atau kebijakan internal. Jangan gunakan untuk pertanyaan umum."
),
"inputSchema": {"json": {
"type": "object",
"properties": {
"kueri": {"type": "string",
"description": "Kata kunci pencarian dalam bahasa Indonesia"},
"departemen": {"type": "string", "enum": ["hr", "keuangan", "teknik"]},
},
"required": ["kueri"],
}},
}
}]
}
Deskripsi tool adalah bagian dari prompt-mu. Model memilih tool berdasarkan teks ini — bukan berdasarkan nama fungsinya. Tulis kapan tool harus dipakai dan kapan tidak boleh. Sebagian besar keluhan "agent-ku memanggil tool yang salah" sebenarnya masalah deskripsi, bukan masalah model.
Loop lengkapnya
import json
import boto3
runtime = boto3.client("bedrock-runtime")
FUNGSI = {"cari_dokumen": cari_dokumen} # peta nama tool → fungsi Python
def jalankan(pertanyaan: str, maks_giliran: int = 5) -> str:
pesan = [{"role": "user", "content": [{"text": pertanyaan}]}]
for _ in range(maks_giliran): # batas langkah — WAJIB ada
resp = runtime.converse(
modelId=MODEL_ID,
messages=pesan,
toolConfig=TOOLS,
inferenceConfig={"maxTokens": 1024, "temperature": 0},
)
keluaran = resp["output"]["message"]
pesan.append(keluaran) # simpan jawaban model apa adanya
if resp["stopReason"] != "tool_use":
return "".join(b["text"] for b in keluaran["content"] if "text" in b)
# Model meminta satu atau lebih tool
hasil = []
for blok in keluaran["content"]:
if "toolUse" not in blok:
continue
minta = blok["toolUse"]
try:
nilai = FUNGSI[minta["name"]](**minta["input"])
hasil.append({"toolResult": {
"toolUseId": minta["toolUseId"],
"content": [{"json": nilai}],
}})
except Exception as e:
# Kirim errornya ke model — sering ia bisa memperbaiki sendiri
hasil.append({"toolResult": {
"toolUseId": minta["toolUseId"],
"content": [{"text": f"error: {e}"}],
"status": "error",
}})
pesan.append({"role": "user", "content": hasil})
raise RuntimeError("batas giliran tercapai tanpa jawaban akhir")
Bagian yang mudah salah
| Kesalahan | Akibat |
|---|---|
| Tidak menyimpan pesan asisten ke riwayat | Model kehilangan konteks permintaannya sendiri; loop kacau |
toolUseId tidak dikembalikan persis | ValidationException |
Hasil tool dikirim dengan role assistant | Harus user — ini kontra-intuitif tapi memang begitu |
| Tidak ada batas giliran | Loop tak terbatas yang membakar token sampai timeout |
| Exception tool dilempar ke atas | Kehilangan kesempatan model memperbaiki argumennya sendiri |
Beberapa toolUse dalam satu respons diabaikan | Model bisa meminta lebih dari satu tool sekaligus |
Memaksa perilaku tertentu
TOOLS["toolChoice"] = {"auto": {}} # default: model yang memutuskan
TOOLS["toolChoice"] = {"any": {}} # wajib pakai salah satu tool
TOOLS["toolChoice"] = {"tool": {"name": "cari_dokumen"}} # wajib pakai tool ini
toolChoice berguna untuk ekstraksi terstruktur: definisikan satu tool yang skema masukannya
adalah bentuk data yang kamu inginkan, lalu paksa model memakainya. Hasilnya JSON tervalidasi, bukan teks
yang harus kamu parse dengan harapan.
Batas pengaman
Exam guide menyebut ini eksplisit sebagai safeguarded AI workflows. Minimal yang harus ada:
- Batas jumlah giliran — seperti
maks_gilirandi atas. - Timeout per tool — satu tool yang menggantung tidak boleh menahan seluruh permintaan.
- Izin IAM sempit untuk fungsi yang menjalankan tool — tool bukan pintu masuk ke seluruh akunmu.
- Validasi argumen sebelum dieksekusi. Skema JSON adalah petunjuk untuk model, bukan jaminan keamanan.
- Persetujuan manusia untuk tool yang mengubah keadaan — pakai Step Functions dari Fase 1.
Latihan: hubungkan tool cari_dokumen ke knowledge base Fase 4 dan jalankan loop di atas.
Ajukan dua pertanyaan: satu yang jelas butuh dokumen internal, satu pertanyaan umum. Buktikan model hanya
memanggil tool pada yang pertama — lalu ubah deskripsi tool jadi asal-asalan dan amati perilakunya rusak.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.