Function calling
Function calling memungkinkan model meminta kodemu melakukan sesuatu yang tidak bisa dilakukannya sendiri, misalnya mencari pesanan atau membaca database. Jelaskan fungsi yang tersedia. Model memilih fungsi dan mengirim argumennya. Jalankan fungsi tersebut, lalu kirim hasilnya kembali agar model bisa menulis jawaban akhir. Fitur ini tersedia di Chat completions, Messages, dan Responses.
Pilih model yang mendukung tools
Section titled “Pilih model yang mendukung tools”Model mendukung function calling jika tool_call bernilai true di GET /v1/models. Endpoint ini publik, jadi kamu bisa memfilternya tanpa key:
curl -s https://kenari.id/v1/models | jq -r '.data[] | select(.tool_call == true) | .id'kenari tidak memblokir model yang tidak punya flag ini, tetapi model tersebut bisa mengabaikan tools-mu. Contoh di halaman ini memakai step-3-7-flash:free, yang mendukung tools dan gratis dipanggil.
Alur dengan Chat completions
Section titled “Alur dengan Chat completions”Panggilan tool adalah percakapan pendek: request-mu, panggilan dari model, hasil darimu, lalu jawaban model.
- Kirim pesan user dan array
tools. - Model mengembalikan pesan assistant dengan
tool_callsdanfinish_reason: "tool_calls". - Jalankan setiap fungsi. Tambahkan pesan assistant tadi, lalu satu pesan
tooluntuk setiap panggilan, masing-masing dengantool_call_idyang sesuai. - Kirim ulang seluruh percakapan. Kali ini model menjawab dengan teks biasa.
Setiap tool punya name, description yang memberi tahu model kapan memakainya, dan JSON Schema untuk parameters. Ini balasan model pada langkah 2:
{ "choices": [ { "index": 0, "message": { "role": "assistant", "content": null, "tool_calls": [ { "id": "call_abc123", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\": \"Jakarta\"}" } } ] }, "finish_reason": "tool_calls" } ]}arguments adalah string berisi JSON, bukan objek. Urai string JSON ini sebelum memakainya. Alur lengkap dengan OpenAI SDK:
import jsonimport os
from openai import OpenAI
client = OpenAI( base_url="https://kenari.id/v1", api_key=os.environ["KENARI_API_KEY"],)
tools = [ { "type": "function", "function": { "name": "get_weather", "description": "Ambil cuaca saat ini untuk sebuah kota.", "parameters": { "type": "object", "properties": { "city": {"type": "string", "description": "Nama kota, misalnya Jakarta"} }, "required": ["city"], }, }, }]
def get_weather(city: str) -> dict: return {"city": city, "temperature_c": 31, "conditions": "berawan"}
messages = [{"role": "user", "content": "Bagaimana cuaca di Jakarta sekarang?"}]
for _ in range(5): # hentikan loop yang berjalan terus response = client.chat.completions.create( model="step-3-7-flash:free", messages=messages, tools=tools, ) message = response.choices[0].message if not message.tool_calls: print(message.content) break
messages.append( { "role": "assistant", "content": message.content, "tool_calls": [call.model_dump() for call in message.tool_calls], } ) for call in message.tool_calls: arguments = json.loads(call.function.arguments) result = get_weather(**arguments) messages.append( { "role": "tool", "tool_call_id": call.id, "content": json.dumps(result), } )else: print("Berhenti setelah 5 putaran: model masih meminta panggilan tool.")content pada pesan tool berupa string. Kirim JSON sebagai teks, atau pesan error biasa jika fungsinya gagal, supaya model bisa menanganinya.
Alur dengan Messages
Section titled “Alur dengan Messages”Di /v1/messages, sebuah tool berbentuk {name, description, input_schema}. Model mengembalikan blok tool_use dan stop_reason: "tool_use". Kamu menjawab dengan blok tool_result di pesan user berikutnya.
Arahkan Anthropic SDK ke https://kenari.id, tanpa /v1. SDK menambahkan path-nya sendiri.
import jsonimport os
import anthropic
client = anthropic.Anthropic( base_url="https://kenari.id", api_key=os.environ["KENARI_API_KEY"],)
tools = [ { "name": "get_weather", "description": "Ambil cuaca saat ini untuk sebuah kota.", "input_schema": { "type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"], }, }]
messages = [{"role": "user", "content": "Bagaimana cuaca di Jakarta sekarang?"}]
for _ in range(5): response = client.messages.create( model="step-3-7-flash:free", max_tokens=2048, tools=tools, messages=messages, ) if response.stop_reason != "tool_use": print("".join(block.text for block in response.content if block.type == "text")) break
messages.append({"role": "assistant", "content": response.content}) results = [] for block in response.content: if block.type == "tool_use": output = {"city": block.input["city"], "temperature_c": 31} results.append( { "type": "tool_result", "tool_use_id": block.id, "content": json.dumps(output), } ) messages.append({"role": "user", "content": results})else: print("Berhenti setelah 5 putaran: model masih meminta panggilan tool.")Di /v1/responses, model mengembalikan item function_call dan kamu membalas dengan item function_call_output yang membawa call_id yang sama. Pada Responses, name dan parameters berada langsung di objek tool, yaitu {"type": "function", "name": ..., "parameters": ...}. Lihat Responses.
Atur kapan model memanggil tool
Section titled “Atur kapan model memanggil tool”tool_choice menentukan apakah model memanggil tool serta tool yang harus dipanggil. Tanpa field ini, model yang memutuskan.
| Chat completions | Messages | Efek |
|---|---|---|
"auto" | {"type": "auto"} | Model yang memutuskan. |
"required" | {"type": "any"} | Model harus memanggil minimal satu tool. |
{"type": "function", "function": {"name": "get_weather"}} | {"type": "tool", "name": "get_weather"} | Model harus memanggil tool tersebut. |
"none" | {"type": "none"} | Model menjawab tanpa memanggil tool. |
Pilihan paksa tanpa nama ditolak dengan 400. Bentuk yang tidak dikenal ditangani berbeda di tiap format API. Chat completions memperlakukan bentuk yang tidak dikenal, seperti allowed_tools, sebagai "auto". Messages dan Responses menolak tipe tool_choice yang tidak dikenal dengan 400.
Panggilan tool paralel
Section titled “Panggilan tool paralel”Model bisa mengembalikan beberapa panggilan dalam satu balasan: beberapa entri di tool_calls, atau beberapa blok tool_use. Jalankan semuanya, lalu jawab setiap panggilan. Di Chat completions itu berarti satu pesan tool per tool_call_id. Di Messages, semua blok tool_result dikirim dalam satu pesan user.
kenari hanya meneruskan field parallel_tool_calls ke model yang dilayani lewat API gaya OpenAI, dan membuangnya untuk model lain. Field ini juga dibuang setiap kali request mencantumkan server tool kenari:. Jangan mengandalkannya untuk mencegah panggilan paralel. Tulis loop-mu agar bisa menangani satu panggilan maupun banyak.
Streaming panggilan tool
Section titled “Streaming panggilan tool”Dengan "stream": true, sebuah panggilan datang dalam potongan yang harus kamu gabungkan sebelum di-parse. Lihat Streaming untuk field dan event tiap format API.
Tool yang dijalankan kenari untukmu
Section titled “Tool yang dijalankan kenari untukmu”Tool dengan tipe kenari:<name>, misalnya {"type": "kenari:web_search"}, dijalankan di kenari. Kamu tidak perlu menulis loop: model memanggilnya, kenari menjalankannya lalu melanjutkan jawaban. Kamu bisa mencampur server tools dengan fungsimu sendiri dalam satu array tools. Lihat Server tools.
Batasan dan jebakan
Section titled “Batasan dan jebakan”- Kirim array
toolsyang sama di setiap request dalam loop, termasuk request yang mengembalikan jawaban akhir. - Definisikan setiap tool yang dijalankan kodemu sebagai tool
function. Selain server toolkenari:, tipe tool tanpa definisi fungsi tidak dijalankan kenari, jadi jangan bergantung padanya. - Model bisa menghasilkan JSON yang tidak valid di
arguments, atau nilai di luar skema-mu. Validasi sebelum menjalankan apa pun yang punya efek samping. - Request yang mendeklarasikan tools, atau percakapan yang sudah berisi panggilan dan hasil tool, hanya dikirim ke provider yang mampu membawanya, sehingga tools dan hasilmu tidak hilang diam-diam.