1. 从“每周采用度追踪”说起:这个项目到底在做什么
第一次看到“Kimi K3 每周采用度追踪”这个标题,很多人会以为它只是一份简单的数据周报。但如果你真的在一线做模型服务、推理部署或者应用集成,就会明白这类追踪背后其实是一整套工程化的观测体系。它要回答的问题很具体:这一周里,Kimi K3 这个模型在我的业务链路里被调用了多少次、走的哪条推理路径、平均首 token 延迟是多少、有没有出现批量超时、成本相比上周是涨了还是降了。这些指标不是拿来写 PPT 的,而是直接决定下周要不要扩容、要不要换量化方案、要不要调整路由策略。
我之所以对这个话题有感触,是因为过去大半年我一直在折腾大模型的本地与云端混合部署。从最早的 Ollama 一键拉模型,到后来用 LM Studio 做桌面端快速验证,再到把 vLLM 和 SGLang 拉进生产环境做高并发推理,中间踩的坑足够写一本小册子。Kimi K3 这类 MoE 架构的模型,参数量看着吓人,但实际激活的专家只是一小部分,这就让推理侧的优化空间变得特别大。而“每周采用度追踪”本质上就是把这套优化效果量化出来,让你知道钱花在哪、时间耗在哪。
这篇文章适合三类人看。第一类是正在做模型服务选型的工程师,你手里可能同时有 vLLM、SGLang、Ollama 几套方案,不知道该把哪个放到生产;第二类是负责成本控制的团队负责人,你需要知道 OpenRouter 这类聚合平台的计费逻辑和国内可用的替代路径;第三类是对 MoE 架构好奇、想自己动手跑一遍的爱好者,你不需要几百万的预算,一张消费级显卡加上正确的配置就能跑起来。我会把这一周追踪里涉及的核心技术点、参数计算、实操步骤和排查经验全部摊开讲,尽量做到你看完就能照着复现。
需要先说明一点:下面提到的所有配置和参数,都是基于我自己的硬件环境和常见工程实践总结出来的,不是官方标准答案。你的显卡型号、驱动版本、CUDA 版本不一样,结果可能会有出入,但思路是通用的。
2. 核心架构选型:为什么 MoE 模型让推理部署变得不一样
2.1 MoE 架构到底省在哪里
MoE 全称是 Mixture of Experts,混合专家架构。传统稠密模型每处理一个 token,都要把全部参数过一遍;MoE 则把前馈网络拆成很多个“专家”,每个 token 只激活其中少数几个。Kimi K3 这类模型通常采用 Top-K 路由,比如 8 个专家里选 2 个,那实际参与计算的参数量就只有总参数的一小部分。
这个设计带来的直接好处是:显存占用虽然还是按总参数量算(因为所有专家都得加载进来),但计算量大幅下降,推理速度明显提升。打个比方,稠密模型像是一家所有厨师同时开工的餐厅,不管来几个客人,后厨全员都在忙;MoE 则像是一个智能调度系统,来了订单只叫对应的几个厨师上手,其他人待命。客人少的时候,MoE 的响应快得多。
但这里有个容易被忽略的坑:MoE 的显存占用并不会因为“只激活部分专家”而减少。你依然需要把全部专家权重加载到显存里,否则路由到某个专家时它不在,就得从内存重新加载,延迟会爆炸。所以做采用度追踪时,显存峰值和专家命中率是两个必须分开看的指标。我见过有人只盯着 GPU 利用率,发现只有 40% 就以为资源浪费,其实显存早就吃满了,利用率低是因为计算密度本身就不高。
2.2 vLLM、SGLang、Ollama 三条路线的取舍
这一周追踪里,我同时在三条推理路径上跑了 Kimi K3 的量化版本,分别是 vLLM、SGLang 和 Ollama。选这三个不是随便挑的,它们代表了三种典型场景。
vLLM 的核心优势是 PagedAttention 和连续批处理。PagedAttention 把 KV Cache 切成固定大小的块来管理,避免了传统实现里因为序列长度不一导致的内存碎片。连续批处理则让新请求可以随时插入正在运行的批次,而不是等整批跑完。这两点加起来,让 vLLM 在高并发场景下的吞吐量非常能打。我实测下来,同样一张卡,vLLM 在并发 32 的情况下,吞吐量能比朴素实现高出三到四倍。
SGLang 的强项在结构化生成和前缀缓存。如果你的应用里有大量重复的系统提示词,或者需要模型输出严格的 JSON 格式,SGLang 的 RadixAttention 能把公共前缀的 KV Cache 复用起来,省掉大量重复计算。我在做一个客服意图分类的任务时,系统提示词有 800 多 token,用 SGLang 之后首 token 延迟直接降了将近一半。
Ollama 则是另一条路,它主打的是开箱即用。你不需要关心 CUDA 版本、不需要手动编译、不需要调 batch size,一条命令就能把模型跑起来。代价是它的调度策略相对保守,高并发下吞吐量不如前两者,而且对 MoE 架构的专家并行支持也比较有限。但如果你只是本地验证、做 demo、或者个人使用,Ollama 的便利性无可替代。
| 推理框架 | 核心优势 | 适用场景 | 主要限制 |
|---|---|---|---|
| vLLM | PagedAttention、连续批处理、高吞吐 | 生产环境高并发 API 服务 | 配置复杂,对 CUDA 版本敏感 |
| SGLang | RadixAttention、前缀缓存、结构化输出 | 重复提示词多、需严格格式输出 | 生态相对 vLLM 小一些 |
| Ollama | 开箱即用、模型管理方便 | 本地验证、个人使用、快速 demo | 高并发吞吐弱,MoE 支持有限 |
2.3 为什么追踪周期定在“每周”
有人会问,为什么不是每天追踪,或者每月追踪一次。这里有个实际考量:模型服务的负载是有明显周期性的。工作日白天是高峰,晚上和周末会降下来。如果你按天看,周一的峰值和周三的峰值可能因为一次营销活动就差出好几倍,数据波动太大,看不出真实趋势。按月看又太粗,等发现成本异常时,账单已经出去了。
按周追踪刚好能平滑掉日间波动,又能及时捕捉到趋势变化。我一般会在每周一早上拉取上周的汇总数据,重点看四个指标:总调用量、平均首 token 延迟、P95 延迟、每千 token 成本。这四个指标里,总调用量反映业务热度,首 token 延迟反映用户体验,P95 延迟反映长尾问题,成本则直接关系到预算。任何一个指标连续两周往坏的方向走,就得动手排查了。
3. 环境搭建与核心配置:把 Kimi K3 跑起来的关键步骤
3.1 CUDA 版本与 vLLM 的匹配问题
这一周我在一台新机器上部署 vLLM 时,又遇到了那个经典问题:CUDA 版本和 vLLM 预编译轮子不匹配。vLLM 对 CUDA 版本相当敏感,官方轮子通常是针对特定 CUDA 版本编译的。如果你机器上的 CUDA 是 12.8,而 vLLM 轮子是按 12.1 编译的,运行时就会报找不到符号的错误。
我的建议是,先确认驱动支持的 CUDA 版本上限,然后去 vLLM 的发布页面找对应版本的轮子。如果找不到完全匹配的,宁可降 CUDA 版本,也不要强行混用。具体操作上,可以用nvidia-smi看驱动版本,再用nvcc --version看当前 CUDA 工具包版本。两者不一致是正常的,驱动版本通常高于工具包版本。
# 查看驱动支持的 CUDA 版本 nvidia-smi # 查看当前 CUDA 工具包版本 nvcc --version # 查看 vLLM 安装后实际链接的 CUDA 版本 python -c "import vllm; print(vllm.__version__)"如果确实需要多版本 CUDA 共存,可以用 conda 创建独立环境,在里面装对应版本的 cudatoolkit。这样不同项目之间不会互相干扰。我自己的做法是,每个推理框架单独一个 conda 环境,vLLM 一个、SGLang 一个、Ollama 直接用系统级安装,互不影响。
注意:不要试图在一个环境里同时装 vLLM 和 SGLang 的完整依赖,它们的 CUDA 运行时和 PyTorch 版本要求经常冲突。分开环境是最省心的做法。
3.2 模型权重的获取与量化选择
Kimi K3 这类 MoE 模型,原始权重动辄几百 GB,普通机器根本放不下。所以实际部署时基本都会用量化版本。常见的量化格式有 GPTQ、AWQ、GGUF 几种。GPTQ 和 AWQ 主要面向 GPU 推理,GGUF 则更多用于 CPU 或混合推理场景。
我的经验是,如果显存足够,优先选 AWQ。AWQ 在 4bit 量化下对精度的保留比 GPTQ 稍好一些,尤其是在 MoE 模型上,因为专家之间的权重分布差异较大,AWQ 的激活感知量化策略更能照顾到那些“冷门专家”。GPTQ 的优势是生态成熟,各种框架支持都比较好。GGUF 则适合显存不够、需要部分层跑在 CPU 上的情况,但速度会慢很多。
量化等级的选择上,我一般会做一个简单的精度对比测试。拿一百条左右的真实业务请求,分别用原始模型和量化模型跑一遍,对比输出结果的差异。如果关键字段的准确率下降在可接受范围内,就用量化版本。4bit 量化通常能把显存占用降到原来的四分之一左右,对 MoE 模型来说,这意味着原本需要多卡才能跑起来的模型,现在单卡就能装下。
3.3 vLLM 启动参数详解与计算过程
vLLM 的启动参数里,有几个直接决定了性能和稳定性,我逐个说明。
--tensor-parallel-size是张量并行度,也就是用几张卡来分摊模型。对于 MoE 模型,这个参数需要特别注意,因为专家分布在不同卡上时,路由通信会成为瓶颈。我的经验是,如果卡间带宽足够(比如 NVLink),可以适当增大并行度;如果是普通 PCIe,并行度太高反而会因为通信开销拖慢速度。
--gpu-memory-utilization控制 vLLM 预分配多少显存。默认是 0.9,意思是拿 90% 的显存来做 KV Cache 和模型权重。这个值不能设得太满,因为 CUDA 本身和一些临时缓冲区还需要空间。我一般设 0.85 到 0.88 之间,留一点余量。如果设成 0.95,很容易在负载高的时候 OOM。
--max-model-len是最大序列长度。这个值直接决定了 KV Cache 的占用。计算公式大致是:KV Cache 大小 = 层数 × 2 × 注意力头数 × 头维度 × 序列长度 × 批大小 × 数据类型字节数。以 Kimi K3 为例,假设 60 层、64 个注意力头、头维度 128、序列长度 8192、批大小 16、FP16 存储,那 KV Cache 大约是 60 × 2 × 64 × 128 × 8192 × 16 × 2 字节,算下来接近 32GB。这还没算模型权重本身。所以如果你的卡显存不够,要么降序列长度,要么降批大小,要么用量化 KV Cache。
# vLLM 启动示例,针对 MoE 模型调整 python -m vllm.entrypoints.openai.api_server \ --model /path/to/kimi-k3-awq \ --tensor-parallel-size 2 \ --gpu-memory-utilization 0.86 \ --max-model-len 8192 \ --max-num-batched-tokens 4096 \ --quantization awq \ --dtype float16 \ --port 8000--max-num-batched-tokens控制一个批次里最多处理多少 token。这个值越大,吞吐越高,但延迟也会增加。我一般会从 2048 开始试,逐步往上加,观察 P95 延迟的变化。如果 P95 延迟还在可接受范围内,就继续加;一旦超过阈值,就回退一档。
4. 采用度追踪的实操流程:从数据采集到成本核算
4.1 埋点与指标采集的具体做法
做采用度追踪,第一步是把数据采上来。我的做法是在 API 网关层做统一埋点,而不是在每个调用方那里分别记录。网关层能拿到最完整的信息:请求时间、模型名称、输入 token 数、输出 token 数、首 token 延迟、总延迟、状态码、调用方标识。这些字段足够支撑后续所有分析。
具体实现上,我用了一个轻量的中间件,在请求进入时打上时间戳,在响应返回时计算延迟并记录 token 数。token 数可以从 vLLM 的响应里直接拿,它在 usage 字段里会返回 prompt_tokens 和 completion_tokens。如果用的是流式输出,首 token 延迟需要单独计算,就是在收到第一个 chunk 时记录时间差。
数据落地我选了 ClickHouse,因为写入量大、查询模式固定,用列式存储很合适。每天几百万条记录,ClickHouse 压缩后占不了多少空间,查询聚合也快。如果量不大,用 PostgreSQL 或者直接写日志文件再离线分析也行,不必一上来就上重型方案。
4.2 首 token 延迟与 P95 延迟的解读
首 token 延迟是用户体验的核心指标。用户发出请求后,等第一个字出来要多久,直接决定了他是继续等还是直接关掉。对于 MoE 模型,首 token 延迟受几个因素影响:路由决策时间、专家加载时间(如果专家不在显存里)、KV Cache 分配时间、以及排队时间。
我这一周的数据里,vLLM 在并发 16 的情况下,首 token 延迟中位数在 180ms 左右,P95 在 420ms 左右。SGLang 因为前缀缓存的原因,在重复提示词场景下中位数能压到 120ms,但 P95 反而略高,因为它的调度策略在突发流量下不如 vLLM 平滑。Ollama 的中位数在 350ms 左右,P95 超过 1 秒,差距很明显。
P95 延迟比中位数更能反映问题。如果中位数很好但 P95 很差,说明大部分请求很快,但有一小部分请求特别慢。这通常是因为长序列请求、专家路由冲突、或者显存碎片导致的。排查时我会把 P95 那部分请求单独捞出来,看它们的输入长度分布、调用时间分布,往往能定位到具体原因。
4.3 成本核算:每千 token 到底花多少钱
成本核算这块,很多人只算 GPU 租用费用,忽略了其他开销。我的算法是:总成本 = GPU 小时费用 + 存储费用 + 网络费用 + 运维人力分摊。然后除以总 token 数,得到每千 token 成本。
以一张 A100 为例,按需价格大约每小时 3 到 4 美元。如果一周跑了 100 小时,那就是 300 到 400 美元。这一周总共处理了 5000 万 token,那每千 token 成本大约是 0.006 到 0.008 美元。这个数字看起来很小,但如果你的业务量是几十亿 token,那就是几万美元的差距。
对比 OpenRouter 这类聚合平台,它们的定价通常按每百万 token 计算,不同模型价格差异很大。用 OpenRouter 的好处是不用自己维护基础设施,按量付费,适合流量波动大的场景。但缺点是数据要经过第三方,对数据敏感的业务不太合适。而且国内访问 OpenRouter 的稳定性和支付方式也是需要考虑的问题,这个后面会细说。
| 成本项 | 计算方式 | 本周实测值 |
|---|---|---|
| GPU 小时费用 | 卡数 × 小时数 × 单价 | 约 320 美元 |
| 存储费用 | 模型权重 + 日志存储 | 约 15 美元 |
| 网络费用 | 出站流量计费 | 约 8 美元 |
| 总 token 数 | 输入 + 输出 | 约 5200 万 |
| 每千 token 成本 | 总成本 / 总 token 数 × 1000 | 约 0.0066 美元 |
4.4 周报模板与趋势对比方法
每周追踪的产出是一份简洁的周报。我的模板固定包含几个部分:本周总调用量及环比、首 token 延迟中位数及 P95、每千 token 成本及环比、异常事件记录、下周优化计划。环比数据很重要,单看绝对值看不出问题,只有对比才能发现趋势。
趋势对比我一般看四周移动平均,而不是只看上周。因为单周数据可能受偶发事件影响,四周平均更能反映真实走向。如果四周平均连续上升,那就说明有系统性问题,需要深入排查。如果只是单周跳变,先看看是不是有一次性活动或者异常请求。
5. 常见问题与排查技巧实录
5.1 显存溢出与专家路由冲突
MoE 模型最常见的报错就是显存溢出。但有意思的是,它往往不是模型权重放不下,而是 KV Cache 或者专家路由的临时缓冲区爆了。我遇到过好几次,模型加载正常,跑了几十个请求之后突然 OOM。排查下来发现是某些请求路由到了同一批专家,导致那部分专家的计算队列堆积,临时激活值占用飙升。
解决办法有两个方向。一是限制单批次的专家并发数,在 vLLM 里可以通过调整--max-num-seqs来间接控制。二是给专家路由加一点随机性,避免大量请求同时命中同一组专家。有些框架支持专家并行策略配置,可以把热门专家复制多份,分散负载。
提示:如果 OOM 发生在运行一段时间之后而不是启动时,优先怀疑 KV Cache 碎片和专家路由堆积,而不是模型权重本身。
5.2 首 token 延迟突然飙升的排查路径
首 token 延迟突然从 200ms 涨到 2 秒,这种问题最让人头疼。我的排查顺序是这样的:先看是不是所有请求都慢,还是只有部分慢。如果全部慢,检查 GPU 利用率和显存占用,看是不是有别的进程在抢资源。如果部分慢,看这些请求的共同点,比如输入长度、调用时间、调用方。
有一次我发现延迟飙升是因为某个调用方开始发送超长系统提示词,每条请求的输入都超过 4000 token,导致 KV Cache 分配变慢。后来给这个调用方单独做了前缀缓存,问题就解决了。还有一次是因为磁盘 IO,模型权重放在机械硬盘上,专家加载时读盘慢,换成 SSD 之后恢复正常。
5.3 OpenRouter 国内使用的现实问题
OpenRouter 作为一个模型聚合平台,确实方便,一个 API 就能调不同厂商的模型。但国内使用它有几个现实障碍。首先是网络连通性,直连经常不稳定,需要额外的网络配置。其次是支付,它主要支持国际信用卡,国内用户充值不太方便,有人会问能不能用支付宝,目前来看官方并没有直接支持。
如果你确实需要用 OpenRouter 做对比测试或者作为备用通道,我的建议是把它当作补充而不是主力。主力还是用自己的 vLLM 或者 SGLang 部署,可控性强,数据也不出本地。OpenRouter 可以用来跑一些你不常的模型,做效果对比,或者在你自己的服务出故障时临时顶一下。
| 问题现象 | 可能原因 | 排查方法 | 解决方向 |
|---|---|---|---|
| 运行中 OOM | 专家路由堆积、KV Cache 碎片 | 看 OOM 时间点、请求分布 | 限制并发、调整路由策略 |
| 首 token 延迟飙升 | 长输入、磁盘 IO、资源竞争 | 按输入长度分组对比 | 前缀缓存、换 SSD、隔离资源 |
| 吞吐量上不去 | batch size 太小、并行度不当 | 逐步调大 batch 观察 | 调 max-num-batched-tokens |
| 输出质量下降 | 量化精度损失 | 对比原始模型输出 | 换量化方案或提高精度 |
5.4 量化后精度下降的补偿手段
4bit 量化之后,模型在某些任务上确实会变笨,尤其是需要精细推理或者长链条逻辑的任务。我的补偿手段有几个。一是对关键任务保留高精度版本,比如用 8bit 或者 FP16 跑核心业务,用 4bit 跑边缘业务。二是在提示词里加一些引导,让模型更明确地按步骤思考,减少量化带来的随机性。三是做输出后校验,对格式要求严格的字段做规则检查,不合格就重试。
实测下来,4bit AWQ 在分类、摘要、抽取这类任务上,和原始模型的差距很小,基本可以忽略。但在数学推理、代码生成这类任务上,差距就比较明显了。所以量化方案的选择要结合具体业务,不能一刀切。
6. 这一周追踪下来的个人体会
跑完这一周的追踪,我最大的感受是,MoE 模型的推理优化空间比稠密模型大得多,但也更复杂。稠密模型你调来调去就是 batch size、序列长度那几个参数,MoE 则多了一层专家路由的维度。同样的硬件,路由策略调得好和调得差,吞吐量能差出一倍。
另一个体会是,追踪这件事本身要轻量化。我见过有人搞了一套特别复杂的监控系统,结果维护监控系统的时间比优化模型的时间还多。我的做法是,核心指标就那几个,采集链路尽量短,报表尽量简单。数据准比数据多重要,能指导决策比好看重要。
最后说一个容易被忽略的点:每周追踪一定要留出时间做对比实验。不要只盯着生产环境的数据,每周花一两个小时,在测试环境跑一组对照实验,比如换个量化方案、调个参数、试试新版本的推理框架。这些实验的结果可能不会立刻反映在周报里,但积累几周之后,你会对什么配置适合什么场景有非常清晰的判断。这种判断力,是任何文档都给不了的。