Saya telah menggunakan tool use Claude (yang disebut OpenAI sebagai function calling) di produksi untuk aplikasi fitness AI Gymbro selama beberapa bulan. Dokumentasi Anthropic bagus, tetapi ada kesenjangan antara contoh tutorial dan kekacauan produksi nyata. Posting ini mencakup apa yang saya harapkan seseorang memberitahu saya ketika saya mulai.
Tool use Claude bekerja dengan memberikan model schema JSON yang mendeskripsikan alat yang tersedia. Kualitas deskripsi alat Anda adalah faktor terpenting dalam akurasi pemanggilan alat. Deskripsi yang tidak jelas seperti 'mencatat latihan' menyebabkan model menebak nilai argumen.
Gunakan tipe enum sebisa mungkin untuk membatasi pilihan model. Jika field hanya bisa 'sets', 'reps', atau 'weight', definisikan sebagai enum. Tambahkan contoh di field deskripsi — model menggunakan contoh ini untuk mengoreksi diri saat tidak yakin dengan format yang benar.
API Claude mendukung parameter tool_choice yang memungkinkan Anda mengontrol apakah model harus menggunakan alat (tool_choice: 'any' atau menentukan nama alat) atau boleh menggunakan alat secara opsional. Menggunakan tool_choice: { type: 'tool', name: 'log_workout' } memaksa model untuk selalu mengembalikan panggilan alat log_workout.
Claude Tool Use Flow
User: "Log 3 sets of 8 reps bench press at 80kg"
│
▼
┌──────────────────────────────────────┐
│ Claude receives: │
│ - User message │
│ - Tool definitions (JSON Schema) │
│ - System prompt (cached) │
└──────────────────┬───────────────────┘
│
▼
┌──────────────────────────────────────┐
│ Claude returns: │
│ stop_reason: "tool_use" │
│ content: [{ │
│ type: "tool_use", │
│ name: "log_workout_set", │
│ input: { │
│ exercise: "Barbell Bench Press",│
│ sets: 3, reps: 8, weight_kg: 80│
│ } │
│ }] │
└──────────────────┬───────────────────┘
│
▼
┌──────────────────────────────────────┐
│ Your App: Execute Tool │
│ - Validate args (enum, range) │
│ - Write to database │
│ - Return tool_result │
└──────────────────┬───────────────────┘
│
▼
┌──────────────────────────────────────┐
│ Second Claude call with result │
│ → Natural language confirmation │
│ "Logged 3x8 Barbell Bench Press..."│
└──────────────────────────────────────┘Untuk alur kerja multi-alat yang kompleks di API Claude, saya mendefinisikan alat 'done' yang dipanggil agent saat selesai. Alat ini mengambil parameter 'summary' yang mendeskripsikan apa yang telah dicapai. Pola ini memecahkan masalah 'bagaimana saya tahu kapan agent selesai' dengan bersih.
Pemanggilan alat gagal karena dua alasan: model memanggil alat dengan argumen tidak valid (validasi schema Anda menangkap ini), atau eksekusi alat itu sendiri gagal. Kedua kasus memerlukan pengembalian hasil ke model dengan informasi error — ini dilakukan dengan mengembalikan tool_result dengan is_error: true.
API streaming Claude mengirim peristiwa tool use saat dibuat, tetapi argumen pemanggilan alat tiba dalam fragmen. Membangun parser streaming untuk pemanggilan alat memerlukan buffering stream argumen dan hanya memicu eksekusi alat setelah peristiwa stop_reason: 'tool_use' tiba.
// Claude tool definition with precise schema
const tools = [
{
name: "log_workout_set",
description:
"Records a single completed exercise set to the user's workout log. " +
"Call this ONCE per set, not once per exercise. " +
"Use the exact exercise name from our library, e.g. 'Barbell Back Squat'.",
input_schema: {
type: "object",
properties: {
exercise_name: {
type: "string",
description: "Exercise name from library, e.g. 'Barbell Bench Press', 'Cable Row'",
},
reps: { type: "integer", minimum: 1, maximum: 100 },
weight_kg: { type: "number", minimum: 0, maximum: 1000 },
set_type: {
type: "string",
enum: ["working", "warmup", "dropset", "failure"],
description: "Type of set — default 'working' if not specified",
},
},
required: ["exercise_name", "reps"],
},
},
{
name: "done",
description: "Call when you have finished all requested actions.",
input_schema: {
type: "object",
properties: {
summary: { type: "string", description: "Brief summary of what was accomplished" },
},
required: ["summary"],
},
},
]
// Handle tool call errors gracefully
async function executeTool(name: string, args: Record<string, unknown>) {
try {
const result = await toolHandlers[name](args)
return { type: "tool_result", content: JSON.stringify(result), is_error: false }
} catch (error) {
return {
type: "tool_result",
content: JSON.stringify({
error: String(error),
suggestion: "Try using a different exercise name or check the arguments",
}),
is_error: true,
}
}
}Definisi alat berkontribusi pada jumlah token input Anda. Alat tipikal dengan schema dan deskripsi rinci biaya 100-300 token per definisi alat. Saya mengimplementasikan pemilih alat yang sadar konteks yang mengurangi 60% overhead alat.
Claude terkadang mengembalikan beberapa pemanggilan alat dalam satu respons. Jika implementasi alat Anda memiliki efek samping atau membaca dari state bersama, eksekusi paralel dapat menyebabkan race condition. Saya belajar hal ini dengan cara yang sulit ketika dua panggilan log_workout paralel membuat catatan latihan duplikat.
Menguji aplikasi LLM yang bergantung pada pemanggilan alat memerlukan pendekatan berbeda dari pengujian unit tradisional. Saya menggunakan strategi pengujian dua lapisan: mock test yang menstub LLM, dan integration test yang menggunakan panggilan LLM nyata terhadap set percakapan uji.
Setelah enam bulan tool use Claude di produksi: tingkat keberhasilan pemanggilan alat 94,2% pada percobaan pertama, 98,8% setelah satu retry. Rata-rata token per definisi alat: 180. Rata-rata pemanggilan alat per sesi pengguna: 4,3. Mode kegagalan paling umum: model memanggil alat dengan argumen yang secara semantik salah.