第 7 章:工程化上线:推理优化、并发与成本
讲清一个训练好的调研 Agent 要上线扛真实流量,工程上要解决哪些问题:推理为什么慢且贵、KV Cache 和 continuous batching 怎么提吞吐、调研 Agent 特有的上线挑战,以及怎么把成本压下来
📊 学习时长:60-75 分钟 🎯 完成后能力:讲清一个训练好的调研 Agent 要上线扛真实流量,工程上要解决哪些问题:推理为什么慢且贵、KV Cache 和 continuous batching 怎么提吞吐、调研 Agent 特有的上线挑战,以及怎么把成本压下来 🔗 关联面试题:5 道(覆盖 5 个角度,见 Part 3)
🧭 这一章讲什么:推理优化、并发、降本这些是大模型应用工程师的硬通货。本章把通用原理和调研 Agent 上线特有的挑战讲清楚,面试和实战都够用。
这一章你会学到什么
- ✓ 想清一个根本落差:训练好的模型 ≠ 能上线的服务,真实流量来了要面对并发、延迟、成本、稳定性
- ✓ 搞懂推理服务的关键指标(TTFT / TPOT / 吞吐 / 单次成本),以及 LLM 推理为什么天生慢且贵
- ✓ 掌握两个最核心的推理优化:KV Cache(省重复计算)和 continuous batching(提 GPU 利用率,配可跑小实验)
- ✓ 理解调研 Agent 上线特有的挑战:一次任务几十次 LLM 调用、跑几分钟、成本随轨迹长度涨
- ✓ 建立降本的整体思路:缓存、模型路由、限流降级,以及上线后要监控什么
本章按三段式组织:
段落 给谁看 内容 占比 🚀 Part 1 · 主线实战 零基础,想先看懂 训练 vs 上线的落差 + 推理为什么慢 + batching 小实验 ~45% 🎯 Part 2 · 面试深度 想讲透、备战面试 指标 / KV Cache / batching / Agent 上线挑战 / 降本 / 监控 + 私货 ~45% 🏆 Part 3 · 验收串题 检验学到位没 关联面试题 + 自检清单 ~10%
🚀 Part 1 · 主线实战 | ~45% 这部分先看清「训练好 ≠ 能上线」的落差,再用一个零依赖小实验,看懂 continuous batching 为什么能提吞吐。
先讲个真实场景(这是本章的「为什么」)
前六章我们把一个调研 Agent 从零训练出来了。在自己机器上单跑一次 demo,效果很惊艳。但当你想把它上线给真实用户用,问题立刻全冒出来:
- 一个用户的调研任务,可能要调用 LLM 几十次、跑好几分钟,中间还要等搜索、等网页抓取。
- 同时来 100 个用户怎么办?GPU 就那么几张,排队还是并发?
- 每次任务烧多少 token、花多少钱?一个月的账单扛得住吗?
- 万一某次任务卡住了、工具超时了、模型输出崩了,整个服务会不会被拖垮?
这就是**「训练好的模型」和「能上线的服务」之间的鸿沟**。模型只是发动机,要让它变成一辆能载客上路的车,还需要一整套工程:推理优化、并发调度、成本控制、稳定性保障。本章讲的就是这套工程。
概念:推理服务的关键指标
要谈优化,先得知道「衡量什么」。推理服务有几个关键指标:
- TTFT(Time To First Token):从请求发出到吐出第一个字的延迟。决定「用户等多久才看到反应」。
- TPOT(Time Per Output Token):之后每个字的间隔。决定「出字快不快」。
- 吞吐(Throughput / QPS):单位时间能服务多少请求。决定「一张卡能养多少用户」。
- 单次成本:一次请求烧多少 token、占多少 GPU 时间。决定「账单」。
延迟和吞吐常常是一对矛盾:为了提吞吐把请求攒成大批一起算,单个请求的延迟就上去了。工程的艺术就在这个权衡里。
概念:LLM 推理为什么天生慢且贵
LLM 生成是**自回归(autoregressive)**的:一次只能生成一个 token,生成下一个时要把前面所有 token 再「看」一遍。这带来两个硬伤:
- 没法并行生成:一句 100 字的回答,就得串行跑 100 次前向。
- 显存带宽是瓶颈:每生成一个 token,都要把巨大的模型权重从显存搬一遍,瓶颈不在算力而在「搬运」。
这两点决定了:LLM 推理优化的核心,就是想办法「少搬运、多复用、把 GPU 喂饱」。下面两个技术正是冲着这个去的。
🛠️ 跟着做:一个零依赖的 batching 吞吐小实验
GPU 最怕「闲着」。把多个请求攒成一批一起算(batching),能显著提利用率。但怎么攒有讲究。下面这段零依赖代码,对比两种攒法。新建 batching_demo.py:
# 零依赖,演示 continuous batching 为什么比 static batching 吞吐高
# 8 个请求,每个要生成的 token 数(decode 步数)不同;GPU 同时只有 4 个槽位
reqs = [10, 3, 8, 2, 9, 4, 7, 5]
SLOTS = 4
useful = sum(reqs)
# static batching:4 个一批,整批必须等批内最长的那个跑完才能换下一批
static_wall = sum(max(reqs[i:i+SLOTS]) for i in range(0, len(reqs), SLOTS))
static_slotsteps = sum(max(reqs[i:i+SLOTS]) * SLOTS for i in range(0, len(reqs), SLOTS))
static_util = useful / static_slotsteps
# continuous batching:某个槽位一空,立刻塞入队列里的下一个请求
slots = reqs[:SLOTS]
queue = reqs[SLOTS:]
t = 0
while any(s > 0 for s in slots):
slots = [s - 1 if s > 0 else 0 for s in slots] # 走一步,所有非空槽 -1
t += 1
for j in range(SLOTS): # 空了的槽立刻补人
if slots[j] == 0 and queue:
slots[j] = queue.pop(0)
cont_wall = t
cont_util = useful / (cont_wall * SLOTS)
print(f"8 个请求,生成长度 {reqs},GPU 槽位 {SLOTS} 个\n")
print(f"{'方案':<22}{'总步数(墙钟)':>10}{'利用率':>9}")
print('-' * 44)
print(f"{'static batching':<22}{static_wall:>10}{static_util:>9.0%}")
print(f"{'continuous batching':<22}{cont_wall:>10}{cont_util:>9.0%}")
print(f"\n同样的活,continuous 少用 {static_wall - cont_wall} 步,利用率 {static_util:.0%} → {cont_util:.0%}")
运行
python batching_demo.py
你应该看到(确定性输出):
8 个请求,生成长度 [10, 3, 8, 2, 9, 4, 7, 5],GPU 槽位 4 个
方案 总步数(墙钟) 利用率
--------------------------------------------
static batching 19 63%
continuous batching 14 86%
同样的活,continuous 少用 5 步,利用率 63% → 86%
看懂了关键差别:static batching 整批要等批里最长的那个跑完,短请求早早算完了,槽位却空着干等(就是那 37% 浪费)。continuous batching 一旦某个请求生成完,立刻把排队的下一个塞进空槽,GPU 几乎不闲着。这就是 vLLM 这类推理框架能把吞吐拉高几倍的核心机制之一。
🐛 跑不通看这里:纯标准库,不该报错。这是简化模型(忽略了 prefill 阶段、显存对 batch 大小的限制),只为让你看清「为什么不能让槽位空等」这个直觉。
📌 说清楚:这是简化模型。真实的 continuous batching 还要配合 PagedAttention(管理 KV Cache 显存)、动态 batch 大小、抢占调度等。这些 vLLM / TensorRT-LLM 已经做好了,你通常是用而不是自己写。本章帮你理解「它为你解决了什么」。
🧭 你刚才看到的,等于真实系统的什么? 你模拟的「槽位」= GPU 上同时在解码的请求位置。真实系统里,槽位数受显存(尤其 KV Cache)限制,请求长度事先不知道。但「槽位一空就补人、别让 GPU 闲着」这个核心思想,和 vLLM 的 continuous batching 完全一致。
🎯 Part 2 · 面试深度 | ~45% 这部分把推理优化和 Agent 上线的工程挑战讲透。这些是大模型应用 / 推理工程岗的高频考点。
2.1 KV Cache:推理优化的地基
刚才说自回归生成时「要把前面所有 token 再看一遍」。如果每生成一个 token 都重新计算前面所有 token 的注意力,那是巨大的浪费。KV Cache 就是把前面 token 算过的 Key / Value 缓存下来,生成新 token 时直接复用,只算新 token 的部分。
- 省什么:把「每步重算全部历史」变成「每步只算一个新 token」,计算量从平方级降到线性级。
- 代价:KV Cache 要占显存,而且和上下文长度成正比。对长程调研 Agent(上下文动辄几万 token),KV Cache 能吃掉大量显存,这也是为什么长上下文推理这么贵。
- 联系第 2 章:还记得 IterResearch 用「演进报告」把上下文压成常量吗?那个设计直接受益于此:上下文短,KV Cache 就小,推理又快又省显存。架构选择和推理成本是连在一起的。
2.2 Continuous Batching:把 GPU 喂饱
(回扣小实验)static batching 的问题是「整批等最慢」,GPU 利用率低。continuous batching(也叫 in-flight batching)在每一步解码后做一次检查:谁生成完了就让它走、把排队的新请求填进空出来的位置。注意它不是「把整个批次推倒重排」,而是动态地增删批次里的成员,让 GPU 始终保持满负荷。
它和 PagedAttention 是绝配:PagedAttention 像操作系统管内存那样,把 KV Cache 切成小页按需分配,让不同长度的请求能灵活共享显存,continuous batching 才能自由地塞人放人。这套组合是 vLLM 的看家本领。
业内行话:面试聊推理优化,能说清「continuous batching 解决的是 static batching 的 head-of-line blocking(队头阻塞),配合 PagedAttention 管 KV Cache 显存」,就比只会说「我用了 vLLM」专业得多。
2.3 调研 Agent 上线,有哪些「特有」挑战
普通 LLM 服务是「一问一答」,而调研 Agent 是一个长时间、多步骤、带外部 IO 的任务,上线挑战完全不同:
- 长时任务:一次调研跑几分钟,不能像普通请求那样同步等。要做成异步任务 + 进度查询(提交任务拿个 id,前端轮询或推送进度)。
- 多次 LLM 调用 + 工具 IO:一次任务调几十次模型、十几次工具,任何一步超时 / 失败都要有重试、降级、断点,不能一崩全崩(回扣第 3 章的工具容错)。
- 状态保持与并发:多用户并发时,每个任务的中间状态(报告、记忆)要隔离存储,不能串。
- 成本随轨迹长度涨:这是 Agent 最痛的点,单独讲。
2.4 成本:Agent 最痛的点
普通问答一次就几百 token,调研 Agent 一次任务几十步、几万 token,成本是数量级的差别。而且有个隐藏的放大器:
还记得第 2 章 ReAct 的上下文爆炸吗?每多一步,就要把越来越长的历史重新喂给模型一次,token 消耗是「步数 × 累积长度」,接近平方级增长。这不只是慢,更是真金白银的成本。IterResearch 的「演进报告」把每步上下文压成常量,成本就从平方级降回线性级。架构设计直接决定了上线后的账单,这是第 2 章那个设计的工程价值落地。
2.5 降本的三个常用手段
- 缓存复用:工具结果缓存(回扣第 3 章)、相同子查询的结果缓存,避免重复调用和重复推理。
- 模型路由:不是每一步都要最强的模型。简单的步骤(比如判断「信息够不够」)用小模型 / 便宜模型,关键的综合分析才上大模型。一次任务的成本能降一大截。
- 限流与降级:高峰期限制并发任务数排队;必要时降级(减少最大步数、缩短报告长度),保证服务不被拖垮,而不是所有人一起卡死。
2.6 上线后要监控什么
模型上线不是终点,是持续运营的起点。调研 Agent 要盯的监控:
- 系统指标:延迟(TTFT / 任务总时长)、吞吐、GPU 利用率、错误率、超时率。
- 成本指标:单次任务 token 消耗、日 / 月成本趋势,异常飙升要告警。
- 质量指标:任务成功率、平均步数、工具调用失败率,以及用户反馈。质量掉了要能及时发现。
讲师私货:很多人觉得「模型训出来就完事了」,其实上线后的工程和运营,决定了这个 Agent 能不能真的被用起来、烧不烧得起钱。面试时如果你能从「训练」一路讲到「上线后怎么监控成本和质量」,面试官会认定你是能端到端落地的人,而不只是调模型的。能把「训练」和「上线运营」连起来讲,本身就是稀缺的。
🧭 这一章到这儿:推理优化、Agent 上线挑战、降本与监控的原理和思路都讲透了。最后一章,我们回答一个一直没正面碰的问题:怎么知道这个 Agent 到底做得好不好?
🏆 Part 3 · 验收串题 | ~10%
关联面试题(5 道,覆盖 5 个角度)
- 【推理框架对比】 比较主流的大模型推理框架(vLLM / TensorRT-LLM / HF 等)。
- 【KV Cache】 自回归推理里 KV Cache 用来加速解码,分析它的空间复杂度。
- 【显存优化】 训练或推理时显存不足是常见瓶颈,有哪些有效的显存优化技术?
- 【量化】 对 13B 模型做 INT8 / INT4 量化后,存储和推理会受什么影响?
- 【高并发会话状态】 多用户并发的 Agent / 对话系统,会话状态怎么存储和管理?
自检清单
- 能讲清「训练好的模型」和「能上线的服务」之间隔着什么(并发 / 延迟 / 成本 / 稳定性)
- 能说出推理的关键指标(TTFT / TPOT / 吞吐 / 单次成本)和延迟与吞吐的矛盾
- 能讲清 KV Cache 省了什么、代价是什么,以及它和上下文长度、IterResearch 的关系
- 能讲清 continuous batching 解决 static batching 的什么问题(队头阻塞),和 PagedAttention 的关系
- 能说出 Agent 上线的特有挑战(长时 / 多调用 / 状态 / 成本随长度涨)和降本三手段
学完这一章,你已经把一个调研 Agent 从「训练出来」推到了「稳定上线、成本可控」。下一章,我们换个视角,讲怎么系统地评估这个 Agent 做得好不好:调研类任务没有标准答案,怎么定义「好」、怎么自动化打分、怎么防止「刷分」。