对应 Maps to:CMU 11-868 / 11-968 Large Language Model Systems(Spring 2026,Lei Li)课表末尾列出、本学期未排课的主题 App Stack and Model Serving(slides:llmsys-30-serving.pdf,Lei Li,49 页)。 阅读材料:a16z, Emerging Architectures for LLM Applications(2023);NVIDIA Triton Inference Server 文档;Hugging Face Text Generation Inference 文档;LightLLM、MLC LLM 的项目文档;Yu et al. (2022) Orca(OSDI)。 依据说明:slides 两部分。LLM 应用的架构:a16z 的应用栈三段——数据预处理与嵌入(数据管道、嵌入模型、向量数据库)、提示构造与检索(编排框架 LangChain、LlamaIndex)、提示执行与推理(LLM API、托管、LLM 缓存、校验、日志、应用托管);以及用 AI 智能体自动完成任务(AutoGPT)。LLM 服务框架:两个 “Triton”(NVIDIA 的推理服务器 vs OpenAI 的内核语言)、Triton 推理服务器的特点与动态批处理、Triton + LightSeq / TensorRT-LLM / FasterTransformer、Text Generation Inference(TGI)、OpenLLM、MLC LLM、LightLLM(异步的分词 / 推理 / 去分词、Token Attention、高效路由器)。slides 的代码页是”用 docker 启动服务器、发请求”的截图,没有可提取的文字。本讲义的 LLM 缓存实验、动态批处理与路由器的模拟、Token Attention 的对照、本地部署的估算,都是本讲义自己设计的,不代表课堂上讲了什么;时间来自第 26 讲的”纸面 GPU”模型。 配套代码 Code:
code/appendixA1/(4 个脚本 +appserve.py;复用第 19 讲的模型与第 22、24、26 讲的模拟器;都在 3 秒以内) 预计阅读时间:2 小时(含运行代码)
0. 本讲导航 · How to read this lecture
0.1 学习目标 Learning goals
- 画出一个 LLM 应用的”栈”:从数据管道、嵌入、向量数据库、编排,到 LLM 调用、缓存、校验、日志,说出每一层解决什么问题。
- 解释语义缓存为什么省钱又危险,校验层能拦下什么、拦不下什么。
- 用”等多久 vs 批多大”解释 Triton 的动态批处理,并说明为什么它不适合 LLM 生成(需要迭代级批处理)。
- 说出 TGI、OpenLLM、MLC LLM、LightLLM 各自的定位;解释 LightLLM 的 Token Attention 与”未来显存峰值”路由器。
- 估算一个模型在手机、笔记本、显卡上能不能跑、能跑多快。
0.2 先修与本讲范围
| 默认你已经会 | 本讲只给直觉 |
|---|---|
| 连续批处理(第 22 讲)、PagedAttention 与抢占(第 24 讲) | 检索与向量数据库的内部(附加讲 A3) |
| 量化(第 19、20 讲);解码受带宽限制(第 26 讲) | 智能体框架、提示工程 |
0.3 本讲地图
§1 LLM 应用栈:三段、十几个组件 (slides)
§2 应用层的 LLM 缓存与校验 ← 代码 01
§3 通用的模型服务器:NVIDIA Triton 与动态批处理 ← 代码 02
§4 专门的 LLM 服务框架:TGI、OpenLLM、LightLLM ← 代码 03
§5 本地部署:MLC LLM ← 代码 04
§6 怎样选
§7 小结 §8 常见误区 §9 练习 §10 延伸阅读 §11 下一讲预告
1. LLM 应用栈 · The LLM app stack
前面 27 讲都在讲”模型怎样跑得快”。可一个真实的 LLM 应用,模型只是其中一个组件。slides 用 a16z 2023 年的那张图把应用拆成三段:
① 数据预处理与嵌入(离线)
- 数据管道:加载器、解析器、预处理(Databricks、Airflow、Unstructured)——把 PDF、网页、数据库变成干净的文本块;
- 嵌入模型:把文本块变成向量(OpenAI 便宜好用、Cohere 专注嵌入、Hugging Face 的开源模型、自己训的 BERT);
- 向量数据库:为向量的存储与相似度查询优化(Pinecone 全托管、Chroma 本地、Faiss 是 Meta 的库、Weaviate 开源)。
② 提示构造与检索(每个请求)
- 编排框架(LangChain 通用、LlamaIndex 专注检索):把提示链式地组织起来、调用外部 API、从向量数据库取上下文、在多次 LLM 调用之间保持记忆,最后产出一个或一串提示。
③ 提示执行与推理(每个请求)
- LLM API:专有的(OpenAI、Anthropic)或开放的(Hugging Face、Replicate);slides 提醒:公共的聊天服务在生产环境里时延可能不稳定;
- LLM 托管:通用云(AWS、GCP、Azure)或”有主见的云”(Databricks、Anyscale、Mosaic);
- LLM 缓存(Redis、SQLite、GPTCache)、校验(Guardrails、Rebuff、Guidance)、日志(Weights & Biases、MLflow、PromptLayer)、应用托管(Vercel、Steamship、Anyscale、Modal)。
slides 最后提到 AutoGPT:让一个基于 LLM 的智能体自己决定下一步做什么,把结果再喂回提示,迭代地逼近目标。今天的智能体框架是这条路线的延续——对系统而言,它意味着一个用户请求会变成几十次相互依赖的 LLM 调用(第 22 讲 SGLang 的”LLM 程序”、第 26 讲 Dynamo 的 KV 感知路由都是为此设计的)。
这一讲沿着这张图挑几个可以量化的组件:缓存与校验(§2)、模型服务框架(§3–§5)。检索与向量数据库留给附加讲 A3。
2. 应用层的 LLM 缓存与校验 · LLM cache and validation
2.1 两种缓存
同一个问题被反复问——热门的客服问题、反复调用的工具——直接返回上次的答案,就省掉一次 LLM 调用。
- 精确缓存:问题字符串完全相同才命中(Redis、SQLite 当键值存储)。永远不会答错,但”同一个意思的不同问法”命中不了。
- 语义缓存(GPTCache 一类):把问题嵌入成向量,与某个缓存过的问题足够相似(余弦相似度 ≥ 阈值)就返回它的答案。能命中改写,也会把”看起来像、其实不同”的问题当成一样。
注意它和前面几讲的 KV 缓存不同:KV 缓存省的是预填充,答案仍由模型逐 token 生成、完全正确;应用层缓存省的是整个调用,靠”同样的问题应该有同样的答案”这个假设。
2.2 实验
01 号脚本用第 19 讲的城市 LLaMA 同时当”LLM”和”嵌入模型”:问题是城市语言里一句话的前半句(“in boston it is often”),答案是 LLM 贪心给出的下一个词。2000 个问题、40 种意图(4 种句型 × 10 个城市,按 Zipf 分布出现),其中句型 T3 有大量同义改写(“the chefs from boston who cook at night love the” 和 “the artists from boston who sing every day love the” 问的是同一件事)。
| 缓存 | 命中率 | 答错(占全部问题) | LLM 调用 |
|---|---|---|---|
| 不缓存 | 0% | 0% | 2000 |
| 精确匹配 | 77.7% | 0% | 446 |
| 语义匹配,阈值 0.99 | 96.1% | 0% | 78 |
| 语义匹配,阈值 0.95 | 97.0% | 5.7% | 60 |
| 语义匹配,阈值 0.90 | 98.7% | 30.0% | 27 |
| 语义匹配 0.90 + 校验 | 98.0% | 19.4% | 39 |
同一意图的改写在嵌入空间里挤在一起(相似度平均 0.93),所以阈值 0.99 时语义缓存把命中率从 78% 提到 96%、仍然不答错。阈值再低,命中率几乎不涨,错答却迅速增加:答案不同的两个问题里,最像的一对是 “portland has very nice”(答 food)和 “seattle has very nice”(答 views),相似度 0.985——嵌入几乎一样,只差一个城市名。
2.3 校验能拦下什么
校验层(guardrail)检查输出是否”合法”:格式、安全、事实约束。脚本用城市语言的真实分布当校验器(这个词能不能接在这个前半句后面):它拦下了 15 次不合法的答案(例如缓存给 “the teachers from denver who cook on weekends love the” 返回了 “coffee”——denver 没有咖啡),错答从 30% 降到 19%。但”合法却不对”的答案(给 seattle 返回了 portland 的 “food”,这在 seattle 也合法)它拦不住。
教训:语义缓存是用正确性换成本,阈值要按业务能容忍的错误率来定;校验只能拦下一部分错误;日志要能还原每一次调用(哪个缓存条目、哪个阈值、哪个模型版本),出了错才能查。
⏱ 01 号脚本第 2 部分还量了每一层的时间:命中缓存只要嵌入 + 查询(约 0.5 ms),不命中还要加上 LLM 调用(约 4.4 ms,生成 8 个 token)。真实系统里差距大得多——嵌入模型只有几亿参数、一次前向;LLM 有几百亿参数、生成几百个 token。
3. 通用的模型服务器:NVIDIA Triton · Triton Inference Server
3.1 两个 Triton
slides 先澄清一个常见的混淆:NVIDIA Triton 是推理服务器(部署模型、接请求、批处理);OpenAI Triton 是写 GPU 内核的语言与编译器(第 13 讲 Pallas 的”同类”、FlashAttention 的很多实现用它写)。本节讲前者。
Triton 推理服务器是一个通用的模型服务器:支持多种框架(TensorFlow、PyTorch、ONNX、TensorRT……);支持多种查询(实时、批量、流式);能部署在公有云、数据中心、边缘设备上。它管理一个”模型仓库”(每个模型一个目录、若干版本、一份配置),每个模型可以开多个实例(instance group),每个实例前面有一个调度器。
3.2 动态批处理
GPU 喜欢大批:02 号脚本第 1 部分,一个 BERT-base 大小的编码器(每个请求 128 个 token),A100 上批大小 1 一批 1.23 ms,批 32 一批 5.31 ms——平均到每个请求从 1.23 降到 0.17 ms,吞吐上限从 813 提高到 6,023 请求 / 秒。可请求是一个一个到的,要攒成批就得让先到的等一等。
Triton 的动态批处理器有两个主要旋钮:最大批(max_batch_size)和最长排队时间(max_queue_delay)。模型空闲时,队列里够最大批就立刻发;不够就最多等到最早的请求已经等了 max_queue_delay,然后把队列里的全发出去。
02 号脚本第 2 部分(单个模型实例,泊松到达):满足 P99 ≤ 10 ms 时能承受的最大到达率——
| 设置 | 最大到达率 |
|---|---|
| 不批处理 | 642 请求 / 秒 |
| 最大批 32,不等待 | 5,387 |
| 最大批 32,最多等 2 ms | 5,373 |
| 最大批 32,最多等 8 ms | 294 |
两个发现:(1) 即使不等待,“模型一空就把排着的全拿走”也是一种批处理——负载越高批越大,P99 不变的前提下能承受的到达率高 8 倍;(2) 最长排队时间是”用时延换批大小”:低负载时让每个请求白等(8 ms 时连每秒几百个请求都满足不了 P99 ≤ 10 ms),高负载时批本来就够大,它几乎不起作用。只有”固定开销很大、到达又稀疏”时才值得开,而且要小于 SLO 留出的余量。
3.3 它为什么不够用于 LLM
Triton 的动态批处理是请求级的:一批进去、一批出来。LLM 一个请求要生成几十到几百个 token,长度各不相同——请求级的批要等最长的那个生成完(第 22 讲的静态批处理)。02 号脚本第 3 部分(LLaMA-3-8B,每秒 40 个请求):请求级批处理平均批只有 6.0、吞吐 1,176 token/秒、平均 TTFT 22.9 秒;迭代级批处理平均批 19.6、吞吐 3,685、TTFT 0.12 秒。
所以 slides 说”Triton + LightSeq / TensorRT-LLM”:Triton 负责接收请求、管理模型、提供 HTTP / gRPC 接口;真正的批处理与 KV 管理交给后端引擎——TensorRT-LLM 的”飞行中批处理”(in-flight batching)就是 ORCA 的迭代级调度。通用的模型服务器与专门的 LLM 引擎在这里分了工。
4. 专门的 LLM 服务框架 · LLM serving frameworks
4.1 Text Generation Inference(TGI)
Hugging Face 的 TGI(slides 第 27–29 页):
- 针对推理优化的 Transformer 实现:FlashAttention(第 21 讲)、PagedAttention(第 24 讲);原生支持 Hugging Face 上的模型;
- 面向生产:能监控服务器负载、用 OpenTelemetry 做分布式追踪、导出 Prometheus 指标;
- 丰富的推理选项:精度调整、量化;
- 架构:一个 Rust 写的路由器(接请求、做连续批处理、流式返回 token)+ 若干个张量并行的模型分片(gRPC 通信)。
4.2 OpenLLM
BentoML 的 OpenLLM(slides 第 30–31 页)的重点不在内核,而在”组合”:把 LLM 与其他模型、服务(LangChain、LlamaIndex、Hugging Face)组合成应用;支持自带模型、微调;开源、迭代快。它代表了”服务框架往应用栈上层延伸”的方向。
4.3 LightLLM
LightLLM(slides 第 36–48 页)是一个轻量的、纯 Python + Triton 内核的推理框架,有三个值得一讲的设计。
异步的分词、推理、去分词。推理服务器每一步除了 GPU 的前向,还有 CPU 的活:调度、准备输入、去分词、把 token 流式发给用户。LightLLM 把分词、路由 + 推理、去分词拆成三个进程,CPU 的工作与 GPU 的计算重叠。03 号脚本第 3 部分的模型(每个请求每步 25 μs 的 CPU 开销是假设的量级):H100 上批 256 时,重叠比串行快 35%——GPU 越快、批越大,CPU 开销占的比例越大。第 24 讲 vLLM 的异步调度、第 22 讲 SGLang 的零开销调度器是同一个问题的不同解法。
Token Attention。KV 缓存按 token 分配——相当于块大小为 1 的 PagedAttention。03 号脚本第 1 部分(OPT-13B,A100-40GB,KV 约 15,000 个 token,每秒 8 个请求;第 24 讲的模拟器):
| 分配方式 | 显存利用率 | 平均批 | 吞吐 | 抢占 |
|---|---|---|---|---|
| 按最大长度预留 | 20% | 6.8 | 1.07 | 0 |
| 分页,块 16 | 98.5% | 28.8 | 3.51 | 152 |
| 按 token | ≈ 100% | 29.7 | 3.48 | 606 |
块 16 的内部碎片本来就小(每个请求最多浪费 15 个 token),按 token 分配只让批多一点;而在 vLLM 式的贪心接纳下,塞进去的请求越多,生成途中显存耗尽、不得不抢占的次数也越多——吞吐没升,抢占多了 4 倍。还有工程代价:块表长了 16 倍、注意力内核要逐 token 查表。这正是 LightLLM 要把 Token Attention 和下面的路由器配在一起的原因。
高效路由器(Efficient Router)。决定”现在能不能再接纳一个请求”。三种思路:
- 按”提示 + 最大输出”预留(Orca、FasterTransformer):永不抢占,但每个请求都按 max_new_tokens 占位,太保守;
- 贪心(vLLM):现在放得下就接,生成途中不够了再抢占(重算或换出);
- LightLLM:估计”接纳之后,如果每个请求都生成到它的上界,显存的峰值是多少”,峰值放得下才接。
峰值怎么算?请求 i 现在占 cur_i 个 token、最多再生成 rem_i 个;t 步之后,rem_i ≥ t 的请求占 cur_i + t,其余已经结束、释放。峰值只可能出现在某个请求结束的前一刻,所以只要在 t = rem_i 这些点上算 usage(t) = Σ_{rem_i ≥ t}(cur_i + t)(appserve.future_peak)。它算的是峰值而不是总和——请求是陆续结束的——所以比”按最大输出预留”大方得多,又永远不需要抢占。
03 号脚本第 2 部分(LLaMA-3-8B,A100;提示中位数约 400、实际输出中位数约 200、max_new = 1024):
| KV 容量 | 输出上界 | 策略 | 吞吐 token/秒 | 平均批 | 抢占 | P99 时延 |
|---|---|---|---|---|---|---|
| 16K | max_new | 按最大输出预留 | 770 | 9.7 | 0 | 157 秒 |
| 16K | max_new | 贪心 + 抢占 | 1,229 | 18.3 | 211(重算 115K token) | 64 秒 |
| 16K | max_new | LightLLM | 999 | 13.2 | 0 | 98 秒 |
| 16K | 实际 × 2 | LightLLM | 1,139 | 15.5 | 0 | 76 秒 |
| 32K | max_new | 贪心 + 抢占 | 1,835 | 30.3 | 45 | 21.5 秒 |
| 32K | 实际 × 2 | LightLLM | 1,790 | 28.7 | 0 | 20.7 秒 |
在这个纸面模型里,显存很紧时”贪心 + 抢占”反而吞吐更高、P99 更低——重算一次预填充太便宜;容量宽松、长度估计更准时两者接近,LightLLM 一个 token 都不重算。路由器的价值在于可预测:没有抢占,就没有被反复踢出队列的请求;它的效率取决于对输出长度估计得多准——“预测输出长度”因此成了一个研究方向。真实系统里抢占更贵(长上下文的重算、换出到 CPU 的带宽),天平会更偏向不抢占的做法。
5. 本地部署:MLC LLM · Running LLMs on local devices
MLC LLM(slides 第 32–35 页)的目标是让模型在消费级设备上原生运行:用机器学习编译器(TVM)把同一个模型编译到各种平台——C++ 命令行、浏览器里的 JavaScript(WebGPU)、iOS 的 Swift、Android 的 Kotlin。本地 LLM 的好处:隐私(数据不出设备)、离线可用、没有服务费、时延可控。
本地部署的系统目标和云端相反:只有一个用户,没有”批”来摊薄读权重的成本,解码几乎完全受内存带宽限制(第 26 讲)。04 号脚本的上限估计(token/秒 ≈ 70% 的带宽 / 权重字节数):
| 设备 | 3B,4 位 | 8B,FP16 | 8B,4 位 | 70B,4 位(约 40 GB) |
|---|---|---|---|---|
| 手机(约 51 GB/s,8 GB) | 20 | 放不下 | 8 | 放不下 |
| 轻薄本(M2,100 GB/s,16 GB) | 39 | 放不下 | 16 | 放不下 |
| 高端笔记本(M4 Pro,273 GB/s,48 GB) | 106 | 12 | 42 | 放不下 |
| 游戏显卡(RTX 4090,1 TB/s,24 GB) | 392 | 44 | 157 | 放不下 |
位数减到约 1/3.5,速度就快约 3.5 倍,能放下的模型也大 3.5 倍——所以本地部署几乎总是 4 位量化(第 19、20 讲的 GPTQ、AWQ 一类)。70B 级别的模型即使 4 位也要约 40 GB,一张游戏显卡放不下:要么多卡,要么像附加讲 A2 的 KTransformers 那样把大部分权重放进 CPU 内存。
6. 怎样选 · Choosing a framework
| 需求 | 合适的选择 | 理由 |
|---|---|---|
| 一个服务里有多种模型(检测、分类、嵌入、LLM),要统一的部署、监控、版本管理 | Triton(+ TensorRT-LLM 作为 LLM 后端) | 通用的模型服务器、模型仓库、多后端 |
| 高吞吐的 LLM 在线服务 | vLLM、SGLang、TensorRT-LLM、TGI | 迭代级批处理、分页 KV、前缀缓存、各种并行 |
| 结构化的多次调用、共享前缀很多(智能体、少样本) | SGLang | RadixAttention、前端语言(第 22 讲) |
| 研究新的调度或 KV 管理算法 | LightLLM(纯 Python + Triton 内核,代码少)或 vLLM | 好改 |
| 大规模、多节点、预填充 / 解码分离 | Dynamo、llm-d(第 26 讲)+ LMCache(第 27 讲) | 编排、路由、分层 KV |
| 手机、浏览器、离线 | MLC LLM、llama.cpp | 编译到各种后端、低位量化 |
这些框架还在快速演化:今天的 TGI、vLLM、SGLang 已经互相吸收了对方的大部分技术。比框架名字更重要的是它们背后的几个反复出现的问题——批怎样组、KV 怎样管、CPU 开销怎样藏、显存会不会在半路耗尽。
7. 小结 · Summary
- LLM 应用是一个栈:数据管道 → 嵌入 → 向量数据库 → 编排 → LLM(API 或自托管)→ 缓存、校验、日志。模型之外的每一层都有成本,也都有失败的方式。
- 语义缓存用正确性换成本:同义改写能命中,“只差一个词”的不同问题也会命中;校验只能拦下不合法的输出。
- Triton 是通用的模型服务器,动态批处理在”等多久”与”批多大”之间取舍;LLM 生成需要迭代级批处理,交给 TensorRT-LLM 等后端。
- LightLLM:异步流水线藏起 CPU 开销;Token Attention 把 KV 分配粒度降到 1;路由器按”未来显存峰值”接纳请求、永不抢占,效率取决于输出长度估计得多准。
- 本地部署受内存带宽与容量限制,4 位量化是常态;MLC LLM 用编译器覆盖五花八门的硬件。
8. 常见误区 · Common pitfalls
- “语义缓存的阈值越低越好,命中越多越省钱。” 命中率涨得很少,错答涨得很快(阈值 0.95 → 0.90:错答 5.7% → 30%)。
- “有了校验就不怕缓存答错。” 校验只检查合法性,“合法却答非所问”的输出拦不住。
- “动态批处理的排队时间设得越长,吞吐越高。” 高负载时批本来就满,排队时间不起作用;低负载时它只会增加时延。
- “Triton 的动态批处理也能用来服务 LLM。” 它是请求级的;LLM 需要迭代级批处理,由后端引擎负责。
- “KV 分配的粒度越细越好。” 块 16 的内部碎片本来就小;粒度更细带来更多的表项、更不规则的访存,在贪心接纳下还会更频繁地抢占。
- “不抢占的调度一定更慢。” 取决于对输出长度的估计与抢占的代价;可预测性本身就有价值。
- “本地设备算力够就能跑大模型。” 单用户解码受带宽限制,而且模型首先得放得下。
9. 练习 · Exercises
- 列出 a16z 应用栈里每个请求都会经过的组件,并标出哪些会产生 LLM 调用、哪些可能让答案出错。
- 一个语义缓存在阈值 0.95 时命中 97%、错答 5.7%;不缓存时每次 LLM 调用花 0.002 美元、“答错一次”的业务代价是 0.05 美元。每 1000 个问题,缓存省下多少钱、损失多少?值得吗?
- 编码器一批的时间是 1.2 ms + 0.13 ms × 批大小。不批处理时的最大吞吐是多少?最大批 32 时呢?
- 为什么在高负载下,Triton 的 max_queue_delay 几乎不影响时延和吞吐?
- 三个正在生成的请求:(cur, rem) = (500, 100)、(300, 400)、(800, 50)。用 future_peak 的方法算显存峰值。
- 上题再来一个 (prompt = 400, max_new = 300) 的新请求,KV 容量 2600 个 token。LightLLM 的路由器会接纳它吗?“按最大输出预留”呢?
- LightLLM 的路由器什么时候会比”贪心 + 抢占”吞吐更低?什么时候会更好?
- 一部内存带宽 60 GB/s 的手机跑 4 位量化的 7B 模型(每个参数 4.5 位),解码上限约多少 token/秒(有效带宽取 70%)?
- 为什么服务框架要把分词 / 去分词放到单独的进程,而不是线程?(提示:Python)
参考答案
- 每个请求:编排(构造提示)→ 嵌入查询 → 向量数据库检索 → LLM 缓存查询 →(未命中)LLM 调用 → 校验 → 日志。产生 LLM 调用的:LLM 调用本身(智能体与链式编排可能多次调用);可能出错的:检索(取错文档)、语义缓存(返回别的问题的答案)、LLM(幻觉)、校验(误报 / 漏报)。
- 省:970 次命中 × 0.002 = 1.94 美元;损失:57 次错答 × 0.05 = 2.85 美元——不值得;换成阈值 0.99(96.1% 命中、0 错答)则省 1.92 美元、无损失。阈值要按错误的代价来定。
- 不批处理:1 / 1.33 ms ≈ 752 请求 / 秒;批 32:32 / (1.2 + 4.16) ms ≈ 5,970 请求 / 秒。
- 高负载时,模型一空闲,队列里就已经攒够了(或接近)最大批,立刻发出;排队时间这个”最多等多久”的上限根本用不到。
- 起点:500 + 300 + 800 = 1600。t = 50:三个都在,500+50 + 300+50 + 800+50 = 1750;t = 100:(800, 50) 已结束,500+100 + 300+100 = 1000;t = 400:只剩第二个,300 + 400 = 700。峰值 1750。
- 加上 (400, 300):t = 50:1750 + 450 = 2200;t = 100:1000 + 500 = 1500;t = 300:300+300 + 400+300 = 1300;t = 400:700。峰值 2200 ≤ 2600,接纳。按最大输出预留:(500+100) + (300+400) + (800+50) + (400+300) = 2850 > 2600,不接纳。
- 更低:显存很紧、输出上界远大于实际长度、抢占(重算)很便宜时——它为”可能用到但实际用不到”的显存留了位置。更好:长度估计准、抢占很贵(长上下文、换出带宽有限)、时延要求稳定时。
- 7e9 × 4.5 / 8 ≈ 3.9 GB;0.7 × 60 / 3.9 ≈ 10.7 token/秒。
- CPython 有全局解释器锁(GIL),同一进程里的 Python 线程不能同时执行 Python 代码;分词、去分词是 Python(或通过 Python 调用)的 CPU 工作,放在同一个进程里会和调度、准备输入抢 GIL。拆成进程才能真正并行,代价是进程间通信。
10. 延伸阅读 · Further reading
- a16z, Emerging Architectures for LLM Applications(2023);Chip Huyen, Building LLM Applications for Production(2023)。
- NVIDIA Triton Inference Server 与 TensorRT-LLM 文档(动态批处理、in-flight batching)。
- Hugging Face Text Generation Inference;BentoML OpenLLM;MLC LLM(mlc.ai);LightLLM(github.com/ModelTC/lightllm)。
- GPTCache(语义缓存);Guardrails AI(校验)。
- Yu et al. (2022) Orca(迭代级调度);输出长度预测与调度:如 Zheng et al. (2023) Response Length Perception and Sequence Scheduling。
11. 下一讲预告 · Next
本讲的最后看到:70B 的模型 4 位量化后也放不进一张游戏显卡。附加讲 A2 讲异构硬件上的 LLM 服务:不同的硬件擅长不同的维度——算力、显存带宽、内存容量、价格。Mooncake(Kimi 的服务平台)把预填充、解码、KV 缓存分别放在最合适的硬件上;KTransformers 把 MoE 的专家放到 CPU 内存里,让一张 GPU 加一台服务器就能跑 6710 亿参数的 DeepSeek-V3。