文档
聊天补全
Kunavo 的 /v1/chat/completions 端点为 Claude 和 GPT 系列提供 OpenAI chat completions 协议。可通过同一 SDK 使用 streaming、tools 和 JSON 输出;reasoning_effort 的作用取决于模型系列,本页面会说明具体情况。
端点:POST /v1/chat/completions。请求和响应格式与 OpenAI chat completions API 完全一致,包括流式传输以及可选的 tool_calls / reasoning_tokens 字段。
基本调用
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)参数
接受所有标准 OpenAI 参数。其中有些只适用于特定供应商 — 转换器会传递各上游支持的参数。
| 参数 | 类型 | 备注 |
|---|---|---|
model | 字符串(必填) | /v1/models 中任意已启用的模型代号。 |
messages | 数组(必填) | 标准 OpenAI 消息格式。 |
temperature | 0..2 | 采样温度。默认值为 1。对本表所列模型无效。 |
top_p | 0..1 | 核采样。与 temperature 一样存在例外。 |
max_tokens | int | 输出上限;同时发送时以 max_ 为准。对于 GPT 模型,推理令牌也计入该上限。Claude 请求若两者都未发送,则默认值为 4,096。 |
stream | bool | 以 SSE 形式传输分块。详见下文。 |
tools | array | 函数 / 工具定义。Claude 和 GPT 均支持工具调用。 |
tool_choice | auto| | 强制使用特定工具,或让模型自行决定。 |
response_ | object | JSON 输出。在 Claude 上会强制执行 json_,不会强制执行 json_object — 各系列的详细说明请参见 JSON 输出。 |
reasoning_ | string | 仅适用于 GPT 模型 — 将其作为 reasoning. 转发。不会转发给 Claude。参见 推理。 |
seed | int | 在支持的情况下进行确定性采样。 |
stop | string|array | 硬性停止序列。 |
temperature、top_p 或 top_k。Kunavo 会从发往这些模型的请求中移除这三项,而不是把供应商返回的 400 错误直接返回给您,因此它们对这些模型不起作用。流式传输
设置 stream=True。Kunavo 会按 OpenAI 的完全相同格式发送服务器推送事件:每个分块都是带有 choices[0].delta.content 的 chat.completion.chunk。最终 usage 负载会随 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)工具 / 函数调用
所有供应商均支持工具调用。请将工具定义为 JSON schema;模型会在消息中返回 tool_calls;您执行工具后,再将结果作为 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)JSON 输出(response_format)
response_format 用于请求 JSON 输出。由于各模型系列的请求会被转换成不同的上游机制,因此其保证程度取决于模型系列:
| 系列 | json_schema | json_object |
|---|---|---|
| Claude | 强制执行。 请求会以 Anthropic 的结构化输出格式(output_)发送;回复会受到您的架构约束。已于 2026-09-24 在 Kunavo 提供服务的每个 Claude 模型上完成检查。 | 不强制执行。 Anthropic 没有不指定架构的 JSON 模式,因此该参数会被接受但忽略 — 回复可能以说明文字或代码围栏开头。 |
| GPT | 作为 Responses API 的 text.format 转发,但当前上游并非在每次请求中都会应用该设置。解析前请先验证。 | 作为 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使用 Claude 时,有四点需要了解:
- 架构会基本按原样发送给 Anthropic。Anthropic 要求对象包含
additionalProperties: false,因此 Kunavo 会为列出属性的对象添加该字段,并保持未设置状态 — 这正是 Pydantic 的model_json_schema()所生成的内容。Anthropic 仍会拒绝以下内容,并返回指出问题的 400 错误:未封闭的对象(additionalProperties设置为任何非false的值,或未列出属性且未设置additionalProperties),以及oneOf— 请改用anyOf。其余限制请参见Anthropic 的结构化输出页面。 strict和name均会被忽略:Anthropic 会强制执行它接受的所有架构,无论是否为 strict。- 架构不能与最后一条
assistant消息(预填充内容)同时使用;Anthropic 会返回 400 错误。 - 当
max_tokens在对象生成到一半时耗尽,JSON 会被截断,且finish_reason为"length"。
视觉 / 多模态输入
支持 vision 能力的模型可以接受图像内容块。您可以使用 HTTPS URL 或 data: base64 URI。
# 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)目录中的视觉能力模型包括 Claude Opus 5.5 — 其余模型请参见模型列表。
对于 https 图像,Kunavo 会自行下载文件并将其以内联形式交给模型,因为某些上游会忽略直接提供的图像 URL。限制:每个请求最多 16 张图像,每张图像 5 MB,总计 20 MB,每次下载最长 10 秒。无法获取的图像会导致错误,并指出对应图像,不会被跳过。
推理
此端点上的推理控制如何生效取决于模型系列,因为各系列的请求会被转换为不同的上游 API:
| 系列 | reasoning_ | usage 中的推理令牌 |
|---|---|---|
| GPT | 在 GPT-6 Astra、GPT-6 Sol、GPT-6 Luna、GPT-5.6 Sol、GPT-5.6 Terra和GPT-5.5 上按原值转发为 Responses API 的 reasoning.。可接受的值由模型本身决定;在 GPT-6 Sol 和 GPT-6 Luna 上,none 会关闭推理,max 为最高级别。 | 计入 completion_,并单独列为 completion_,按输出费率计费。 |
| Claude | 不会转发。 Anthropic 请求根据固定字段列表构建 — model、max_、messages、stream、temperature、top_、top_、stop、tools、tool_ 和 response_ — 因此 reasoning_、thinking 及所有其他不在列表中的字段都会在此处丢弃。 | 不单独统计。Anthropic 会将任何思考内容计入其 output_,这也正是 completion_ 所报告的内容。 |
# 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 原样传递给 Anthropic。提示缓存
较长的系统提示、参考文档或少量示例 — 任何稳定前缀都可以缓存在上游,并在后续调用中以远低于输入价格的费用重放。缓存命中会在 usage 对象中显示为 prompt_tokens_details.cached_tokens。
GPT 模型会自动缓存 — 无需更改请求。cached_tokens 是 prompt_tokens 的子集,按较低的缓存读取费率计费。
Claude 只会缓存到 cache_control 断点为止,而对于较长的提示,此端点会为您设置断点:设在系统提示、工具定义,以及对话中已有助手回合时的最后一条消息上。若要自行选择前缀,请像下面这样将 cache_control 附加到内容块;Kunavo 会保留您设置的断点,只在您留空的位置添加自己的断点:
# 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 用量字段——请使用 原生 Messages API。 此端点同样会缓存系统提示和工具定义,一个请求中可以设置多个断点,并以 cache_creation_input_tokens 报告缓存写入、以 prompt_tokens_details.cached_tokens 报告缓存读取;只有原生端点才会原样转发您的请求体而不添加任何断点。用量对象
每个响应(以及流式传输的最后一个数据块)都包含一个 usage 对象:
| 字段 | 含义 |
|---|---|
prompt_ | 我们计费的输入 token 数,包含缓存 token。 |
prompt_ | 缓存输入量,是 prompt_ |
completion_ | 我们计费的输出 token。对于 GPT 模型,这包括推理 token;对于 Claude,这对应 Anthropic 的 output_ |
completion_ | GPT 模型:completion_ |
total_tokens | prompt_ |
Ollama OpenAI 兼容接口 — /v1/chat/completions
Ollama 通过 http://localhost:11434/v1 上的 OpenAI 兼容 API 提供本地模型,实现了本页所述的同一套 /chat/completions 合约。因此,两者在客户端可互换:任何基于 Ollama v1 API 编写的程序,只需更改 base URL 和模型,即可调用 Kunavo。
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."}],
)切换服务提供商时通常会出问题的部分在这里不会出问题,因为两者使用相同的线路格式:
| 功能 | Ollama v1 | Kunavo v1 |
|---|---|---|
| 端点路径 | /v1/ | /v1/ |
| 流式传输 | SSE,chat. | 完全一致 — delta 结构相同 |
| 工具调用 | tools / tool_calls | Claude 和 GPT 完全一致 |
| 视觉输入 | 多模态本地模型上的 image_url 块 | 相同的区块;URL 或 base64 数据 URI |
| api_key | 占位符,会被忽略 | 真实的 Kunavo key |
| model | 已拉取的标签(llama3.2) | 托管模型的 slug(claude-sonnet-5) |
| usage 扩展字段 | 仅 token 数量 | 还包含 cached_ |
| 不止聊天 | completions、embeddings | 还包括图像、视频和音频端点 |
base_url、model 和密钥,并按环境切换——本地模型用于离线迭代,在质量至关重要时使用托管模型,同时沿用同一套代码。完整演练涵盖 Ollama 的 OpenAI 接口支持和不支持的功能,详见 Ollama OpenAI 兼容 API 指南。Ollama 的 OpenAI 兼容 /v1/chat/completions 端点官方文档在哪里?
Ollama 在其自有代码库的 docs/openai.md 中介绍了 OpenAI 兼容层,该文档是了解本地服务器实现了哪些 OpenAI 字段的权威参考。本页面是 Kunavo 托管式 /v1/chat/completions 端点的对应参考:同样遵循 OpenAI chat completions 合约,并在上文逐字段说明,您可以直接比较这两个接口。简而言之,两者的请求和响应格式相同 — Ollama 在 http://localhost:11434/v1 上提供服务,使用本地拉取的模型;Kunavo 在 https://api.kunavo.com/v1 上提供服务,使用托管的 Claude 和 GPT 模型。
Kunavo 的 /v1/chat/completions 与 Ollama 的 OpenAI API 兼容吗?
兼容 — 两者都实现了相同的 OpenAI chat completions 合约,因此,基于 Ollama 的 http://localhost:11434/v1 编写的客户端可以直接用于 https://api.kunavo.com/v1,无需修改。请求字段(messages、temperature、max_tokens、stream、tools、tool_choice、response_format、stop、seed)和响应字段(choices[].message、流式传输时的 choices[].delta、usage)均相同。托管模型会带来预期的差异:api_key 需要使用真实密钥,而非占位符;model 需要使用 claude-sonnet-5 这样的托管模型代号,而非 llama3.2 这样的已拉取模型标签;usage 还包含本地模型不会报告的 cached_tokens 和 reasoning_tokens。
如何将 Ollama 应用迁移到托管的 Claude 或 GPT?
只需修改两行:将 base_url 从 http://localhost:11434/v1 改为 https://api.kunavo.com/v1,并将 model 从本地标签改为托管模型代号。使用真实的 Kunavo 密钥,而不是 Ollama 会忽略的占位符。由于 SSE 和 tool_calls 格式完全相同,流式传输、工具调用和视觉处理代码路径都无需更改。
我可以在开发时继续使用 Ollama,并在生产环境中使用托管模型吗?
可以,而且这是很常见的配置 — 从环境变量读取基础 URL、模型和密钥,并根据环境进行切换。两端使用相同的 OpenAI 协议,因此无需维护第二套代码路径:离线迭代时使用本地 Llama 或 Qwen,需要高质量结果时使用托管的 Claude 或 GPT。工具定义和流式处理程序可以原样共用。
Kunavo 在 Ollama 的兼容接口基础上增加了哪些 OpenAI 端点?
Ollama 的 OpenAI 兼容接口包括 /chat/completions、/completions、/embeddings 和 /models。Kunavo 使用同一个密钥增加了媒体端点:/v1/images/generations、/v1/images/edits、/v1/video/generations、/v1/videos 和 /v1/audio/music;此外还有 Claude 使用的原生 Anthropic /v1/messages 端点。另有两点需要说明:/v1/audio/speech、/v1/audio/transcriptions 和 /v1/embeddings 虽已实现对应的线路格式,但目前没有启用任何模型,因此暂时无法成功调用;并且 Kunavo 不像 Ollama 那样在本地运行模型。GET /v1/models 始终是确认当前可调用模型的权威来源。