Tài liệu
hoàn thành cuộc trò chuyện
Endpoint /v1/chat/completions của Kunavo dùng giao thức Chat Completions của OpenAI cho các họ Claude và GPT. Streaming, tools và đầu ra JSON hoạt động qua cùng SDK; tác dụng của reasoning_effort phụ thuộc vào họ mô hình và trang này nêu rõ tác dụng đó.
Endpoint: POST /v1/chat/completions. Hình dạng yêu cầu và phản hồi khớp chính xác với API Chat Completions của OpenAI — bao gồm streaming và các trường tùy chọn tool_calls / reasoning_tokens.
Lệnh gọi cơ bản
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)Tham số
Mọi tham số OpenAI tiêu chuẩn đều được chấp nhận. Một số tham số chỉ có ý nghĩa với một số nhà cung cấp nhất định — bộ chuyển đổi sẽ chuyển tiếp những tham số mà từng nhà cung cấp thượng nguồn hỗ trợ.
| Tham số | Loại | Ghi chú |
|---|---|---|
model | string (bắt buộc) | Mọi slug đã bật trong /v1/models. |
messages | array (bắt buộc) | Định dạng thông điệp OpenAI tiêu chuẩn. |
temperature | 0..2 | Nhiệt độ lấy mẫu. Mặc định là 1. Không có tác dụng với các mô hình được liệt kê bên dưới bảng này. |
top_p | 0..1 | Lấy mẫu theo hạt nhân. Có cùng ngoại lệ như temperature. |
max_tokens | int | Giới hạn đầu ra; max_ được ưu tiên nếu gửi cả hai. Trên các mô hình GPT, token suy luận được tính vào giới hạn này. Yêu cầu Claude không gửi giá trị nào trong hai giá trị sẽ dùng 4.096. |
stream | bool | Truyền các phần dữ liệu theo dạng SSE. Xem bên dưới. |
tools | array | Định nghĩa hàm/công cụ. Cả Claude và GPT đều hỗ trợ sử dụng công cụ. |
tool_choice | auto| | Buộc sử dụng một công cụ cụ thể hoặc để mô hình tự quyết định. |
response_ | object | Đầu ra JSON. Trên Claude, json_schema được thực thi còn json_object thì không — xem Đầu ra JSON để biết chi tiết cho từng họ. |
reasoning_ | string | Chỉ áp dụng cho mô hình GPT — được chuyển tiếp dưới dạng reasoning.. Không chuyển tiếp cho Claude. Xem Suy luận. |
seed | int | Lấy mẫu xác định trong trường hợp được hỗ trợ. |
stop | string|array | Các chuỗi dừng bắt buộc. |
temperature, top_p hoặc top_k. Kunavo xóa ba tham số này khỏi yêu cầu gửi đến các mô hình đó thay vì chuyển tiếp lỗi 400 của nhà cung cấp cho bạn, nên chúng không có tác dụng với các mô hình ấy.Truyền dữ liệu theo luồng
Đặt stream=True. Kunavo phát các sự kiện do máy chủ gửi theo đúng định dạng của OpenAI: mỗi phần dữ liệu là một chat.completion.chunk có choices[0].delta.content. Tải trọng usage cuối cùng được gửi kèm 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)Gọi công cụ / hàm
Gọi công cụ hoạt động trên nhiều nhà cung cấp. Định nghĩa công cụ bằng lược đồ JSON; mô hình trả về tool_calls trong thông điệp của nó; bạn thực thi công cụ rồi gửi kết quả trở lại dưới dạng thông điệp 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)Đầu ra JSON (response_format)
response_format yêu cầu đầu ra JSON. Mức độ bảo đảm phụ thuộc vào họ mô hình vì yêu cầu của từng họ được dịch sang một cơ chế thượng nguồn khác nhau:
| Họ | json_schema | json_object |
|---|---|---|
| Claude | Được thực thi. Gửi dưới dạng structured outputs của Anthropic (output_); phản hồi bị giới hạn theo lược đồ của bạn. Đã kiểm tra trên mọi mô hình Claude mà Kunavo cung cấp, 2026-09-24. | Không được thực thi. Anthropic không có chế độ JSON không cần lược đồ, nên tham số được chấp nhận nhưng bỏ qua — phản hồi có thể bắt đầu bằng văn xuôi hoặc khối mã. |
| GPT | Được chuyển tiếp dưới dạng text.format của Responses API, nhưng nhà cung cấp thượng nguồn hiện tại không áp dụng tham số này cho mọi yêu cầu. Hãy xác thực trước khi phân tích cú pháp. | Được chuyển tiếp dưới dạng 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 schemaCó bốn điều cần biết về Claude:
- Lược đồ được gửi đến Anthropic gần như nguyên trạng như bạn đã viết. Anthropic yêu cầu
additionalProperties: falsetrên các đối tượng, vì vậy Kunavo thêm trường này vào mọi đối tượng có liệt kê thuộc tính và để trống giá trị — đúng như cáchmodel_json_schema()của Pydantic tạo ra. Những trường hợp Anthropic vẫn từ chối sẽ trả lỗi 400 nêu rõ vấn đề: một đối tượng để mở (additionalPropertiesđược đặt thành bất kỳ giá trị nào khácfalse, hoặc không liệt kê thuộc tính nào vàadditionalPropertiesđể trống), cùng vớioneOf— hãy dùnganyOf. Trang structured outputs của Anthropic liệt kê các trường hợp còn lại. strictvànamebị bỏ qua: Anthropic thực thi mọi lược đồ mà họ chấp nhận, dù ở chế độ strict hay không.- Không thể kết hợp lược đồ với thông điệp
assistantcuối cùng (prefill); Anthropic trả lỗi 400. - Khi
max_tokenshết giữa chừng trong một đối tượng, JSON sẽ bị cắt cụt vàfinish_reasonlà"length".
Đầu vào vision / đa phương thức
Các mô hình có khả năng vision chấp nhận khối nội dung hình ảnh. Dùng URL HTTPS hoặc 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)Các mô hình có khả năng thị giác trong danh mục bao gồm Claude Opus 5.5 — xem danh sách mô hình để biết các mô hình khác.
Với hình ảnh https, Kunavo tự tải tệp xuống rồi gửi trực tiếp cho mô hình vì một số nhà cung cấp thượng nguồn bỏ qua URL hình ảnh thuần túy. Giới hạn: 16 hình ảnh cho mỗi yêu cầu, 5 MB mỗi hình ảnh, tổng cộng 20 MB, thời gian tải xuống 10 giây. Nếu không thể tải hình ảnh xuống, hệ thống trả về lỗi nêu tên hình ảnh đó thay vì bỏ qua.
Suy luận
Tác dụng của điều khiển suy luận trên endpoint này phụ thuộc vào họ mô hình vì yêu cầu của từng họ được dịch sang API thượng nguồn khác nhau:
| Họ | reasoning_ | Token suy luận trong usage |
|---|---|---|
| GPT | Được chuyển tiếp nguyên giá trị dưới dạng reasoning. của Responses API trên GPT-6 Astra, GPT-6 Sol, GPT-6 Luna, GPT-5.6 Sol, GPT-5.6 Terra và GPT-5.5. Các giá trị được chấp nhận là giá trị riêng của mô hình; trên GPT-6 Sol và GPT-6 Luna, none tắt suy luận còn max là mức cao nhất. | Được tính trong completion_ và tách riêng thành completion_, tính phí theo mức giá đầu ra. |
| Claude | Không được chuyển tiếp. Yêu cầu Anthropic được tạo từ một danh sách trường cố định — model, max_tokens, messages, stream, temperature, top_p, top_k, stop, tools, tool_choice và response_ — vì vậy reasoning_, thinking và mọi trường khác nằm ngoài danh sách này đều bị loại bỏ tại đây. | Không có phần phân tách. Anthropic tính mọi nội dung suy nghĩ bên trong output_, đây là giá trị mà completion_ báo cáo. |
# 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)thinking đến Anthropic mà không dịch.bộ nhớ đệm prompt
Một system prompt dài, tài liệu tham chiếu, một khối few-shot — bất kỳ tiền tố ổn định nào cũng có thể được lưu vào bộ nhớ đệm ở upstream và phát lại trong các lần gọi sau với chi phí đầu vào chỉ bằng một phần nhỏ. Cache hit được hiển thị trong đối tượng usage dưới dạng prompt_tokens_details.cached_tokens.
Các mô hình GPT tự động lưu bộ nhớ đệm — không cần thay đổi request. cached_tokens là tập con của prompt_tokens và được tính phí theo mức đọc từ bộ nhớ đệm giảm giá.
Claude chỉ lưu bộ nhớ đệm đến một điểm ngắt cache_control, và với prompt dài, endpoint này đặt các điểm ngắt thay cho bạn: trên system prompt, trên các định nghĩa công cụ và trên tin nhắn cuối cùng khi cuộc trò chuyện đã có lượt trả lời của trợ lý. Để tự chọn tiền tố, hãy gắn cache_control vào một content block như bên dưới; Kunavo giữ nguyên các điểm ngắt của bạn và chỉ thêm điểm ngắt của mình vào những vị trí bạn để trống:
# 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)cache_creation_input_tokens / cache_read_input_tokens — hãy dùng Messages API gốc. Endpoint này cũng lưu system prompt và các định nghĩa công cụ vào bộ nhớ đệm, nhận nhiều điểm ngắt trong một yêu cầu, và báo cáo phần ghi vào bộ nhớ đệm dưới dạng cache_creation_input_tokens, phần đọc từ bộ nhớ đệm dưới dạng prompt_tokens_details.cached_tokens; điều chỉ endpoint gốc làm là chuyển tiếp phần thân yêu cầu của bạn mà không thêm điểm ngắt nào.Đối tượng usage
Mỗi phản hồi (và chunk cuối cùng của luồng) đều có đối tượng usage:
| Trường | Ý nghĩa |
|---|---|
prompt_ | Số token đầu vào được tính phí — bao gồm cả token được lưu trong bộ nhớ đệm. |
prompt_ | Đầu vào được lưu trong bộ nhớ đệm — một tập con của prompt_ |
completion_ | Số token đầu ra đã tính phí. Trên các mô hình GPT, số này bao gồm token suy luận; trên Claude, đây là output_ |
completion_ | Các mô hình GPT: phần token suy luận trong completion_ |
total_tokens | prompt_ |
Khả năng tương thích OpenAI của Ollama — /v1/chat/completions
Ollama cung cấp các mô hình chạy cục bộ thông qua API tương thích với OpenAI tại http://localhost:11434/v1, triển khai cùng hợp đồng /chat/completions được mô tả trên trang này. Nhờ đó, hai API có thể thay thế cho nhau ở phía client: mọi thứ được viết cho API v1 của Ollama đều chạy được với API của Kunavo chỉ bằng cách đổi URL cơ sở và mô hình.
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."}],
)Những phần thường gặp lỗi khi chuyển đổi nhà cung cấp vẫn hoạt động ở đây, vì định dạng truyền tải là như nhau:
| Tính năng | Ollama v1 | Kunavo v1 |
|---|---|---|
| Đường dẫn endpoint | /v1/ | /v1/ |
| Truyền dữ liệu theo luồng | SSE, chat. | Giống hệt — cùng cấu trúc delta |
| Gọi công cụ | tools / tool_calls | Giống hệt trên Claude và GPT |
| Đầu vào hình ảnh | Các khối image_url trên những mô hình cục bộ đa phương thức | Các khối giống nhau; URL hoặc URI dữ liệu base64 |
| api_key | Giá trị giữ chỗ, bị bỏ qua | Một khóa Kunavo thật |
| model | Một tag đã tải về (llama3.2) | Một slug lưu trữ (claude-sonnet-5) |
| usage bổ sung | Chỉ số lượng token | Bổ sung cached_ |
| Ngoài chat | completions, embeddings | Cộng thêm các endpoint hình ảnh, video và âm thanh |
base_url, model và khóa từ các biến môi trường rồi chuyển đổi theo môi trường — mô hình cục bộ để lặp lại khi ngoại tuyến, mô hình lưu trữ khi cần chất lượng, tất cả trên cùng một luồng mã. Hướng dẫn đầy đủ, bao gồm những gì giao diện OpenAI của Ollama có và không triển khai, có trong hướng dẫn API tương thích với OpenAI của Ollama.Tài liệu chính thức về endpoint /v1/chat/completions tương thích OpenAI của Ollama ở đâu?
Ollama lưu tài liệu về lớp tương thích OpenAI trong kho mã nguồn riêng, tại docs/openai.md; đây là tài liệu tham khảo có thẩm quyền về các trường OpenAI mà máy chủ cục bộ hỗ trợ. Trang này là tài liệu tương đương cho endpoint /v1/chat/completions được lưu trữ trên Kunavo: cùng hợp đồng Chat Completions của OpenAI, được mô tả từng trường ở trên, để bạn có thể đối chiếu trực tiếp hai giao diện. Tóm lại, hình dạng yêu cầu và phản hồi là giống nhau — Ollama cung cấp endpoint tại http://localhost:11434/v1 cho các mô hình được tải xuống cục bộ, còn Kunavo cung cấp endpoint tại https://api.kunavo.com/v1 cho các mô hình Claude và GPT được lưu trữ.
Endpoint /v1/chat/completions của Kunavo có tương thích với API OpenAI của Ollama không?
Có — cả hai đều triển khai cùng hợp đồng Chat Completions của OpenAI, nên ứng dụng viết cho Ollama tại http://localhost:11434/v1 sẽ hoạt động nguyên trạng với https://api.kunavo.com/v1. Các trường yêu cầu (messages, temperature, max_tokens, stream, tools, tool_choice, response_format, stop, seed) và trường phản hồi (choices[].message, choices[].delta trong luồng stream, usage) đều trùng khớp. Khác biệt đúng như dự kiến đối với các mô hình được lưu trữ: api_key là khóa thực thay vì giá trị giữ chỗ, model nhận slug được lưu trữ như claude-sonnet-5 thay vì thẻ mô hình đã tải như llama3.2, và usage có cached_tokens cùng reasoning_tokens mà các mô hình cục bộ không báo cáo.
Làm cách nào để chuyển ứng dụng Ollama sang Claude hoặc GPT được lưu trữ?
Thay đổi hai dòng: đặt base_url từ http://localhost:11434/v1 thành https://api.kunavo.com/v1, rồi đặt model từ thẻ cục bộ thành slug được lưu trữ. Dùng khóa Kunavo thực thay cho giá trị giữ chỗ mà Ollama bỏ qua. Không cần thay đổi mã xử lý streaming, gọi công cụ hay vision vì cấu trúc SSE và tool_calls giống hệt nhau.
Tôi có thể tiếp tục dùng Ollama để phát triển và dùng mô hình được lưu trữ trong môi trường production không?
Có, đây là cách thiết lập phổ biến — đọc URL cơ sở, mô hình và khóa từ các biến môi trường rồi chuyển đổi theo từng môi trường. Vì cả hai đầu đều dùng cùng giao thức OpenAI nên bạn không cần duy trì nhánh mã thứ hai: dùng Llama hoặc Qwen cục bộ để phát triển ngoại tuyến, rồi dùng Claude hoặc GPT được lưu trữ khi cần chất lượng cao. Có thể dùng nguyên trạng chung định nghĩa công cụ và trình xử lý streaming.
Kunavo bổ sung những endpoint OpenAI nào ngoài giao diện tương thích của Ollama?
Giao diện tương thích OpenAI của Ollama hỗ trợ /chat/completions, /completions, /embeddings và /models. Kunavo bổ sung các endpoint đa phương tiện dùng cùng một khóa: /v1/images/generations, /v1/images/edits, /v1/video/generations, /v1/videos và /v1/audio/music, cùng Claude trên endpoint /v1/messages gốc của Anthropic. Có hai điểm cần nêu rõ theo chiều ngược lại: /v1/audio/speech, /v1/audio/transcriptions và /v1/embeddings được triển khai theo định dạng truyền tải, nhưng hiện chưa có mô hình nào được bật phía sau chúng nên hiện tại sẽ không gọi thành công — và khác với Ollama, Kunavo không chạy mô hình cục bộ. GET /v1/models luôn là nguồn có thẩm quyền để biết những gì có thể gọi.