Contoh Pemanggilan Alat API Ollama dengan SDK OpenAI
Pemanggilan alat memungkinkan model meminta kode Anda menjalankan fungsi dan kemudian menggunakan hasilnya dalam jawabannya. Di bawah ini adalah contoh lengkap dengan SDK OpenAI terhadap endpoint yang di-host, termasuk streaming dan kesalahan yang menyebabkan sebagian besar kegagalan.
Diperbarui

Poin utama
- Kirim fungsi Anda sebagai skema JSON dalam tools; model membalas dengan tool_calls alih-alih teks.
- Anda menjalankan fungsi, menambahkan hasilnya sebagai pesan role tool, dan memanggil API lagi.
- Selalu uraikan argumen secara defensif, karena model dapat mengembalikan JSON yang tidak valid atau tidak terduga.
- Panggilan alat yang dialirkan tiba dalam fragmen yang harus Anda gabungkan berdasarkan indeks.
Seperti apa bentuk loopnya
Jika Anda mencari contoh ollama api tool calling yang berfungsi terhadap endpoint yang di-host, bentuknya adalah standar OpenAI. Anda mendeskripsikan fungsi Anda dalam array tools. Model baik menjawab dalam teks atau mengembalikan daftar tool_calls yang menamai fungsi dan argumennya. Model tidak menjalankan apa pun. Kode Anda menjalankan fungsi, mengirimkan output kembali, dan model menulis balasan akhir.
Hal ini berarti satu putaran penggunaan alat memerlukan dua panggilan API:
- Kirim pesan pengguna dan definisi alat.
- Terima pesan asisten dengan
tool_calls. Jalankan setiap panggilan secara lokal. - Kirim pesan asli, pesan asisten, dan satu pesan
role: "tool"untuk setiap panggilan beserta hasilnya. - Terima jawaban teks akhir.
Contoh menggunakan base URL https://api.ollamaapi.com/v1 dan ID model uncensored. Endpoint adalah layanan yang di-host, jadi kunci berasal dari halaman kunci API. Kode yang sama juga berjalan di server Ollama lokal jika Anda mengubah base URL, kunci, dan nama model, selama model lokal mendukung tools.
Contoh Python lengkap
Contoh memberikan model satu fungsi, get_order_status, yang didukung oleh kamus kecil. Aplikasi nyata akan melakukan kueri ke basis data atau layanan internal pada titik tersebut.
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.ollamaapi.com/v1", api_key="YOUR_KEY")
ORDERS = {"A1001": "shipped", "A1002": "processing", "A1003": "delivered"}
def get_order_status(order_id: str) -> str:
return ORDERS.get(order_id, "not found")
tools = [{
"type": "function",
"function": {
"name": "get_order_status",
"description": "Look up the status of an order by its ID.",
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "string", "description": "Order ID such as A1001"}
},
"required": ["order_id"],
},
},
}]
messages = [{"role": "user", "content": "Where is order A1002?"}]
first = client.chat.completions.create(
model="uncensored",
messages=messages,
tools=tools,
tool_choice="auto",
)
msg = first.choices[0].message
if msg.tool_calls:
messages.append(msg) # keep the assistant turn with its tool_calls
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = get_order_status(**args)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": result,
})
final = client.chat.completions.create(
model="uncensored",
messages=messages,
tools=tools,
)
print(final.choices[0].message.content)
else:
print(msg.content)Tiga hal penting di sini. Pesan asisten yang berisi tool_calls harus dimasukkan kembali ke riwayat sebelum hasil alat, atau permintaan berikutnya akan ditolak atau membingungkan. Setiap pesan alat harus menyertakan tool_call_id dari panggilan yang dijawabnya. Dan permintaan kedua harus tetap menyertakan tools, karena model mungkin ingin memanggil fungsi lain setelah melihat hasil pertama.
Permintaan yang sama dengan curl
Menguji dengan curl menghilangkan SDK dari persamaan, yang membantu ketika Anda tidak yakin apakah masalah ada di kode Anda atau di permintaan.
curl https://api.ollamaapi.com/v1/chat/completions \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "uncensored",
"messages": [{"role": "user", "content": "Where is order A1002?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_order_status",
"description": "Look up the status of an order by its ID.",
"parameters": {
"type": "object",
"properties": {"order_id": {"type": "string"}},
"required": ["order_id"]
}
}
}],
"tool_choice": "auto"
}'Balasan pertama yang berhasil memiliki finish_reason diatur ke tool_calls, content kosong atau null, dan array tool_calls. Bidang arguments adalah string yang berisi JSON, bukan objek bersarang, itulah mengapa contoh Python memanggil json.loads.
Bidang tool_choice mengontrol seberapa tegas permintaan tersebut. auto membiarkan model memutuskan. Melewatkan objek yang menyebutkan fungsi meminta fungsi spesifik tersebut. Gunakan auto kecuali Anda memiliki alasan, karena memaksa panggilan pada pesan yang tidak membutuhkannya menghasilkan argumen yang diciptakan.
Loop yang sama di Node
Versi Node menggunakan paket openai resmi dan mengikuti langkah yang sama. Ini menangani lebih dari satu panggilan per giliran dengan Promise.all.
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.ollamaapi.com/v1",
apiKey: process.env.API_KEY,
});
const handlers = {
get_order_status: async ({ order_id }) =>
({ A1001: "shipped", A1002: "processing" })[order_id] ?? "not found",
};
const tools = [{
type: "function",
function: {
name: "get_order_status",
description: "Look up the status of an order by its ID.",
parameters: {
type: "object",
properties: { order_id: { type: "string" } },
required: ["order_id"],
},
},
}];
const messages = [{ role: "user", content: "Where is order A1001?" }];
const first = await client.chat.completions.create({
model: "uncensored", messages, tools,
});
const msg = first.choices[0].message;
if (msg.tool_calls?.length) {
messages.push(msg);
const results = await Promise.all(msg.tool_calls.map(async (call) => {
const args = JSON.parse(call.function.arguments);
const out = await handlers[call.function.name](args);
return { role: "tool", tool_call_id: call.id, content: String(out) };
}));
messages.push(...results);
const final = await client.chat.completions.create({
model: "uncensored", messages, tools,
});
console.log(final.choices[0].message.content);
} else {
console.log(msg.content);
}Streaming panggilan alat
Dengan stream: true, balasan tiba melalui SSE, dan panggilan alat tiba dalam potongan. Setiap chunk memiliki entri delta.tool_calls dengan index. Potongan pertama untuk index tertentu berisi ID panggilan dan nama fungsi. Potongan selanjutnya menambahkan irisan string arguments. Anda menggabungkan irisan per index, dan hanya mem-parsing JSON setelah stream berakhir.
stream = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": "Where is order A1003?"}],
tools=tools,
stream=True,
)
calls = {}
for chunk in stream:
if not chunk.choices:
continue
delta = chunk.choices[0].delta
for part in (delta.tool_calls or []):
slot = calls.setdefault(part.index, {"id": "", "name": "", "args": ""})
if part.id:
slot["id"] = part.id
if part.function and part.function.name:
slot["name"] = part.function.name
if part.function and part.function.arguments:
slot["args"] += part.function.arguments
for slot in calls.values():
print(slot["name"], json.loads(slot["args"]))Ingat bahwa permintaan yang di-stream mempertahankan slot konkurensinya hingga stream selesai. Kunci penuh memungkinkan 8 permintaan sekaligus dan 300 per menit, kunci uji coba 2 dan 60. Jika Anda menjalankan loop alat untuk banyak pengguna secara paralel, hitung setiap stream terbuka terhadap angka pertama.
Jebakan dan cara memperbaikinya
Argumen yang tidak valid atau hilang
Model adalah open-weight model, dan model open terkadang mengembalikan argumen yang bukan JSON valid, melewatkan bidang yang diperlukan, atau menciptakan bidang tambahan. Bungkus json.loads dalam blok try, validasi terhadap skema Anda, dan ketika gagal, kirimkan kesalahan kembali sebagai pesan alat. Model biasanya memperbaiki dirinya sendiri pada giliran berikutnya. Batasi loop pada beberapa iterasi agar kegagalan yang membandel tidak berjalan selamanya.
Deskripsi yang terlalu samar
Model memilih fungsi dengan membaca nama dan deskripsinya. Deskripsi seperti "mendapatkan data" tidak memberinya bahan kerja. Katakan apa yang dilakukan fungsi, apa arti inputnya, dan sertakan nilai contoh dalam deskripsi parameter.
Terlalu banyak alat sekaligus
Setiap definisi alat dihitung sebagai token input pada setiap permintaan. Pada $0,15 per 1M token input, sepuluh alat dengan 150 token masing-masing menambah 1.500 token, yang merupakan $0,000225 per permintaan, kecil tetapi tidak nol pada volume. Lebih penting lagi, menu yang panjang membuat pemilihan kurang andal. Tawarkan hanya alat yang relevan dengan langkah saat ini.
Hasil alat yang terlalu besar
Apa pun yang Anda kembalikan akan diberikan kembali sebagai input. Potong baris basis data besar atau halaman web ke bidang yang dibutuhkan model. Jendela konteks adalah 100.000 token secara total, sehingga hasil yang sangat besar dapat menggeser percakapan.
Mencampur alat dengan mode JSON
Mode JSON (response_format dengan json_object) tersedia, tetapi gunakan untuk jawaban akhir, bukan untuk giliran di mana Anda ingin model memanggil fungsi. Uji kombinasi ini pada prompt Anda sendiri sebelum bergantung padanya.
Beralih dari Ollama lokal dan apa yang harus diperiksa
Jika Anda membuat loop alat pertama Anda terhadap server Ollama lokal, hampir tidak ada perubahan. Ganti URL dasar dengan https://api.ollamaapi.com/v1, gunakan kunci yang sebenarnya, dan atur model menjadi uncensored. Rute Ollama asli seperti /api/chat tidak ada di sini. Hanya POST /v1/chat/completions dan GET /v1/models yang tersedia, sehingga kode yang ditulis untuk API asli memerlukan panggilan bergaya OpenAI.
Sebelum Anda meluncurkan, jalankan daftar periksa singkat ini:
- Verifikasi bahwa kunci berfungsi dengan
GET /v1/models. - Log header
X-Request-Iduntuk setiap panggilan, agar kegagalan dapat dilacak. - Pantau
X-Balance-USDdalam header respons jika Anda menjalankan loop alat secara tidak diawasi. - Tangani HTTP 429: tunggu pada
rate_limitedatauconcurrency, dan patuhiRetry-After: 5saat kelebihan beban. - Atur batas keras pada iterasi loop.
Loop alat membuat setidaknya dua permintaan per pertanyaan pengguna, sehingga biaya meningkat sesuai dengan itu. Sebagai contoh, 2.000 loop dengan 1.200 token input dan 150 token output per permintaan, dua permintaan masing-masing, berjumlah 4.000 permintaan, 4,8 juta token input dan 0,6 juta token output. Itu adalah $0,72 ditambah $0,30, atau total $1,02. Halaman harga memiliki opsi isi saldo, dan dokumentasi mencantumkan bidang permintaan yang didukung. Pengguna baru dapat mencoba semua ini dengan kredit uji coba $0,50, yang tidak memerlukan kartu.
Panduan lainnya
Tanya jawab
Apakah endpoint mendukung pemanggilan fungsi?
Ya. Ini menerima alat dan tool_choice, mengembalikan tool_calls, mengalirkannya sebagai delta, dan menerima hasil kembali sebagai pesan dengan role: tool.
Mengapa permintaan kedua gagal setelah panggilan alat?
Penyebab umumnya adalah pesan asisten yang hilang atau pesan alat tanpa tool_call_id yang sesuai. Tambahkan giliran asisten yang berisi tool_calls terlebih dahulu, lalu kirimkan satu pesan alat untuk setiap panggilan.
Dapatkah model memanggil beberapa alat dalam satu giliran?
Model dapat mengembalikan daftar dengan lebih dari satu entri, jadi lakukan perulangan pada semua entri dan kirimkan satu hasil untuk setiap entri. Jangan mengasumsikan daftar hanya memiliki satu item.
Apakah Anda memerlukan pustaka Ollama untuk ini?
Tidak. SDK resmi OpenAI sudah cukup. Arahkan base URL ke endpoint dan gunakan model uncensored.
Kunci Anda tersedia setelah satu langkah formulir
Buat akun, salin kunci, ubah URL dasar. Itu saja seluruh proses pengaturannya.