学习手册 / 全栈性能实验与结课项目课程官网 ↗

CHAPTER 12 / 推理与系统

全栈性能实验与结课项目

从慢在哪开始,以可复现的质量、成本和延迟结果结束。

进阶建议阅读 35 分钟,练习另计自编配套教程
读完这一章,你应该能
  • 建立跨 Agent、工具、服务和模型的时间线
  • 用 profile、明确假设与控制变量完成一次可解释优化
  • 交付包含评测集、基线、改动、失败分析和复现方法的项目

先画出用户实际等待的关键路径

一个研究助手总耗时二十秒,可能包含检索六秒、模型十二秒、解析与整理两秒。模型变快并不会自动消除检索等待。多工具并行时,总耗时也不是所有子任务耗时相加,而取决于依赖关系中的关键路径。例如三个独立查询耗时二、三、四秒,理想并行完成约需四秒;若后一个必须读取前一个结果,就仍然需要相加。

为每次任务生成 trace_id,记录模型调用、工具执行、重试和验收的开始结束时间,以及它们的父子关系。把用户可见的总耗时与分段耗时放在一起看。日志应记录足够解释行为的元信息,敏感输入不必原样保留。没有这条时间线,许多所谓模型优化其实只是碰巧命中了上一次的缓存。

用上限判断这件事值不值得做

假设总耗时中模型占 60%,其余占 40%,模型阶段加速两倍后,新总时间比例是 0.4 + 0.6/2 = 0.7,整体加速约为 1.43 倍。即使模型阶段瞬间完成,整体也最多加速 2.5 倍。这是 Amdahl 定律在串行阶段近似下的应用,帮助你先估计收益上限,再决定投入。

这个估算假定各阶段比例稳定且没有新增开销。真实系统中批处理、并发和缓存会互相影响,一个阶段变快可能把瓶颈转移到另一阶段。因此上限计算用于筛选假设,最终仍需端到端实验。对于交互任务,还要分别估计首个可用反馈与完整完成时间,避免优化了后台尾部却没有改善用户最在意的等待。

先用轻量观测缩小范围

先看任务日志与服务指标,判断时间花在排队、prefill、decode、工具还是客户端。只有证据指向模型执行,才进一步用 profiler 看算子、设备活动、内存分配和同步。PyTorch Profiler 可记录 CPU 和设备事件,但开启堆栈、形状或内存跟踪本身也会引入开销;用于定位的一次 profile,不应直接当作最终性能基准。

GPU 操作通常异步提交,CPU 函数返回不代表设备已经完成。测量时使用框架提供的设备计时方法,或在明确定义的边界同步;不要把同步插满每个操作而意外改变执行方式。冷启动、编译与预热单列,正式比较使用相同的采集方法。看到某个算子累计时间很大,还要确认它是否位于关键路径。

本机实验:计算阶段加速的实际收益

下面用标准库分析一组确定的模拟记录,不通过 sleep 制造假基准。每行阶段按串行相加,故它只适用于本节的简化假设。保存为 fullstack_lab.py 并运行。

from statistics import mean
runs = [
    {"tool": 6.0, "model": 12.0, "other": 2.0},
    {"tool": 5.0, "model": 10.0, "other": 2.0},
    {"tool": 7.0, "model": 14.0, "other": 2.0},
]
before = [sum(r.values()) for r in runs]
after = [r["tool"] + r["model"] / 2 + r["other"] for r in runs]
print("before mean", mean(before))
print("after mean", mean(after))
print("speedup", round(mean(before) / mean(after), 3))
assert mean(before) == 20
assert mean(after) == 14
# First trace: model is 60% of the serial critical path.
assert abs(1 / (0.4 + 0.6 / 2) - 20 / 14) < 1e-9

预期平均耗时从二十秒变为十四秒,整体约 1.429 倍。继续计算检索加速两倍,以及模型和检索都加速两倍的情况。再把检索改成可重叠阶段,重新画依赖图,你会发现原来的简单求和已经不适用。

把优化建议写成可证伪的假设

好的假设应同时写出原因、改动和预期观察,例如“固定系统提示占输入的大部分,启用前缀复用应降低热请求 TTFT,而对冷请求收益较小”。保持模型、数据集、输出限制、采样参数、硬件和负载不变,只切换这一项。按交错顺序运行基线与实验组,并记录请求是否热缓存,减少时间顺序与环境变化带来的偏差。

质量也属于控制条件。若缩短答案让 token 数减少,却漏掉问题要求,速度改善不能算达标。保存每个任务的结果与验收,报告成功率、成功任务成本、延迟分位数和错误分布。对失败样本逐个比较,是确认优化有没有偷偷转移工作或损害困难任务的有效办法。

完成一个别人能复跑的结课项目

建议选择前面做过的文档问答或代码修复 Agent。准备固定的任务集,覆盖正常、困难和工具失败情形;先保留一套简单可靠基线,再从观测中选出一个主要瓶颈。可以优化检索去重、前缀稳定性、模型路由、调度参数或工具并行,但每轮只改变一项。每个方案保留独立版本和结果文件,避免只剩一张无法解释的最终成绩表。

交付内容包括任务与验收定义、运行环境、启动步骤、基线、优化假设、结果表和失败分析。若没有 GPU,可以完成 Agent 层与标准库模拟实验,但应明确哪些是模拟,哪些来自真实模型。最有价值的结论有时是“这个优化在长输出任务上无明显收益”,只要证据与适用范围清楚,它仍然是一份合格的系统实验。

LEARN BY DOING

提交一份可复现的全栈优化报告

  1. 选择一个 Agent,准备至少 20 个固定任务和明确的成功验收条件。
  2. 保存任务 trace,画出典型成功与失败请求的关键路径,列出主要瓶颈。
  3. 基于证据提出一个假设,只改一个配置,重复运行相同任务与负载。
  4. 汇总质量、成功任务成本、TTFT、总延迟与失败原因,记录完整复现步骤。
  5. 选择一个失败或无收益样本,解释假设为何没有成立。

验收标准

  • 任何一个表格数据都能回溯到任务级记录,包含失败与超时。
  • 基线与实验组的模型、提示词、负载等差异有明确列表,没有隐含变更。
  • 报告区分实测、模拟与推断,提供收益范围和至少一个适用限制。
  • 另一位学习者可以按文档重建实验输入与统计结果。
下载配套离线实验包 ↓ · 脚本使用模拟模型与数据,运行无需 API。

合上书,检查一下

先作答,再看解释。答错的地方,正好是值得再读一遍的地方。

1. 某阶段占总耗时 60%,把该阶段加速两倍,整体大约加速多少?
2. 哪种实验最有助于解释前缀缓存的收益?

配合本章看视频

下面按本站章节主题选配。为什么没有采用原课录播 →

下面的视频帮助你测量 GPU 与 kernel 性能。完成本站全栈项目时,还要把模型、工具、网络和排队耗时放在一起分析,并保持任务质量的验收标准。

YouTube · 英语同主题参考 · 非 CS2680 原课

Stanford CS336 · Lecture 6: Kernels, Triton (Spring 2025) ↗

补齐从基准测试到 profiler 定位瓶颈的方法,适合结课实验中解释加速来自哪里。

带着问题看 · benchmarking 与 profiling 的区别;GPU 计时、预热与同步;PyTorch profiler、Nsight Systems 与 kernel 性能分析;先测量瓶颈,再判断 fusion 或 Triton 优化是否有效。

查看来源与观看说明 →

继续读原始资料

完成状态与自测成绩独立记录。