Function Calling & Tool Use — AI Web

Function Calling LLM bisa "memanggil fungsi" di backend kamu. Model tidak benar-benar execute kode — model menghasilkan JSON yang menunjukkan fungsi mana yang…

Function calling (di Anthropic namanya tool use) artinya kamu memberi model daftar fungsi yang boleh dipakai, dan model bisa membalas "tolong panggil cekStok dengan judul Laskar Pelangi" alih-alih menjawab langsung. Server-mu yang menjalankan fungsinya, mengirim hasilnya balik, lalu model menjawab dengan data asli. Bayangin asisten toko yang melayani lewat telepon tapi gak boleh masuk gudang. Dia bilang ke kamu, "tolong cek rak Laskar Pelangi", kamu yang ke gudang dan melapor "ada 12", lalu dia menjawab pelanggan. Asistennya gak pernah menyentuh gudang.

🧪 Tebakan cepat: model membalas dengan permintaan memanggil cekStok untuk "Laskar Pelangi". Siapa yang benar-benar menjalankan GET /books?q=Laskar%20Pelangi: model di server OpenAI, atau server Toko Buku? Tebak dulu, jawabannya ada di bagian "Loop-nya, langkah demi langkah".

Tool: nama, deskripsi, dan JSON Schema

Satu tool (alat) didefinisikan dengan nama, deskripsi kapan dipakai, dan JSON Schema untuk argumennya. JSON Schema adalah format standar untuk menjelaskan bentuk sebuah JSON: field apa saja, tipenya apa, mana yang wajib. Bentuk di Responses API OpenAI (API reference dan panduan "Function calling", dicek Oktober 2026):

const tools = [
  {
    type: "function",
    name: "cekStok",
    description: "Cek stok dan harga buku di Toko Buku. Pakai setiap kali pelanggan menanyakan ketersediaan atau harga.",
    parameters: {
      type: "object",
      properties: {
        judul: { type: "string", description: "Judul buku, misalnya Laskar Pelangi" },
      },
      required: ["judul"],
      additionalProperties: false,
    },
    strict: true,
  },
];

Loop-nya, langkah demi langkah

Jalannya di Lab untuk "Stok Laskar Pelangi masih ada?". Balasan model di Lab adalah stand-in yang ditulis tangan; bentuk JSON-nya mengikuti API reference.

# Dari, ke Isinya
1 Server, ke OpenAI input: pertanyaan pelanggan, tools: cekStok
2 OpenAI, ke server item {"type":"function_call","call_id":"call_1","name":"cekStok","arguments":"{\"judul\":\"Laskar Pelangi\"}"}
3 Server, ke API Toko Buku GET /books?q=Laskar%20Pelangi, dijawab 200 [{"id":1,"title":"Laskar Pelangi","price":89000,"stock":12}]
4 Server, ke OpenAI input yang sama, plus {"type":"function_call_output","call_id":"call_1","output":"[{\"judul\":\"Laskar Pelangi\",\"harga\":89000,\"stok\":12}]"}
5 OpenAI, ke server pesan: "Masih ada, stok Laskar Pelangi 12, harganya Rp89.000."

Langkah 3 dijalankan server Toko Buku. Itu jawaban tebakannya. Model cuma menulis JSON berisi nama fungsi dan argumennya; dia gak bisa menyentuh database atau API-mu. Jadi function calling adalah kemampuan model memutuskan kapan dan dengan argumen apa sebuah fungsi perlu dipanggil, sedangkan yang mengeksekusi tetap kode aplikasimu.

Kodenya di server, mengikuti contoh di panduan "Function calling":

import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";

async function tanyaAsisten(pertanyaan) {
  const input = [{ role: "user", content: pertanyaan }];
  const minta = () => client.responses.create({ model: "gpt-6-luna", reasoning: { effort: "none" }, instructions: ATURAN, tools, input });
  let res = await minta();
  for (let putaran = 1; putaran <= 3; putaran++) {
    const panggilan = res.output.filter((item) => item.type === "function_call");
    if (panggilan.length === 0) return res.output_text; // model sudah menjawab
    input.push(...toResponseInputItems(res.output)); // simpan permintaan model di riwayat
    for (const p of panggilan) {
      const hasil = await jalankanTool(p.name, p.arguments);
      input.push({ type: "function_call_output", call_id: p.call_id, output: JSON.stringify(hasil) });
    }
    res = await minta();
  }
  if (!res.output.some((item) => item.type === "function_call")) return res.output_text; // balasan request ke-4 tetap dibaca
  return "Maaf, aku belum bisa menjawab itu.";
}

Validasi argumen di server

strict: true menjamin bentuk, bukan isi. judul bisa string kosong, 5.000 karakter, atau berisi teks aneh hasil prompt injection. Periksa dulu sebelum dipakai:

async function jalankanTool(nama, argumenJson) {
  if (nama !== "cekStok") return { error: `tool ${nama} gak dikenal` };
  let argumen;
  try {
    argumen = JSON.parse(argumenJson); // arguments datang sebagai teks JSON
  } catch {
    return { error: "argumen bukan JSON yang valid" };
  }
  const judul = typeof argumen.judul === "string" ? argumen.judul.trim() : "";
  if (judul === "" || judul.length > 100) return { error: "judul wajib diisi, paling banyak 100 karakter" };
  const res = await fetch(`https://api.tokobuku.test/books?q=${encodeURIComponent(judul)}`);
  const books = await res.json();
  return books.map((b) => ({ judul: b.title, harga: b.price, stok: b.stock }));
}

Tool yang menulis: minta konfirmasi dulu

cekStok cuma membaca, jadi boleh jalan otomatis. Tool yang mengubah sesuatu, misalnya pesanBuku yang memanggil POST /orders, lain cerita. Model bisa salah paham ("pesan" padahal cuma tanya), atau terbujuk teks jahat. Aturannya:

  1. Saat model meminta pesanBuku({"book_id":1,"jumlah":2}), server gak memanggil POST /orders. Server mengembalikan {"status":"menunggu_konfirmasi","total":178000} ke model, dan menampilkan tombol Konfirmasi ke pelanggan.
  2. POST /orders baru dikirim saat pelanggan menekan tombol itu, lewat endpoint biasa dengan sesi dan pengecekan hak aksesnya sendiri.
  3. Tool yang cuma untuk admin (ubah harga, hapus buku) gak pernah diberikan ke model.

Bentuk yang sama di Anthropic

Idenya sama, nama field-nya beda (dokumentasi "Tool use with Claude", platform.claude.com, dicek Oktober 2026):

const res = await anthropic.messages.create({
  model: "claude-haiku-5-5",
  max_tokens: 1024,
  tools: [{ name: "cekStok", description: "Cek stok dan harga buku.", input_schema: { type: "object", properties: { judul: { type: "string" } }, required: ["judul"] } }],
  messages,
});
// res.stop_reason === "tool_use"
const tu = res.content.find((b) => b.type === "tool_use"); // { type: "tool_use", id: "toolu_...", name: "cekStok", input: { judul: "Laskar Pelangi" } }
messages.push(
  { role: "assistant", content: res.content },
  { role: "user", content: [{ type: "tool_result", tool_use_id: tu.id, content: JSON.stringify(await cekStok(tu.input.judul)) }] },
);
OpenAI Responses Anthropic Messages
Schema argumen parameters input_schema
Permintaan model item function_call, argumen berupa teks JSON di arguments blok tool_use, argumen sudah berupa object di input
Hasil dari server item function_call_output dengan call_id blok tool_result dengan tool_use_id, di pesan user
Tanda error isi output sendiri is_error: true

Di Anthropic, pesan user yang membawa tool_result harus langsung setelah pesan assistant yang berisi tool_use, dan blok tool_result harus di depan teks lain.

⚠️ Jebakan yang sering ketemu

TL;DR: Function calling membuat model bisa memutuskan kapan memanggil fungsi dan dengan argumen apa; yang mengeksekusi tetap kode aplikasimu. Tool didefinisikan dengan type: "function", name, description, parameters (JSON Schema) dan strict: true (dengan additionalProperties: false dan semua field di required). Loop: model membalas function_call, server memvalidasi argumen dan memanggil GET /books?q=..., hasilnya dikirim sebagai function_call_output dengan call_id yang sama, lalu model menjawab; batasi putarannya. Di Anthropic: input_schema, blok tool_use, lalu tool_result dengan tool_use_id di pesan user. Tool yang menulis (POST /orders) jangan jalan tanpa konfirmasi pengguna.

Yang akan kamu pelajari