OpenAI Chat Completions
用手头的 OpenAI SDK 半价调用 GPT、Claude 和 Gemini。涵盖带用量的流式输出、函数调用、推理强度设置以及 Responses API。
为 OpenAI SDK 写的代码,只要把 base URL 改成 https://halfoff.dev/v1、密钥换成你的 Half Off Dev 密钥,就能直接在 Half Off Dev 上运行。POST /v1/chat/completions 遵循 OpenAI 的定义,请求体原样转发,所以每个字段都可以对照 OpenAI API 文档。每个 token 都按官方标价的一半计费,而且同一个客户端还能调用 Claude 和 Gemini。
切换客户端#
curl https://halfoff.dev/v1/chat/completions \
-H "Authorization: Bearer $HALFOFF_API_KEY" \
-H "content-type: application/json" \
-d '{
"model": "gpt-6.1-sol",
"messages": [
{"role": "system", "content": "你是一位言简意赅的 SQL 老师。"},
{"role": "user", "content": "什么时候该用 LEFT JOIN?"}
]
}'SDK 会读取环境变量 OPENAI_BASE_URL 和 OPENAI_API_KEY,所以大多数兼容 OpenAI 协议的应用只需填这两项。部分应用的配置见 OpenAI 兼容应用。
这里能调用哪些模型#
GET /v1/models 中的所有文本模型目前都支持 Chat Completions,Claude 和 Gemini 也不例外。想用一个客户端调用所有厂商,这是最省事的方式。
| 家族 | 示例 ID | 注意 |
|---|---|---|
| GPT | gpt-6.1-sol、gpt-6-astra、gpt-5.6-terra、gpt-5.6-luna | 原生格式。 |
| Claude | claude-sonnet-5.5、claude-opus-5.5 | 需要 cache_control 或思考设置时,请通过 Anthropic Messages 调用。 |
| Gemini | gemini-3.1-pro、gemini-3-flash | 需要 thinkingConfig 等 Gemini 专属字段时,请用 Gemini API。 |
厂商专属的选项只在该厂商的格式下保证有效,见各模型家族的原生格式。
流式输出,结尾附带用量#
设置 stream: true。网关总会加上 stream_options.include_usage: true,因此 data: [DONE] 之前的最后一个 chunk 里 choices 为空数组,并带有本次调用的 usage。读取 delta 前先确认 choices 不为空。
stream = client.chat.completions.create(
model="gpt-6.1-sol",
messages=[{"role": "user", "content": "按离太阳由近到远列出八大行星。"}],
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
if chunk.usage:
print("\nTokens:", chunk.usage.prompt_tokens, "in,", chunk.usage.completion_tokens, "out")具体的数据格式以及流中途出错的表现,见流式输出。
函数调用#
在 tools 中列出你的函数。模型要调用某个函数时,finish_reason 为 tool_calls;执行函数后,回一条 tool 消息,带上对应的 tool_call_id。
import json
tools = [{
"type": "function",
"function": {
"name": "check_stock",
"description": "返回某个商品的库存数量。",
"parameters": {
"type": "object",
"properties": {"sku": {"type": "string"}},
"required": ["sku"],
},
},
}]
messages = [{"role": "user", "content": "SKU KB-204 还有货吗?"}]
completion = client.chat.completions.create(model="gpt-6.1-sol", messages=messages, tools=tools)
msg = completion.choices[0].message
if msg.tool_calls:
messages.append(msg)
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = {"sku": args["sku"], "units": 17} # 这里换成你的实现
messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})
completion = client.chat.completions.create(model="gpt-6.1-sol", messages=messages, tools=tools)
print(completion.choices[0].message.content)tool_choice、parallel_tool_calls 和 response_format 都原样转发。
推理强度#
GPT-5 和 GPT-6 系列会先推理再作答。用 reasoning_effort 控制推理力度,用 max_completion_tokens 限制总输出(含推理 token)。可选的 effort 值因模型而异,见 OpenAI 推理指南。
completion = client.chat.completions.create(
model="gpt-6.1-sol",
reasoning_effort="high",
max_completion_tokens=8000,
messages=[{"role": "user", "content": "为什么大多数语言里 0.1 + 0.2 != 0.3?"}],
)
print(completion.choices[0].message.content)
print("reasoning tokens:", completion.usage.completion_tokens_details.reasoning_tokens)Chat Completions 不返回推理过程本身。推理 token 计入 usage.completion_tokens,按输出单价计费。
Responses API#
对 GPT 模型,POST /v1/responses 提供 OpenAI Responses API,Codex CLI 用的就是它。base URL 和密钥不变,client.responses.create() 无需改动。
curl https://halfoff.dev/v1/responses \
-H "Authorization: Bearer $HALFOFF_API_KEY" \
-H "content-type: application/json" \
-d '{
"model": "gpt-6.1-sol",
"instructions": "只用一个词回答。",
"input": "“受延迟限制”的反义是什么?"
}'开启 stream: true 后,你会收到该 API 的类型化事件,从 response.created、response.output_text.delta 一直到 response.completed;按 response.completed 中的用量计费。需要注意:
- 服务端不存储任何内容。 对
/v1/responses/{id}的GET、DELETE和取消都返回404;previous_response_id只有在对话恰好留在同一渠道时才有效。请像 Codex 那样,设置"store": false并在input中发送完整历史。 - 仅限 GPT。 其他模型返回
404和not served in responses format,请改用 Chat Completions 或其原生 API。 - 响应中的
instructions回显你发送的内容;没发送则为null。 prompt_cache_key会让对话留在同一渠道,与 Chat Completions 中一样。
提示缓存#
OpenAI 模型会自动缓存较长的提示前缀,无需额外设置。命中缓存的部分在 usage.prompt_tokens_details.cached_tokens 中报告,按更低的缓存读取单价计费。设置 prompt_cache_key 能提高命中率,同时告诉网关哪些请求属于同一个对话。见提示缓存。
不支持的功能#
OpenAI 格式的端点只有 Chat Completions 和 Responses API。以下接口返回 404:
- 已存储的 response:对
/v1/responses/{id}的GET、DELETE或取消。 - Embeddings:
/v1/embeddings。 - 音频:
/v1/audio/*。 - 旧版 Completions、Assistants、文件、批处理、微调和内容审核。
client.models.list() 可以正常读取 GET /v1/models;按 ID 获取单个模型则不支持。
请求头#
| 请求头 | 行为 |
|---|---|
Authorization: Bearer | 你的 Half Off Dev 密钥,必填。 |
openai-beta | 原样转发。 |
x-halfoff-group | 可选。为本次请求指定渠道分组;密钥已绑定分组时无效。 |
x-session-id | 可选。把多个请求标记为同一个对话,用于缓存感知路由。请求体里的 prompt_cache_key 或 user 效果相同。 |
错误沿用 OpenAI 的格式 {"error": {"message": "...", "type": "...", "code": "..."}},见错误。