Nebius Token Factory 接入实录:末尾斜杠与文档域名迁移两个坑
先说结论:Nebius Token Factory 的接入本身没什么可讲的。它是 OpenAI 兼容平台,官方文档写的就是 “OpenAI-compatible API”,代码示例直接用标准 OpenAI 客户端库。你手上那份跑在别家的代码,改 base_url、改 key、改模型名三处,剩下的 messages 构造、流式处理、异常捕获一行都不用动。这个套路我在 改 base_url 切换 OpenAI 兼容接口 里已经写烂了。
真正会绊人的是两个不起眼的细节,而且它们都不在”接入教程”的正文里,是你在照抄文档的过程中撞上去才会意识到的:
一是官方给出的 base_url 是 https://api.tokenfactory.nebius.com/v1/,末尾带一个斜杠。多数平台的文档写的是不带斜杠的形式,这里跟你的肌肉记忆不一样。
二是文档域名做过迁移。你搜到的、同事发给你的、甚至你自己半年前收藏的 docs.nebius.com/studio/... 链接,现在会 307 跳到 docs.tokenfactory.nebius.com。
这两件事都不难,但都属于”不知道就要多花半小时”的类型。这篇就围绕它们展开。
三步接入
第一步:base_url,以及末尾那个斜杠
官方写法是 https://api.tokenfactory.nebius.com/v1/。
为什么要专门拿一段来讲一个标点?因为绝大多数 SDK 拿到 base_url 之后,是把接口路径拼接上去的。OpenAI 官方 SDK 内部会去请求 chat/completions 这样的相对路径,最终得到什么,取决于客户端库用的是什么拼接策略——有的走 URL join 语义,有的就是朴素的字符串相加,还有的会先把末尾斜杠规范化掉。
所以当 base_url 末尾带斜杠时,最终地址有可能变成 .../v1/chat/completions(正常),也有可能变成 .../v1//chat/completions(多了个斜杠)。
这里我必须把话说准:我没有核实过双斜杠在这个平台上会不会失败。服务端对重复斜杠的处理方式各家不同,有的路由层直接归一化,有的严格匹配就报 404。我不知道 Nebius 属于哪一种,所以不会替你断言。
我给出的是一个不依赖猜测的流程:
- base_url 照官方原样填,包括末尾斜杠。文档怎么写你怎么抄,别自作聪明去掉。
- 先用 curl 把完整地址打通。绕开所有 SDK 的拼接逻辑,手写一条完整 URL,确认服务端这条路是通的、key 是有效的。这一步成功,你就有了一个”已知正确”的基准。
- 再倒推 SDK 配置。SDK 跑通就完事;SDK 报 404 而 curl 是 200,那八成就是拼接出了问题,这时候把 base_url 的末尾斜杠去掉再试一次。
顺带说一句排错的直觉:404 和 401 是两种完全不同的信号。地址拼错了通常给你 404 或者一个奇怪的路由错误,key 不对才是 401。很多人第一次接入失败就一头扎进 key 里查半天,其实是地址的问题。这条经验在 用 OpenAI SDK 接入第三方平台 里也提过一次,值得记住。
第二步:鉴权
标准 Bearer token:
Authorization: Bearer $NEBIUS_API_KEY
环境变量用 NEBIUS_API_KEY。别把 key 写死在代码里,也别图省事塞进前端——这类基本纪律我在 API Key 管理 里单独写过一篇。
第三步:模型 ID
官方示例给的是 deepseek-ai/DeepSeek-R1-0528。两段式,前面是发布方,后面是模型名,而且模型名尾部带一个日期版本后缀。
这个 ID 要一字不差地抄。两段式模型 ID 少写前半截是很典型的翻车方式,报错信息经常长得像权限问题,把人往错误方向带。
代码
Python,标准 OpenAI SDK:
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.tokenfactory.nebius.com/v1/",
api_key=os.environ["NEBIUS_API_KEY"],
)
resp = client.chat.completions.create(
model="deepseek-ai/DeepSeek-R1-0528",
messages=[
{"role": "user", "content": "用一句话解释什么是 OpenAI 兼容端点"},
],
)
print(resp.choices[0].message.content)
curl,用来做第一步里说的”基准验证”:
curl https://api.tokenfactory.nebius.com/v1/chat/completions \
-H "Authorization: Bearer $NEBIUS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-ai/DeepSeek-R1-0528",
"messages": [
{"role": "user", "content": "hello"}
]
}'
curl 这条是完整地址,不经过任何拼接逻辑。它通了,说明网络、域名、鉴权、模型 ID 四件事全对;它不通,你就有明确的错误码可以定位,而不是在 SDK 的抽象层里瞎猜。
模型 ID 里的日期后缀意味着什么
DeepSeek-R1-0528 结尾那四位数字,是把版本快照直接暴露在了模型标识符里。这不是随手加的装饰,它改变了你和这个模型之间的契约。
好的一面是可复现。你今天用这个 ID 跑出来的结果,和三个月后用同一个 ID 跑出来的,理论上来自同一版权重。对于需要固定行为的场景——评测基线、prompt 回归测试、线上输出格式强依赖——这是相当值钱的性质。相比之下,那些”永远指向最新版”的别名式模型名,会在某个你不知道的凌晨悄悄换掉底下的模型,然后你的 prompt 在第二天开始表现漂移,排查起来极其痛苦。
代价是这份稳定要你自己维护。版本快照既然是快照,就有生命周期。某一天这个 ID 下线,而你的服务里这条依赖已经三个月没人看过,你会在报错日志里第一次意识到它的存在。
所以我的做法是三条,都很土但有效:
把模型 ID 收敛到配置里。 一个常量、一处环境变量、一个 config 段落,就一处。最怕的是模型 ID 散落在代码各个角落——某个 service 里写一次,某个脚本里写一次,测试用例里再硬编码一次。等你要迁版本的时候,全局搜索能不能搜干净全靠运气。
加一条启动日志,打印”模型 ID 生效值”。 不是打印配置文件里写了什么,是打印程序真正拿到手、准备发出去的那个值。配置覆盖、环境变量优先级、默认值兜底,这几层叠在一起经常会有意外,而一行启动日志能在事故发生时一秒钟给出答案:当时跑的到底是哪一版。
定期回看。 频率不用高,一个季度一次就够。看一眼控制台里当前可用的模型列表,确认你依赖的那个快照还在,顺手记一下有没有更新的日期后缀可以评估。这件事花不了十分钟,但它把”某天突然崩”变成了”我早知道要换”。
文档域名迁移:影响的不是代码,是你的链接
前面提到的现象,再复述一次,只讲我能观察到的部分:docs.nebius.com/studio/... 这个路径会 307 跳转到 docs.tokenfactory.nebius.com。至于为什么迁、什么时候迁的、背后是什么安排,我不知道,也不打算编。
我想讲的是这件事对工程的普适影响,因为它绝不是某一家的个例:
文档链接会悄悄过期。 你收藏夹里的那条、README 里”详见官方文档”后面挂的那个 URL、甚至代码注释里 // see https://... 的那一行,全都会在某一天指向别处。307 跳转还算客气,至少你能到达目的地;更常见的情况是文档改版之后旧路径直接 404,或者跳到一个泛泛的首页,你要重新搜一遍才能找回原来那页。
API 地址和文档地址是两回事,别搞混。 这是我最想强调的一点。看到 docs.nebius.com 跳到了 docs.tokenfactory.nebius.com,第一反应很容易是”那我代码里的接口地址是不是也得跟着改”。不要慌。文档站的域名和 API 端点的域名归属于不同的生命周期,文档搬家并不等于端点搬家。真要判断端点变没变,靠的是打一次请求看结果,或者看当次能打开的官方文档怎么写,而不是从文档域名的变化去推断。
对应的做法也很简单:
以当次能打开的官方文档为准。 别信自己脑子里的记忆,也别信半年前的收藏。每次真要动接入代码的时候,重新走一遍官方入口,看当下那一页写的是什么。文档站变了没关系,跳转会把你带过去。
代码里只记 API 地址,不记文档地址。 配置文件、常量、环境变量里只放你真正要请求的那个 endpoint。文档 URL 属于给人看的东西,放在 README 或者内部 wiki 里,并且默认它会腐烂——写的时候顺手带上”核对日期”,比写一个看起来很确定的链接有用得多。如果一定要在注释里留链接,那就同时把关键结论抄一份到注释里,这样链接死了信息还在。
我不知道的部分,一个数都不编
这篇没有价格、没有免费额度、没有速率限制。
原因很实在:我在写这篇的时候,官方定价页取不到内容(/studio/pricing 返回 404)。免费额度和限速也一样没有核实到可靠出处。既然如此,我就一个数都不写。你在别处看到的”某某平台每百万 token 多少钱”,如果作者没告诉你数据是哪天从哪个页面上抄的,那个数字就没有引用价值——这类信息的半衰期以周计。
这些数值一律以控制台为准,登录进去看当下的计费页面和配额页面,那才是对你账户生效的口径。
在没有拿到确切数值之前,我建议这样起步:
低并发开始。 别一上来就把线上流量全切过去。先跑单并发,再到个位数并发,观察是否稳定。不知道限速阈值的时候,试探比推测安全。并发这块的一般性打法可以参考 并发与限流 那篇的思路。
先观测,再加压。 把每次请求的耗时、状态码、返回的 token 数记下来,跑够一段时间形成基线。你要的是自己业务场景下的真实数据,不是别人博客里的实测截图。跨境访问的链路情况也建议一并观测,参考 海外 API 延迟。
准备好退避重试。 无论限速是多少,触发限速是迟早的事。指数退避加抖动、区分可重试和不可重试的错误码,这套东西在你不知道阈值的时候尤其重要——它让你可以安全地”撞一下墙”而不是直接把用户请求打挂。
先用小批量任务算出自己的单位成本,再谈规模。 官方标价只是标价,你的真实成本取决于 prompt 长度、输出长度、重试率、缓存命中率这些非常个性化的东西。拿一批真实任务跑出”每个业务单元花多少钱”,这个数字才是能拿去做决策的。
接入自查清单
- base_url 是否照官方原样填的
https://api.tokenfactory.nebius.com/v1/,末尾斜杠没被手动删掉? - 有没有先用 curl 打通一条完整地址,拿到”已知正确”的基准,再去配 SDK?
- SDK 报 404 的时候,是否检查过最终请求地址有没有出现双斜杠,而不是一头扎进 key 里查?
- key 是否走
NEBIUS_API_KEY环境变量,没有硬编码、没有进版本库? - 模型 ID
deepseek-ai/DeepSeek-R1-0528是否一字不差,包括两段式前缀和日期后缀? - 模型 ID 是否只在一处配置里出现,并且启动日志会打印生效值?
- 价格、额度、限速有没有从控制台确认过,而不是引用某篇文章里的数字?
接入这件事本身花不了二十分钟,值钱的是这些边角。真正让你半夜被叫醒的从来不是”怎么发第一个请求”,而是某个你以为不会变的东西悄悄变了。