Permalink to Chat CompletionsChat Completions
POST /v1/chat/completions 是整套 API 里兼容性最好的一条。请求基本逐字节转发给上游,响应也基本
原样回来,所以只要是 OpenAI 兼容客户端能发的东西,在这里都能发。
curl https://hypit.ai/v1/chat/completions \
-H "Authorization: Bearer $HYPIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3.1-pro",
"messages": [
{"role": "system", "content": "用一句话回答。"},
{"role": "user", "content": "Hypit 是什么?"}
]
}'Permalink to 配合-openai-sdk配合 OpenAI SDK
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["HYPIT_API_KEY"],
base_url=os.environ.get("HYPIT_BASE_URL", "https://hypit.ai/v1"),
)
completion = client.chat.completions.create(
model="gemini-3.1-pro",
messages=[{"role": "user", "content": "Hypit 是什么?"}],
max_tokens=200,
)
print(completion.choices[0].message.content)
print(completion.usage)import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.HYPIT_API_KEY,
baseURL: process.env.HYPIT_BASE_URL ?? "https://hypit.ai/v1",
});
const completion = await client.chat.completions.create({
model: "gemini-3.1-pro",
messages: [{ role: "user", content: "Hypit 是什么?" }],
max_tokens: 200,
});
console.log(completion.choices[0].message.content);Permalink to 我们读什么转发什么我们读什么,转发什么
只有两个字段是必填的,被网关真正读取的也只有这几个:
| 字段 | 我们为什么读它 |
|---|---|
model | 必填——决定路由 |
messages | 必填且非空——遍历它找图片分片 |
stream | 选择 SSE 路径 |
stream_options | 见下 |
modalities | ["text","image"] 让支持出图的对话模型返回像素 |
其余一切——max_tokens、max_completion_tokens、temperature、top_p、stop、tools、
tool_choice、response_format、reasoning_effort,以及任何我们从没听说过的厂商私有字段——都会
原封不动地送到上游。请求体上限 32 MiB。
响应体是上游的原文,只有两处例外:
- 厂商的账单字段会被剥掉(
credits、cost、cost_usd、balance、billing及其同类,顶层和usage内部都剥),免得别人家的账本泄漏进你的。你真实的花费以额度计,不在那个字段里。 - 如果我们把你的模型名映射成了另一个上游模型名,顶层
"model"字符串会被改写回你请求的那个名字。 没有映射时,厂商自己的细化名(比如gpt-4o-2024-08-06)会保留。
usage 本身不做改动——上游报什么你看到什么。我们内部会把它归一化用于计费,但这从不改变线上的字节。
Permalink to 流式流式
设置 "stream": true。响应是 text/event-stream,每个 chunk 是上游帧的原文,流以
data: [DONE] 结束——上游没发这个哨兵时由我们补上。
stream = client.chat.completions.create(
model="gemini-3.1-pro",
messages=[{"role": "user", "content": "写一首关于纸船的俳句。"}],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="", flush=True)const stream = await client.chat.completions.create({
model: "gemini-3.1-pro",
messages: [{ role: "user", content: "写一首关于纸船的俳句。" }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}curl -N https://hypit.ai/v1/chat/completions \
-H "Authorization: Bearer $HYPIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"gemini-3.1-pro","stream":true,
"messages":[{"role":"user","content":"写一首关于纸船的俳句。"}]}'Permalink to 流式下的-usage流式下的 usage
如果你完全没有传 stream_options,我们会替你补上 {"include_usage": true},这样最后一帧会带
usage。只要你自己传了 stream_options——包括 {"include_usage": false}——我们就原样照办,不动它。
流一旦开始,既不会故障转移,也不会改状态码
第一个字节上线之后,HTTP 状态码就永远是 200 了。之后发生的失败会以一个 SSE 帧的形式送达,帧里
是标准错误信封,随后是 data: [DONE]:
data: {"error":{"message":"…","type":"upstream_error","code":"stream_broken","param":null}}
data: [DONE]请对每一帧检查 error,而不只是看 HTTP 状态码。另外注意:流式过程中断开连接不会让这次请求
免于计费——token 已经生成了。
Permalink to 视觉视觉
图片分片的写法与 OpenAI 一致:
{
"model": "gemini-3.1-pro",
"messages": [
{
"role": "user",
"content": [
{ "type": "text", "text": "这张图里有什么?" },
{ "type": "image_url", "image_url": { "url": "https://example.com/boat.png" } }
]
}
]
}http(s) 图片 URL 会由网关下载,在选择上游之前就地改写成 data: URL,这样只接受内联图片的
模型也能用。最多四张图并发抓取,总预算 20 秒,超时返回 400 image_fetch_timeout。data: URL
原样透传,而且总是更快的那条路。
只允许 http、https 和 data: 三种 scheme,抓取过程逐跳拒绝内网与链路本地地址。
Permalink to 错误错误
| 状态 | code | 含义 |
|---|---|---|
400 | empty_body / invalid_request_body | 请求体缺失或不是 JSON 对象 |
400 | missing_model / missing_messages | 两者都必填 |
400 | invalid_message_content | 某个 content 无法解码 |
400 | invalid_media_url / unsupported_media_url_scheme | image_url.url 未通过策略 |
400 | image_fetch_timeout / image_fetch_failed | 引用的图片抓不到 |
413 | request_too_large | 超过 32 MiB |
404 | model_not_found / no_capable_provider | 这把 Key 下该模型不可用于对话 |
502 | empty_response / empty_stream | 上游什么都没返回 |
502 | stream_broken | 流提前中断——以 SSE 帧形式送达 |
503 | no_available_provider | 所有候选上游都在冷却中 |
504 | request_timeout |
上游失败会被分类,而不是原样透出:upstream_error(502)、upstream_rate_limited(429)、
upstream_quota_exhausted(402)、upstream_unauthorized(401)和 upstream_rejected_request
(厂商自己的 4xx,消息脱敏后转发)。我们返回的任何内容里都不会出现上游名称、base URL、上游模型名
或凭据。
公共错误码见错误与限流。