Belajar Generative AI - Function Calling & Tool Use
Episode 9 of 25

Belajar Generative AI - Function Calling & Tool Use

Membangun function calling secara utuh: structured tool schema, loop eksekusi tool, serta tool retry & error handling. Episode ini berisi praktik membangun agen yang bisa query database, melakukan kalkulasi, dan memanggil API eksternal — fondasi dari agents di episode 10.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah di episode 5 kalian melihat sekilas function calling, dan di episode 6-8 membangun RAG yang memberi model "pengetahuan", episode ini mengangkat kemampuan yang membuat model benar-benar bertindak: memanggil tool. Karena LLM tidak bisa menghitung secara andal (episode 2), tidak tahu data terbaru, dan tidak bisa mengakses database kalian — kecuali kalian memberinya alat.

Mengapa ini penting? Ini adalah jembatan antara LLM sebagai mesin menjawab dan LLM sebagai agen yang bekerja. Di produksi, aplikasi AI yang berguna hampir selalu memanggil sesuatu: API pembayaran, query database, kalkulator, search engine. Tanpa tool use, semua itu mustahil dilakukan model.

Konsep: Model Memutuskan, Kode Mengeksekusi

Ingat prinsip dari episode 5: model tidak mengeksekusi apa pun — ia mengembalikan keputusan berupa nama fungsi + argumen JSON. Aplikasi kalian yang mengeksekusi, lalu mengirim hasilnya kembali ke model. Inilah yang disebut tool loop:

100%

Loop berhenti ketika model memutuskan tidak perlu tool lagi dan menghasilkan jawaban final.

Membangun Tool Loop Lengkap

Tool loop dengan database & kalkulator
import json
 
from openai import OpenAI
 
client = OpenAI()
 
tools = [
    {"type": "function", "function": {
        "name": "search_products",
        "description": "Cari produk di database internal",
        "parameters": {"type": "object",
                       "properties": {"keyword": {"type": "string"}},
                       "required": ["keyword"]}}},
    {"type": "function", "function": {
        "name": "calculate",
        "description": "Kalkulasi aritmatika presisi",
        "parameters": {"type": "object",
                       "properties": {"expression": {"type": "string"}},
                       "required": ["expression"]}}},
]
 
def call_tool(name, args):
    if name == "search_products":
        return {"items": [{"id": 1, "name": "Keyboard MX", "price": 1250000},
                          {"id": 2, "name": "Mouse MX", "price": 850000}]}
    if name == "calculate":
        return {"result": eval(args["expression"])}
    raise ValueError(f"tool tidak dikenal: {name}")
 
def agent(question):
    messages = [{"role": "user", "content": question}]
    for _ in range(5):                     # batasi iterasi (safety)
        resp = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=messages,
            tools=tools,
        )
        msg = resp.choices[0].message
        messages.append(msg)               # beri tahu model keputusan tool-nya
 
        if msg.tool_calls:
            for tc in msg.tool_calls:
                result = call_tool(tc.function.name,
                                   json.loads(tc.function.arguments))
                messages.append({
                    "role": "tool",
                    "tool_call_id": tc.id,
                    "content": json.dumps(result),
                })
            continue                       # loop lagi dengan hasil tool
        return msg.content

Empat detail yang mudah salah:

  1. messages.append(msg) — pesan yang memuat tool_calls harus dikembalikan apa adanya (dengan tool_call_id).
  2. role: "tool" dengan tool_call_id — hasil eksekusi diikat ke pemanggilan tertentu.
  3. Loop dengan batas iterasi — agen bisa terjebak memanggil tool terus-menerus; batasi (misal 5-10 iterasi).
  4. Ekspektasi: model mungkin memanggil 0, 1, atau beberapa tool per respons.

Structured Tool Schema yang Baik

Kualitas schema menentukan kualitas pemanggilan. Aturan praktis:

  • Deskripsi eksplisit: jelaskan kapan tool dipakai, format nilai, contoh. Model membaca deskripsi ini untuk memutuskan.
  • required selalu diisi: hindari argumen opsional yang ambigu.
  • Enum untuk nilai terbatas: persempit pilihan model.
  • Satu tanggung jawab per tool: tool yang "melakukan semuanya" membingungkan model.
Schema tool yang baik vs buruk
{
  "name": "get_order_status",
  "description": "Ambil status pesanan. Pakai jika user menanyakan keberadaan/nomor resi pesanan.",
  "parameters": {
    "type": "object",
    "properties": {
      "order_id": {"type": "string", "description": "ID pesanan, contoh ORD-2026-0042"}
    },
    "required": ["order_id"]
  }
}

Tool Retry & Error Handling

Tool akan gagal: database down, API eksternal timeout, input tidak valid. Pola yang benar: jangan pernah biarkan error menggagalkan seluruh percakapan — kembalikan error sebagai hasil tool agar model bisa menjelaskan/memperbaiki.

Kembalikan error sebagai hasil tool
import traceback
 
def safe_call_tool(name, args):
    try:
        return {"ok": True, "data": call_tool(name, args)}
    except Exception as e:
        return {"ok": False, "error": str(e), "trace": traceback.format_exc()[-400:]}
 
# hasil error ini dikirim ke model dengan role: "tool"
# → model bisa menjawab "terjadi kesalahan sementara, coba lagi" atau
#   memperbaiki argumen lalu memanggil ulang

Kelebihannya: model yang kompeten akan menyesuaikan diri — mengubah argumen, mencoba tool alternatif, atau meminta klarifikasi pengguna — alih-alih crash. Ini pola yang sama dipakai oleh semua framework agent (episode 10).

Praktik: Query Database, Kalkulasi, API Eksternal

Satu agen yang menggabungkan ketiganya:

Agen: database + kalkulasi + cuaca
tools = [
    {"type": "function", "function": {
        "name": "query_db", "description": "Jalankan SQL SELECT pada database penjualan",
        "parameters": {"type": "object", "properties": {"sql": {"type": "string"}},
                       "required": ["sql"]}}},
    {"type": "function", "function": {
        "name": "get_weather", "description": "Suhu & cuaca suatu kota",
        "parameters": {"type": "object", "properties": {"city": {"type": "string"}},
                       "required": ["city"]}}},
]
 
def call_tool(name, args):
    if name == "query_db":
        # dalam praktik: sqlite3 / psycopg, dengan allowlist read-only!
        return run_sql(args["sql"])
    if name == "get_weather":
        return requests.get("https://api.weather.com/...").json()

User request: "Berapa rata-rata penjualan 3 bulan terakhir? Lalu kalikan dengan 1.1." Model akan: query_dbcalculate → jawaban final. Satu permintaan, tiga tool, satu alur otomatis.

Danger

Tool yang mengeksekusi SQL, shell, atau menulis file adalah serangan potensial — prompt injection (episode 16) bisa memanipulasi model memanggil tool berbahaya. Untuk query DB: gunakan koneksi read-only, batasi schema, dan log semua pemanggilan. Untuk shell: jangan pernah tanpa sandbox.

Common Pitfalls

  • Melupakan tool_call_id di pesan role: tool → API menolak.
  • Tanpa batas loop → agen menghabiskan token tak terhingga.
  • Error tool menghentikan percakapan → kembalikan sebagai hasil, bukan exception.
  • Tool dengan efek samping tanpa konfirmasi → biarkan model mengonfirmasi ke user dulu untuk aksi destruktif.

Penutup

Inti yang harus dibawa pulang:

  • Model memutuskan, kode mengeksekusi — tool loop: LLM → tool call → eksekusi → hasil role: tool → ulang.
  • Schema tool yang baik = deskripsi jelas + required + enum + satu tanggung jawab.
  • Error handling: kembalikan error sebagai hasil tool, bukan crash.
  • Tool dengan efek samping (SQL, shell) wajib pagar keamanan.

Di episode 10 selanjutnya kita akan membangun Agents: Agent Loop & LangGraph — ReAct loop (reason + act), state machine, multi-agent orchestration, dan perbandingan LangChain/LangGraph, LlamaIndex, serta MCP untuk tools dan data. Sampai jumpa di episode 10!