跳转至

模型推理与部署

模型推理与部署

模型训练完之后,剩下的问题全在推理:用户点击发送,到看见第一个字,中间发生了什么?为什么长文生成那么慢?为什么"1 万并发"那么贵?本文从机制讲起——两阶段推理、KV Cache、批处理、量化、MoE,最后落到产品视角的延迟-成本-吞吐三角。本文讲机制;怎么选供应商、怎么算账,分别见 LLM API 与供应商LLM 成本测算

推理的两阶段

大模型生成一段回答,内部经历两个计算特征完全不同的阶段:

预填充(Prefill)

  • 一次并行处理完整输入(prompt),算出每个位置的隐藏状态,建立初始 KV Cache;
  • 计算量大(输入越长越大),但并行度高,GPU 利用率好;
  • 决定首 token 延迟(TTFT,Time To First Token)——用户"看到第一个字"要等多久。

解码(Decode)

  • 逐 token生成:每步只处理一个新 token,串行进行;
  • 每步矩阵很小但要读取全部历史 KV Cache 和模型权重,瓶颈常在显存带宽而非算力;
  • 决定生成速率(TPOT,相邻 token 间隔)——用户"看到后面的字"多快。

两阶段的计算特征对比

阶段并行度计算特征主要瓶颈体验指标
Prefill高(序列维度并行)大矩阵乘,随输入长度近似平方增长计算量、长序列注意力TTFT
Decode低(时间上串行)每步小矩阵,读取权重 + 全部 KV Cache显存带宽、调度TPOT / TPS

为什么解码慢

训练时 GPU 可以并行处理整段文本;推理时下一个 token 依赖前一个 token 的输出,时间上无法并行。单请求的生成延迟 ≈ 输出长度 × 每 token 耗时,所以"写 2000 字"天然比"写 50 字"慢一个量级——这不是网络问题,是自回归机制决定的。

工程应对

  • Chunked Prefill:把超长输入切块处理,避免一个长 prompt 独占 GPU 太久、阻塞其他请求的 Decode;
  • Prefill/Decode 分离部署:两种阶段的资源需求完全不同(一个要算力、一个要带宽),生产上可以拆成两套服务分别扩缩容;
  • TTFT 与生成速率分开优化:TTFT 高 → 压 prompt 长度、上提示词缓存;生成慢 → 量化、批处理、投机解码。先定位是哪个指标差,再对症下药,不要"换更大的模型"一刀切。

从请求到响应:完整链路

一次 API 调用在推理服务内部经历的完整链路,按顺序排查问题就靠它:

1
2
3
4
用户请求 → 排队(调度器分配槽位)
→ Tokenizer 编码 → Prefill(并行处理输入,建立 KV Cache)→ 首个 token 返回
→ Decode 循环(逐 token:读 KV Cache → 计算 → 采样 → 追加缓存 → 流式推送)
→ 停止条件触发 → Tokenizer 解码 → 结束

对应地,用户感知的延迟可以拆成四段:排队时间 + Prefill 时间(决定 TTFT)+ 生成时间(输出长度 × TPOT)+ 网络传输。产品侧排查延迟问题,先问"哪一段慢"——排队慢是容量问题(加卡/错峰),TTFT 慢是输入太长(压 prompt/缓存),生成慢是模型太大或带宽受限(量化/小模型),只盯着总延迟数字会误判。

KV Cache

缓存已算的 Key/Value

生成第 t 个 token 时,注意力机制需要让新 token 的 Query 与所有历史 token 的 Key/Value 做计算。历史 token 的 K/V 一旦算过就不会变——所以推理引擎把每层的 K/V 存下来(KV Cache),每步只算新 token 的 K/V 并追加,避免重复计算整个前缀。没有 KV Cache 的话,生成 1000 token 要重算约 50 万次前向,完全不可用。

为什么只缓存 K/V 不缓存 Q?因为历史的 Q 只服务于它自己当时的查询;未来步骤需要的是"历史位置可以被匹配的 K"和"可以被取回的 V",Q 用不上了。

显存估算

KV Cache 的显存 ≈ 2(K 和 V)× 层数 × KV 头数 × 单头维度 × 已缓存 token 数 × 每元素字节数。举个算例:32 层、8 个 KV 头、单头维度 128、BF16(2 字节)的模型,每个 token 的缓存 ≈ 32 × 2 × 8 × 128 × 2 ≈ 128 KiB

  • 单请求上下文 8K token → 约 1 GB;
  • 并发 100 请求 → 约 100 GB——显存瞬间吃光。

为什么显存吃紧

KV Cache 是长上下文 × 大模型 × 高并发的三重乘积:

  • 上下文 100 万 token 的模型,单条请求的 KV Cache 可达数 GB;
  • 并发 100 个请求就要 100 份缓存;
  • 权重占显存是固定的,KV Cache 却随请求动态增长——并发上限往往不是算力决定的,而是 KV Cache 显存决定的

相关优化

优化思路效果
MQA/GQA多个 Query 头共享同一组 K/V 头缓存缩到原来的几分之一(架构层面)
PagedAttentionKV Cache 分页管理,按需分配消除预留浪费与碎片,提并发(见「吞吐优化」)
KV Cache 量化缓存用 INT8 存储显存再砍一半,质量影响通常小
窗口/淘汰只保留最近 N 个 token 的缓存适合流式对话,放弃超远历史
MLA把 K/V 压缩到低维潜空间再投影DeepSeek 系架构,缓存大幅缩水

采样与解码策略

大模型基础 讲过 temperature/top-p/top-k,这里补全解码侧的完整图景:

策略机制场景
贪心每步取概率最高 token结构化抽取、要求可复现
温度采样按缩放后的概率随机抽取对话、创作(配合 top-p/top-k)
束搜索(beam search)同时保留若干高分候选序列翻译、摘要等追求整体序列质量
结构化约束解码限制每步候选必须符合语法(如 JSON Schema)工具调用、结构化输出

停止条件

生成何时停?常见停止条件:生成结束符(EOS)、命中停止序列(stop strings)、达到 max_tokens 上限、结构化解码器确认语法已闭合、业务主动中止(超时、用户打断)。模型"说完一句话"不会天然停止——话痨、截断、停不下来这些问题,一半是停止条件没设好。

参数推荐与常见坑

  • 默认值只是起点:temperature 0.7 + top_p 0.9 是通用起点,事实类任务直接降到 0-0.3,不要怕"单调";
  • 重复惩罚别乱加:frequency penalty 对"车轱辘话"有效,但加多了会让模型回避常用词,输出变得怪异;
  • max_tokens 设大不如设对:按业务真实输出长度分布设上限,防止话痨烧钱,也防止长回答被硬截断;
  • 种子 ≠ 完全可复现:固定 seed 减少随机性,但并行服务与浮点实现的差异仍可能造成不一致,别把它当测试铁律;
  • 结构化任务用约束解码:需要合法 JSON/SQL/函数参数时,用结构化约束解码而不是祈祷模型自觉。

结构化约束解码

结构化约束解码(constrained decoding)值得单独强调:它不是"提示词要求输出 JSON"(那只是请求,模型可能不听话),而是在解码每一步时屏蔽不符合语法的 token,从机制上保证输出一定合法。工具调用、Agent 流程、数据管线里这是标配,能消灭一整类"解析失败"的 bug(见 Agent 与工作流)。

吞吐优化

三种批处理方式

方式组批时机优点局限
静态批处理运行前固定实现简单被最长请求拖死,padding 浪费多
动态批处理等短窗口凑一批矩阵规模大等待窗口增加排队延迟
连续批处理token 粒度动态调度空槽即插即走,吞吐最高状态与 KV Cache 管理复杂

早期推理是静态批处理:一批请求等最慢的生成完才整体退出,短的被长的拖死。连续批处理(Continuous Batching)在 token 粒度上调度:谁生成完了谁退出,新请求随时补进来,GPU 空槽被填满。这是 vLLM 等生产引擎吞吐碾压早期方案的核心原因。批越大吞吐越高,但单个请求的排队延迟(TPOT)会变差——引擎要在吞吐与延迟之间设调度阈值(如限制最大 batch token 数)。

PagedAttention

PagedAttention 解决的是 KV Cache 的显存管理问题(不是把注意力算得更好):借鉴操作系统虚拟内存,把 KV Cache 切成固定大小的"页",每个请求按需分配、物理上不要求连续,生成完了释放。收益:消除"按最大长度预留"的浪费与外部碎片,支持请求动态增长,显著提高单卡可容纳的并发数。FlashAttention 优化算子 IO、PagedAttention 优化缓存管理,两者可同时使用。

并发上限

并发能力由权重显存 + KV Cache 显存 + 批处理效率共同决定:单卡能同时服务多少请求,主要看 KV Cache 还剩多少显存。长上下文请求会剧烈压缩并发——这是"1M 上下文 API 很贵"的机制原因之一。

流式输出与体感

解码本来就是逐 token 的,服务端用 SSE(Server-Sent Events) 边生成边推送,用户首字等待 = TTFT 而非完整生成时间。对对话产品这是决定性的体验优化:长回答从"转圈 20 秒"变成"1 秒出字 + 逐字输出"。代价是内容安全审核要改为流式分段审核、中断续传要处理。

投机解码(Speculative Decoding)

投机解码的思路:让一个小模型先"打草稿"生成一串候选 token,大模型一次性并行校验——草稿对了就跳过计算,错了再从错处重来。数学上不改变输出分布(采样等价),实践中解码速度可提升约 2 倍(效果因模型与硬件而异)。生产引擎(vLLM/SGLang)已内置支持。

提示词缓存(Prompt Caching)

LLM 的输入里通常有大量重复前缀:系统提示词、知识库片段、多轮对话历史。提示词缓存把已计算过的前缀 K/V 存下来,相同前缀的请求直接复用,省掉重新 Prefill 的计算与时间。计费上命中缓存的部分按折扣价计费(各厂商折扣不同,缓存输入通常比原价低一个量级,以官方定价页为准)。产品侧的配合:把固定内容放在 prompt 前缀并保持字节级一致(别在开头插时间戳、随机串),持续吃折扣——这是成本优化的第一杠杆(见 LLM 成本测算)。

量化

量化:用更低精度的数字表示权重,换取显存下降与(部分场景)速度提升。

精度每参数字节相对 FP16 显存质量影响
FP16 / BF162 字节1 倍(基线)
INT81 字节约一半通常可忽略,敏感任务需验证
INT40.5 字节约四分之一小模型与数学/代码任务可能明显掉点

要点:

  • 显存收益确定,速度收益看硬件:INT4 让 70B 模型从"要 140 GB"降到"约 35 GB",单卡可跑;但若硬件没有高效的低精度算子,量化后反而可能变慢(要反量化回高精度计算);
  • 质量影响与模型大小反相关:模型越小、任务越敏感(数学、代码、长文档),量化掉点越明显——"能跑"不等于"能打";
  • KV Cache 也可以量化(INT8 缓存),进一步省显存、提并发,与权重量化叠加;
  • BF16 是训练与推理的现代基线:指数位多、数值稳定,与 FP16 同为 2 字节但不易溢出;
  • 量化选型顺序:先 INT8 看质量,能接受再上 INT4;数学/代码/长文档场景务必用同一评测集做量化前后对比(评测方法见 评估与评测)。

量化格式与工具

实际部署中量化格式和工具链要匹配:GGUF 是 llama.cpp/Ollama 生态的格式(本地首选);AWQGPTQ 是 vLLM/SGLang 生产环境的常见格式(按模型与推理引擎的支持选);部分新引擎还支持 FP8(H 系列 GPU 原生加速)。注意:同一模型在不同格式下的质量与速度差异可能不小,别只看"多少 bit"就下结论——用你的任务实测。

稀疏化与 MoE

专家混合(MoE)

MoE(Mixture of Experts,专家混合) 把模型的 FFN 层替换成多个"专家"子网络,每次由路由网络(Router)为每个 token 挑选少量专家计算。代表:Mixtral 8x7B(总参数约 47B,每 token 激活约 13B)、Qwen3-MoE、DeepSeek V3。

激活参数 vs 总参数

  • 总参数:所有专家 + 共享层,决定存储与显存
  • 激活参数:每个 token 实际经过的参数,决定单 token 算力与成本

MoE 的价值是"用总参数买容量,用激活参数控制开销"——总参数 47B 的 Mixtral,推理成本接近 13B 的稠密模型,能力却强得多。比较模型时必须说明是总参数还是激活参数,否则"谁更大"没有意义。

对部署的意义

  • 权重全部要存:MoE 模型总参数大,单卡放不下,需要多卡切分(专家并行),小显存设备跑不了;
  • 低并发下优势不明显:请求太少时每个专家收到的 token 少,GPU 利用率低,稠密模型可能反而更稳;
  • 路由带来跨卡通信(all-to-all)开销,部署比稠密模型复杂;
  • 路由还可能负载不均:热门专家过载、冷门专家闲置,需要负载均衡策略(辅助损失、容量因子、共享专家)。

私有化部署

本地运行时与生产引擎

工具定位特点
Ollama本地运行与管理(个人/原型)一条命令跑模型、HTTP API、跨平台,适合试用
llama.cpp底层推理库(GGUF 格式)极省资源、CPU 也能跑,量化生态成熟
vLLM生产级高吞吐引擎连续批处理 + PagedAttention,OpenAI 兼容 API
SGLang生产级推理引擎高吞吐、结构化生成优化,Agent/RL 场景友好

OpenAI 兼容 API 是事实标准:vLLM/SGLang 都提供 /v1/chat/completions 格式接口,业务代码可以"换底座不换代码"——先 Ollama 本地跑通原型,再 vLLM 上生产,这是开源模型落地的最短路径。

部署决策:API vs 本地

维度云 API私有化部署
数据数据出域(留存策略各异)数据不出域,合规可控
成本按量付费,有缓存/错峰折扣固定算力成本,规模化后边际成本低
能力旗舰模型,持续更新开源模型,自己跟进版本
运维零运维自担 GPU、监控、扩缩容、升级

GPU 显存估算公式

1
显存 ≈ 权重(参数量 × 精度字节)+ KV Cache(并发 × 长度 × 层数 × 头维度)+ 激活(少量工作区)

权重是固定大头:7B 模型 FP16 约 14 GB,INT4 约 3.5 GB;70B 模型 FP16 约 140 GB,INT4 约 35 GB。

单卡显存可跑规模(INT4 量级)典型卡
8 GB1-3BRTX 3060/4060
16 GB7-8BRTX 4080/4090 Laptop
24 GB13-14B,或 32B 勉强RTX 4090
48 GB32B 舒适、70B 可跑A6000/L40S
80 GB70B BF16A100/H100

上表为"权重放得下"的量级参考,不代表跑得快——要同时算 KV Cache 余量与解码带宽;具体以实测为准。开源权重各自的许可证也要查清楚(Qwen 系 Apache 2.0 可商用、Llama 系需 Meta 许可门控等),"能下载"不等于"能商用"。

私有化部署的典型演进路径

不追求一步到位,按业务阶段演进:

1
2
3
4
5
个人试用:Ollama / llama.cpp 单机跑通,验证模型可行性
→ 原型验证:同一模型 + OpenAI 兼容 API,业务代码不换接口
→ 小规模生产:vLLM / SGLang 单机多卡,量化 + 连续批处理
→ 规模化:多机集群 + 负载均衡 + 监控告警 + 版本管理
→ 可选:API + 本地混合,本地扛量大场景,API 兜底最难任务

关键决策点:接口抽象在第一天就做(OpenAI 兼容 API),否则后面每换一次引擎/模型都要改业务代码;量化与评测同步做,别先量化后才发现任务掉点。

规模化成本

1K 并发的量级推演:假设每请求平均 2000 输出 token、TPOT 20 ms(约 50 token/s/请求),需要服务端合计约 5 万 token/s 的输出吞吐;一张 H100 跑 7B 级模型的实测输出吞吐在万级 token/s,意味着需要数张到十余张卡(70B 级则要更多),再叠加冗余与弹性。真实数字受模型、量化、输入长度、批大小影响极大,上线前必须用真实流量压测。省钱思路:小模型路由扛常规量、量化 + 缓存 + 批处理压单价、错峰与批处理折扣(见 LLM API 与供应商LLM 成本测算)。

压测口径

性能数字可比的前提是口径统一:硬件型号、模型与精度、输入长度分布、输出长度分布、并发数、流式与否、统计口径(平均还是 P95/P99)、冷启动还是稳态——脱离负载分布的"峰值 TPS"没有意义。报告性能时把这八项写清楚,否则数字不可比。

产品视角

延迟-成本-吞吐三角

推理侧存在一个不可能三角:延迟低、吞吐高、成本低,三者只能取其二

  • 要低延迟(对话、助手)→ 减少批大小、用更贵的大卡 → 单位成本上升;
  • 要高吞吐(批处理、离线)→ 加大批、排队 → 延迟上升;
  • 要低成本 → 小模型/量化/排队 → 能力或延迟让步。

产品经理的功课不是追求"每一项都最好",而是明确产品对三角的优先级:实时对话要延迟,离线分析要吞吐,创业期要成本。配套的监控指标:TTFT、TPOT、P95/P99 延迟、吞吐(token/s)、GPU 利用率、KV Cache 显存水位、单请求成本——上线后按月复盘,指标恶化先定位到阶段(排队?Prefill?Decode?显存?)再动刀。

常见故障排查表

症状优先检查常见根因
首 token 慢排队、Prefillprompt 过长、缓存未命中、并发超卖
首字快但后续慢Decode、KV 读取批太大、带宽瓶颈、模型太大
吞吐低、GPU 空转调度、批处理静态批处理、小请求碎片、Tokenizer 在 CPU 上
OOM 随并发增长KV Cache长上下文 + 高并发、未用 PagedAttention
量化后变慢Kernel 支持硬件无低精度算子、格式不匹配
输出乱码/角色串线Tokenizer、模板模型与 tokenizer 不匹配、EOS 错误
结果变差上下文、采样、模型检索错误、温度过高、模型更新漂移

排查顺序口诀:先固定输入复现 → 区分质量问题还是性能问题 → 性能再拆排队/Prefill/Decode/显存 → 单请求基线 → 逐步加压 → 只改一个变量

延迟预算分配:从 SLA 反推架构

产品要求"用户点击到首字 ≤ 1.5 秒,P95"。预算拆分:网络 200 ms + 排队 300 ms + Prefill 500 ms + Tokenizer 与调度 200 ms,还剩约 300 ms 余量。反推:输入 prompt 必须控制在 2K token 以内(否则 Prefill 超预算)→ 长文档走 RAG 摘要而非全文塞入 → 用提示词缓存把系统提示与历史前缀命中;并发峰值时排队超预算 → 加容量或降级到快模型。延迟是设计出来的,不是测出来的——从 SLA 反推每一段的预算,架构决策才有依据。

把"等模型"移出用户关键路径

模型生成是慢动作(秒级),用户等待是最贵的体验损耗。三个成熟手段:

  1. 异步化:生成不阻塞用户——任务进队列,完成后推送/轮询结果(如报告生成、批量分析),用户该干嘛干嘛;
  2. 预生成:高频问答、常见场景提前生成缓存结果,命中直接返回(应用层缓存,连模型都不用调);
  3. 分层:简单请求走快模型/低 effort,复杂请求才上旗舰/高 effort——把"重计算"留给真正需要的 10%(路由做法见 模型能力与选型)。

与相关页面的分工

页面回答什么
本文(llm-inference)推理的机制:为什么慢、为什么贵、怎么优化
LLM API 与供应商怎么:供应商、模型、API 参数、评测清单
LLM 成本测算怎么算账:单次成本、月预算、降本杠杆
模型训练与对齐模型侧的另一半:训练、微调、对齐

来源说明

本文为原创整理,综合以下资料撰写,访问验证日期 2026-08-23;推理引擎与价格变动频繁,以官方页面为准。

  1. AIGC-Interview-Book「大模型基础(精华版)」:模型架构与工作原理(Prefill/Decode、KV Cache、批处理、量化、MoE 章节)(预取参考材料)
  2. vLLM:连续批处理、PagedAttention 与高吞吐推理
  3. SGLang:结构化生成与推理优化
  4. Ollamallama.cpp:本地运行时
  5. DeepSeek-R1:MoE 与蒸馏部署案例
  6. 站内关联:大模型基础模型训练与对齐模型能力与选型LLM API 与供应商LLM 成本测算