Lunos logoLunos

Tool & Function Calling

Tool call (atau function call) memungkinkan model AI untuk berinteraksi dengan alat atau layanan eksternal melalui aplikasi Anda. Perlu dipahami bahwa model tidak mengeksekusi tool tersebut secara langsung. Model hanya menyarankan tool mana yang perlu dipanggil beserta argumennya. Aplikasi Anda lah yang bertanggung jawab menjalankan tool tersebut, lalu mengirimkan hasilnya kembali ke model agar model bisa menyusun jawaban akhir.

Pola ini sangat cocok digunakan untuk:

  • Mencari atau mengambil data dari sistem internal perusahaan.
  • Menjalankan perhitungan dengan logika kode yang deterministik (pasti).
  • Memicu aksi dalam workflow bisnis (seperti penagihan, notifikasi, antrian pesan, dan lain-lain).

Lunos kompatibel dengan format standar OpenAI. Jika model yang Anda pilih mendukung tool calling, Anda dapat langsung menggunakan alur standar tools + tool_calls pada endpoint POST /v1/chat/completions.

Model yang Mendukung Tool Calling

Tidak semua model memiliki kemampuan tool calling. Sebelum mengandalkan fitur ini, pastikan Anda sudah memverifikasi model yang akan digunakan melalui API GET /v1/models.

Alur Standar Tiga Langkah

Proses tool calling pada umumnya mengikuti tiga langkah berikut.

1. Kirim Request yang Menyertakan Definisi tools

Saat Anda ingin memberikan izin kepada model untuk memanggil tool tertentu, sertakan array tools di dalam body request chat.

Contoh (request awal):

{
  "model": "openai/gpt-4o",
  "messages": [
    {
      "role": "user",
      "content": "What are the titles of some James Joyce books?"
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "searchBooks",
        "description": "Search for books based on provided keywords",
        "parameters": {
          "type": "object",
          "properties": {
            "search_terms": {
              "type": "array",
              "items": { "type": "string" },
              "description": "List of keywords to search for books"
            }
          },
          "required": ["search_terms"]
        }
      }
    }
  ]
}

2. Jalankan Tool yang Diminta di Aplikasi Anda

Jika model memutuskan bahwa sebuah tool perlu dipanggil, response akan berisi properti tool_calls. Aplikasi Anda kemudian perlu:

  1. Membaca nama tool dari tool_calls.
  2. Mengurai (parse) argumen tool tersebut (biasanya berupa JSON).
  3. Menjalankan fungsi lokal yang sesuai dengan nama tool.
  4. Mengubah hasilnya menjadi string (umumnya format JSON) untuk dikirim kembali ke model.

3. Kirim Hasil Tool Kembali ke Model

Setelah tool berhasil dijalankan, kirimkan request chat baru yang berisi: konteks percakapan sebelumnya, pesan assistant yang berisi tool_calls, dan satu pesan bertipe tool untuk setiap hasil tool call.

Contoh (langkah mengirim hasil tool):

{
  "model": "openai/gpt-4o",
  "messages": [
    {
      "role": "user",
      "content": "What are the titles of some James Joyce books?"
    },
    {
      "role": "assistant",
      "content": null,
      "tool_calls": [
        {
          "id": "call_abc123",
          "type": "function",
          "function": {
            "name": "searchBooks",
            "arguments": "{\"search_terms\":[\"James\",\"Joyce\"]}"
          }
        }
      ]
    },
    {
      "role": "tool",
      "tool_call_id": "call_abc123",
      "content": "[{\"id\":4300,\"title\":\"Ulysses\",\"authors\":[{\"name\":\"Joyce, James\"}]}]"
    }
  ],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "searchBooks",
        "description": "Search for books based on provided keywords",
        "parameters": {
          "type": "object",
          "properties": {
            "search_terms": {
              "type": "array",
              "items": { "type": "string" },
              "description": "List of keywords to search for books"
            }
          },
          "required": ["search_terms"]
        }
      }
    }
  ]
}

Setelah hasil tool tersedia, model akan menggunakan informasi tersebut untuk menyusun jawaban akhir yang lengkap.

Contoh: Loop Tool Calling (TypeScript)

Peringatan: @lunos/client bisa tertinggal dari API; jika contoh ini gagal, gunakan SDK JavaScript OpenAI dengan baseURL Lunos.

Contoh berikut menunjukkan implementasi loop minimal yang:

  • Memanggil API Lunos dengan definisi tools.
  • Menjalankan setiap tool_call yang diminta model.
  • Mengirimkan setiap hasil tool kembali ke model.
  • Berhenti secara otomatis ketika model sudah tidak lagi meminta tool tambahan.
import { LunosClient } from "@lunos/client";

const client = new LunosClient({
  apiKey: process.env.LUNOS_API_KEY!,
  baseURL: "https://api.lunos.tech/v1",
  appId: "tool-function-calling-v1",
});

const MODEL = "openai/gpt-4o";
const MAX_TOOL_ITERATIONS = 5;

const tools = [
  {
    type: "function",
    function: {
      name: "searchBooks",
      description: "Search for books based on provided keywords",
      parameters: {
        type: "object",
        properties: {
          search_terms: {
            type: "array",
            items: { type: "string" },
            description: "List of keywords to search for books",
          },
        },
        required: ["search_terms"],
      },
    },
  },
];

async function searchBooks(search_terms: string[]) {
  const url = "https://gutendex.com/books";
  const searchQuery = encodeURIComponent(search_terms.join(" "));
  const response = await fetch(`${url}?search=${searchQuery}`);
  const data = await response.json();
  return (data.results ?? []).map((book: any) => ({
    id: book.id,
    title: book.title,
    authors: book.authors,
  }));
}

const TOOL_MAPPING: Record<
  string,
  (args: any) => Promise<unknown>
> = {
  searchBooks: ({ search_terms }) => searchBooks(search_terms),
};

async function run() {
  const baseMessages = [
    {
      role: "system",
      content: "You are a helpful assistant.",
    },
    {
      role: "user",
      content: "What are the titles of some James Joyce books?",
    },
  ];

  let messages = [...baseMessages];
  let iterations = 0;
  let finalContent = "";

  while (iterations < MAX_TOOL_ITERATIONS) {
    iterations += 1;

    const result = await client.chat.completions.create({
      model: MODEL,
      tools,
      messages,
    });

    const assistantMessage = result.choices[0]?.message;
    if (!assistantMessage) break;

    const toolCalls = assistantMessage.tool_calls ?? [];
    if (toolCalls.length === 0) {
      finalContent = assistantMessage.content ?? "";
      break;
    }

    const nextMessages: any[] = [...messages, assistantMessage];

    for (const toolCall of toolCalls) {
      const toolName = toolCall.function.name;
      const rawArgs = toolCall.function.arguments ?? "{}";
      const args = JSON.parse(rawArgs);

      const toolFn = TOOL_MAPPING[toolName];
      if (!toolFn) {
        throw new Error(`No local tool handler for ${toolName}`);
      }

      const toolResult = await toolFn(args);

      nextMessages.push({
        role: "tool",
        tool_call_id: toolCall.id,
        content: JSON.stringify(toolResult),
      });
    }

    messages = nextMessages;
  }

  console.log(finalContent);
}

void run();

Tips Mendefinisikan Schema Tool

Saat mendefinisikan tool, fokus utama Anda adalah kejelasan:

  • Gunakan nama fungsi yang spesifik dan deskriptif agar model mudah memahami kapan harus menggunakannya.
  • Berikan deskripsi yang menjelaskan secara jelas dalam kondisi apa tool tersebut sebaiknya dipanggil.
  • Gunakan JSON Schema yang terstruktur dengan baik untuk parameter.
  • Batasi jumlah parameter agar tetap ringkas dan terarah.

Memilih Model untuk Tool Calling

Sebelum digunakan di lingkungan produksi, pastikan:

  • Model yang Anda pilih memang mendukung fitur tool calling.
  • Model dapat menghasilkan argumen tool yang konsisten sesuai dengan schema yang Anda definisikan.
  • Aplikasi Anda memvalidasi input dari tool sebelum mengeksekusi aksi terhadap sistem eksternal.

Mengontrol Penggunaan Tool (Opsional)

Beberapa implementasi yang kompatibel dengan OpenAI menawarkan parameter tambahan untuk mengontrol perilaku tool. Jika model atau proxy Anda mendukungnya, berikut beberapa opsi yang mungkin tersedia:

  • tool_choice — untuk meminta model menggunakan tool tertentu atau menonaktifkan tool calling sama sekali.
  • parallel_tool_calls — untuk mengatur apakah beberapa tool bisa diminta secara bersamaan dalam satu turn.

Pastikan Anda selalu memeriksa dokumentasi parameter untuk model atau proxy yang sedang digunakan.

Interleaved Thinking (Reasoning di Antara Tool Calls)

Beberapa model dapat melakukan proses reasoning (berpikir logis) dengan memanfaatkan hasil tool sebelum meminta tool berikutnya. Kemampuan ini sangat bermanfaat untuk meningkatkan kualitas jawaban dalam workflow yang bersifat bertahap.

Detail implementasinya bergantung pada model spesifik yang digunakan. Sebelum mengandalkan fitur ini, periksa terlebih dahulu apakah model mendukung mode reasoning yang relevan (misalnya melalui metadata model pada GET /v1/models), lalu pastikan nama parameter yang tersedia pada dokumentasi model Anda.

Streaming dengan Tool Calls

Jika Anda mengaktifkan mode streaming (stream: true), response akan dikirimkan dalam bentuk chunk secara bertahap. Tool calls bisa muncul sebagai delta, dan nilai finish_reason di akhir stream akan menunjukkan apakah model meminta tool tambahan atau sudah mengakhiri jawabannya.

Di sisi client, kumpulkan data tool_calls sampai stream menandakan saatnya untuk mengeksekusi tool. Jalankan tool secara lokal, lalu kirim hasilnya kembali dalam request lanjutan (bisa non-streaming atau dilanjutkan dalam loop sesuai implementasi Anda).

Parallel Tool Calls

Beberapa implementasi mengizinkan model untuk meminta beberapa tool sekaligus dalam satu turn percakapan.

Jika Anda mengharuskan eksekusi tool berjalan secara berurutan (satu per satu), nonaktifkan fitur ini:

{
  "parallel_tool_calls": false
}

Multi-Tool Workflows

Anda bisa mendefinisikan beberapa tool sekaligus dan membiarkan model merangkainya secara natural sesuai kebutuhan. Pendekatan ini paling efektif jika setiap tool memiliki tujuan yang sempit dan terdefinisi dengan jelas.

Contoh:

{
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "searchProducts",
        "description": "Search for products in your catalog",
        "parameters": {
          "type": "object",
          "properties": {
            "query": { "type": "string" }
          },
          "required": ["query"]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "getProductDetails",
        "description": "Fetch detailed information for a product",
        "parameters": {
          "type": "object",
          "properties": {
            "productId": { "type": "string" }
          },
          "required": ["productId"]
        }
      }
    },
    {
      "type": "function",
      "function": {
        "name": "checkInventory",
        "description": "Check inventory levels for a product",
        "parameters": {
          "type": "object",
          "properties": {
            "productId": { "type": "string" }
          },
          "required": ["productId"]
        }
      }
    }
  ]
}

Praktik Terbaik (Best Practices)

  • Perlakukan setiap argumen tool sebagai input yang tidak tepercaya. Selalu lakukan validasi dan sanitasi sebelum menjalankan aksi yang berpotensi berbahaya.
  • Tambahkan mekanisme timeout dan retry untuk setiap pemanggilan tool ke layanan eksternal.
  • Batasi jumlah maksimum iterasi tool agar tidak terjadi loop yang berjalan terlalu lama.
  • Catat (log) metadata eksekusi tool dengan aman — hindari menyimpan data sensitif atau API key di dalam log.