这周对写服务端的人有两条消息,一条在 GitHub,一条在财报里。
GitHub 上那条是 DeepSeek 把自家推理框架开源了,仓库叫 DeepInfer,10 月 16 日建仓,二十天 25.5k Star、3.1k Fork。README 里写得很清楚:这是支撑 DeepSeek 大规模生产服务的推理框架,开源版放出离线推理的核心能力。
财报里那条是微软不再续签从甲骨文租的 AI 算力,理由是那批服务器的英伟达卡代际太老,不符合当前规格。而甲骨文披露过,用了约四年的 GPU 续约价格比原合同高 20%。
两条消息其实指向同一个工程问题:模型越来越大,硬件换代越来越快,中间那层推理框架要同时兜住两侧的变化。
这篇不聊估值,只聊代码和架构。
DeepInfer 到底解决了什么
先看支持的模型和硬件,这两项决定它的适用边界。
模型目前只支持 DeepSeek-V4.1-Flash,硬件支持 NVIDIA SM100 和华为昇腾 950 NPU。这个组合本身就说明它是为超大规模 MoE 模型调的,不是通用推理引擎。
功能清单里几个设计值得逐条拆:
并行策略。Attention 层走 DP,配均衡的 CP;MoE 走 EP 加 EPLB 做专家负载均衡。3 万亿参数的模型,专家数量多到单机能放下的部分很有限,EPLB 的作用是在线感知各专家的负载并把热点专家重新分布,避免某几张卡被压死。
DSpark 与置信度调度验证。用草稿 token 加速解码,再用置信度估计决定验证哪些位置。开关是 `DEEPINFER_ENABLE_MTP_VARLEN=1`,`DEEPINFER_USE_NEXTN_DECODE` 控制最大草稿长度,默认 5。
SWA 有界重放。这个设计我很喜欢。长上下文场景下,decoder 的 prefill 会被反复重算,开销巨大。它只重放一个有界后缀,把工作量砍掉。默认配置是 `DEEPINFER_YOCO_PREFILL_TRUNCATION_MODE=compact` 加 `DEEPINFER_YOCO_PREFILL_KEEP_TOKENS=140`,保留的后缀必须覆盖 SWA 窗口加最大回溯长度。
异步调度。CPU 侧的批调度和设备执行重叠,默认开启,属于零开销批调度的常规做法,但真要做到"零开销"需要在锁和队列上抠很多细节。
batch-invariant 推理。这是我觉得最被低估的特性。同一段 prompt,放在不同 batch 组合里跑,结果必须一致。开 `DEEPINFER_BATCH_INVARIANT=1`(仅 NVIDIA)。
确定性采样。相同输入 token、相同采样参数,输出完全相同。需要同时开 batch-invariant、关掉 `DEEPINFER_ENABLE_MTP_VARLEN`,并给 `SamplingParams` 传固定的 `seq_seed`。
为什么这两条重要?做过线上推理的都懂:batch 一变,logits 就会有微小差异,采样一放大,输出就跑偏。评测复现不了、线上问题抓不住、A/B 实验对不齐,全是这个原因。
结构化输出。支持正则、JSON schema、EBNF 语法约束,通过 `SamplingParams` 的 `so_args` 传。
底层 kernel 用的是 FlashMLA、DeepGEMM、DeepEP、TileKernels、DeepSelect,加自定义 TileLang 算子。架构基于 vLLM,README 里也承认参考了 SGLang 和 TensorRT-LLM。
依赖环境:Linux、GCC 13 以上、Python 3.12、CUDA 13(NVIDIA)或 CANN 9.2(昇腾)。
上手:编一个,跑一个
编译入口只有一个环境变量切换后端。
```bash
建一个干净的 Python 3.12 环境后
export DEEPINFER_ACCELERATOR=nvidia # 昇腾用 ascend
./build.sh
```
跑离线推理,默认会拉 HuggingFace 上的 `deepseek-ai/DeepSeek-V4.1-Flash-1017`,本地已有权重就指过去,省一次下载。
```bash
export DEEPINFER_HF_MODEL_DIR=/data/models/DeepSeek-V4.1-Flash-1017
python examples/offline_inference.py
```
一个能直接用的 batch-invariance 验证脚本
README 说了这个特性,但没给验证方法。线上要真信它,得自己量。
下面这个脚本打任何 OpenAI 兼容端点都能用(DeepInfer 起服务后,或 vLLM、SGLang 都行),思路是把同一条 prompt 分别放在单条请求、2 条批、8 条批里跑,比较输出哈希。
```python
import hashlib
import os
import sys
from openai import OpenAI
client = OpenAI(
base_url=os.getenv("BASE_URL", "http://127.0.0.1:8000/v1"),
api_key=os.getenv("API_KEY", "EMPTY"),
)
PROMPT = "用一句话解释什么是 MoE 的专家并行,不要超过 40 字。"
SEED = 42
def one(n_repeat: int) -> liststr:
"""把同一条 prompt 复制 n 份发出去,返回每份的文本。"""
resp = client.chat.completions.create(
model=os.getenv("MODEL", "deepseek-v4.1-flash"),
messages={"role": "user", "content": PROMPT} for _ in range(n_repeat),
temperature=0.0,
seed=SEED,
max_tokens=64,
)
return c.message.content.strip() for c in resp.choices
def digest(s: str) -> str:
return hashlib.sha256(s.encode()).hexdigest():12
baseline = one(1)0
print(f"single {digest(baseline)} {baseline}")
ok = True
for n in (2, 8, 16):
outs = one(n)
uniq = {digest(o) for o in outs}
dup_within = len(uniq) == 1
match_base = outs0 == baseline
flag = "OK" if (dup_within and match_base) else "MISMATCH"
if flag != "OK":
ok = False
print(f"batch={n:<3} 内部一致={dup_within} 与单条一致={match_base} {flag}")
sys.exit(0 if ok else 1)
```
跑法很简单:
```bash
pip install openai
BASE_URL=http://127.0.0.1:8000/v1 MODEL=deepseek-v4.1-flash python check_batch_invariance.py
```
脚本返回非 0 就说明这个端点没做到 batch-invariant。注意 temperature 必须设 0,否则比的是采样噪声不是框架行为。另外 `seed` 参数只是让服务端有机会对齐,真确定性还得靠框架自己开 `DEEPINFER_BATCH_INVARIANT=1`。
我拿 vLLM 默认配置试过,batch 从 1 涨到 8 时输出就开始飘,这不是 bug,是浮点累加顺序变了。所以这个检查有实际意义。
另一条线:算力租约的账,比框架更难算
回到微软那条新闻。它给的工程信号是:卡的有效寿命,正在短于合同周期。
四年前买的卡,今天续约要涨价 20%,同时被大客户判定"不符合规格"。这两件事同时成立,说明算力市场已经分层:新卡按性能定价,旧卡按稀缺定价。
对做技术选型的人来说,这意味着 TCO 模型得改。以前按五年折旧摊,现在得按三年算,还要把"第三年开始降级使用"写进去。
一个粗糙但能用的估算脚本:
```python
def tco(card_price: float, cards: int, years: int, kwh_price: float,
watts_per_card: float, utilization: float,
tokens_per_hour_per_card: float) -> dict:
"""单卡 TCO 摊到每百万 token 的成本。"""
capex = card_price * cards
hours = years * 365 * 24 * utilization
power = watts_per_card / 1000 * hours * kwh_price * cards
机房、网络、运维按电费的 1.8 倍粗估
opex = power * 1.8
total_tokens = tokens_per_hour_per_card * hours * cards / 1e6
return {
"total_cost_usd": round(capex + opex, 0),
"total_m_tokens": round(total_tokens, 0),
"cost_per_m_token": round((capex + opex) / total_tokens, 4),
}
for yrs in (3, 5):
print(yrs, "年折旧:", tco(30000, 64, yrs, 0.12, 700, 0.65, 120000))
```
跑出来的差异会很明显。以 64 张单价 3 万美元的卡、电价 0.12 美元/度、单卡 700W、利用率 65%、每卡每小时 12 万 token 这组假设为例:按五年摊,每百万 token 成本约 10 美元;按三年摊,涨到约 15.9 美元,涨幅接近六成。而收入端的推理单价还在往下走。这就是前面说的那笔账。
框架层面的应对其实只有一个方向:提高单位算力的有效吞吐。DeepInfer 那些设计(EPLB、DSpark、SWA 重放、异步调度)本质都在做同一件事,把每一张卡的利用率往上抬。抬得动的部分,就是折旧加速吃掉的那部分。
给做选型的人几句实话
第一,别只看 benchmark 里的吞吐峰值。峰值通常在 batch 拉满、序列长度固定的理想条件下测出来,线上很少是这个形状。
第二,把确定性当成一项功能来验收。有评测、有对账、有回归测试的业务,输出漂移带来的排查成本远高于多花的那点算力。
第三,硬件代际要写进架构假设。如果框架强依赖某种卡的新特性(比如 SM100 的特定指令),换代时迁移成本会很高。DeepInfer 同时支持 SM100 和昇腾 950,这个双栈设计本身就是一种风险对冲。
第四,MoE 的负载均衡不要等上线再调。EPLB 这类机制在流量平稳时看不出价值,一旦某个专家被热点请求打爆,整机吞吐会断崖式下跌。
聊两句
两个问题想问实际操作过的朋友:
-
你们线上跑 MoE 模型时,专家负载不均导致的尾部延迟有多严重?是靠框架自动均衡,还是自己在路由层做限流?
-
团队做算力 TCO 时,折旧按几年算?有没有人把"第三年后降级跑小模型"这条路真的算进模型里?
我个人倾向于按三年算,宁可保守。财报可以按五年写,业务不能。
有更好的验证脚本思路也欢迎扔到评论区,尤其是怎么在流式输出场景下量确定性,我还没找到特别干净的测法。