DeepInfra 接入实操:base URL、token 鉴权与模型 ID 的三个坑
手上有个已经跑在 OpenAI SDK 上的服务,代码里 client.chat.completions.create() 调了几十处,现在要把后端换成 DeepInfra。这种活我做过不止一次,官方的说法也很干脆:从标准 OpenAI 配置切过来只需三处改动——改 base URL、换 token、指定其模型目录里的模型;现有 OpenAI 客户端库改动极小即可工作。
这话没有夸大,但「三处改动」容易让人低估调试时间。真正吃掉一个下午的不是改这三行代码,而是这三行里每一行都藏着一个跟直觉相反的细节:
- base URL 的路径顺序是
/v1/openai,不是你以为的/openai/v1; - 环境变量叫
DEEPINFRA_TOKEN,不叫DEEPINFRA_API_KEY; - 模型 ID 是
组织/模型名的 HuggingFace 风格,而且大小写敏感。
三个坑的共同点是:报错信息都不会告诉你真正原因。404 不会说「路径写反了」,鉴权失败不会说「你读的那个环境变量是空的」,模型找不到也不会提示「大写字母写成小写了」。
第一步:base URL 的路径顺序
OpenAI 兼容端点是:
https://api.deepinfra.com/v1/openai
请把注意力放在最后两段的顺序上:先 v1,后 openai。
之所以强调,是因为不少同类平台的写法恰恰反过来——把 openai 当作兼容层的命名空间放前面,版本号放后面。如果你的团队接过那类平台,或者配置文件是从别处抄来的,手指会非常自然地打出 /openai/v1。而这个错误的表现形式是 404。
404 是所有报错里信息量最低的一种。你会怀疑模型名写错了、怀疑账号没开通、怀疑网络出口被拦了,唯独不会第一时间怀疑那个已经复制粘贴过无数次的 base URL。所以接入任何 OpenAI 兼容平台,第一件事都该是把 base URL 单独拎出来用 curl 打一次,再去动业务代码。这一层的通用注意事项我在改 base URL 接入第三方模型里写得更细。
还有个连带问题:SDK 通常会在你给的 base_url 后面自己拼接 /chat/completions,所以你填的应该是到 /v1/openai 为止的部分。多写了同样是 404,而且这个 404 和路径顺序写反的 404 长得一模一样。
第二步:token 鉴权与那个不叫 API_KEY 的环境变量
鉴权走标准的 Bearer 方案:
Authorization: Bearer $DEEPINFRA_TOKEN
官方的环境变量名是 DEEPINFRA_TOKEN。这看起来微不足道,但在有配置管理的项目里是实打实的坑:大多数团队的密钥管理有约定,比如第三方模型凭据统一以 _API_KEY 结尾,注入脚本按后缀批量扫描,CI 的 secret 检查规则也按后缀写。DeepInfra 用 _TOKEN 结尾,于是它会安静地从这些自动化流程里漏掉——本地 .env 手写了一份所以能跑通,一部署到测试环境就变成 401,CI 日志里没有任何提示说「有个变量没注入」。
小项目直接按官方名字用 DEEPINFRA_TOKEN,别自作聪明改名,省得以后对着文档排查时多一层心智转换。有统一密钥层的项目,就在配置层做一次显式映射:内部仍叫 DEEPINFRA_API_KEY,在构造客户端的地方读它,留一行注释说明官方名字是 DEEPINFRA_TOKEN。关键是显式,别用 os.getenv("A") or os.getenv("B") 这种隐式回退,出问题时你会分不清到底哪个生效了。
另外,Bearer 后面是一个空格,token 本身不要带引号。从控制台复制时尾部很容易带上换行符,header 里混进 \n 会直接被拒,读取后统一 .strip() 是个好习惯。
第三步:HuggingFace 风格的模型 ID,以及大小写
官方文档里的示例模型 ID 是:
deepseek-ai/DeepSeek-V3
这是 组织/模型名 的 HuggingFace 风格命名。从 OpenAI 迁过来的人在这里翻车的比例最高,我认为有两个原因。
一是形态陌生。OpenAI 的模型名是扁平的单段字符串,没有斜杠;DeepInfra 的模型 ID 带一个斜杠,前半段是组织名。如果你的代码里有基于模型名做路由、打点或者拼路径的逻辑,那个斜杠会在某些地方被当成路径分隔符,出现莫名其妙的截断——我见过日志系统把 deepseek-ai/DeepSeek-V3 当成两级目录来分桶。
二,也是更常见的,大小写敏感。deepseek-ai/DeepSeek-V3 里,组织名是全小写的 deepseek-ai,模型名却是驼峰的 DeepSeek-V3——大写的 D、S、V。写成 deepseek-v3 或者 DeepSeek-ai/... 都是另一个字符串。从 OpenAI 迁过来的人容易栽在这,是因为 OpenAI 的模型名本来就全小写,大家形成了「模型名反正都是小写」的肌肉记忆,敲 ID 时会不自觉把驼峰按平。而报错通常只说模型不存在,不会给拼写建议。
我的做法是:所有模型 ID 集中定义在一个常量文件里,值直接从官方模型目录页复制粘贴,绝不手打。同时在服务启动时做一次冒烟调用,模型 ID 错了就在启动阶段崩掉,而不是等第一个真实用户请求进来才暴露。
Python(OpenAI SDK)
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["DEEPINFRA_TOKEN"].strip(),
base_url="https://api.deepinfra.com/v1/openai",
)
resp = client.chat.completions.create(
model="deepseek-ai/DeepSeek-V3", # 大小写敏感,从官方模型页复制
messages=[
{"role": "system", "content": "你是一个简洁的技术助手。"},
{"role": "user", "content": "用一句话解释什么是 OpenAI 兼容端点。"},
],
)
print(resp.choices[0].message.content)
注意 api_key 这个参数名是 OpenAI SDK 自己的,不用改;变的只是它的取值来源。SDK 侧的写法细节可以对照用 OpenAI SDK 接第三方模型服务。
curl
curl -sS https://api.deepinfra.com/v1/openai/chat/completions \
-H "Authorization: Bearer $DEEPINFRA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-ai/DeepSeek-V3",
"messages": [{"role": "user", "content": "ping"}]
}'
curl 这段建议留在项目 README 里。分不清是平台的问题还是自己代码的问题时先跑它——十秒内把「网络、鉴权、路径、模型名」四件事一次性验完,比在应用里加日志快得多。
计费口径:三档价,以及它对提示词设计的影响
DeepInfra 的定价按每 100 万 token 计,并且区分输入 / 缓存输入 / 输出三档。以下是官方定价页上的数字($ / 1M tokens),以官方定价页为准:
| 模型 | 输入 | 缓存输入 | 输出 |
|---|---|---|---|
| DeepSeek-V4-Pro | $1.30 | $0.10 | $2.60 |
| DeepSeek-V4-Flash | $0.09 | $0.018 | $0.18 |
| DeepSeek-V3.2 | $0.26 | $0.13 | $0.38 |
| DeepSeek-V3.1-Terminus | $0.27 | $0.13 | $0.95 |
| DeepSeek-V3.1 | $0.25 | $0.13 | $0.95 |
值得关注的不是某一行的绝对值,而是「三档」这个结构本身。
只有输入/输出两档价的平台上,成本模型很简单:总成本 ≈ 输入量 × 输入价 + 输出量 × 输出价,系统提示词写长一点成本就线性贵一点,仅此而已。多了缓存输入这一档就不同了:V4-Pro 普通输入 $1.30,缓存输入 $0.10,差了大约 13 倍。同样一段 token,是不是命中缓存,成本能差一个数量级。于是「系统提示词长不长」这个问题的答案变了——长提示词只要稳定不变、能被缓存命中,边际成本非常低;反之,如果里面塞了时间戳、用户 ID、随机排序的示例,每次前缀都不同,那这段长提示词每一次请求都得按全价计。
另外注意各模型的缓存折扣力度并不一样:V4-Flash 是 $0.018 对 $0.09,V3.2 是 $0.13 对 $0.26。比例差异不小,选型时别把「有缓存价」当成统一假设。
一个纯算术的演示
下面这组数字是我为了说明结构而编的算例,不是任何真实项目的实测数据,你可以把参数换成自己的量级重算一遍。
设定:用 V4-Pro,系统提示词 4000 token,每次用户输入 500 token,输出 300 token,每天 2 万次调用,一个月按 30 天算。
先算量:
- 输入总量 = (4000 + 500) × 20000 × 30 = 2700M token,其中系统提示词部分占 2400M
- 输出总量 = 300 × 20000 × 30 = 180M token
输出这块跟缓存无关,固定是 180 × $2.60 = $468。
输入这块随命中率变化:
- 缓存命中率 0%:2700 × $1.30 = $3510。加上输出,月成本 $3978。
- 命中率 50%(系统提示词那 2400M 里一半命中):1200 × $0.10 + 1200 × $1.30 + 300 × $1.30 = $120 + $1560 + $390 = $2070。加输出,$2538。
- 命中率 100%:2400 × $0.10 + 300 × $1.30 = $240 + $390 = $630。加输出,$1098。
从 0% 到 100%,月成本从 $3978 降到 $1098。这中间没有换模型、没有裁功能、没有降质量,改的只是「让请求前缀保持稳定」这一件工程上的事。
这就是三档价结构给工程决策带来的实质变化:两档价的世界里,省钱靠压缩 token 数量,而压缩通常要牺牲效果;三档价的世界里,省钱首先靠提高前缀稳定性,这件事基本不牺牲效果,只需要把动态内容从系统提示词挪到用户消息的后半段。具体做法(前缀设计、什么会打破命中、多轮对话怎么组织)见提示词缓存怎么省钱。
另外记得把 usage 里的 token 统计打进自己的日志按天聚合。挂牌价再清楚,也不如自己账上跑出来的数字有说服力,尤其是命中率这种强依赖流量形态的指标。
关于速率限制和免费额度:本文不写
说得直白些:本文不给出 DeepInfra 的任何速率限制数值,也不说它有没有免费额度或注册赠送。
原因是官方那份速率限制文档当前取不到,页面返回 404;免费额度也没有找到可核实的官方来源。这种情况下只有两条路:凭印象编一个「大概多少 RPM」,或者明确说不知道。前者对你没有任何好处——你会拿这个数去做容量规划,然后在生产环境里发现它是错的。请以控制台和官方文档为准,这两处才是唯一有效的信息源。
但「不知道限速」不等于「没法上线」。不知道限速时该怎么做,本身就是一套成熟的通用方法,它甚至比知道具体数字更有用——限速值会变,方法不会。
从低并发起步。 别一上来就把连接池开到几十。先用个位数并发跑通全链路,观察一段时间。这个阶段的目标不是压出上限,而是确认「在明显安全的水位下功能完全正常」。有了这个基线,后面出任何问题你都能判断是不是压力导致的。
先观测再加压。 加压前把观测埋好:响应状态码、耗时分布、429 的出现频次。然后阶梯式提并发,每提一档观察足够长的时间。你要找的信号是 429 开始零星出现的那个点——那就是实际能用的水位,比任何文档数字都准,因为它是你这个账号、这个模型、这个时段的真实值。
把重试和退避提前准备好,别等撞墙了再加。 指数退避加随机抖动是标配,抖动是为了避免所有实例同时重试造成二次冲击。一定要设重试上限和总超时,否则平台侧一次短暂波动就会把线程池全堵死,变成比限速严重得多的故障。另外只对可重试的错误重试——429 和 5xx 可以,400 这种请求本身有问题的重试多少次结果都一样。
把限速当成配置项而不是常量。 并发数、QPS 上限应该能热改,最好按模型分别设置。你今天观测出来的水位,可能因为平台侧调整或账户等级变化而改变,写死在代码里意味着每次调整都要发版。
做好降级路径。 想清楚撞到限速之后业务怎么办:排队等待、降级到另一个模型,还是切到备用平台。如果是最后一种,架构上就该早点把模型调用收敛到一层网关后面,而不是让 base URL 和模型 ID 散落在几十个业务文件里,做法见自建 OpenAI 兼容网关。
接入自查清单
上线前对着过一遍,七条:
- base URL 是
https://api.deepinfra.com/v1/openai,路径顺序是先v1后openai,没写反,也没把/chat/completions重复拼进去。 - 环境变量确认叫
DEEPINFRA_TOKEN(或你显式映射过),并且在测试环境、CI、生产环境里都真的注入到位了——本地能跑通不算数。 - 模型 ID 从官方模型目录页复制粘贴,
组织/模型名两段齐全,大小写逐字符核对过(DeepSeek-V3不是deepseek-v3)。 - token 读取后做过
strip(),没有尾随换行或引号混进 Authorization header。 - 有一条 curl 冒烟命令存在 README 里,任何人在任何环境都能十秒内验完网络、鉴权、路径、模型名。
- 启动时有冒烟调用,模型 ID 或凭据错误在启动阶段就崩,而不是等第一个真实请求。
- 并发从低起步,429 计数已进监控,指数退避 + 重试上限 + 总超时三件套齐全;限速与免费额度以控制台和官方文档为准,代码里不写死任何假设值。
最后重复一遍最容易被忽略的那条:路径顺序是 /v1/openai。只记一件事的话就记这个——它是唯一一个会让完全正确的代码收到 404 的细节。