Function Calling LLM 2026: Panduan OpenAI Tool Use, Anthropic, dan Structured Outputs untuk Agen Produksi

Perbandingan mendalam function calling OpenAI vs tool use Anthropic vs structured outputs di 2026: schema JSON, strict mode, validasi Pydantic, parallel tool calls, dan kapan beralih ke MCP - dengan contoh kode produksi.

Function Calling LLM 2026: Panduan Lengkap

Diperbarui: 15 Juni 2026

Function calling adalah mekanisme yang memungkinkan LLM seperti GPT, Claude, dan Gemini mengembalikan argumen JSON terstruktur untuk memanggil fungsi yang Anda definisikan, sementara structured outputs memaksa model mematuhi skema JSON pada level token generation. Keduanya saling melengkapi: tool use cocok untuk agen yang memilih tindakan secara dinamis, sedangkan structured outputs cocok untuk ekstraksi data yang harus konsisten. Di 2026, praktik produksi berkonvergensi pada pola berlapis: native structured output di provider, validasi Pydantic/Instructor di SDK, plus gateway validator sebagai jaring pengaman terakhir.

  • OpenAI menggunakan istilah "function calling", Anthropic menyebutnya "tool use", tetapi keduanya menggunakan JSON Schema dan mekanisme yang nyaris identik. Perbedaan terbesar ada pada format argumen yang dikembalikan.
  • OpenAI mengembalikan argumen sebagai string JSON yang harus di-parse, sementara Anthropic dan Gemini sudah mengembalikan objek yang ter-parse.
  • Setting strict: true di OpenAI dan menggunakan tool tunggal sebagai "response shape" di Anthropic adalah cara paling andal untuk memaksa skema.
  • Anthropic menambahkan 313–346 token system prompt overhead per request saat tools dilampirkan, dan ini biaya yang akumulatif pada skala produksi.
  • GPT-5, Claude 4.6, dan Gemini 2.x mendukung parallel tool calls, memangkas latensi pada workflow multi-step.
  • MCP (Model Context Protocol) telah menjadi standar lintas-provider; OpenAI menjadwalkan sunset Assistants API pada pertengahan 2026 demi MCP.

Apa itu function calling dan bagaimana cara kerjanya?

Saya akan jujur: saya menghabiskan dua tahun terakhir mengintegrasikan LLM ke dalam sistem backend, dan satu-satunya hal yang saya pegang lebih kuat dari opini soal function calling adalah opini soal evaluasi. Function calling (atau "tool use" dalam terminologi Anthropic) adalah cara LLM mengembalikan argumen JSON terstruktur yang merepresentasikan keputusan untuk memanggil fungsi yang Anda definisikan. Modelnya tidak mengeksekusi kode apa pun; ia hanya memutuskan "tool mana yang dipanggil" dan "dengan argumen apa". Kode Andalah yang mengeksekusi, lalu mengirim hasilnya kembali ke model dalam pesan role tool.

Alur kerjanya empat langkah: (1) Anda mendaftarkan daftar tool berisi nama, deskripsi, dan input_schema JSON Schema; (2) model memilih nol, satu, atau beberapa tool berdasarkan permintaan user; (3) aplikasi mengeksekusi fungsi yang sesuai; (4) hasil dikirim kembali sebagai pesan baru sehingga model bisa menyusun respons final. Jika Anda pernah membaca artikel saya tentang pola desain alur kerja AI agentik, pola ReAct dan tool-router yang dibahas di sana semuanya bertumpu pada mekanisme ini.

Yang sering disalahpahami: function calling bukan jaminan struktural di level token. Schema yang Anda berikan adalah hint yang sangat kuat, bukan constraint mutlak. Tanpa strict mode (OpenAI) atau validasi pasca-generasi (Anthropic), model masih bisa mengembalikan JSON yang tidak valid pada sekitar 1–5% kasus, terutama untuk skema dengan nested objects atau enum panjang. Itulah alasan structured outputs lahir sebagai lapisan terpisah.

Perbedaan function calling, tool use, dan structured outputs

Tiga istilah ini sering dipertukarkan, dan saya melihat banyak tim memilih yang salah karena tidak membedakannya. Function calling dan tool use adalah hal yang sama. OpenAI memakai istilah pertama, Anthropic memakai yang kedua. Keduanya tentang memilih tindakan secara dinamis. Structured outputs berbeda: ia memaksa setiap output model mematuhi satu skema, biasanya untuk ekstraksi data, klasifikasi terstruktur, atau membentuk respons API yang dikonsumsi sistem lain. Tabel di bawah ini merangkum perbedaan yang paling penting bagi saya saat memilih pendekatan.

DimensiFunction Calling (OpenAI)Tool Use (Anthropic)Structured Outputs
Tujuan utamaPilih dan jalankan tool dinamisPilih dan jalankan tool dinamisPaksa output sesuai satu skema
Format argumenString JSON (perlu JSON.parse)Objek sudah ter-parseObjek/string sesuai skema
Penegakan skemastrict: true = constrained decodingHint + validasi SDKConstrained decoding di token level
Streaming argumenTerbatasPenuh, per-toolPenuh (provider-dependent)
Parallel callsYaYaTidak relevan
Token overhead tools~120–200 per request313–346 per request~50 (skema saja)
Best untukAgen multi-toolAgen multi-tool, streaming UIEkstraksi data, klasifikasi

Aturan praktis yang saya pakai: kalau model harus memilih antara beberapa tindakan, pakai tool use. Kalau model selalu mengembalikan satu bentuk data yang sama (mis. mengekstrak {customer_name, order_id, sentiment} dari email), pakai structured outputs. Pertanyaan paling sering dari tim klien saya adalah "boleh kombinasi keduanya?", dan jawabannya ya, dan biasanya dengan satu tool tunggal yang skema inputnya adalah shape data target Anda. Ini pola yang dipakai banyak Anthropic SDK wrapper untuk meniru structured outputs.

Setelah debugging puluhan agen produksi, saya bisa mengatakan bahwa kualitas skema lebih menentukan keberhasilan tool calling daripada pilihan model. Aturan pertama yang saya tegakkan di setiap repo: schema-first. Definisikan skema sebelum prompt, jangan setelahnya. Kalau Anda mengetik prompt dulu lalu menyesuaikan skema, Anda hampir pasti akan mendapat field opsional yang tidak konsisten.

Empat panduan praktis yang konsisten memperbaiki akurasi di production saya:

  1. Buat skema datar. Setiap level nesting menambah error rate. Saya pernah memecah satu skema 4-level menjadi dua tool terpisah, dan validation failure turun dari 6% ke 0.4%.
  2. Gunakan enum, bukan pattern. Enum dipatuhi mendekati 100% oleh constrained decoder. Pattern regex sering bocor, terutama pada Claude yang membuang pattern ke description.
  3. Tulis description di setiap property. Dokumentasi Google secara eksplisit menyebut deskripsi sebagai "krusial untuk membimbing output model". Saya menulis deskripsi seperti menulis untuk junior developer, termasuk contoh nilai valid jika field ambigu.
  4. Batasi jumlah tool aktif. Dokumentasi Gemini merekomendasikan maksimal 10–20 tool per request. Di luar itu, akurasi pemilihan turun drastis. Untuk agen yang butuh lebih, pakai router tool. Lihat artikel context engineering untuk pola dynamic tool selection.

Hal lain yang sering dilupakan: additionalProperties: false dan required array harus diisi setiap property kalau Anda mengaktifkan OpenAI strict mode. Spec strict mode OpenAI menolak skema yang tidak menutup penuh.

Implementasi function calling di OpenAI dengan strict mode

Berikut contoh function calling produksi pada SDK OpenAI Python 1.x dengan strict mode aktif. Tool ini mensimulasikan lookup harga produk e-commerce. Perhatikan validasi argumen lewat Pydantic sebelum eksekusi. Jaring pengaman wajib walau strict aktif.

from openai import OpenAI
from pydantic import BaseModel, Field
import json

client = OpenAI()

class ProductLookupArgs(BaseModel):
    sku: str = Field(..., min_length=4, description="SKU produk, contoh 'A4321'")
    currency: str = Field("IDR", description="Kode mata uang ISO 4217")

tools = [{
    "type": "function",
    "function": {
        "name": "get_product_price",
        "description": "Ambil harga terkini suatu produk berdasarkan SKU.",
        "strict": True,
        "parameters": {
            "type": "object",
            "additionalProperties": False,
            "required": ["sku", "currency"],
            "properties": {
                "sku": {"type": "string", "description": "SKU produk."},
                "currency": {
                    "type": "string",
                    "enum": ["IDR", "USD", "EUR", "SGD"],
                    "description": "Kode mata uang."
                }
            }
        }
    }
}]

def get_product_price(sku: str, currency: str) -> dict:
    # Simulasi panggilan ke database harga internal Anda.
    return {"sku": sku, "price": 249000, "currency": currency}

resp = client.chat.completions.create(
    model="gpt-5",
    messages=[{"role": "user", "content": "Berapa harga SKU A4321 dalam rupiah?"}],
    tools=tools,
    tool_choice="auto",
)

msg = resp.choices[0].message
if msg.tool_calls:
    call = msg.tool_calls[0]
    raw_args = json.loads(call.function.arguments)
    args = ProductLookupArgs.model_validate(raw_args)
    result = get_product_price(args.sku, args.currency)
    print(result)

Dua detail yang sering jadi bug: call.function.arguments selalu berupa string JSON, bukan objek (perbedaan utama dengan Anthropic), dan tool_choice bisa di-set ke {"type": "function", "function": {"name": "..."}} untuk memaksa pemanggilan tool tertentu, berguna saat Anda sudah tahu intent user.

Implementasi tool use di Anthropic Claude

Saya pribadi lebih sering memakai Claude untuk agen yang butuh streaming UI karena dukungan streaming per-tool jauh lebih matang. Contoh berikut dengan Claude 4.6 dan SDK Python 0.40+:

import anthropic

client = anthropic.Anthropic()

tools = [{
    "name": "get_product_price",
    "description": "Ambil harga terkini suatu produk berdasarkan SKU.",
    "input_schema": {
        "type": "object",
        "required": ["sku", "currency"],
        "properties": {
            "sku": {"type": "string", "description": "SKU produk, mis. 'A4321'."},
            "currency": {
                "type": "string",
                "enum": ["IDR", "USD", "EUR", "SGD"],
                "description": "Kode mata uang."
            }
        }
    }
}]

resp = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=1024,
    tools=tools,
    messages=[{"role": "user", "content": "Berapa harga SKU A4321 dalam rupiah?"}],
)

if resp.stop_reason == "tool_use":
    for block in resp.content:
        if block.type == "tool_use":
            # block.input sudah merupakan dict, tidak perlu json.loads
            sku = block.input["sku"]
            currency = block.input["currency"]
            result = {"sku": sku, "price": 249000, "currency": currency}

            followup = client.messages.create(
                model="claude-opus-4-7",
                max_tokens=512,
                tools=tools,
                messages=[
                    {"role": "user", "content": "Berapa harga SKU A4321 dalam rupiah?"},
                    {"role": "assistant", "content": resp.content},
                    {"role": "user", "content": [{
                        "type": "tool_result",
                        "tool_use_id": block.id,
                        "content": str(result),
                    }]},
                ],
            )
            print(followup.content[0].text)

Perhatikan stop_reason == "tool_use", sinyal eksplisit dari Anthropic yang tidak dimiliki OpenAI dengan setegas itu. Saya menggunakan stop reason sebagai gate utama di state machine agen alih-alih membaca konten message, karena lebih tahan terhadap perubahan format internal.

Validasi, retry, dan error handling produksi

Bagian ini yang membuat saya keras kepala tentang "evals before deploy". Output yang valid secara sintaks tidak berarti benar secara semantik. Saya melihat model mengembalikan confidence: 0.99 untuk input satu kata, atau category: "electronics" untuk ulasan makanan. Structured output mencegah error struktural, bukan semantik. Karena itu, stack validasi produksi saya selalu berlapis tiga:

  1. Provider-level constrained decoding (strict mode OpenAI, tool use Claude).
  2. SDK-level schema validation dengan Pydantic, Instructor, atau Outlines. Default max_retries Instructor adalah 0; setel ke 3 dengan error feedback dimasukkan ke prompt sistem.
  3. Gateway/application validator untuk semantic checks (range nilai, foreign keys, business rules) sebelum hasil diserahkan ke sistem hilir.

Pola retry yang saya pakai: tiga kali percobaan, dengan pesan error validator dimasukkan persis ke prompt sistem retry. Library default-nya 0 retry, jadi Anda harus eksplisit. Untuk error tool execution, kembalikan struktur yang LLM bisa baca, seperti {"error": "SKU tidak ditemukan. Coba SKU lain."}, jangan throw exception ke user. Selalu pasang max tool call limit 10–15 untuk mencegah loop tak terbatas, lalu ukur tail latency-nya. Tanpa benchmark evaluasi (lihat perbandingan framework evaluasi LLM), Anda menebak-nebak apakah perubahan prompt memperbaiki atau memperburuk akurasi.

Parallel tool calls dan kontrol biaya token

Parallel tool calling adalah optimasi termurah yang sering diabaikan. Pada pertanyaan seperti "berapa cuaca di Jakarta dan Surabaya?", model bisa mengembalikan dua tool call dalam satu respons; aplikasi Anda menjalankan keduanya paralel, lalu mengirim kedua hasil dalam satu pesan berikutnya. Wall-clock latency turun dari N×t menjadi maks(t).

Untuk biaya token, ada tiga hal yang saya ukur sebelum produksi:

  • Overhead system prompt tools. Anthropic menambahkan 313–346 token per request saat tools dilampirkan. Untuk volume 1 juta request/bulan dengan input pricing $3/MTok, itu sekitar $930–$1,038/bulan overhead murni. Pertimbangkan caching tool definitions via prompt caching.
  • Active tool count vs accuracy. Saya menguji satu agen dengan 8 vs 25 tool. Akurasi pemilihan turun dari 94% ke 71%. Gunakan tool router untuk skema besar.
  • Token argumen retry. Setiap retry menggandakan input cost. Optimasi schema sebelum optimasi retry.

Migrasi ke MCP untuk kompatibilitas lintas-provider

Saya akan terus terang: jika Anda memulai proyek baru di 2026, pertimbangkan serius membangun di atas Model Context Protocol. MCP awalnya dirilis Anthropic November 2024, kemudian diadopsi OpenAI dan Google. OpenAI menjadwalkan deprecation Assistants API dengan sunset pertengahan 2026 demi MCP. Artinya: tool yang Anda definisikan sekali sebagai MCP server dapat dikonsumsi oleh Claude, GPT, dan Gemini tanpa rewrite per-provider.

Untuk panduan praktis membangun MCP server dari nol, saya sudah menulis tutorial khusus di membangun MCP server dengan Python FastMCP 3.0. Pendekatannya: definisikan tool sebagai resource MCP dengan input_schema yang sama dengan yang Anda pakai sekarang, lalu sambungkan lewat MCP client di SDK masing-masing provider.

Alternatif praktis jika MCP belum sesuai: dokumentasi function calling OpenAI dan overview tool use Anthropic adalah dua sumber paling otoritatif yang saya rujuk mingguan. Untuk multi-provider tanpa MCP, library abstraksi seperti LangChain, LiteLLM, atau Vercel AI SDK menormalkan perbedaan format argumen dan event streaming, tetapi ingat, tidak ada abstraksi yang bebas pajak: setiap layer menambah token, latensi, dan potensi bug.

Pertanyaan yang sering diajukan

Apa perbedaan utama antara function calling OpenAI dan tool use Anthropic?

Mekanismenya identik. Keduanya mendefinisikan tool via JSON Schema dan mengembalikan argumen terstruktur. Perbedaan terbesar: OpenAI mengembalikan argumen sebagai string JSON yang harus di-JSON.parse, sedangkan Anthropic mengembalikan objek yang sudah ter-parse. Anthropic juga memberi stop_reason: "tool_use" sebagai sinyal eksplisit dan mendukung streaming per-tool lebih matang.

Apakah Claude mendukung structured outputs seperti response_format OpenAI?

Tidak secara langsung. Pola yang dipakai adalah mendefinisikan satu tool dengan input_schema sebagai shape data target Anda, lalu memaksa penggunaannya via tool_choice. SDK Anthropic memvalidasi hasil pasca-generasi dan retry jika constraint seperti minimum atau pattern tidak terpenuhi.

Berapa banyak tool yang sebaiknya saya daftarkan dalam satu request?

Dokumentasi Gemini merekomendasikan maksimal 10–20 tool aktif. Lebih dari itu, akurasi pemilihan turun signifikan dan biaya token naik. Untuk agen yang butuh lebih, gunakan pola router-tool: satu LLM memilih kategori, baru request kedua dengan subset tool yang relevan.

Bagaimana cara menangani error saat function calling di produksi?

Tiga lapisan: aktifkan strict mode atau constrained decoding di provider; validasi argumen dengan Pydantic/Instructor (set max_retries=3, bukan default 0); kirim error sebagai tool_result yang readable model, mis. {"error": "SKU tidak ditemukan"}, jangan throw exception. Selalu pasang batas 10–15 tool call untuk mencegah loop tak terbatas.

Kapan saya sebaiknya beralih ke MCP daripada native function calling tiap provider?

Jika Anda menargetkan multi-provider sekarang atau khawatir lock-in, mulai dengan MCP. Untuk proyek single-provider yang stabil dan butuh fitur terbaru cepat (mis. cache prompt khusus OpenAI), tetap di SDK native lebih sederhana. OpenAI sunset Assistants API pertengahan 2026 mendorong banyak tim mempertimbangkan migrasi MCP lebih awal.

Daichi Watanabe
Tentang Penulis Daichi Watanabe

LLM integration specialist with a strong opinion about function calling and an even stronger one about evaluations.