> 本文所有代码均在 2026-09-05 实跑验证,usage 输出为真实返回值,未做美化。
> 涉及的价格为当日实查,**AI API 降价频繁,自己用之前请重新核对**——文末有核价方法。

## 目录

- [一、什么场景下需要网关](#一)
- [二、路径一:OpenAI 兼容端点](#二)
- [三、路径二:原生 Anthropic Messages(Claude Code / Cursor)](#三)
- [四、流式与 usage 回传](#四)
- [五、四个实测踩到的坑](#五)
- [六、计费自查:用 usage 反算账单](#六)
- [七、核价方法](#七)

---

<h2 id="一">一、什么场景下需要网关</h2>

先说不需要的场景:**只用一家模型、账号已经开好、不在意跨家切换**,那直接用官方 SDK 就行,加一层网关只是增加故障点。

真正需要的是这几种:

1. **同时要 GPT / Claude / Gemini 三家**,不想维护三套账号、三套计费、三套额度告警;
2. **拿不到官方账号**——OpenAI 的图像模型要组织认证,Anthropic 的付费额度要海外支付方式;
3. **要做 A/B 或成本比较**,希望换模型只改一个字符串;
4. **国内直连**,不想为每个环境配代理。

网关的核心价值就一句:**把"换模型"从一次改造降级成一次改字符串**。

本文以 OpenAI 兼容网关为例,代码里的 base URL 换成任何一家同类服务都成立,不绑定具体厂商。

---

<h2 id="二">二、路径一:OpenAI 兼容端点</h2>

这是覆盖面最广的一条路。只要对方实现了 `/v1/chat/completions`,官方 openai SDK 就能直接用,**改两行**:

### 2.1 Python

```python
from openai import OpenAI

client = OpenAI(
    api_key="YOUR_KEY",
    base_url="https://api.apimodels.app/v1",   # 只改这一行
)

r = client.chat.completions.create(
    model="gpt-5.6-luna",
    max_tokens=16,
    messages=[{"role": "user", "content": "用一个词回答:1+1"}],
)

print(r.model)                       # gpt-5.6-luna
print(r.choices[0].message.content)  # 二
print(r.usage)
```

实跑返回:

```
model: gpt-5.6-luna
reply: 二
usage: prompt=14 cached=0 completion=5
```

### 2.2 curl

```bash
curl https://api.apimodels.app/v1/chat/completions \
  -H "Authorization: Bearer $YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.6-luna",
    "max_tokens": 20,
    "messages": [{"role": "user", "content": "用一个词回答:你好"}]
  }'
```

### 2.3 换模型 = 换字符串

```python
for m in ["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna",
          "claude-sonnet-5", "gemini-3.8-flash", "glm-5.3"]:
    r = client.chat.completions.create(
        model=m, max_tokens=8,
        messages=[{"role": "user", "content": "hi"}])
    print(m, r.usage.prompt_tokens, r.usage.completion_tokens)
```

**注意 Node 侧有个常见错误**:`baseURL` 要带 `/v1`,而且不要再手动拼一次:

```javascript
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.YOUR_KEY,
  baseURL: "https://api.apimodels.app/v1",   // ✅
  // baseURL: "https://api.apimodels.app",   // ❌ 会 404
});
```

---

<h2 id="三">三、路径二:原生 Anthropic Messages(Claude Code / Cursor)</h2>

Claude 有个容易被忽略的点:**很多网关是把 Claude 套成 OpenAI 形状转译的**,这会丢掉 thinking 块、原生 tool_use 结构和部分流式事件类型。如果你要接的是 Claude Code、Anthropic 官方 SDK 或 Cursor,**必须走原生 `/v1/messages`**,不能走转译层。

判断方法很简单:看返回体是 `{"type":"message","content":[...]}`(原生)还是 `{"choices":[...]}`(转译)。

### 3.1 Python(anthropic SDK)

```python
import anthropic

client = anthropic.Anthropic(
    api_key="YOUR_KEY",
    base_url="https://api.apimodels.app",   # 注意:这里不带 /v1
)

m = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=16,
    messages=[{"role": "user", "content": "Reply with one word"}],
)
print(m.model, m.stop_reason)
print(m.content[0].text)
print(m.usage)
```

实跑返回:

```
model: claude-sonnet-5 | stop: max_tokens
reply: Sure.
usage: in=29 out=13 cache_read=0
```

⚠️ **两条路径的 base URL 写法不一样**,这是最容易踩的低级错误:

| 路径 | base_url | 端点 |
|---|---|---|
| OpenAI 兼容 | `https://api.apimodels.app/v1` | `/chat/completions` |
| 原生 Anthropic | `https://api.apimodels.app` | `/v1/messages` |

因为 anthropic SDK 自己会拼 `/v1/messages`,openai SDK 只拼 `/chat/completions`。

### 3.2 curl

```bash
curl https://api.apimodels.app/v1/messages \
  -H "Authorization: Bearer $YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-sonnet-5",
    "max_tokens": 20,
    "messages": [{"role": "user", "content": "Reply with one word"}]
  }'
```

### 3.3 Claude Code 指过来

Claude Code 认两个环境变量,不需要改配置文件:

```bash
export ANTHROPIC_BASE_URL="https://api.apimodels.app"
export ANTHROPIC_AUTH_TOKEN="YOUR_KEY"
claude
```

Cursor 同理,在设置里把 Anthropic 的 base URL 和 key 换掉即可。因为走的是原生协议,**tool use、thinking、流式事件形状都不变**,不需要改任何业务代码。

---

<h2 id="四">四、流式与 usage 回传</h2>

流式的坑在于:**默认不返回 usage**,你会拿不到 token 数,没法对账。OpenAI 协议要显式打开:

```python
stream = client.chat.completions.create(
    model="gpt-5.6-luna",
    max_tokens=64,
    stream=True,
    stream_options={"include_usage": True},   # 关键
    messages=[{"role": "user", "content": "写一句话"}],
)

usage = None
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:            # 最后一个 chunk 才带
        usage = chunk.usage
print("\n", usage)
```

curl 验证:

```bash
curl -N https://api.apimodels.app/v1/chat/completions \
  -H "Authorization: Bearer $YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-5.6-luna","max_tokens":10,"stream":true,
       "stream_options":{"include_usage":true},
       "messages":[{"role":"user","content":"hi"}]}'
```

最后一个 SSE 事件里能看到:

```json
"usage":{"prompt_tokens":4387,"completion_tokens":14,"total_tokens":4401,
         "prompt_tokens_details":{"cached_tokens":3840}}
```

---

<h2 id="五">五、四个实测踩到的坑</h2>

### 坑 1:`input_tokens` 会莫名其妙很大,而且不稳定

同一个 `"hi"`,两次调用的 usage 可能差 300 倍:

```
第一次(curl):  prompt_tokens = 4387,其中 cached_tokens = 3840
第二次(SDK):   prompt_tokens = 14,  其中 cached_tokens = 0
```

原因是上游会给请求注入系统前缀,**大小取决于你被路由到哪个池子**。我们线上记录里,同一个模型的最小输入 token 从个位数到四千多都出现过。

**影响**:对高频短请求(批量分类、抽取、改写)这个量级会实打实进账单。好消息是前缀绝大部分走缓存命中、按缓存价计费,真实成本没有数字看上去那么吓人。

**结论:不要按固定下限估算成本,读每次响应的 `usage`。** 任何"每次调用最少 N 个 token"的说法都别当真——包括厂商自己文档里写的。

### 坑 2:长上下文有阶梯计价,而且是整单生效

GPT-5.6 三档都有这条:**单次请求输入超过 272,000 token 时,该请求整体按输入 2 倍、输出 1.5 倍计费。**

注意是**整单**,不是超出部分。272,001 个 token 的请求,全部 272,001 个都按 2 倍算。

这条在做长文档处理时特别容易翻车——分块阈值卡在 27 万附近的话,成本会在某个输入长度上突然跳一倍。**分块上限建议压到 25 万以内留余量。**

### 坑 3:推理深度后缀已经不存在了

网上很多教程还在写 `gpt-5.6-sol-high`、`gpt-5.6-terra-max` 这种带推理深度后缀的模型名。**这批 id 已经下架**,现在只有三个基础 id。

好的实现应该给你一个明确的 404,而不是悄悄映射到别的模型上——**如果某个网关对不存在的模型名不报错、还正常返回,那你根本不知道自己在用什么模型,也不知道在按什么价计费**。这是选网关时值得实测一下的点:故意传一个不存在的模型名,看它是报错还是装作没事。

### 坑 4:缓存命中要自己核,别信"支持缓存"四个字

缓存价通常是输入价的 1/10,但**只有真命中才便宜**。核对方法是看 usage 里的字段:

- OpenAI 协议:`prompt_tokens_details.cached_tokens`
- Anthropic 协议:`cache_read_input_tokens` 和 `cache_creation_input_tokens`

⚠️ Anthropic 这边有个额外的坑:**cache_creation(写缓存)是要额外收钱的**,通常是输入价的 1.25 倍。如果你的 prompt 每次都变一点点,会变成"每次都写缓存、从不命中",**比不用缓存还贵**。

自查方法:统计一段时间内 `cache_read / (cache_read + cache_creation)` 的比值。低于 50% 说明缓存策略是负收益,该调 prompt 结构了。

---

<h2 id="六">六、计费自查:用 usage 反算账单</h2>

无论用哪家网关,**都建议自己算一遍**。下面这个脚本对任意 OpenAI 兼容端点都成立:

```python
# cost_check.py —— 用 usage 反算单次调用成本,和账单对照
PRICES = {   # $/1M tokens, 2026-09-05 实查,用前请重新核对
    "gpt-5.6-sol":     {"in": 1.324, "out": 6.618, "cached": 0.132},
    "gpt-5.6-terra":   {"in": 0.551, "out": 3.309, "cached": 0.055},
    "gpt-5.6-luna":    {"in": 0.16,  "out": 0.96,  "cached": 0.016},
    "claude-sonnet-5": {"in": 1.60,  "out": 8.00,  "cached": 0.10},
}

def cost(model, usage):
    p = PRICES[model]
    cached = (usage.prompt_tokens_details.cached_tokens
              if usage.prompt_tokens_details else 0) or 0
    fresh = usage.prompt_tokens - cached
    return (fresh * p["in"] + cached * p["cached"]
            + usage.completion_tokens * p["out"]) / 1_000_000

r = client.chat.completions.create(
    model="gpt-5.6-luna", max_tokens=64,
    messages=[{"role": "user", "content": "写一句话"}])
print(f"本次约 ${cost('gpt-5.6-luna', r.usage):.8f}")
```

**对账时最容易误判的两件事**(我自己就误判过一次):

1. **忘了算缓存命中**。把全部 `prompt_tokens` 按输入价乘,会算出一个远高于实际的数,然后误以为对方少收了。
2. **忘了账号折扣**。很多平台有邀请折扣、阶梯折扣,实扣是"理论价 × 折扣",直接比对不上。

正确做法是:`理论成本 = (未命中输入 × 输入价 + 命中输入 × 缓存价 + 输出 × 输出价) / 1e6 × 折扣系数`,再和账单比。

另外注意**四舍五入位数**:很多平台按 4 位小数记账,单次成本低于 $0.00005 的调用可能记成 0,别拿单条对账,拿一天的汇总对。

---

<h2 id="七">七、核价方法(比价目表本身更重要)</h2>

AI API 降价太频繁,**任何写死的价格表都会过期**。2026 年 8 月 21 日 OpenAI 就把 GPT-5.6 全线降了一次(Sol $5/$30 → $4/$20,Luna $1/$6 → $0.20/$1.20),两周后仍有大量文章和汇总站在用旧价目。

我现在的核价顺序:

1. **模型厂商官方定价页**——最权威,但要注意看有没有"限时价""即将调整"这类注记;
2. **真按这个价结算的市场**(比如 OpenRouter 的模型页)——它标错价自己要赔钱,所以比汇总站可靠;
3. **汇总站 / 评测文**——默认不信。我遇到过页面顶上写着"3 天前更新"、给的却是一整套降价前旧价目的情况。

还有两个具体教训:

- **只跟官方普通挂牌价比,别跟促销价比。** 某模型当时在市场上挂着 50% off,拿促销价当基准写"我们更便宜",促销一结束就变成假话。
- **注意"被取消的涨价"。** Claude Sonnet 5 现价是 $2/$10,但网上大量内容按 $3/$15 写——那是原定 2026-09-01 生效、后来被官方明确取消的涨价。它不是谣言,是**一个作废了的真事实**,最难防。

---

## 附:2026-09-05 实测价目(每百万 token)

| 模型 | 输入 | 输出 | 缓存命中 |
|---|---|---|---|
| gpt-5.6-sol | $1.324 | $6.618 | $0.132 |
| gpt-5.6-terra | $0.551 | $3.309 | $0.055 |
| gpt-5.6-luna | $0.16 | $0.96 | $0.016 |
| claude-fable-5-1 | $5.00 | $25.00 | $0.22 |
| claude-opus-5 | $3.00 | $15.00 | $0.391 |
| claude-sonnet-5 | $1.60 | $8.00 | $0.10 |
| gemini-3.8-flash | $0.450 | $2.250 | $0.172 |

以上为 [apimodels.app](https://apimodels.app) 的实测价,完整清单和各家官方挂牌价的逐档对照在 [GPT-5.6 价格对比页](https://apimodels.app/access/gpt-5-6-api-pricing) 和 [Claude 价格对比页](https://apimodels.app/access/claude-api-pricing),里面也写了不适合用网关的情况——比如 OpenAI 和 Anthropic 的 Batch API 都打五折而我们不转售,大批量离线任务直接走官方更便宜。

本文代码全部实跑验证于 2026-09-05。价格会变,方法不会变——**照着第七节自己核一遍,比抄任何一张表都可靠。**
 

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐