halfoff.dev文档
获取密钥
模型 API

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注意
GPTgpt-6.1-sol、gpt-6-astra、gpt-5.6-terra、gpt-5.6-luna原生格式。
Claudeclaude-sonnet-5.5、claude-opus-5.5需要 cache_control 或思考设置时,请通过 Anthropic Messages 调用。
Geminigemini-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": "..."}},见错误。