Dokumentasi

Dokumentasi

penyelesaian chat

Endpoint /v1/chat/completions Kunavo menggunakan protokol Chat Completions OpenAI untuk keluarga Claude dan GPT. Streaming, alat, dan output JSON berfungsi melalui SDK yang sama; fungsi reasoning_effort bergantung pada keluarga model, dan halaman ini menjelaskan perbedaannya.

Endpoint: POST /v1/chat/completions. Bentuk permintaan dan respons sama persis dengan API Chat Completions OpenAI — termasuk streaming dan kolom opsional tool_calls / reasoning_tokens.

Panggilan dasar

resp = client.chat.completions.create(
    model="claude-sonnet-5",
    messages=[
        {"role": "system", "content": "You are a senior staff engineer."},
        {"role": "user", "content": "Pros and cons of postgres LISTEN/NOTIFY for a job queue?"},
    ],
    max_tokens=800,
)
print(resp.choices[0].message.content)

Parameter

Semua parameter standar OpenAI diterima. Beberapa hanya relevan untuk penyedia tertentu — penerjemah meneruskan parameter yang didukung setiap penyedia hulu.

ParameterTipeCatatan
modelstring (wajib)Slug apa pun yang diaktifkan dari /v1/models.
messagesarray (wajib)Format pesan standar OpenAI.
temperature0..2Suhu sampling. Default 1. Tidak berpengaruh pada model yang tercantum di bawah tabel ini.
top_p0..1Sampling nukleus. Pengecualian sama seperti temperature.
max_tokensintBatas output; max_completion_tokens diutamakan jika keduanya dikirim. Pada model GPT, token penalaran ikut dihitung dalam batas ini. Permintaan Claude yang tidak mengirim keduanya akan menggunakan 4.096.
streamboolKirim potongan sebagai SSE. Lihat di bawah.
toolsarrayDefinisi fungsi/alat. Claude dan GPT sama-sama mendukung penggunaan alat.
tool_choiceauto|none|namedPaksa penggunaan alat tertentu atau biarkan model yang menentukan.
response_formatobjectOutput JSON. Pada Claude, json_schema diberlakukan dan json_object tidak — lihat Output JSON untuk informasi setiap keluarga.
reasoning_effortstringHanya untuk model GPT — diteruskan sebagai reasoning.effort. Tidak diteruskan untuk Claude. Lihat Penalaran.
seedintSampling deterministik jika didukung.
stopstring|arrayUrutan penghentian tegas.
Claude Fable 5.1, Claude Fable 5, Claude Opus 5.5, Claude Opus 5, Claude Opus 4.8, Claude Opus 4.7, dan Claude Sonnet 5 tidak menerima temperature, top_p, atau top_k. Kunavo menghapus ketiganya dari permintaan ke model tersebut, alih-alih meneruskan error 400 dari vendor kepada Anda, sehingga ketiganya tidak berpengaruh pada model itu.

Pengaliran data

Atur stream=True. Kunavo mengirimkan peristiwa server-sent dalam format OpenAI yang persis: setiap potongan berupa chat.completion.chunk dengan choices[0].delta.content. Payload penggunaan terakhir tiba bersama data: [DONE].

stream = client.chat.completions.create(
    model="claude-haiku-4-5",
    messages=[{"role": "user", "content": "Explain B-trees in one paragraph."}],
    stream=True,
)

for chunk in stream:
    delta = chunk.choices[0].delta.content
    if delta:
        print(delta, end="", flush=True)
Streaming berfungsi untuk setiap model chat. Untuk Claude (penyedia hulu berprotokol Anthropic), kami menerjemahkan aliran peristiwa Anthropic menjadi delta OpenAI secara langsung — SDK Anda tidak akan menyadari perbedaannya.

Pemanggilan alat / fungsi

Pemanggilan alat berfungsi di berbagai penyedia. Definisikan alat sebagai skema JSON; model mengembalikan tool_calls dalam pesannya; jalankan alat tersebut, lalu kirimkan hasilnya kembali sebagai pesan role: "tool".

tools = [{
    "type": "function",
    "function": {
        "name": "get_current_weather",
        "description": "Get current weather for a city",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string"},
                "unit": {"type": "string", "enum": ["c", "f"]},
            },
            "required": ["city"],
        },
    },
}]

resp = client.chat.completions.create(
    model="claude-sonnet-5",
    messages=[{"role": "user", "content": "What's the weather in Tokyo?"}],
    tools=tools,
    tool_choice="auto",
)

# Inspect tool calls the model wants to make
for call in resp.choices[0].message.tool_calls or []:
    print(call.function.name, call.function.arguments)

Output JSON (response_format)

response_format meminta output JSON. Jaminannya bergantung pada keluarga model, karena permintaan setiap keluarga diterjemahkan ke mekanisme penyedia hulu yang berbeda:

Keluargajson_schemajson_object
ClaudeDiberlakukan. Dikirim sebagai structured outputs Anthropic (output_config.format); respons dibatasi agar sesuai dengan skema Anda. Diverifikasi pada setiap model Claude yang disediakan Kunavo, 2026-09-24.Tidak diberlakukan. Anthropic tidak memiliki mode JSON tanpa skema, sehingga permintaan diterima dan diabaikan — respons dapat diawali teks biasa atau blok kode.
GPTDiteruskan sebagai text.format milik Responses API, tetapi penyedia hulu saat ini tidak menerapkannya pada setiap permintaan. Validasi sebelum Anda mengurai respons.Diteruskan sebagai text.format.
import json

resp = client.chat.completions.create(
    model="claude-haiku-4-5",
    messages=[{"role": "user", "content": "Jane Doe <jane@example.com> wants the Pro plan."}],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "signup",
            "schema": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "email": {"type": "string"},
                    "plan": {"type": "string", "enum": ["free", "pro", "enterprise"]},
                },
                "required": ["name", "email", "plan"],
                "additionalProperties": False,
            },
        },
    },
)
signup = json.loads(resp.choices[0].message.content)  # constrained to the schema

Empat hal yang perlu diketahui tentang Claude:

  • Skema diteruskan ke Anthropic hampir persis seperti yang Anda tulis. Anthropic mewajibkan additionalProperties: false pada objek, jadi Kunavo menambahkannya pada setiap objek yang mencantumkan propertinya dan membiarkannya tidak ditetapkan — seperti yang dihasilkan oleh model_json_schema() milik Pydantic. Anthropic tetap akan menolak hal-hal berikut dengan error 400 yang menjelaskan masalahnya: objek yang dibiarkan terbuka (additionalProperties ditetapkan ke nilai selain false, atau tidak ada properti yang dicantumkan dan additionalProperties tidak ditetapkan), serta oneOf — gunakan anyOf. Halaman structured outputs Anthropic mencantumkan hal lainnya.
  • strict dan name diabaikan: Anthropic memberlakukan setiap skema yang diterimanya, baik strict maupun tidak.
  • Skema tidak dapat digabungkan dengan pesan assistant terakhir (prefill); Anthropic akan menjawab dengan error 400.
  • Jika max_tokens habis di tengah objek, JSON akan terpotong dan finish_reason bernilai "length".

Input visi / multimodal

Model dengan kapabilitas vision menerima blok konten gambar. Gunakan URL HTTPS atau URI base64 data:.

# Pass an image URL or a base64 data URI as part of a multimodal message
resp = client.chat.completions.create(
    model="claude-haiku-4-5",
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": "What's in this image?"},
            {"type": "image_url", "image_url": {
                "url": "https://example.com/cat.jpg"
            }},
        ],
    }],
)
print(resp.choices[0].message.content)

Model berkemampuan visi dalam katalog mencakup Claude Opus 5.5 — lihat daftar model untuk model lainnya.

Untuk gambar https, Kunavo mengunduh berkasnya sendiri lalu mengirimkannya langsung ke model, karena beberapa penyedia hulu mengabaikan URL gambar biasa. Batas: 16 gambar per permintaan, 5 MB per gambar, total 20 MB, 10 detik per unduhan. Gambar yang tidak dapat diambil akan menghasilkan error yang menyebutkan gambar tersebut, bukan dilewati.

Penalaran

Fungsi kontrol penalaran pada endpoint ini bergantung pada keluarga model, karena permintaan setiap keluarga diterjemahkan ke API penyedia hulu yang berbeda:

Keluargareasoning_effortToken penalaran dalam usage
GPTDiteruskan sebagai reasoning.effort milik Responses API, dengan nilai yang sama persis, pada GPT-6 Astra, GPT-6 Sol, GPT-6 Luna, GPT-5.6 Sol, GPT-5.6 Terra, dan GPT-5.5. Nilai yang diterima adalah nilai yang ditetapkan model; pada GPT-6 Sol dan GPT-6 Luna, none menonaktifkan penalaran dan max adalah tingkat tertinggi.Dihitung sebagai bagian dari completion_tokens dan ditampilkan terpisah sebagai completion_tokens_details.reasoning_tokens, ditagih dengan tarif output.
ClaudeTidak diteruskan. Permintaan Anthropic dibuat dari daftar kolom tetap — model, max_tokens, messages, stream, temperature, top_p, top_k, stop, tools, tool_choice, dan response_format — sehingga reasoning_effort, thinking, dan apa pun di luar daftar tersebut dihapus di sini.Tidak ada perincian. Anthropic menghitung pemikiran apa pun di dalam output_tokens-nya, yang dilaporkan oleh completion_tokens.
# GPT models: reasoning_effort is forwarded as the Responses API's
# reasoning.effort. Reasoning tokens are part of completion_tokens.
resp = client.chat.completions.create(
    model="gpt-6-sol",
    messages=[{"role": "user", "content": "Plan a 3-week MLOps migration."}],
    reasoning_effort="high",
)
details = resp.usage.completion_tokens_details   # absent when no reasoning ran
print(details.reasoning_tokens if details else 0)
Extended thinking pada Claude menggunakan Messages API native, yang meneruskan thinking ke Anthropic tanpa diterjemahkan.

caching prompt

Prompt sistem yang panjang, dokumen referensi, blok few-shot — setiap prefiks yang stabil dapat di-cache di sisi penyedia dan digunakan kembali pada panggilan berikutnya dengan biaya input yang jauh lebih rendah. Cache hit ditampilkan dalam objek penggunaan sebagai prompt_tokens_details.cached_tokens.

Model GPT menyimpan cache secara otomatis — tidak perlu mengubah permintaan. cached_tokens adalah subset dari prompt_tokens dan dikenai tarif baca cache yang lebih rendah.

Claude hanya menyimpan cache sampai titik henti cache_control, dan pada prompt yang panjang endpoint ini menetapkan titik henti untuk Anda: pada prompt sistem, pada definisi tool, dan pada pesan terakhir begitu percakapan berisi giliran asisten. Untuk memilih prefiks sendiri, lampirkan cache_control ke blok konten seperti di bawah ini; Kunavo mempertahankan titik henti Anda dan hanya menambahkan titik hentinya sendiri pada posisi yang Anda biarkan kosong:

# Claude caches prefixes you mark with cache_control. Attach it to a content
# block; later calls reusing that prefix read it at ~10% of the input price.
resp = client.chat.completions.create(
    model="claude-sonnet-5",
    messages=[{
        "role": "user",
        "content": [
            {
                "type": "text",
                "text": LONG_DOCUMENT,            # the stable, reused prefix
                "cache_control": {"type": "ephemeral"},
            },
            {"type": "text", "text": "Summarize the document above."},
        ],
    }],
)
print(resp.usage.prompt_tokens_details.cached_tokens)
Untuk kendali penuh atas caching prompt Claude — menyimpan prompt sistem dan definisi tool, beberapa titik henti, serta kolom penggunaan native cache_creation_input_tokens / cache_read_input_tokens — gunakan Messages API native. Endpoint ini juga menyimpan prompt sistem dan definisi tool ke cache, menerima beberapa titik henti dalam satu permintaan, serta melaporkan penulisan cache sebagai cache_creation_input_tokens dan pembacaan cache sebagai prompt_tokens_details.cached_tokens; yang hanya dilakukan endpoint native adalah meneruskan isi permintaan Anda tanpa menambahkan titik henti apa pun.

Objek penggunaan

Setiap respons (dan chunk streaming terakhir) menyertakan objek usage:

KolomMakna
prompt_tokensToken input yang ditagihkan kepada Anda — termasuk token yang di-cache.
prompt_tokens_details.cached_tokensInput yang di-cache — subset dari prompt_tokens, dikenai tarif baca cache yang lebih rendah.
completion_tokensToken output yang kami tagihkan. Pada model GPT, ini mencakup token penalaran; pada Claude, ini adalah output_tokens milik Anthropic.
completion_tokens_details.reasoning_tokensModel GPT: bagian penalaran dari completion_tokens. Tidak ada jika nilainya nol, dan tidak dilaporkan untuk Claude.
total_tokensprompt_tokens + completion_tokens.

Kompatibilitas Ollama dengan OpenAI — /v1/chat/completions

Ollama menyajikan model lokalnya melalui API yang kompatibel dengan OpenAI di http://localhost:11434/v1, dengan menerapkan kontrak /chat/completions yang sama seperti yang didokumentasikan di halaman ini. Karena itu, keduanya dapat dipertukarkan di sisi klien: apa pun yang dibuat menggunakan API v1 Ollama dapat dijalankan dengan Kunavo hanya dengan mengganti URL dasar dan model.

import os

from openai import OpenAI

# Before — Ollama's OpenAI-compatible API, local models
client = OpenAI(
    base_url="http://localhost:11434/v1",
    api_key="ollama",                       # ignored locally
)
resp = client.chat.completions.create(
    model="llama3.2",
    messages=[{"role": "user", "content": "Summarize this changelog."}],
)

# After — the same call against hosted frontier models.
# Two lines changed. Everything below them is untouched.
client = OpenAI(
    base_url="https://api.kunavo.com/v1",   # <- was localhost:11434/v1
    api_key=os.environ["KUNAVO_API_KEY"],
)
resp = client.chat.completions.create(
    model="claude-sonnet-5",  # <- was llama3.2
    messages=[{"role": "user", "content": "Summarize this changelog."}],
)

Bagian yang biasanya bermasalah saat berpindah penyedia tidak bermasalah di sini karena format wire-nya sama:

FiturOllama v1Kunavo v1
Jalur endpoint/v1/chat/completions/v1/chat/completions
Pengaliran dataSSE, chat.completion.chunkIdentik — bentuk delta sama
Pemanggilan tooltools / tool_callsIdentik untuk Claude dan GPT
Input visiBlok image_url pada model lokal multimodalBlok yang sama; URI data URL atau base64
api_keyPlaceholder, diabaikanKunci Kunavo sungguhan
modelTag yang telah diunduh (llama3.2)Slug yang dihosting (claude-sonnet-5)
Ekstra penggunaanHanya jumlah tokenMenambahkan cached_tokens dan reasoning_tokens
Di luar chatcompletions, embeddingsDitambah endpoint gambar, video, dan audio
Menggunakan keduanya? Baca base_url, model, dan kunci dari variabel lingkungan, lalu beralih sesuai lingkungan — model lokal untuk iterasi offline, model yang dihosting saat kualitas penting, dengan satu jalur kode. Panduan lengkap, termasuk hal-hal yang didukung dan tidak didukung oleh antarmuka OpenAI Ollama, tersedia di Panduan API Ollama yang kompatibel dengan OpenAI.

Di mana dokumentasi resmi endpoint /v1/chat/completions Ollama yang kompatibel dengan OpenAI?

Ollama mendokumentasikan lapisan kompatibilitas OpenAI di repositorinya sendiri, di docs/openai.md. Dokumen tersebut merupakan acuan resmi untuk mengetahui kolom OpenAI yang diterapkan server lokal. Halaman ini adalah referensi setara untuk endpoint /v1/chat/completions yang dihosting Kunavo: kontrak OpenAI Chat Completions yang sama, didokumentasikan kolom demi kolom di atas, sehingga Anda dapat membandingkan kedua antarmuka secara langsung. Singkatnya, bentuk permintaan dan responsnya sama — Ollama menyediakannya di http://localhost:11434/v1 untuk model yang diunduh secara lokal, sedangkan Kunavo menyediakannya di https://api.kunavo.com/v1 untuk model Claude dan GPT yang dihosting.

Apakah /v1/chat/completions Kunavo kompatibel dengan OpenAI API Ollama?

Ya — keduanya menerapkan kontrak OpenAI Chat Completions yang sama, sehingga klien yang dibuat untuk Ollama di http://localhost:11434/v1 dapat digunakan di https://api.kunavo.com/v1 tanpa perubahan. Kolom permintaan (messages, temperature, max_tokens, stream, tools, tool_choice, response_format, stop, seed) dan kolom respons (choices[].message, choices[].delta untuk streaming, usage) cocok. Perbedaannya sesuai dengan yang diharapkan dari model yang dihosting: api_key menggunakan kunci sungguhan, bukan placeholder; model menggunakan slug yang dihosting seperti claude-sonnet-5, bukan tag yang diunduh seperti llama3.2; dan usage memuat cached_tokens serta reasoning_tokens yang tidak dilaporkan oleh model lokal.

Bagaimana cara memigrasikan aplikasi Ollama ke Claude atau GPT yang dihosting?

Ubah dua baris: atur base_url dari http://localhost:11434/v1 menjadi https://api.kunavo.com/v1, lalu atur model dari tag lokal menjadi slug yang dihosting. Gunakan kunci Kunavo sungguhan, bukan placeholder yang diabaikan Ollama. Jalur kode untuk streaming, pemanggilan alat, dan visi tidak perlu diubah karena bentuk SSE dan tool_calls identik.

Bisakah saya tetap menggunakan Ollama untuk pengembangan dan model yang dihosting di produksi?

Ya, ini merupakan konfigurasi yang umum — baca URL dasar, model, dan kunci dari variabel lingkungan, lalu ganti nilainya sesuai lingkungan. Karena kedua pihak menggunakan protokol OpenAI yang sama, tidak ada jalur kode kedua yang perlu dipelihara: gunakan Llama atau Qwen lokal untuk iterasi luring, serta Claude atau GPT yang dihosting saat kualitas menjadi prioritas. Definisi alat dan penangan streaming dapat digunakan bersama tanpa perubahan.

Endpoint OpenAI apa saja yang ditambahkan Kunavo di luar antarmuka kompatibel Ollama?

Antarmuka Ollama yang kompatibel dengan OpenAI mencakup /chat/completions, /completions, /embeddings, dan /models. Kunavo menambahkan endpoint media dengan kunci yang sama: /v1/images/generations, /v1/images/edits, /v1/video/generations, /v1/videos, dan /v1/audio/music, serta Claude melalui endpoint native Anthropic /v1/messages. Ada dua catatan penting untuk sisi sebaliknya: /v1/audio/speech, /v1/audio/transcriptions, dan /v1/embeddings sudah diterapkan sebagai format kawat, tetapi saat ini tidak ada model yang diaktifkan di baliknya, sehingga belum dapat digunakan — dan berbeda dengan Ollama, Kunavo tidak menjalankan model secara lokal. GET /v1/models selalu menjadi acuan untuk mengetahui apa yang dapat dipanggil.

Langkah selanjutnya