性能优化推理部署本地大模型

我在懒猫算力仓上跑了 DeepSeek V4,然后跟“慢”死磕了三天

2026-09-14 · PM Parker · 阅读约 9 分钟

8 月 28 号,我的懒猫算力仓到货:两台 Jetson Thor T5000,单台 128GB 统一内存,4 条 25Gb MGBE 互联。

当天晚上的任务很明确:把当时最热的 DeepSeek V4 Flash 跑起来,验两件事,这套硬件行不行,以及自托管推理到底离“生产可用”有多远。

当时圈子里对这套组合的预期是不低的。DeepSeek V4 Flash 刚发布,开源榜登顶;Thor 是 NVIDIA 新一代边缘推理旗舰;懒猫官方 CLI 3.0.8 宣传一键部署,几分钟跑通。两台机器组分布式,320K 上下文,“谁还买 API”的声音不是没有。

部署确实快。官方 CLI 一路下一步,两台节点(一台 rank0 出 API,一台 rank1 headless)拉起 NVFP4 量化的 vLLM,KV 池 20GiB,内网端点通的那一刻,还挺有成就感。

然后我发起了第一个真实请求。

要一句三十字的介绍。

等了四十五秒。

三十个字。四十五秒。宣传里那三分钟跑通的是“跑通”,不是“能用”。

接下来三天,我把这套服务里里外外翻了一遍,最后把“慢”拆成了三个互不相干的问题。这篇文章把每个问题的证据、根因、解法都摊开,文末还有个意外收获:一个提交给 vLLM 上游的 bug。

先立规矩:把“慢”拆成三段再动手

排查之前先说方法论,因为它决定了这三天没有白干。

一次 LLM 请求的“慢”,其实是三段完全不同的时间:

分段实测数据根因归属
吐字速度(decode)20–27 tok/s硬件路线天花板
首字延迟(TTFT)10–13 秒Triton JIT 冷编译
出字前的“思考”(reasoning)单题烧 1252 thinking tokens默认开启深度思考

三段的根因毫无关系,解法也毫无关系。混在一起调,就是白费劲。

第一段:解码速度,是硬件路线的天花板

实测每秒 20 到 27 个 token。我调了各种参数,纹丝不动。

深挖到源码层才找到根因:Thor 的 MGBE 互联加这套 NVFP4 量化,在 vLLM 里没有原生 FP4 计算路径,走的是 Marlin 解量化的迂回路线,每一层都带着额外的解压开销。这是硬件路线决定的,调参救不了。

所以我做了个决定:这段,认了,停止投入,等上游适配。

别觉得这是认输。性能优化里最大的浪费,就是在一个没有解的层面反复使劲。知道哪里没救,本身就是巨大的节省。我的精力全部腾给了后面两段。

第二段:首字延迟,是编译器在冷启动

首字延迟 10 到 13 秒。这个数字里有相当一部分,来自一个特别容易被忽略的机制。

vLLM 第一次运行某类计算时,要靠 Triton 即时编译计算内核。一次性开销,编完就正常了。

也就是说,“服务重启后头几分钟特别卡”不是 bug,是 Triton 在冷启动。

解法简单到离谱:服务就绪之后,自动发几个预热请求,把编译开销提前消耗掉。三行脚本,现象彻底消失。

但这段排查往下挖,挖出了后面真正的深渊:为什么预热之后,同样的请求首字延迟还是不对劲?顺着查下去,我发现这套 Thor 路径上 prefix caching 压根不生效:78 万次查询,零命中。同一段 13K 的 prompt 发三次,TTFT 三次都是 15.9 秒。

这个坑深挖下去是另一个故事(我给 vLLM 上游提了 issue,还开源了整套调优记录),按下不表,先回主线。

第三段:四十五秒去哪了

回到开头那句三十字的介绍。45 秒到底花在哪了?

我一开始以为是网络,还重启了路由器。后来把单次请求拆开量,才发现模型在回答之前先自己写了一千二百字的草稿。三十个字的活,它先打 1252 个 thinking token 的腹稿。

这是 DeepSeek V4 的默认行为,深度思考默认开。我是部署完第三天才知道有这个开关的。

解法是请求 body 里的一个参数:

"chat_template_kwargs": {"thinking": false}

同样的题目,重测:

46.8 秒,变成 1.75 秒。27 倍。

finish reason 正常,输出质量没有任何区别。

三天排查里最贵的归因,花了一天多。而最便宜的优化,只是一个请求参数。

这一段还顺带排掉一个阴间雷。max_tokens 给小了的时候,DeepSeek V4 会先把思考 token 烧完,预算耗尽,正文一个字没写,接口返回成功,content 是空的。我盯着那个“成功”看了好久。

解法倒是不复杂:思考类任务 max_tokens 给到 256 以上,或者干脆关思考。又是同一个开关。

意外收获:从踩坑到给上游报 bug

这三天攒下的东西,最后没有烂在我的 NAS 里。

prefix cache 零命中那个问题,我顺着源码往下挖:Thor 上所有 backend 变体都路由到同一个没有 prefix 逻辑的私有实现(这条路径是懒猫 fork 自带的,vLLM 上游 main 里根本没有 thor.py),比上游已知的 H200 变体 bug 还要底层。我把复现数据、源码分析和对照 issue 整理成报告,提交给了 vLLM 官方仓库。

三天的调优过程也整个开源了:双机部署 runbook、FP8 调优器和 7 个预调优 kernel、A/B 基准脚本,以及 5 项试过但无效的否定结果。否定结果也是结果,能替下一个人省三天。

一键部署宣传的是几分钟跑通。这三天的记录算它的另一半:能用是三天的事,搞清楚为什么不能用的路上,还可能给社区留点东西。

三天结束之后,我给自己立了个规矩:以后任何推理服务上线,先把一次请求拆成三段来测。

第一个字出来之前(TTFT):查网络、排队、编译预热,解法是预热和缓存。

吐字的速度(decode):看硬件路线,先确认天花板在哪,别跟物理较劲。

吐字之前的“思考”(reasoning):查配置开关,这里经常藏着最便宜的提速。

所以下次你遇到“这模型太慢了”,别急着换硬件。先归段,不归段的优化就是碰运气。

这个道理放到产品上也一样成立:用户说“你们产品好卡”,首屏慢、操作慢、任务处理慢,是完全不同的三个团队、三套解法。把主观的“慢”翻译成可测量的分段指标,是性能工作的第一步。

prefix cache 那个深坑后来还发酵过一次:平台更新把配置一夜打回原形,见 两行配置提速一倍,然后被平台更新一夜打回原形;同一条链路的漂移排查,见 推理性能漂移实录。


← 返回博客列表 · 相关阅读:配置被平台覆盖回退 · 双机部署实录