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

网关工作原理

同一个域名原生提供 Anthropic、OpenAI 和 Gemini 三种 API。端点、base URL、模型 ID 写法、鉴权方式,以及 Half Off Dev 会改动请求的哪些地方。

用 Half Off Dev 的前提是:你现有的代码一行都不用重写。Claude、GPT、Gemini 各自用厂商原生的协议格式,在同一个域名下提供,价格是官方标价的一半。SDK 发出的 JSON 和直连厂商时完全一样,要换的只有 base URL 和密钥。

中间没有任何格式转换层。Anthropic 格式的请求交给支持 Anthropic 格式的渠道,OpenAI 格式的请求交给支持 OpenAI 格式的渠道,依此类推。除了两处很小的改动,请求体原样到达渠道,所以 thinking、cache_control、tools、generationConfig 这类厂商参数的行为,和各家官方文档里写的一致。

端点一览#

把下表里的 base URL 交给 SDK,路径由 SDK 自己拼。

协议格式路径SDK 的 base URL指南
Anthropic MessagesPOST /v1/messages、POST /v1/messages/count_tokenshttps://halfoff.devAnthropic Messages
OpenAI Chat CompletionsPOST /v1/chat/completionshttps://halfoff.dev/v1OpenAI
OpenAI Responses(仅 GPT)POST /v1/responseshttps://halfoff.dev/v1Responses API
GeminiPOST /v1beta/models/{model}:generateContent、:streamGenerateContent、:countTokenshttps://halfoff.devGemini
模型目录GET /v1/models、GET /v1beta/models价格

表外的端点均不提供,详见不能调用的接口。

密钥放在哪里#

每个端点都会在四个位置查找密钥,因此各家 SDK 用默认鉴权方式即可:

位置常见发送方
Authorization: Bearer ho-...OpenAI SDK、通过 ANTHROPIC_AUTH_TOKEN 配置的 Claude Code、普通 HTTP 客户端
x-api-key: ho-...Anthropic SDK
x-goog-api-key: ho-...Google Gen AI SDK、Gemini CLI
?key=ho-...Gemini 的 REST 示例

两个模型目录端点是公开的,无需密钥。密钥的创建、限额和轮换见身份验证。

各模型家族的原生格式#

每个模型家族都是围绕一种 API 设计的,用它的原生格式调用,才能用全厂商提供的功能。

模型家族原生格式目前也接受
Claude(claude-*)Anthropic MessagesOpenAI Chat Completions、Gemini
GPT(gpt-*)OpenAI Chat Completions、OpenAI ResponsesAnthropic Messages、Gemini
Gemini(gemini-*)GeminiOpenAI Chat Completions、Anthropic Messages

用非原生格式调用时,渠道会把请求转换成模型能接受的形式,厂商独有的参数可能在转换中被忽略或被拒绝。Anthropic 的 cache_control 和 thinking、OpenAI 的 reasoning_effort、Gemini 的 thinkingConfig,只有在原生格式下才保证生效。

一个模型接受哪些格式,取决于为它服务的渠道,因此会有变化。模型广场列出了每个模型当前支持的格式。如果没有任何渠道接受你用的格式,会返回 404,消息类似 Model 'gpt-6.1-sol' is not served in gemini format in any group.

模型 ID#

标准 ID 以 GET /v1/models 返回的为准,例如 claude-opus-5.5、gpt-6.1-sol、gemini-3-flash。各种工具有自己的写法,网关会先做归一化,所以照样能找到正确的模型:

发送的 ID实际对应
Claude-Opus-5-5claude-opus-5.5
anthropic/claude-opus-5.5claude-opus-5.5
claude-haiku-4-5-20251001claude-haiku-4.5
gemini-3.1-pro-previewgemini-3.1-pro
models/gemini-3-flashgemini-3-flash

归一化规则:转成小写;去掉开头的 vendor/ 或 models/;. 和 - 视为同一个字符;去掉末尾的日期(-20251001)、-preview 或 -latest。计费、日志和密钥的模型白名单一律记录标准 ID。

找不到对应模型的 ID 返回 404:Model '<id>' is not available. See GET /v1/models.

一个请求的完整路径#

  1. 校验密钥。 密钥未启用或已过期,返回 401。
  2. 解析模型。 按上面的规则归一化 ID,再对照密钥的模型白名单;不在白名单内返回 403。
  3. 检查余额。 余额小于等于零,或密钥已用完消费上限,返回 402。
  4. 密钥限额。 执行密钥的每分钟请求数和并发数限制(429),详见速率限制与故障转移。
  5. 选择渠道。 进行中的对话回到持有其提示缓存的渠道;新对话进入所在渠道分组里状态最好的渠道。详见提示缓存。
  6. 调用模型。 渠道在产生任何输出之前失败,就换一个渠道,最多尝试三次。流式响应在第一个 token 到达前会被暂扣,所以切换过程你看不到。详见流式输出。
  7. 计量。 按响应中的 token 数、以官方标价的一半计费,几秒内从余额扣除。详见价格。

网关会改动什么#

请求体只有两处改动,此外一概不动:

  1. model 字段。 网关会替换成服务渠道所需的写法。因此响应里的 model 可能是厂商的写法,比如 claude-opus-5-5。
  2. OpenAI 流式响应里的用量。 所有流式 Chat Completions 请求都会被加上 stream_options.include_usage: true,以便计费。所以流的末尾会多出一个 chunk,它的 choices 为空数组,并带有 usage。读取 chunk 时请处理 choices 为空的情况。

你发送的请求头都不会转发,只有三个例外:anthropic-version、anthropic-beta、openai-beta。未带 anthropic-version 时,网关补上 2023-06-01。Gemini 路径上的查询参数(如 alt=sse)会转发,key 则被移除。

响应体逐字节原样返回。content-type 和 cache-control 会保留,网关再加上自己的响应头;厂商的请求 ID 和限流相关响应头不会透传。

如果模型认为请求本身无效(400、404、413、422),你会按所调用 API 的错误格式收到同样的状态码和原因。其他失败会先在另一个渠道上重试。详见速率限制与故障转移和错误。

每个响应都带的响应头#

响应头内容
x-halfoff-request-id本次调用的 ID,如 req_6f1c...,对应日志里的那条记录。联系客服时请附上。
x-halfoff-group实际响应的渠道分组,如 gpt-value。
x-halfoff-channel该分组的渠道标签,经过 URL 编码,如 Pooled%20capacity。
x-halfoff-queued-ms仅在调用等待过容量时出现:等待的毫秒数。

前三个已列入 access-control-expose-headers,前端 JavaScript 可以直接读取。

不能调用的接口#

上表就是模型相关的全部端点。以下这些明确不提供:

  • OpenAI:已存储的 response(/v1/responses/{id})、旧版 Completions、embeddings、音频、文件和批处理。Responses API 本身只支持 GPT 模型。
  • Anthropic:Message Batches、Files,以及按 ID 获取单个模型。
  • Gemini:cachedContents(显式上下文缓存)、文件上传、embedContent 和 Live API。

具体客户端怎么配置,见接入工具。