)
本文所有代码均在 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 Pythonpythonfrom openai import OpenAIclient OpenAI(api_keyYOUR_KEY,base_urlhttps://api.apimodels.app/v1, # 只改这一行)r client.chat.completions.create(modelgpt-5.6-luna,max_tokens16,messages[{role: user, content: 用一个词回答:11}],)print(r.model) # gpt-5.6-lunaprint(r.choices[0].message.content) # 二print(r.usage)实跑返回:model: gpt-5.6-lunareply: 二usage: prompt14 cached0 completion5### 2.2 curlbashcurl 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 换模型 换字符串pythonfor 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(modelm, max_tokens8,messages[{role: user, content: hi}])print(m, r.usage.prompt_tokens, r.usage.completion_tokens)**注意 Node 侧有个常见错误**:baseURL 要带 /v1,而且不要再手动拼一次:javascriptimport 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)/h2Claude 有个容易被忽略的点:**很多网关是把 Claude 套成 OpenAI 形状转译的**,这会丢掉 thinking 块、原生 tool_use 结构和部分流式事件类型。如果你要接的是 Claude Code、Anthropic 官方 SDK 或 Cursor,**必须走原生 /v1/messages**,不能走转译层。判断方法很简单:看返回体是 {type:message,content:[...]}(原生)还是 {choices:[...]}(转译)。### 3.1 Python(anthropic SDK)pythonimport anthropicclient anthropic.Anthropic(api_keyYOUR_KEY,base_urlhttps://api.apimodels.app, # 注意:这里不带 /v1)m client.messages.create(modelclaude-sonnet-5,max_tokens16,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_tokensreply: Sure.usage: in29 out13 cache_read0⚠️ **两条路径的 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 curlbashcurl 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 认两个环境变量,不需要改配置文件:bashexport ANTHROPIC_BASE_URLhttps://api.apimodels.appexport ANTHROPIC_AUTH_TOKENYOUR_KEYclaudeCursor 同理,在设置里把 Anthropic 的 base URL 和 key 换掉即可。因为走的是原生协议,**tool use、thinking、流式事件形状都不变**,不需要改任何业务代码。---h2 id四四、流式与 usage 回传/h2流式的坑在于:**默认不返回 usage**,你会拿不到 token 数,没法对账。OpenAI 协议要显式打开:pythonstream client.chat.completions.create(modelgpt-5.6-luna,max_tokens64,streamTrue,stream_options{include_usage: True}, # 关键messages[{role: user, content: 写一句话}],)usage Nonefor chunk in stream:if chunk.choices and chunk.choices[0].delta.content:print(chunk.choices[0].delta.content, end, flushTrue)if chunk.usage: # 最后一个 chunk 才带usage chunk.usageprint(\n, usage)curl 验证:bashcurl -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 事件里能看到:jsonusage:{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_tokensif usage.prompt_tokens_details else 0) or 0fresh usage.prompt_tokens - cachedreturn (fresh * p[in] cached * p[cached] usage.completion_tokens * p[out]) / 1_000_000r client.chat.completions.create(modelgpt-5.6-luna, max_tokens64,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七七、核价方法(比价目表本身更重要)/h2AI 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。价格会变,方法不会变——**照着第七节自己核一遍,比抄任何一张表都可靠。**