Anthropic mengembalikan hasil tool use sebagai content block di dalam pesan — yang bisa bercampur dengan blok teks — bukan sebagai field function_call terpisah seperti OpenAI. Artinya kode Anda harus mengiterasi semua content block untuk menemukan entri tool_use, lalu mengembalikan blok tool_result di pesan berikutnya. Keuntungannya adalah model dapat secara alami menyelipkan teks penjelasan di antara tool call, namun parsing respons menjadi lebih kompleks.
Kedua API mendukung tool call paralel, di mana model mengembalikan beberapa blok tool_call atau tool_use sekaligus untuk dieksekusi secara bersamaan. Untuk agen yang membutuhkan 3 sumber data, panggilan berurutan memerlukan 3 round trip, sedangkan panggilan paralel memangkasnya menjadi 1 round trip untuk pemilihan alat ditambah 1 untuk hasil — pengurangan latensi sekitar 60% menurut post ini.
Daripada menyebarkan exception, kembalikan objek error terstruktur di dalam hasil alat yang berisi error_type, message, dan boolean retry_suggested. Ini memberi model kemampuan untuk memutuskan apakah akan mencoba ulang, beralih ke alat alternatif, atau menjelaskan kegagalan kepada pengguna. Post ini juga merekomendasikan penerapan exponential backoff untuk kegagalan sementara sebelum error dikembalikan ke model.
Definisi alat dihitung sebagai token input di setiap panggilan API meskipun model tidak menggunakannya. Dua puluh definisi alat yang detail bisa menambah 2.000–5.000 token per panggilan, yang pada harga GPT-4o setara $0,005–$0,012 ekstra per panggilan — kecil secara individual namun signifikan pada volume tinggi. Solusi yang direkomendasikan adalah perutean alat: jalankan langkah pra-klasifikasi dengan model murah seperti GPT-4o-mini atau Claude Haiku untuk mengidentifikasi alat yang relevan, lalu teruskan hanya subset tersebut ke model yang mahal.
Post ini merekomendasikan tool use Anthropic ketika Anda membutuhkan model paling andal (Claude Opus 4) atau ketika kasus penggunaan Anda mendapat manfaat dari kemampuan model mencampur penjelasan secara alami bersama tool call. Function calling OpenAI lebih tepat saat Anda membutuhkan kompatibilitas ekosistem framework agen terluas, JSON mode ketat untuk output terstruktur, atau dukungan model yang sudah di-fine-tune. Untuk sistem yang mungkin perlu berpindah provider, membangun lapisan abstraksi tipis yang mendukung kedua API sangat dianjurkan.
Function calling (atau tool use, tergantung API yang Anda gunakan) adalah fitur yang mengubah LLM dari generator teks menjadi agen yang mampu mengambil tindakan dunia nyata. Saya telah mengimplementasikan integrasi function calling dengan API OpenAI dan Anthropic untuk sistem produksi — pencarian data ERP, panggilan API eksternal, penulisan database, dan orkestrasi multi-langkah. API terlihat serupa di permukaan tetapi memiliki perbedaan bermakna dalam cara menangani panggilan paralel, penggunaan alat yang diperlukan vs opsional, dan pelaporan error.
Function calling OpenAI (sekarang disebut 'tools' di API v2) dan tool use Anthropic keduanya didasarkan pada konsep yang sama: Anda mendefinisikan sekumpulan fungsi dengan deskripsi JSON Schema, model memutuskan kapan memanggilnya, dan Anda mengeksekusi panggilan dan mengembalikan hasil. Perbedaan filosofisnya ada pada kontrol. OpenAI menawarkan tool_choice: 'required', 'auto', atau pemaksaan alat tertentu. Anthropic menawarkan tool_choice dengan 'auto', 'any' (harus menggunakan setidaknya satu alat), dan pemaksaan alat tertentu.
Tool use Anthropic mengembalikan hasil sebagai content block daripada field function_call terpisah. Respons mungkin berisi blok teks dan tool_use yang dicampur. Kode Anda harus mengiterasi blok konten, mengidentifikasi blok tool_use, mengeksekusi masing-masing, dan mengembalikan blok tool_result dalam pesan berikutnya.
┌─────────────────────────────────────────────────────────────┐
│ Parallel Tool Call Flow (Anthropic) │
│ │
│ User: "What is the status of order #123 and invoice #456?" │
│ │ │
│ ▼ │
│ Model returns TWO tool_use blocks in one response: │
│ ┌────────────────────┐ ┌────────────────────┐ │
│ │ get_order_status │ │ get_invoice_status │ │
│ │ id: "tool_abc" │ │ id: "tool_def" │ │
│ │ order_id: "123" │ │ invoice_id: "456" │ │
│ └─────────┬──────────┘ └──────────┬─────────┘ │
│ │ parallel execution │ │
│ ▼ ▼ │
│ ┌────────────────────────────────────────────┐ │
│ │ Promise.all([getOrder(123), getInv(456)]) │ │
│ └────────────────────┬───────────────────────┘ │
│ │ │
│ ▼ │
│ Return BOTH tool_result blocks → Model synthesizes answer │
└─────────────────────────────────────────────────────────────┘Dari pengalaman saya membangun agen multi-alat: implementasikan dispatcher eksekusi alat generik dari awal, bukan rantai if/else per alat. Petakan nama alat ke fungsi handler dalam kamus, validasi input terhadap skema sebelum mengeksekusi, dan bungkus setiap handler dalam try/catch dengan pengembalian error terstruktur.
Kedua API mendukung tool call paralel — model mengembalikan beberapa blok tool_call/tool_use dalam satu respons, dan Anda mengeksekusinya secara bersamaan sebelum mengembalikan semua hasil. Ini secara dramatis mengurangi latensi untuk operasi yang dapat berjalan secara paralel. Tanpa panggilan alat paralel, agen yang membutuhkan 3 sumber data akan memerlukan 3 round trip. Dengan panggilan paralel, ini adalah 1 round trip untuk pemilihan alat ditambah 1 untuk hasil — pengurangan latensi sekitar 60%.
Eksekusi alat produksi akan gagal. Timeout jaringan, error database, batas rate API eksternal — semua ini harus dikomunikasikan kembali ke model sehingga dapat menanganinya dengan baik. Kembalikan error terstruktur dalam hasil alat daripada menyebarkan pengecualian. Sertakan: error_type, message, dan boolean retry_suggested.
import Anthropic from "@anthropic-ai/sdk"
const client = new Anthropic()
// Generic tool dispatcher
const toolHandlers: Record<string, (params: unknown) => Promise<unknown>> = {
get_order: async (p) => fetchOrder(p as { order_id: string }),
get_invoice: async (p) => fetchInvoice(p as { invoice_id: string }),
list_products: async (p) => fetchProducts(p as { category?: string }),
}
// Agentic loop with parallel tool execution
async function runAgent(userMessage: string, maxIterations = 10) {
const messages: Anthropic.Messages.MessageParam[] = [
{ role: "user", content: userMessage }
]
for (let i = 0; i < maxIterations; i++) {
const response = await client.messages.create({
model: "claude-opus-4-5",
max_tokens: 4096,
tools: Object.keys(toolHandlers).map(name => ({
name,
description: toolDescriptions[name],
input_schema: toolSchemas[name],
})),
messages,
})
// Collect all tool_use blocks
const toolUseBlocks = response.content.filter(b => b.type === "tool_use")
if (toolUseBlocks.length === 0 || response.stop_reason === "end_turn") {
// No more tool calls — return final text response
const textBlock = response.content.find(b => b.type === "text")
return textBlock?.type === "text" ? textBlock.text : ""
}
// Execute all tool calls in PARALLEL
const toolResults = await Promise.all(
toolUseBlocks.map(async (block) => {
if (block.type !== "tool_use") return null
try {
const handler = toolHandlers[block.name]
if (!handler) throw new Error(`Unknown tool: ${block.name}`)
const result = await handler(block.input)
return { type: "tool_result" as const, tool_use_id: block.id, content: JSON.stringify(result) }
} catch (err) {
return {
type: "tool_result" as const,
tool_use_id: block.type === "tool_use" ? block.id : "",
content: JSON.stringify({ error: String(err), retry_suggested: true }),
is_error: true,
}
}
})
)
// Append assistant response + all tool results to messages
messages.push({ role: "assistant", content: response.content })
messages.push({ role: "user", content: toolResults.filter(Boolean) as Anthropic.Messages.ToolResultBlockParam[] })
}
throw new Error("Max iterations reached")
}Pola kuat yang sering diabaikan: gunakan tool calling semata-mata untuk ekstraksi output terstruktur, tanpa eksekusi fungsi aktual. Definisikan alat dengan skema struktur yang ingin Anda ekstrak dari teks, atur tool_choice untuk memaksa alat tertentu itu, dan model akan selalu mengembalikan struktur JSON yang valid sesuai skema Anda.
Definisi alat dihitung sebagai token input di setiap panggilan API, bahkan ketika model tidak menggunakan alat tersebut. Sekumpulan 20 definisi alat yang detail dapat menambahkan 2.000-5.000 token per panggilan. Optimasi: gunakan perutean alat untuk hanya mengirim definisi alat yang relevan berdasarkan niat pesan pengguna. Panggilan pra-klasifikasi dengan model murah dapat merutekan ke subset alat yang sesuai sebelum memanggil model yang mahal.
Agen kompleks memerlukan beberapa putaran penggunaan alat. Polanya adalah loop agentik: panggil model, periksa penggunaan alat, eksekusi alat, tambahkan hasil, panggil model lagi, ulangi hingga model mengembalikan respons hanya teks. Implementasikan batas iterasi maksimum (biasanya 10-15 langkah) untuk mencegah loop tak terbatas.
Untuk proyek baru, saya merekomendasikan tool use Anthropic ketika Anda membutuhkan model paling mampu (Claude Opus 4) atau ketika kasus penggunaan Anda mendapat manfaat dari model yang secara alami mencampur penjelasan dengan tool call. Gunakan function calling OpenAI ketika Anda membutuhkan kompatibilitas ekosistem terluas atau ketika Anda menggunakan model yang di-fine-tune.
Sumber & Bacaan Lanjutan