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

Anthropic Messages

现有的 Anthropic SDK 代码改个 base URL 就能半价调用 Claude。流式输出、扩展思考、工具调用、提示缓存和 token 计数照常可用。

如果你的代码已经用 Anthropic SDK 调 Claude,迁移到 Half Off Dev 只需改两项配置:base URL 设为 https://halfoff.dev,密钥换成 Half Off Dev 的密钥。POST /v1/messages 和 POST /v1/messages/count_tokens 的行为与 Anthropic 的定义一致,请求体原样转发,因此每个字段都以 Anthropic API 文档为准。所有 token 都按官方标价的一半计费。

让 SDK 指向 Half Off Dev#

Anthropic SDK 把密钥放在 x-api-key 里;用 Authorization: Bearer 发送也可以。

curl https://halfoff.dev/v1/messages \
  -H "x-api-key: $HALFOFF_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{
    "model": "claude-sonnet-5.5",
    "max_tokens": 1024,
    "messages": [{"role": "user", "content": "给一个代码评审机器人起三个名字。"}]
  }'

使用默认客户端的代码甚至不用改:SDK 会从环境变量读取 ANTHROPIC_BASE_URL 和 ANTHROPIC_API_KEY,执行 export ANTHROPIC_BASE_URL=https://halfoff.dev 并设好密钥即可。

目前可用的 Claude 模型包括 claude-fable-5.1、claude-opus-5.5、claude-sonnet-5.5、claude-haiku-5.5,以及更早的版本。完整列表和价格以 GET /v1/models 为准。

边生成边接收#

设置 stream: true,或使用 SDK 的流式辅助方法。事件顺序与 Anthropic 一致:message_start、content_block_start、content_block_delta、content_block_stop、message_delta、message_stop。

with client.messages.stream(
    model="claude-sonnet-5.5",
    max_tokens=2048,
    messages=[{"role": "user", "content": "为一个修复 bug 的小版本写一段简短的发布说明。"}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)
    final = stream.get_final_message()
print("\n", final.usage)

第一个 token 出现之前,网关会先把流扣在自己这边;这段时间里渠道出错,会由另一个渠道接手,你完全察觉不到。细节见流式输出。

让 Claude 调用你的函数#

用 JSON Schema 的 input_schema 描述每个函数。响应里出现 stop_reason: "tool_use" 时,执行对应函数,再用 tool_result 块把结果发回去。

tools = [{
    "name": "convert_currency",
    "description": "在两种货币之间换算金额。",
    "input_schema": {
        "type": "object",
        "properties": {
            "amount": {"type": "number"},
            "from_currency": {"type": "string"},
            "to_currency": {"type": "string"},
        },
        "required": ["amount", "from_currency", "to_currency"],
    },
}]
messages = [{"role": "user", "content": "250 欧元能换多少日元?"}]

response = client.messages.create(
    model="claude-sonnet-5.5", max_tokens=1024, tools=tools, messages=messages,
)
if response.stop_reason == "tool_use":
    call = next(b for b in response.content if b.type == "tool_use")
    result = {"converted": 40125.0, "currency": call.input["to_currency"]}  # 这里换成你的实现
    messages += [
        {"role": "assistant", "content": response.content},
        {"role": "user", "content": [
            {"type": "tool_result", "tool_use_id": call.id, "content": str(result)},
        ]},
    ]
    response = client.messages.create(
        model="claude-sonnet-5.5", max_tokens=1024, tools=tools, messages=messages,
    )
print(response.content[0].text)

tool_choice、strict 等其他选项原样转发,用法见 Anthropic 的工具调用指南。

开启扩展思考#

按 Anthropic 对所调用模型的规定发送 thinking 和 output_config。新模型采用自适应思考,配合 effort 档位;Claude 4.5 及更早的模型使用固定的 budget_tokens。各模型的规则见 Anthropic 思考指南。

reply = client.messages.create(
    model="claude-opus-5.5",
    max_tokens=16000,
    thinking={"type": "adaptive", "display": "summarized"},
    output_config={"effort": "high"},
    messages=[{"role": "user", "content": "火车 09:40 出发、14:05 到达,全程多少分钟?"}],
)
for block in reply.content:
    if block.type == "thinking":
        print("推理:", block.thinking)
    elif block.type == "text":
        print("结果:", block.text)

思考内容计入 usage.output_tokens,按(减半后的)输出单价计费。在工具调用之后继续对话时,请把 thinking 块原封不动地传回。

缓存每次重复发送的前缀#

在每次请求都不变的那部分内容里,给最后一个块加上 cache_control。第一次请求写入缓存,之后以相同前缀开头的请求按远低于输入单价的价格读取缓存。

response = client.messages.create(
    model="claude-sonnet-5.5",
    max_tokens=1024,
    system=[{
        "type": "text",
        "text": STYLE_GUIDE,
        "cache_control": {"type": "ephemeral"},
    }],
    messages=[{"role": "user", "content": "按规范改写这个标题:'第三季度数据出炉'"}],
)
u = response.usage
print(u.cache_creation_input_tokens, u.cache_read_input_tokens, u.input_tokens)

以 claude-sonnet-5.5 为例,你实际支付的每百万 token 价格:未缓存输入 $1.00,缓存写入 $1.25,缓存读取 $0.05。前缀短于模型的最小长度时不会被缓存,两个缓存字段都返回 0。网关会把每个对话送回持有其缓存的渠道,完整说明见提示缓存。

发送前先数 token#

POST /v1/messages/count_tokens 接受与消息请求相同的请求体(不含 max_tokens),返回 input_tokens。它不收费,余额为零时也能用。

curl https://halfoff.dev/v1/messages/count_tokens \
  -H "x-api-key: $HALFOFF_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{"model": "claude-sonnet-5.5",
       "messages": [{"role": "user", "content": "这段提示词有多长?"}]}'

估算值,不是账单

计数适合用来对照上下文窗口检查提示词长度,或做预算。实际扣费永远以模型响应里的 usage 为准。

Claude Code#

Claude Code 使用的就是这套 API。设置 ANTHROPIC_BASE_URL=https://halfoff.dev,把密钥填进 ANTHROPIC_AUTH_TOKEN;每个会话都会固定在同一个渠道上,缓存始终有效。包括模型设置在内的完整步骤见 Claude Code。

请求头#

请求头行为
x-api-key 或 Authorization: Bearer你的 Half Off Dev 密钥,必填。
anthropic-version转发;不填时默认为 2023-06-01。
anthropic-beta原样转发。
x-halfoff-group可选。为本次请求指定渠道分组;密钥已绑定分组时无效。
x-session-id可选。把多个请求标记为同一个对话,用于缓存感知路由。请求体里的 metadata.user_id 效果相同。

其他请求头一律不转发。错误沿用 Anthropic 的格式 {"type": "error", "error": {"type": "...", "message": "..."}},错误码见错误。