30 分钟,手把手带你从 0 到 1 跑通一个高性能 Token 服务

用 AMD Radeon 开发者云、vLLM 和 AI Agent,完成一次从服务部署、性能压测、GPU Profiling、Kernel 分析,到自动调优和端到端验证的完整实验。

写在前面

平时我们用大模型写代码、查资料,但能不能让大模型反过来优化大模型推理服务?

AMD 的“AgenticAI 推理自优化”实验给出了一个很有意思的答案:把传统性能工程流程封装成一个 Skill,让 AI Agent 按照预设的步骤启动 vLLM、运行基准测试、采集 GPU Trace、识别瓶颈、调优 GEMM,并用端到端压测验证优化是否真的有效。

这套实验被称为 LLM-for-LLM:使用 LLM Agent 优化 LLM 工作负载。

需要特别说明的是,Agent 并不是凭感觉“魔改”代码。真正起作用的是一个名为 /vllm-optimize 的 Skill。它更像一份可以被 Agent 执行的标准作业程序,明确规定了:

  • 要问用户哪些问题;
  • 每个阶段运行哪些命令;
  • 需要采集哪些性能数据;
  • 什么条件下可以接受优化;
  • 什么条件下必须回滚;
  • 最终报告必须包含哪些内容。

完成本文后,你将跑通下面这条链路:

领取云资源
  → 启动 Notebook 实例
  → 安装并启动 OpenCode
  → 调用 /vllm-optimize Skill
  → 启动 vLLM 服务
  → 并发压测与 GPU Profiling
  → 找到 Kernel 瓶颈和真实 GEMM Shape
  → 离线调优 GEMM
  → 重新进行端到端压测
  → 自动接受或回滚优化
  → 生成 Markdown 分析报告

一、实验环境与前置准备

开始前需要准备:

  1. AMD 开发者社区账号;
  2. AMD 开发者云点数;
  3. 一个可供 OpenCode 使用的 LLM API Key;如果暂时没有,也可以选择平台提供的免费模型;
  4. 大约 30~60 分钟实验时间。模型下载、服务启动和调优耗时会受到网络、模型大小和参数配置影响。

本实验使用的核心技术包括:

  • AMD ROCm:AMD GPU 计算平台;
  • vLLM:高吞吐量大模型推理框架,提供兼容 OpenAI API 的服务;
  • PyTorch Profiler:采集算子、Kernel 和输入 Shape;
  • TunableOps/rocBLAS:针对真实 GEMM Shape 离线选择更快的实现;
  • OpenCode + Skill:负责交互、流程编排、命令执行和报告生成。

本文中的“Token 服务”指的是基于 vLLM 的大模型推理服务,核心指标是每秒生成的 Token 数,即 Output TPS。


二、领取并兑换 AMD 开发者云点数

登录 AMD 开发者社区后,点击“我的权益”。

进入我的权益

点击“领取”。

领取权益

滑动到页面中部,点击“立即兑换”。

立即兑换

输入需要兑换的使用时长。

输入兑换时长

兑换完成后,点击“查看云力券”。

查看云力券

复制兑换链接或兑换码,后面需要在 AMD 开发者云中使用。

复制兑换信息

返回首页,进入“AMD 开发者云”。

进入 AMD 开发者云

打开 Profile 页面,兑换云平台点数。

进入 Profile

兑换点数入口

输入刚才复制的兑换码并完成兑换。

输入兑换码

如果国内站访问较慢,可以尝试国际站:https://radeon.anruicloud.com/。资源兑换流程基本一致。


三、启动“AgenticAI 推理自优化”实验

回到任务列表,选择 AgenticAI 推理自优化。如果页面中的任务顺序没有变化,它通常是第三个任务。

选择实验任务

任务卡片通常有两个入口:

  • Preview:阅读实验介绍;
  • Launch:创建实验实例并启动 Notebook。

点击 Launch

启动实验

实例准备完成后,点击 Open Notebook

打开 Notebook

进入 JupyterLab 后,可以看到以下核心文件:

assets/                         # Notebook 图片和演示材料
skills/
  vllm-optimize -> vllm-optimize-v3
  vllm-optimize-v2/
  vllm-optimize-v3/             # 本实验实际使用的 vLLM 优化 Skill
  inferencex-optimize/
tests/                          # 端到端测试
GUIDE.md
README.md
install.sh                      # 安装 Skill
workshop_LLM_for_LLM_cn.ipynb  # 中文讲解型 Notebook

这里有一个容易误解的地方:workshop_LLM_for_LLM_cn.ipynb 主要是一份讲解型 Notebook,本身几乎没有可执行代码。实际的自动优化逻辑位于 skills/vllm-optimize-v3/ 中。

实验结束后记得销毁实例,避免继续消耗点数。

销毁实例


四、安装 Skill 并启动 OpenCode

在 JupyterLab 左上角点击加号。

打开 Launcher

选择 Terminal,打开终端。

打开终端

执行安装脚本:

bash install.sh

执行安装脚本

安装完成

install.sh 会将 inferencex-optimizevllm-optimize 安装到:

~/.claude/skills/

同时还会为 Cursor 创建 Skill 链接和规则。虽然安装目录名中包含 .claude,但这个 Skill 同样兼容 OpenCode。

安装完成后启动 OpenCode:

opencode

Linux 命令区分大小写。如果输入 OpenCode 提示找不到命令,请改用小写的 opencode


五、选择 Agent 模型并调用 Skill

进入 OpenCode 后,输入:

/models

选择一个可用的 Agent 模型。如果你有自己的 API Key,可以通过:

/connect

配置对应的模型服务。

选择模型

配置模型服务

然后输入:

/skills

选择:

/vllm-optimize

接着输入需要优化的模型,例如:

Qwen/Qwen3-8B

选择 vllm-optimize Skill

输入目标模型


六、如何选择 Skill 的参数

Agent 会分两轮询问实验配置。第一次运行可以优先选择推荐项,但理解这些参数会让实验更有价值。

第一轮:运行方式

通常包括:

  • Run plan:完整优化、仅 Profiling,或使用已有数据继续优化;
  • Output directory:新建带时间戳的结果目录,或指定已有目录;
  • GPU selection:自动选择空闲 GPU、沿用当前环境变量,或手动指定 GPU ID。

第一次体验建议选择:

Full optimize
New timestamped dir
Auto-select least busy

第一轮参数选择

选择完毕后按回车确认。

确认第一轮参数

第二轮:工作负载参数

Agent 完成 GPU 探测后,还会询问:

  • TP:Tensor Parallel 数量;单卡实验选择 1
  • ISL × OSL:输入和输出序列长度;推荐先用 1024 × 1024
  • Concurrency:并发请求数;标准档通常是 1, 4, 16
  • Optimization budget:每个 Kernel 最大优化尝试次数;
  • Demo mode:是否在每个步骤完成后暂停。

第二轮参数选择

确认实验计划

Demo mode 的区别:

  • 选择 Yes:每个关键步骤完成后,Agent 会展示结果并询问是否继续,适合学习;
  • 选择 No:Agent 会连续运行所有阶段,适合无人值守执行。

第一次运行建议选择 Yes,这样可以观察每一个中间产物。


七、/vllm-optimize 到底做了什么

整个 Skill 包含 Phase 0~6,共七个阶段。界面中显示“0/6”是因为编号从 0 开始,并不是只有六项工作。

Phase 0:环境检测

Agent 首先检查:

  • GPU 厂商、架构和数量;
  • AMD rocminforocm-smi 是否正常;
  • PyTorch 能否识别 GPU;
  • vLLM 和 PyTorch 版本。

结果保存到:

env_info.json

环境检测

Phase 1:启动 vLLM 服务

这一阶段会:

  1. 清理遗留的 vLLM API Server 和 VLLM::EngineCore
  2. 自动选择空闲 GPU;
  3. 检查本地模型,必要时下载 Hugging Face 模型;
  4. 设置 ROCm、TunableOps 和 Profiler 环境变量;
  5. 启动兼容 OpenAI API 的 vLLM 服务;
  6. 验证 /v1/models 和 Profiler API 是否可用。

Skill 会先发送 SIGTERM,等待进程优雅退出,只有超时后才使用 SIGKILL。这是因为直接 kill -9 可能留下仍然持有 /dev/kfd 的 EngineCore 子进程,导致显存无法释放。

启动 vLLM

Phase 2:并发压测与 GPU Profiling

Agent 会在不同并发等级下发送请求,并记录:

  • Output TPS:每秒生成 Token 数;
  • Total TPS:输入与输出 Token 总吞吐量;
  • P50 延迟;
  • 成功请求数。

然后在代表性的低并发和高并发负载下启动 PyTorch Profiler。Profiler 使用 record_shapes=True,从实际执行过程记录算子输入 Shape。

默认主要分析 decode 阶段。因为 prefill 和 decode 的执行特征不同:

  • prefill 通常处理较大的矩阵,计算密集;
  • decode 每次只生成少量 Token,矩阵的 M 较小,更容易受到调度和访存影响。

并发压测

Phase 3:识别性能瓶颈

这一阶段完成两项核心分析。

第一项是 Kernel 时间分布。kernel_breakdown.py 会将 GPU Kernel 分类为:

  • GEMM;
  • Attention;
  • 通信;
  • 内存操作;
  • 其他 Kernel。

第二项是提取真实 GEMM Shape。extract_shapes.py 会从 Trace 中得到实际出现的 (M, K, N),而不是根据模型配置猜测。

这非常重要,因为 vLLM 使用 continuous batching。运行时的 batch size 会不断变化,静态的模型参数无法准确反映真实服务中的 GEMM Shape。

GPU Kernel 分析

Phase 4:Kernel 和 GEMM 调优

Skill 默认先尝试 PyTorch TunableOps,而不是立即手写 Triton Kernel。

执行过程是:

  1. 记录运行中尚未调优的 GEMM Shape;
  2. 只保留 Profiler Trace 中真实出现的 Shape;
  3. 针对每个 Shape 离线尝试不同 rocBLAS 实现;
  4. 将最佳算法写入 tuned_gemm.csv
  5. 运行微基准,比较优化前后的速度。

如果 TunableOps 在适用 Shape 上的提升不足 10%,Skill 才建议进一步尝试 Triton Kernel 优化。

需要注意:小批量 decode 的 M <= 4 Shape 往往走 wvSplitKLLMM1,可能绕过 TunableOps;M > 4 的 Shape 更可能走 aten::mm 并被 TunableOps 接管。因此,低并发下接近 1.0x 并不一定表示优化没有生效。

Kernel 调优

Phase 5:注入优化并进行端到端验证

Skill 不会修改 /opt/usr 或 pip 安装的 vLLM 源码,而是生成一个运行时注入文件:

optimized/pypath/sitecustomize.py

启动优化版服务时,通过下面的方式加载:

PYTHONPATH=optimized/pypath:$PYTHONPATH

随后 Agent 会分别测试:

  1. 全新启动、未注入优化的 baseline 服务;
  2. 注入调优配置的 patched 服务。

两次测试必须使用相同模型、序列长度、并发等级和服务参数,才具有可比性。

端到端验证

Phase 6:生成报告并关闭服务

最后生成 Markdown 报告,其中包含:

  • 实验环境与配置;
  • baseline 吞吐量;
  • GPU Kernel 时间分布;
  • 真实 Shape 覆盖情况;
  • 微基准加速比;
  • 各并发等级的端到端加速比;
  • 每个优化目标的接受、拒绝或跳过原因;
  • 最终是否集成优化。

生成分析报告

最终报告摘要

运行完成后,可以在输出目录中找到 report/final_report.md

生成的 Markdown 报告


八、为什么“Kernel 快了”不代表服务一定快了

这是整个实验最值得理解的一点。

一个 Kernel 在微基准中提升 1.5 倍,并不能证明真实服务也提升 1.5 倍,原因可能包括:

  • 该 Kernel 只占总 GPU 时间的一小部分;
  • 优化只覆盖少数 Shape;
  • Shape 分派和 Python Hook 引入额外开销;
  • 自动调优在运行时反复搜索,抵消了收益;
  • 优化了 prefill,但线上瓶颈实际位于 decode;
  • 高并发变快,但单用户延迟发生退化。

因此,Skill 设置了五道验证门:

  1. 服务可用性:vLLM 必须正常启动并能响应请求;
  2. Shape 覆盖率:优化必须覆盖 Profiler 中出现的真实 Shape;
  3. 正确性:优化后的输出必须通过数值或确定性检查;
  4. 全并发 E2E TPS:任一指定并发等级都不能低于 baseline;
  5. 单用户 decode:并发为 1 时不能退化。

只要关键 Gate 失败,Agent 就不会宣称优化成功,而是自动回滚并在报告中记录原因。


九、如何阅读最终结果

建议重点关注以下指标。

1. Output TPS

Output TPS 表示每秒生成的 Token 数,是生成式推理吞吐量最直观的指标。

Speedup = Optimized Output TPS / Baseline Output TPS
  • 大于 1.0x:优化版更快;
  • 接近 1.0x:基本没有变化;
  • 小于 1.0x:发生性能退化,应回滚。

2. 不同并发下的变化

不要只看最高并发:

  • 并发 1 反映单用户体验和 decode 延迟;
  • 中等并发反映日常在线服务;
  • 高并发反映 GPU 饱和后的吞吐能力。

3. Kernel 时间占比

如果 GEMM 占 GPU 活跃时间的大部分,TunableOps 或 Triton GEMM 优化更有意义。如果 Attention 或内存操作才是瓶颈,只调 GEMM 很可能无法带来明显的端到端收益。

4. Shape 覆盖率

优化 Shape 数量太少时,即便微基准结果很好,也不代表能够覆盖真实线上负载。

5. Verdict

最终报告中的 Verdict 比单个 Speedup 数字更重要:

  • Integrated:所有必要验证通过,可以使用;
  • Rolled back:出现端到端退化,已经回滚;
  • Skipped:缺少真实 Shape,或该目标不适合当前优化方式;
  • Not integrated:完成分析,但没有进入生产式集成。

十、常见问题与排查方法

1. opencode: command not found

先确认安装脚本是否执行成功:

bash install.sh

注意启动命令通常为小写:

opencode

2. 找不到 /vllm-optimize

检查 Skill 是否安装:

ls -la ~/.claude/skills/vllm-optimize

必要时重新运行:

bash install.sh

3. 模型下载失败

可能是 Hugging Face 网络或镜像问题。可以:

  • 换用已经缓存到实例中的模型;
  • 检查 HF_ENDPOINT
  • 使用更小的模型先完成流程;
  • 确认实例磁盘空间是否足够。

4. vLLM 启动超时

查看对应输出目录中的服务日志:

tail -n 100 vllm_server.log

常见原因包括显存不足、残留 EngineCore、模型文件不完整、max-model-len 过大。

5. 显存没有释放

不要一开始就直接 kill -9。先向 API Server 和 EngineCore 发送 SIGTERM,等待其清理资源,再对残留进程使用 SIGKILL

可以检查持有 /dev/kfd 的进程:

for pid in /proc/[0-9]*; do
  ls -l "$pid/fd" 2>/dev/null | grep -q '/dev/kfd' && echo "$pid"
done

6. 微基准提升明显,但 E2E 没有提升

这并不反常。重点检查:

  • 优化 Shape 是否真实出现;
  • 这些 Shape 占总 GPU 时间多少;
  • 优化是否只覆盖 prefill;
  • 是否引入运行时 autotune 或分派开销;
  • 低并发请求是否绕过 TunableOps。

7. 实验运行时间超过 30 分钟

标题中的 30 分钟更适合描述“跑通标准流程”的理想情况。以下配置会显著增加耗时:

  • 大模型;
  • 1024 × 8192 等长输出;
  • 完整并发扫描;
  • Deep optimization budget;
  • 首次下载模型;
  • 网络速度较慢。

第一次实验建议使用单卡、标准并发、1024 × 1024 和默认优化预算。


十一、总结

通过这个实验,我们完成的不只是启动一个 vLLM 服务,而是跑通了一套相对完整的推理性能工程闭环:

部署 → 压测 → Profiling → 定位 → 调优 → 集成 → 验证 → 回滚/报告

这套方案最有价值的地方不是“Agent 自动运行了很多命令”,而是把性能工程经验编码进 Skill:只使用真实 Shape、保持实验负载一致、同时验证正确性和端到端性能,并诚实记录失败的优化。

对实际生产环境来说,这种思路也很有启发:Agent 可以提高性能分析和实验执行效率,但最终是否采用优化,仍然必须由可复现的数据和严格的验证门决定。

最后再次提醒:实验完成后,请及时关闭 vLLM 并销毁云实例,避免继续消耗开发者云点数。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐