# 模型推理服务 架构模板 > **代表产品 / 原型**:vLLM、SGLang、NVIDIA Triton、HuggingFace TGI、Ray Serve > **一句话定位**:在 GPU 上把大模型跑起来对外提供服务,靠连续批处理、KV 缓存分页等手段,把昂贵的 GPU 算力榨到最高吞吐、最低延迟。 --- ## 1. 一句话定位 模型推理服务 = **一台围着 GPU 转的「吞吐榨取机」**。它的全部使命就一句话:**把 GPU 喂饱、用满、用省。** 它其实是 [AI 对话产品模板](../ai-chat-product/README.md) 里那个「推理服务」组件的**放大特写**。当你不满足于调别人的 API、要自己跑开源 / 私有模型时,你面对的就是这台机器:输入是「模型权重 + 一堆 prompt」,输出是「源源不断的 token」,而中间最难的事,是**让一块几万块的 GPU 一刻都别空转**。 ## 2. 业务本质:它在解决什么问题 它把「一个训练好的模型文件」变成「一个能扛并发、低延迟、高吞吐的在线服务」。 **为什么它值得单独成一类系统?** 因为它的成本结构极端反常: > 普通服务「多一个请求几乎不要钱」;推理服务**每生成一个 token 都在烧 GPU 时间**。GPU 又贵又缺,所以「**单位 GPU 每秒能生成多少 token**」直接等于毛利率。整套架构就是围绕这个数字做优化。 ## 3. 核心需求与约束 **功能性需求:** - [ ] 加载模型权重到显存 - [ ] 接收请求、批处理推理、**流式**逐 token 输出 - [ ] KV 缓存管理(自回归生成的中间状态) - [ ] 多副本 / 多模型服务 - [ ] (可选)量化、前缀缓存、多卡并行 **非功能性需求 / 质量属性:** | 质量属性 | 目标 | 为什么对这类系统重要 | |---|---|---| | **吞吐(tokens/s/GPU)** | 越高越好 | 直接决定单卡服务人数和成本 | | **首字延迟 TTFT** | < 1s | 用户等第一个字的时间 | | **单 token 延迟 TPOT** | 低且稳 | 决定「读起来流不流畅」 | | **GPU 利用率** | 拉满 | 空转就是烧钱 | | **显存效率** | 越省越好 | 显存是硬上限,省下来能服务更多人 | **关键约束(不可逾越的边界):** - 🔴 **GPU 贵且缺**:头号约束,一切为它的利用率服务。 - 🔴 **推理是有状态的自回归**:生成第 N 个 token 依赖前面所有 token 的中间结果(KV cache),这块**狂吃显存**。 - 🔴 **显存是硬上限**:KV 缓存 + 权重塞满显存后,就服务不了更多并发了。 - 🔴 **吞吐与延迟天然矛盾**:batch 越大吞吐越高,但单请求延迟也越高。 ## 4. 架构全景图 ``` 多个请求(长短不一) ▼ ▼ ▼ ▼ ┌─────────────────────────────────────────────────────────────┐ │ 调度器(Scheduler)—— 灵魂所在 │ │ • 请求排队 │ │ • 【连续批处理】:每一步动态组批,完成的请求立刻出批、 │ │ 新请求立刻进批,不让 GPU 等"最慢的那个" │ └───────────────────────────┬─────────────────────────────────┘ ▼ ┌─────────────────────────────────────────────────────────────┐ │ GPU 执行引擎 │ │ ┌───────────────┐ ┌─────────────────────────────────┐ │ │ │ 模型权重(显存) │ │ KV 缓存(分页管理,像 OS 虚拟内存) │ │ │ └───────────────┘ └─────────────────────────────────┘ │ │ 每一步算出一批 token ──▶ 逐 token 流式吐回 │ └───────────────────────────┬─────────────────────────────────┘ ▼ 模型权重启动时从对象存储加载进显存 ◀══ 流式返回 token ══ ``` > 灵魂部件是**调度器**:它决定了 GPU 是「满负荷连轴转」还是「等一个人写完大家干等」。连续批处理把后者变成前者,这一个决定能让吞吐翻好几倍。 ## 5. 组件职责 - **调度器(Scheduler)**:管理请求队列,**每个生成步都动态重组批次**(continuous batching)。*为什么需要*:这是 GPU 利用率的总开关——见决策 1。 - **KV 缓存管理**:为每个在途请求管理它的 KV cache,用**分页**(PagedAttention)避免显存碎片。*为什么需要*:KV 缓存吃显存且大小动态变化,粗放分配会浪费大量显存——见决策 2。 - **GPU 执行引擎**:真正跑模型前向计算、采样出 token。*为什么需要*:核心算力所在。 - **权重加载**:把几十~上千 GB 的模型文件从对象存储加载进显存。*为什么需要*:模型太大,启动时一次性载入。 - **(可选)前缀缓存**:复用相同前缀(如系统提示)已经算过的 KV。*为什么需要*:省掉重复计算,和 prompt 缓存同源。 - **路由 / 多副本**:把请求分发到多个 GPU 副本。*为什么需要*:单卡撑不住时水平扩。 ## 6. 关键数据流 **场景一:连续批处理(这台机器最核心的魔法)** ``` 传统【静态批处理】: 攒齐 8 个请求 → 一起算 → 必须等最慢(生成最长)的那个写完 → 整批才结束 ✗ 短请求早就算完了,却被迫陪着空等 → GPU 大量空转 【连续批处理】: 每生成一步,就检查:谁写完了?→ 立刻请它出批、把新请求填进来 ✓ GPU 每一步都在满负荷干活,没有"陪等" → 吞吐翻数倍 ``` **场景二:一次流式生成** ``` 1. 请求入队 ──▶ 调度器把它编入当前批次 2. 为它在 KV 缓存里分配分页块(prefill 阶段:处理输入 prompt) 3. 逐步生成(decode 阶段):每步算出下一个 token ──▶ 立刻流式吐回 4. 命中 EOS 或达到上限 ──▶ 该请求出批,释放它的 KV 缓存页给别人用 ``` ## 7. 数据模型与存储选择(本质是显存布局) 这类系统的「数据」主要活在**显存**里,而不是数据库。 | 数据 | 放在哪 | 为什么 | |---|---|---| | 模型权重 | 对象存储 → 加载进显存 | 大、不可变、启动时载入 | | KV 缓存 | 显存(分页块) | 自回归生成的中间态,极吃显存,要精细管理 | | 请求 / 批次状态 | 内存 | 高频、易失、随请求生灭 | | 前缀缓存 | 显存 / 内存 | 复用热点前缀的计算结果 | > 教学点:推理服务的「存储难题」不在磁盘,而在**显存**——怎么在有限显存里塞下尽可能多的并发请求的 KV 缓存,是它和普通系统最不一样的地方。 ## 8. 关键架构决策与权衡 ⭐ **决策 1:静态批处理,还是连续批处理?(吞吐的总开关)⭐** - 静态批处理:攒一批一起算、一起结束。简单,但**短请求被长请求拖着空等**,GPU 利用率低。 - 连续批处理:每步动态进出批。 - **取向**:必选连续批处理。代价是调度复杂,但 GPU 利用率和吞吐的提升是数量级的。 **决策 2:KV 缓存——连续分配还是分页?⭐** - 给每个请求预留一大块连续显存:简单,但请求长度不确定,会产生大量**显存碎片**和浪费。 - 分页(PagedAttention):像操作系统管虚拟内存那样,把 KV 缓存切成小块按需分配。 - **取向**:分页。它借用了 OS 的成熟智慧,大幅提升显存利用率、支持更高并发。 **决策 3:吞吐 vs 延迟,怎么平衡?** - 大 batch:吞吐高,但单请求延迟(尤其尾延迟 P99)被拉高。 - 小 batch:延迟低,但 GPU 没喂饱、吞吐低、成本高。 - **取向**:按业务定调——离线批量任务偏大 batch 求吞吐;在线交互偏小 batch 求延迟;高级做法是把 prefill 和 decode 阶段分离调度。 **决策 4:自建推理,还是直接调 API?(MVP 最该想清楚的)⭐** - 调供应商 API:零运维、按量付费,起步最快。 - 自建:用开源 / 私有模型、数据自留、规模大后单 token 更便宜,但要养 GPU 和这套复杂系统。 - **取向**:**先调 API**(经 [AI 网关](../ai-gateway/README.md)),等到「量大到自建更划算」或「必须私有 / 定制模型」时,再自建。 ## 9. 规模化与瓶颈 - **第一个瓶颈:单卡吞吐。** → 破解:连续批处理 + 分页 KV + 前缀缓存,把单卡榨干。 - **第二个瓶颈:模型太大,单卡放不下。** → 破解:多卡并行(张量并行 / 流水线并行),把一个模型切到多张卡上。 - **第三个瓶颈:请求量超过单副本。** → 破解:多副本 + 负载均衡,水平扩。 - **第四个瓶颈:长上下文吃爆显存。** → 破解:分页 KV、量化、上下文压缩。 - **GPU 扩容慢且贵**:不像加 Web 服务器那样秒扩,容量规划要提前。 ## 10. 安全与合规要点 - **多租户隔离**:共享 GPU 的不同租户之间,显存 / 请求要隔离,防数据串味。 - **输入限制**:超长输入会撑爆显存,可被用来做 DoS,要限制长度。 - **模型权重保护**:私有 / 自研模型权重是核心资产,访问要受控。 - **资源配额**:防止单用户占满 GPU 拖垮所有人。 ## 11. 常见误区 / 反模式 - ❌ **用静态批处理** → ✅ 连续批处理,别让 GPU 陪等。 - ❌ **KV 缓存连续大块分配** → ✅ 分页管理,消除显存碎片。 - ❌ **每个请求单独跑(batch=1)** → ✅ 组批,否则 GPU 严重空转、成本爆炸。 - ❌ **盲目追求超大 batch** → ✅ 平衡吞吐与尾延迟。 - ❌ **MVP 就自建 GPU 集群** → ✅ 先调 API,量到了再自建。 ## 12. 演进路线:MVP → 成长期 → 成熟期(不同阶段怎么设置) | 阶段 | 规模量级 | 怎么设置(具体) | 此时该操心什么 | |---|---|---|---| | **MVP** | 验证想法 | **别自建!** 直接调模型供应商 API(经 [AI 网关](../ai-gateway/README.md))。非要本地 / 私有模型时,单卡用 vLLM / TGI 起一个实例 | 先验证产品,别一上来烧 GPU | | **成长期** | 自建上规模 | 自部署 **vLLM / SGLang**:开连续批处理 + 分页 KV + 前缀缓存;量化省显存;多副本 + 负载均衡 | 把单卡吞吐和单 token 成本压到最优 | | **成熟期** | 大模型 / 高并发 | 多卡并行跑大模型、prefill/decode 分离调度、多区域 GPU 池、模型路由(大小模型混用)、自动扩缩容 | 成本、容量规划、容灾、质量与延迟的平衡 | ## 13. 可复用要点 - 💡 **先认清系统真正的「稀缺资源」,围绕它的利用率做架构。** 这里是 GPU,所以一切为「别让 GPU 空转」服务——和 [AI 对话产品](../ai-chat-product/README.md) 同一条心法。 - 💡 **批处理是吞吐的杠杆。** 把多个请求合并计算,是从数据库到 GPU 都通用的提效手段。 - 💡 **善于从其它领域借成熟智慧。** PagedAttention 直接搬了操作系统「虚拟内存分页」来治 KV 缓存碎片——好架构常常是「旧思想用在新问题上」。 - 💡 **缓存重算代价高的东西。** 前缀缓存复用已算的 KV,等同于 prompt 缓存,是省钱的通用招式。 - 💡 **「自建 vs 购买」先算规模账。** 没到规模就自建重型基础设施,是典型的过度设计。 ## 🎯 随堂检验 --- ## 参考原型与延伸阅读 > 本模板基于以下**真实开源项目**与**论文**的架构理念整理。这几个项目就是当今 LLM 推理服务的事实标准,直接读它们最可靠。 **🔧 开源原型(可直接读代码):** - [vllm-project/vllm](https://github.com/vllm-project/vllm) — 高吞吐、省显存的主流 LLM 推理引擎,连续批处理 + PagedAttention 的标杆实现。 - [sgl-project/sglang](https://github.com/sgl-project/sglang) — 高性能服务框架,带 RadixAttention 前缀缓存、零开销调度、prefill/decode 分离。 - [huggingface/text-generation-inference](https://github.com/huggingface/text-generation-inference) — HuggingFace 的推理服务工具包(现处维护模式,仍是理解架构的好样本)。 - [triton-inference-server/server](https://github.com/triton-inference-server/server) — NVIDIA 的通用推理服务器,支持多框架、多模型、动态批处理。 **📖 论文 / 文档:** - [Efficient Memory Management for LLM Serving with PagedAttention (SOSP'23)](https://arxiv.org/abs/2309.06180) — vLLM 背后的论文,讲清「用 OS 分页思想管 KV 缓存」。 - [SGLang: Efficient Execution of Structured LM Programs](https://arxiv.org/abs/2312.07104) — SGLang 论文,RadixAttention 前缀缓存与高吞吐执行。 --- > 📌 一句话记住模型推理服务:**它不是「把模型跑起来」那么简单,而是「一台围着昂贵 GPU 转、靠连续批处理和显存分页把算力榨到极致的精密机器」——所有设计都在回答『怎么让每一块 GPU 每一秒都在满负荷生成 token』。**