性能测试培训 · 前沿篇
多模态 · Agent · 推理优化
1. 多模态模型架构与性能特征
多模态模型(Multimodal Model)是指能够同时理解和生成多种模态数据的AI模型,包括文本、图片、音频、视频等。相比纯文本大模型,多模态模型的性能测试面临全新的挑战。
1.1 多模态模型通用架构
输入(图/音/视频) → 模态编码器(Vision/Audio Encoder) → 跨模态对齐层(Projection) → 语言模型(LLM Backbone) → 文本/音频/图片输出
📖 架构核心思想
不同模态的数据先通过各自的编码器转换为向量表示(Embedding),再通过对齐层映射到语言模型能理解的统一空间,最终由语言模型完成理解和生成。这意味着每种模态的编码器都会引入额外的计算延迟。
主流多模态模型架构对比
| 模型 | Vision Encoder | Audio Encoder | LLM Backbone | 对齐方式 |
|---|---|---|---|---|
| GPT-5 / GPT-5.1 | 内置视觉编码器 | 内置音频编码器 | GPT-5 系列 | 原生融合 |
| Claude Opus 4.x | 内置视觉编码器 | — | Claude 系列 | 原生融合 |
| Gemini 3 Pro | SigLIP 增强版 | USM | Gemini Decoder | 原生多模态 |
| Qwen3-VL | ViT-bigG 升级版 | Paraformer | Qwen3-LLM | Cross-Attention |
| LLaVA(开源基线) | CLIP ViT-L | — | Vicuna/Llama | 线性投影 |
说明:早期代表(GPT-4o、Claude 3.5、通义千问-VL 等)多为历史版本,2026 年主流已升级为 GPT-5、Claude Opus 4.x、Gemini 3、Qwen3-VL;LLaVA 作为开源教学基线仍具参考价值。
1.2 不同模态的Token化方式与性能影响
对性能测试人员来说,理解不同模态的Token化方式至关重要——它直接决定了推理的计算量和显存占用。
| 模态 | Token化方式 | 典型Token数量 | 对性能的影响 |
|---|---|---|---|
| 文本 | BPE/SentencePiece | 1个汉字 ≈ 1-2个Token | 基准,最轻量 |
| 图片 | Tile切分 → ViT编码 | 256px: ~85 Tokens 1024px: ~765 Tokens 4K: ~5000+ Tokens | 高分辨率图片Token数暴增,TTFT显著增加 |
| 视频 | 抽帧 → 每帧Token化 | 10s视频(1fps): ~850 Tokens 60s视频(1fps): ~5000 Tokens 5min视频: ~25000+ Tokens | 超长Token序列,显存容易爆 |
| 音频 | 梅尔频谱 → Encoder | 1秒音频 ≈ 25-50 Tokens 60秒音频 ≈ 1500-3000 Tokens | 相对轻量,但实时场景对延迟敏感 |
⚠️ Token数量的性能放大效应
一张4K图片可能产生5000+ Tokens,相当于一篇长文章的Token量。10并发发送4K图片 = 50000 Tokens同时涌入,对GPU显存和Prefill计算压力极大。这是多模态性能测试与纯文本性能测试最根本的差异。
1.3 多模态 vs 纯文本的性能差异
| 性能维度 | 纯文本对话 | 图片理解 | 视频理解 | 语音识别 | 图片生成 |
|---|---|---|---|---|---|
| TTFT | 200ms~1s | 500ms~3s | 2s~15s | 300ms~2s | N/A(非流式) |
| Token吞吐 | 30~80 t/s | 20~50 t/s | 10~30 t/s | N/A | N/A |
| 端到端延迟 | 2~10s | 3~15s | 10~60s | 0.5~5s | 5~120s |
| GPU显存 | 基准 | +20~50% | +100~300% | +10~30% | +200~500% |
| 并发能力 | 10~100 | 5~50 | 2~10 | 10~100 | 1~5 |
| 计费 | 按Token | 按Token(图片Token高) | 按Token(极高) | 按音频时长 | 按图片数 |
1.4 代表产品一览
| 模态 | 理解类产品 | 生成类产品 |
|---|---|---|
| 图片 | GPT-5 / Claude Opus 4.x / Gemini 3 Pro / Qwen3-VL | GPT-Image / Midjourney / Stable Diffusion / 即梦 / 可灵 |
| 视频 | Gemini 3 Pro / GPT-5 / Qwen3-VL | 可灵 / Runway / Sora 2 / Vidu |
| 语音 | Whisper / 阿里通义听悟 / 讯飞 / Azure STT | OpenAI TTS / 讯飞 / Azure TTS / ChatTTS / Fish Speech |
| 综合 | GPT-5(原生多模态)/ Gemini 3 Pro(原生多模态) | — |
课堂练习
- 选取你项目中使用的一个多模态模型(如GPT-5或Qwen3-VL),查阅其文档,列出它支持哪些模态以及各模态的Token计费规则
- 估算:发送一张1024px的图片 + 100字文本提问,总共产生多少Token?对比纯文本提问的Token数量
- 讨论:你的团队是否需要对多模态场景做性能测试?哪种模态是你们最常用的?
2. 图片理解性能测试
图片理解是最常见的多模态场景,用户上传一张图片让模型描述、识别文字、分析图表等。看似简单的操作背后涉及图片上传、编码、Token化、推理等多个环节。
2.1 测试场景分类
| 场景 | 典型Prompt | 输出特征 | 性能特点 |
|---|---|---|---|
| 图片描述 | "描述这张图片的内容" | 中等长度文字 | 标准场景,作为基准 |
| OCR文字提取 | "提取图片中所有文字" | 可能很长(取决于图中文字量) | 高分辨率图更准但更慢 |
| 图表数据提取 | "把这个表格转成JSON" | 结构化数据 | 需要高分辨率才能识别 |
| 多图对比分析 | "对比这两张图的差异" | 分析性文字 | Token数翻倍,TTFT显著增加 |
| 物体检测/计数 | "图中有多少个人" | 简短回答 | 推理简单但编码一样耗时 |
| 手写识别 | "识别手写文字内容" | 识别结果 | 需要更精细的编码 |
2.2 图片理解的处理流程与性能瓶颈
图片上传 → 图片解码(JPEG/PNG) → 缩放/Tile切分 → Vision Encoder编码 → 跨模态对齐 → LLM推理 → 文本输出
💡 瓶颈分析
- 图片上传:受网络带宽限制,4K图片~5MB,弱网环境可能耗时数秒
- Vision Encoder编码:计算密集,高分辨率图片编码耗时200-1000ms
- Prefill阶段:图片Token数量远大于文本,Prefill时间显著增加
- 显存占用:图片Token的KV Cache占用大量显存
2.3 性能指标体系
| 指标 | 定义 | 测量方式 | 基准参考值 |
|---|---|---|---|
| 图片预处理耗时 | 上传 → 编码 → Token化 | 服务端日志或API响应中的耗时字段 | 100~500ms |
| TTFT(含图片编码) | 发送请求到首Token | 客户端SSE计时 | 500ms~3s |
| 总响应时间 | 发送到完整回答 | 客户端计时 | 3~15s |
| 分辨率-性能系数 | 不同分辨率下的性能差异 | 控制变量对比 | 4K约为256px的3-5倍 |
| 格式-性能差异 | JPEG/PNG/WebP/HEIC差异 | 相同内容不同格式对比 | 通常差异<10% |
| 多图性能退化 | 图片数量增加时的性能变化 | 1/5/10/20张图片对比 | 接近线性退化 |
2.4 不同分辨率的性能影响
| 分辨率 | 估算Token数 | TTFT (1并发) | 总响应时间 | 显存增量 |
|---|---|---|---|---|
| 256×256 | ~85 | ~400ms | ~3s | +50MB |
| 512×512 | ~340 | ~600ms | ~4s | +150MB |
| 1024×1024 | ~765 | ~1s | ~6s | +400MB |
| 2048×2048 | ~3000 | ~2s | ~10s | +1.5GB |
| 4K (3840×2160) | ~5500 | ~3.5s | ~15s | +3GB |
2.5 不同图片格式的性能差异
| 格式 | 文件大小(1024px) | 解码速度 | API支持度 | 推荐度 |
|---|---|---|---|---|
| JPEG | ~150KB | 快 | 全平台支持 | 推荐 |
| PNG | ~800KB | 中 | 全平台支持 | 推荐 |
| WebP | ~100KB | 快 | 大部分支持 | 推荐 |
| HEIC | ~120KB | 中 | 部分支持 | 需验证 |
| BMP | ~3MB | 快(无压缩) | 部分支持 | 不推荐 |
| Base64编码 | 原始×1.33 | 需额外解码 | 全平台支持 | 体积增大 |
2.6 多图场景的性能影响
图片数量 vs 性能退化(1024px JPEG,GPT-4o):
图片数 Token数 TTFT 总响应时间 显存增量
1张 ~800 ~1s ~5s +400MB
3张 ~2400 ~2s ~8s +1.2GB
5张 ~4000 ~3s ~12s +2GB
10张 ~8000 ~5s ~20s +4GB
20张 ~16000 ~10s ~35s +8GB
结论:
→ Token数与图片数接近线性关系
→ TTFT增长比线性更快(Prefill计算量是O(n²)级别)
→ 超过10张图片时性能显著恶化2.7 完整测试用例表
| 用例ID | 场景 | 输入 | 关注指标 | PASS标准 |
|---|---|---|---|---|
| IMG-01 | 单图描述(低分辨率) | 256px JPEG + "描述这张图" | TTFT / E2E | TTFT P95 < 1s, E2E P95 < 5s |
| IMG-02 | 单图描述(高分辨率) | 1024px JPEG + "描述这张图" | TTFT / E2E | TTFT P95 < 2s, E2E P95 < 10s |
| IMG-03 | 单图描述(4K) | 4K JPEG + "描述这张图" | TTFT / 显存 | TTFT P95 < 5s, 无OOM |
| IMG-04 | OCR文字提取 | 含密集文字的文档图片 | E2E / 准确性 | E2E P95 < 15s |
| IMG-05 | 图表数据提取 | Excel截图 + "转为JSON" | E2E / 输出完整性 | E2E P95 < 15s |
| IMG-06 | 多图对比(2张) | 两张1024px图 + "对比差异" | TTFT / E2E | TTFT P95 < 3s |
| IMG-07 | 多图对比(5张) | 五张1024px图 + "总结共同点" | TTFT / 显存 | TTFT P95 < 6s, 无OOM |
| IMG-08 | 多图对比(10张) | 十张1024px图 + "逐一描述" | TTFT / E2E / 显存 | TTFT P95 < 10s |
| IMG-09 | 不同格式对比 | 同图JPEG/PNG/WebP + 相同Prompt | TTFT差异 | 格式间差异 < 20% |
| IMG-10 | 并发图片请求 | 10并发 × 1024px图片 | TTFT / 错误率 / 显存 | 错误率 < 1%, 无OOM |
| IMG-11 | Base64 vs URL | 同图Base64编码 vs URL引用 | 请求耗时差异 | 记录差异即可 |
| IMG-12 | 超大图片边界 | 10MB+ 图片 | 是否被拒绝/自动压缩 | 有合理处理(非500错误) |
2.8 压测方法:构造多图并发请求
import asyncio
import httpx
import base64
import time
from pathlib import Path
async def image_benchmark(image_paths: list[str], prompt: str, concurrency: int):
"""多图并发图片理解压测"""
def encode_image(path: str) -> str:
with open(path, "rb") as f:
return base64.b64encode(f.read()).decode()
images_b64 = [encode_image(p) for p in image_paths]
async def single_request(client, img_b64):
content = [
{"type": "text", "text": prompt},
{"type": "image_url", "image_url": {
"url": f"data:image/jpeg;base64,{img_b64}",
"detail": "high"
}}
]
payload = {
"model": "gpt-4o",
"messages": [{"role": "user", "content": content}],
"stream": True, "max_tokens": 300
}
t0 = time.perf_counter()
ttft = None
async with client.stream("POST", "/v1/chat/completions",
json=payload) as resp:
async for line in resp.aiter_lines():
if line.startswith("data: ") and line[6:] != "[DONE]":
if ttft is None:
ttft = (time.perf_counter() - t0) * 1000
total = (time.perf_counter() - t0) * 1000
return {"ttft_ms": ttft, "total_ms": total}
sem = asyncio.Semaphore(concurrency)
async def worker(client, img):
async with sem:
return await single_request(client, img)
headers = {"Authorization": "Bearer sk-xxx"}
async with httpx.AsyncClient(
base_url="https://api.openai.com",
headers=headers, timeout=120
) as client:
tasks = [worker(client, img) for img in images_b64]
results = await asyncio.gather(*tasks)
return results⚠️ 费用提醒
图片理解的Token消耗远大于文本!一张1024px高清图片约765 Tokens,相当于一篇500字文章。10并发 × 20张图片 = 约15,000图片Tokens,加上文本和输出,一轮压测可能消耗几万Token。务必先算好预算!
课堂练习
- 准备3张不同分辨率(256/1024/4K)的测试图片,分别测量TTFT和总响应时间,画出分辨率-延迟曲线
- 用同一张图片分别以JPEG、PNG、WebP格式上传,对比性能差异
- 测试多图场景:发送1/3/5/10张图片,观察TTFT的增长趋势
- 计算你的项目中图片理解场景一次压测(10并发×5分钟)的预估费用
3. 图片生成性能测试
图片生成与图片理解在性能特征上截然不同——它不是流式返回的,而是一次性返回完整图片。生成时间可以从几秒到几分钟不等。
3.1 代表产品与API
| 产品/模型 | 类型 | 典型生成时间 | API可用性 | 计费方式 |
|---|---|---|---|---|
| DALL-E 3 | API服务 | 10~30s | 公开API | 按图片数量 |
| Midjourney | SaaS服务 | 30~120s | 非官方API | 按订阅 |
| Stable Diffusion (自部署) | 自部署 | 5~60s | 完全控制 | GPU成本 |
| 可灵 | API服务 | 15~60s | 公开API | 按图片数量 |
| Flux | 自部署/API | 10~40s | 公开API | 按图片数量 |
3.2 图片生成流程
文本Prompt → 文本编码(CLIP) → 扩散模型推理(N步) → 图片解码(VAE) → 后处理/安全检查 → 返回图片
📖 与文本生成的本质区别
- 非流式:文本生成可以逐Token流式返回,图片生成必须等所有扩散步骤完成后一次性返回
- 无TTFT概念:用户必须等到整张图片生成完毕才能看到结果
- GPU显存占用极高:生成1024px图片可能需要6~10GB显存,远超文本推理
- 计算密集型:扩散模型需要反复迭代(20~100步),每步都是完整的前向传播
3.3 性能指标
| 指标 | 定义 | 影响因素 | 典型值 |
|---|---|---|---|
| 生成延迟 | 从提交Prompt到返回图片的总时间 | 图片尺寸、步数、模型 | 5~120s |
| 并发生成能力 | 同时能处理几个生成请求 | GPU显存和数量 | 1~8(单卡) |
| GPU显存峰值 | 生成过程中的最大显存占用 | 图片尺寸、batch size | 6~24GB |
| 每秒迭代步数(it/s) | 扩散模型每秒完成的迭代步数 | GPU算力、模型大小 | 1~10 it/s |
3.4 不同参数组合的性能对比
| 参数组合 | 生成时间(A100) | 显存占用 | 图片质量 |
|---|---|---|---|
| SD1.5, 512px, 20步 | ~3s | ~4GB | 基础 |
| SD1.5, 512px, 50步 | ~7s | ~4GB | 良好 |
| SDXL, 1024px, 30步 | ~12s | ~8GB | 很好 |
| SDXL, 1024px, 50步 | ~18s | ~8GB | 优秀 |
| SD3, 1024px, 28步 | ~15s | ~10GB | 优秀 |
| Flux, 1024px, 20步 | ~20s | ~12GB | 顶级 |
| SDXL, 2048px, 50步 | ~50s | ~16GB | 优秀(超高清) |
3.5 自部署 vs API调用的性能测试差异
| 维度 | 自部署(Stable Diffusion) | API调用(DALL-E 3) |
|---|---|---|
| 可控性 | 完全控制参数、步数、采样器 | 只能控制尺寸、质量等有限参数 |
| 并发上限 | 由GPU数量决定 | 由API配额决定 |
| 性能瓶颈 | GPU计算和显存 | API限流和网络 |
| 压测方法 | GPU监控 + 并发阶梯加压 | 限流探测 + 排队监控 |
| 费用 | GPU租赁/购买成本 | 按图片数量付费 |
3.6 测试用例表
| 用例ID | 场景 | 输入参数 | 关注指标 | PASS标准 |
|---|---|---|---|---|
| GEN-01 | 基础生成(512px) | 短Prompt, 512px, 20步 | 生成延迟 | 延迟 < 10s |
| GEN-02 | 高质量生成(1024px) | 长Prompt, 1024px, 50步 | 生成延迟 | 延迟 < 30s |
| GEN-03 | 超高清生成(2048px) | 1024px, 50步 | 延迟 / 显存 | 延迟 < 60s, 无OOM |
| GEN-04 | 并发生成(2并发) | 2个同时请求 | 各自延迟 / 显存 | 延迟 < 单请求×1.5 |
| GEN-05 | 并发生成(5并发) | 5个同时请求 | 排队 / OOM | 无OOM, 排队透明 |
| GEN-06 | 批量生成(10张) | 连续提交10个请求 | 总耗时 / 平均延迟 | 总耗时合理 |
| GEN-07 | 不同步数对比 | 20/30/50/100步 | 延迟随步数的变化 | 接近线性增长 |
| GEN-08 | 不同尺寸对比 | 512/768/1024/2048 | 延迟随尺寸的变化 | 记录变化趋势 |
课堂练习
- 选择一个图片生成API(DALL-E 3或自部署SD),测量不同尺寸下的生成延迟
- 如果是自部署模型,用
nvidia-smi监控生成过程中的GPU显存变化,找出显存峰值 - 测试并发能力:逐步增加并发数(1→2→3→5),找出单卡GPU的并发上限
- 对比不同步数(20/50)对生成延迟的影响,计算每增加一步的边际延迟
4. 视频理解性能测试
视频理解是多模态中计算量最大的场景——一段60秒的视频经过抽帧和编码后可以产生数千甚至数万个Token,对GPU显存和推理时间提出极大挑战。
4.1 视频理解处理流程
视频上传 → 视频解码 → 抽帧(采样策略) → 每帧Vision Encoder编码 → 时序建模 → LLM推理 → 文本输出
4.2 关键性能瓶颈
抽帧策略对性能和质量的影响
| 抽帧策略 | 帧数(60s视频) | Token数 | 编码时间 | 理解质量 |
|---|---|---|---|---|
| 每秒1帧(1fps) | 60帧 | ~5000 | ~5s | 基本够用 |
| 每秒5帧(5fps) | 300帧 | ~25000 | ~20s | 动作细节好 |
| 关键帧检测 | 10~30帧 | ~1000~2500 | ~2s | 场景变化好,连续动作差 |
| 均匀采样8帧 | 8帧 | ~700 | ~0.5s | 粗略概览 |
⚠️ 视频Token数量的爆炸性增长
视频参数 → Token数量估算:
10秒视频, 1fps, 720p: 10帧 × ~300 tokens/帧 = ~3,000 tokens
60秒视频, 1fps, 720p: 60帧 × ~300 tokens/帧 = ~18,000 tokens
5分钟视频, 1fps, 720p: 300帧 × ~300 tokens/帧 = ~90,000 tokens ← 接近上下文窗口极限!
30分钟视频, 1fps, 720p: 无法直接处理 → 必须分段
对比:一篇3000字文章 ≈ ~5000 tokens
一段60秒视频 ≈ ~18000 tokens = 3.6倍4.3 视频时长 × 分辨率 × 帧率的性能矩阵
| 视频参数 | Token估算 | TTFT | 总响应时间 | 显存需求 |
|---|---|---|---|---|
| 10s, 480p, 1fps | ~1,500 | ~2s | ~8s | +1GB |
| 10s, 1080p, 1fps | ~3,000 | ~3s | ~12s | +2GB |
| 60s, 720p, 1fps | ~12,000 | ~8s | ~30s | +6GB |
| 60s, 1080p, 1fps | ~18,000 | ~12s | ~45s | +10GB |
| 5min, 720p, 1fps | ~60,000 | ~30s | ~120s | +30GB |
| 30min, 720p, 1fps | ~360,000 | 超出窗口 | 需分段处理 | 不可行 |
4.4 长视频分段处理策略
方案A:滑动窗口法
将30分钟视频切分为6段×5分钟
每段独立理解 → 最后汇总
优点:简单可靠
缺点:段间信息丢失,汇总需要额外LLM调用
方案B:层次化摘要
全视频低帧率(0.2fps)粗览 → 生成时间线
关键片段高帧率(5fps)精读 → 详细分析
优点:效率高
缺点:实现复杂
方案C:音频+关键帧
提取音频转文字(ASR) → 关键帧采样 → 结合分析
优点:信息损失少
缺点:多模态流水线,任意环节可能瓶颈4.5 测试用例表
| 用例ID | 场景 | 视频参数 | 关注指标 | PASS标准 |
|---|---|---|---|---|
| VID-01 | 短视频理解 | 10s, 720p | TTFT / E2E | TTFT < 5s, E2E < 15s |
| VID-02 | 中等视频理解 | 60s, 720p | TTFT / E2E / 显存 | TTFT < 15s, E2E < 60s |
| VID-03 | 长视频理解 | 5min, 720p | E2E / 是否超时 | 能完成或合理分段 |
| VID-04 | 高清视频理解 | 10s, 1080p | TTFT / 与720p对比 | 记录差异 |
| VID-05 | 4K视频理解 | 10s, 4K | TTFT / 显存 / OOM | 无OOM |
| VID-06 | 并发视频请求 | 3并发 × 10s视频 | 各自延迟 / 显存 | 无OOM, 错误率<1% |
| VID-07 | 不同抽帧策略对比 | 同视频, 1fps vs 关键帧 | 延迟 vs 质量 | 记录差异 |
| VID-08 | 超长视频边界 | 30min视频 | 系统行为 | 合理拒绝或自动分段 |
课堂练习
- 准备3段不同时长(10s/60s/5min)的测试视频,测量各自的处理时间
- 对比不同抽帧策略(1fps vs 关键帧)的性能和理解质量差异
- 尝试发送超长视频(超过模型上下文窗口),观察系统如何处理
- 如果是自部署模型,在处理视频时监控GPU显存变化趋势
5. 视频生成性能测试
视频生成是当前AI中计算量最大、耗时最长的任务。一段5秒的视频可能需要数分钟甚至数十分钟来生成,对GPU资源的消耗远超其他任何模态。
5.1 代表产品
| 产品 | 典型生成时间 | 最大视频时长 | 最高分辨率 | 接入方式 |
|---|---|---|---|---|
| 可灵 | 2~10min | ~10s | 1080p | API |
| Runway Gen-3 | 1~5min | ~10s | 1080p | API |
| Sora | 5~20min | ~60s | 1080p | 受限API |
| Pika | 1~3min | ~4s | 1080p | API |
| Stable Video Diffusion(自部署) | 3~15min | ~4s | 1024px | 自部署 |
5.2 视频生成流程特殊性
提交生成请求 → 进入排队 → 扩散模型推理(逐帧) → 时序一致性后处理 → 视频编码 → 安全审核 → 可下载
💡 异步任务模型
几乎所有视频生成服务都采用异步任务模型:提交请求后返回task_id,客户端需要定期轮询状态,直到任务完成后下载结果。这与文本/图片理解的同步请求-响应模式完全不同。
1. POST /api/video/generate → 返回 { "task_id": "abc123", "status": "queued" }
2. GET /api/video/status/abc123 → { "status": "processing", "progress": 45 }
3. GET /api/video/status/abc123 → { "status": "completed", "video_url": "..." }
4. GET 视频下载URL → 二进制视频文件5.3 性能指标
| 指标 | 定义 | 典型值 | 说明 |
|---|---|---|---|
| 排队等待时间 | 提交到开始生成 | 0~30min | 取决于平台负载 |
| 实际生成时间 | 开始生成到完成 | 1~20min | 核心指标 |
| 生成比 | 生成时间 / 视频时长 | 10x~100x | 生成5s视频可能需要5min |
| 总端到端时间 | 提交到可下载 | 2~30min | 排队+生成+后处理 |
| 并发任务数 | 平台同时处理的任务数 | 1~3(单用户) | 通常有严格限制 |
| GPU消耗 | 单个生成任务的GPU资源 | 24~80GB显存 | 远超文本和图片 |
5.4 不同参数的性能影响
| 参数 | 选项 | 对生成时间的影响 | 对质量的影响 |
|---|---|---|---|
| 视频时长 | 2s / 5s / 10s | 接近线性增长 | 越长越容易不一致 |
| 分辨率 | 480p / 720p / 1080p | 1080p约为480p的3-5倍 | 更清晰 |
| 帧率 | 8fps / 24fps / 30fps | 30fps约为8fps的3倍 | 更流畅 |
| 风格 | 写实 / 动画 / 电影 | 影响较小(~10%) | 风格化差异 |
5.5 并发测试的特殊性
⚠️ 视频生成并发数极低
不要用文本/图片理解的并发思维来压测视频生成!
文本对话:50并发是正常起步
图片理解:10-20并发可以做
图片生成:5-10并发已经不小
视频生成:1-3并发就是极限(单用户配额)
视频生成压测的重点不是"高并发",而是:
→ 排队机制是否合理
→ 任务状态轮询是否可靠
→ 长时间等待后是否能正常返回
→ 多个用户同时提交时的公平调度5.6 测试用例表
| 用例ID | 场景 | 输入参数 | 关注指标 | PASS标准 |
|---|---|---|---|---|
| VGEN-01 | 短视频生成 | "一只猫在走路", 2s, 720p | 总耗时 | < 5min |
| VGEN-02 | 中等视频生成 | 详细描述, 5s, 1080p | 总耗时 | < 10min |
| VGEN-03 | 长视频生成 | 详细描述, 10s, 1080p | 总耗时 | < 20min |
| VGEN-04 | 并发提交(2个) | 同时提交2个请求 | 排队/并行 | 合理排队或并行 |
| VGEN-05 | 并发提交(5个) | 同时提交5个请求 | 排队顺序/公平性 | 先到先处理 |
| VGEN-06 | 轮询可靠性 | 提交后持续轮询状态 | 状态变化正确性 | queued→processing→completed |
| VGEN-07 | 超时场景 | 提交后等待30min | 是否有超时机制 | 有合理的超时和通知 |
| VGEN-08 | 取消任务 | 生成中取消 | 是否能成功取消 | 能取消且释放资源 |
课堂练习
- 选择一个视频生成API,测量从提交到完成的全流程耗时,区分排队时间和生成时间
- 同时提交2个生成请求,观察是串行排队还是并行处理
- 编写一个轮询脚本,每5秒查询一次任务状态,记录完整的状态变化时间线
- 计算你的视频生成场景的"生成比"(生成时间/视频时长),评估是否满足业务需求
6. 语音识别(ASR)性能测试
语音识别(ASR, Automatic Speech Recognition)将音频转为文字,是AI语音交互的基础能力。与文本和图片不同,ASR有独特的实时性要求——处理速度必须跟上甚至快于说话速度。
6.1 ASR Pipeline
音频输入 → 预处理(降噪/VAD) → 特征提取(梅尔频谱) → 模型推理 → 解码/后处理 → 文本输出
6.2 代表产品/模型
| 产品/模型 | 类型 | 支持语种 | 实时性 | 特点 |
|---|---|---|---|---|
| Whisper (OpenAI) | API/自部署 | 99种语言 | 离线为主 | 准确率高,多语种 |
| Whisper large-v3 | 自部署 | 99种语言 | 离线/流式 | 开源可部署 |
| 阿里达摩院 Paraformer | API/自部署 | 中英 | 实时 | 中文效果好 |
| 讯飞ASR | API | 中英+方言 | 实时 | 方言支持好 |
| Azure Speech | API | 100+语言 | 实时 | 企业级稳定 |
6.3 核心性能指标
| 指标 | 定义 | 计算公式 | 合格标准 |
|---|---|---|---|
| 实时率(RTF) | 处理1秒音频需要多少秒 | 处理时间 / 音频时长 | RTF < 1.0(才能实时) |
| 首字延迟 | 流式场景从开始发送到第一个字 | t(首字) - t(发送) | < 500ms |
| 端到端延迟 | 整段音频从提交到全部文字返回 | t(完成) - t(提交) | < 音频时长 × 1.5 |
| 字错率(WER) | 识别错误率(功能指标) | (S+D+I) / N | < 5%(安静环境中文) |
📐 RTF(Real-Time Factor)详解
RTF = 处理时间 / 音频时长
RTF = 0.1: 处理1秒音频只需0.1秒 → 非常快,有余量
RTF = 0.5: 处理1秒音频需要0.5秒 → 快于实时,可以做流式
RTF = 1.0: 处理1秒音频需要1.0秒 → 刚好实时,无余量
RTF = 2.0: 处理1秒音频需要2.0秒 → 慢于实时,只能离线
要求:
→ 离线转写场景:RTF < 1.0 即可
→ 实时字幕场景:RTF < 0.3(需要余量处理网络抖动)
→ 实时对话场景:RTF < 0.2(用户等不起)6.4 不同音频参数的性能影响
| 参数 | 选项 | 对性能的影响 | 推荐选择 |
|---|---|---|---|
| 采样率 | 8kHz / 16kHz / 44.1kHz | 8k最快但质量差,16k平衡,44.1k数据量大但边际提升小 | 16kHz |
| 编码格式 | WAV / MP3 / AAC / OGG | WAV无压缩最快解码,MP3需解码但文件小 | 16kHz 16bit WAV |
| 通道数 | 单声道 / 立体声 | 立体声数据量翻倍但ASR通常只需单声道 | 单声道 |
| 音频时长 | 1s / 10s / 60s / 5min | 接近线性增长(离线模式) | 分段处理长音频 |
6.5 不同场景的性能差异
| 场景 | 典型RTF | 典型WER | 说明 |
|---|---|---|---|
| 安静环境 + 普通话 | 0.1~0.3 | 2~5% | 最佳场景 |
| 安静环境 + 英语 | 0.1~0.3 | 3~8% | 取决于口音 |
| 嘈杂环境(SNR 10dB) | 0.2~0.4 | 8~15% | 预处理增加延迟 |
| 多人说话(重叠) | 0.3~0.5 | 15~30% | 需要说话人分离 |
| 口音/方言 | 0.2~0.4 | 10~25% | 需要专用模型 |
| 电话音质(8kHz) | 0.1~0.2 | 5~12% | 低采样率影响质量 |
6.6 流式ASR vs 离线ASR
| 维度 | 流式ASR | 离线ASR |
|---|---|---|
| 使用场景 | 实时字幕、语音输入、客服 | 录音转写、会议纪要 |
| 关键指标 | 首字延迟、RTF | 总处理时间、WER |
| 数据发送 | 音频边录制边发送(WebSocket) | 完整音频文件一次上传 |
| 结果返回 | 逐句/逐字实时返回 | 全部处理完一次性返回 |
| 准确率 | 略低(缺少后文上下文) | 更高(有完整上下文) |
| 压测重点 | 首字延迟、WebSocket连接数 | RTF、并发处理能力 |
6.7 测试用例表
| 用例ID | 场景 | 输入参数 | 关注指标 | PASS标准 |
|---|---|---|---|---|
| ASR-01 | 短音频识别 | 5s, 16kHz, WAV, 普通话 | RTF / E2E | RTF < 0.5 |
| ASR-02 | 中等音频识别 | 60s, 16kHz, WAV, 普通话 | RTF / E2E | RTF < 0.5 |
| ASR-03 | 长音频识别 | 5min, 16kHz, WAV | RTF / 是否分段 | RTF < 1.0 |
| ASR-04 | 不同采样率对比 | 同内容, 8k/16k/44.1k | RTF和WER差异 | 记录差异 |
| ASR-05 | 不同编码格式对比 | 同内容, WAV/MP3/AAC | RTF差异 | 格式间差异 < 30% |
| ASR-06 | 嘈杂环境 | 带噪音音频, SNR 10dB | RTF / WER | WER < 15% |
| ASR-07 | 多语种 | 中文/英文/日文 | RTF / WER per lang | 各语种WER合理 |
| ASR-08 | 并发请求(10) | 10并发 × 10s音频 | RTF / 错误率 | RTF < 1.0, 错误率 < 1% |
| ASR-09 | 流式ASR首字延迟 | WebSocket + 边发边识别 | 首字延迟 | 首字 < 500ms |
| ASR-10 | 流式ASR连接数 | 50/100/200 WebSocket连接 | 连接成功率 | 成功率 > 99% |
课堂练习
- 准备不同时长(5s/30s/60s)的测试音频,分别测量RTF,验证是否满足实时性要求
- 用同一段音频分别以WAV和MP3格式上传,对比处理时间差异
- 如果有流式ASR接口,测量WebSocket连接的首字延迟
- 在不同并发(1/5/10/20)下测试离线ASR的RTF变化趋势
7. 语音合成(TTS)性能测试
语音合成(TTS, Text-To-Speech)将文字转化为语音。在AI对话场景中,TTS的性能直接影响用户的"听觉体验"——如果合成速度慢于播放速度,用户就会听到断断续续的语音。
7.1 TTS Pipeline
文本输入 → 文本分析(分句/韵律) → 声学模型(生成频谱) → 声码器(频谱→波形) → 后处理(增益/降噪) → 音频输出
7.2 代表产品/模型
| 产品/模型 | 类型 | 流式支持 | 音色数量 | 特点 |
|---|---|---|---|---|
| OpenAI TTS | API | 支持 | 6种 | 自然度高,多语种 |
| Azure TTS | API | 支持 | 400+ | 企业级,SSML支持 |
| 讯飞TTS | API | 支持 | 100+ | 中文效果好 |
| ChatTTS | 自部署 | 支持 | 可克隆 | 对话式TTS,开源 |
| Fish Speech | 自部署 | 支持 | 可克隆 | 零样本克隆,开源 |
| Bark | 自部署 | 部分 | 有限 | 可生成非语音声音 |
7.3 核心性能指标
| 指标 | 定义 | 计算方式 | 合格标准 |
|---|---|---|---|
| 首字节延迟 | 发送文本到收到第一段音频 | t(首音频) - t(请求) | < 300ms (流式TTS) |
| 合成速度比 | 每秒生成多少秒音频 | 音频时长 / 合成时间 | > 2.0x(至少2倍速) |
| 端到端延迟 | 全部文本转为全部音频的时间 | t(完成) - t(请求) | < 文本朗读时长 |
| 音频质量(MOS) | 主观听感评分(1~5分) | 人工评测或客观指标 | > 4.0 |
💡 流式TTS的关键约束:合成速度必须快于播放速度
场景:用户在听AI的语音回复
播放速度 = 1.0x(正常语速)
合成速度 > 1.0x → 正常,音频数据缓冲区持续增长
合成速度 = 1.0x → 刚好,一旦网络抖动就会卡顿
合成速度 < 1.0x → 必然卡顿!用户听到"一句...停...一句...停..."
推荐:合成速度 > 2.0x,预留足够缓冲应对网络和计算波动7.4 不同参数的性能影响
| 参数 | 选项 | 对延迟的影响 | 对质量的影响 |
|---|---|---|---|
| 文本长度 | 10字 / 100字 / 500字 / 2000字 | 接近线性增长 | 无显著影响 |
| 语速 | 0.5x / 1.0x / 1.5x / 2.0x | 快语速合成更快 | 过快可能失真 |
| 音色 | 不同speaker | 影响较小(< 10%) | 因音色而异 |
| 情感 | 中性 / 高兴 / 悲伤 / 严肃 | 可能增加10~20% | 更自然 |
| 采样率 | 16kHz / 24kHz / 44.1kHz | 高采样率略慢 | 高采样率更清晰 |
7.5 测试用例表
| 用例ID | 场景 | 输入 | 关注指标 | PASS标准 |
|---|---|---|---|---|
| TTS-01 | 短文本合成 | "你好,有什么可以帮你?" | 首字节延迟 | < 300ms |
| TTS-02 | 中等文本合成 | 100字段落 | 合成速度比 | > 2.0x |
| TTS-03 | 长文本合成 | 1000字文章 | E2E延迟 / 合成速度 | 合成速度 > 2.0x |
| TTS-04 | 流式TTS | 边收到文字边合成 | 首字节延迟 / 卡顿率 | 首字节 < 300ms, 无卡顿 |
| TTS-05 | 不同语速对比 | 同文本, 0.5x/1.0x/2.0x | 合成速度差异 | 记录差异 |
| TTS-06 | 并发合成(10) | 10并发 × 短文本 | 合成速度/错误率 | 合成速度 > 1.5x |
| TTS-07 | 并发合成(50) | 50并发 × 短文本 | 合成速度/错误率 | 合成速度 > 1.0x |
| TTS-08 | 多音色对比 | 同文本, 不同音色 | 延迟差异 | 音色间差异 < 20% |
课堂练习
- 选择一个TTS API,测量不同文本长度(10字/100字/1000字)下的合成速度比
- 测试流式TTS的首字节延迟,确认是否满足实时对话需求
- 在不同并发数下测试合成速度的变化,找到"合成速度 < 播放速度"的并发拐点
- 如果你的场景是LLM输出文字+TTS播报,测量"LLM首Token → TTS首音频"的端到端延迟
8. 多模态综合场景
真实业务中,往往不会只用到单一模态。多种模态组合在一起,性能问题会变得更加复杂——任何一个环节的延迟都会影响整体体验。
8.1 场景1:图片+文字混合对话
用户发文字 → AI回复文字 → 用户发图片+文字 → AI理解图片并回复 → 用户追问 → AI结合图片上下文回答
📖 性能挑战
- 第3轮发送图片时,上下文包含前面2轮的文本 + 新图片的Token,总Token数激增
- 第5轮追问时,上下文包含了前面所有轮次的内容(含图片Token),TTFT会显著增加
- 多轮对话中图片Token不会被"遗忘",一直占用上下文窗口
| 对话轮次 | 内容 | 累积Token估算 | TTFT预期 |
|---|---|---|---|
| 第1轮 | 纯文字提问 | ~100 | ~300ms |
| 第2轮 | 纯文字追问 | ~300 | ~400ms |
| 第3轮 | 发送1024px图片 | ~1100 (+800图片) | ~1.2s |
| 第4轮 | 追问图片内容 | ~1400 | ~1.5s |
| 第5轮 | 发送第2张图片 | ~2200 (+800图片) | ~2.5s |
| 第8轮 | 总结所有内容 | ~3500 | ~4s |
8.2 场景2:语音实时对话
用户语音输入 → ASR转文字 → LLM理解+生成 → TTS合成语音 → 播放给用户
⚠️ 端到端延迟要求极其严格
用户说完话 → 听到AI回复 的总延迟分解:
ASR 处理: 200~500ms (流式ASR尾部延迟)
LLM TTFT: 300~1000ms
TTS 首音频: 200~500ms
──────────────────────
总计: 700~2000ms
人类对话的自然停顿 ≈ 500~1500ms
如果AI回复延迟 > 2s → 感觉像在"等对方思考"
如果AI回复延迟 > 4s → 用户会怀疑系统卡了
优化关键:三个环节流水线并行!
→ ASR边识别边传给LLM(流式ASR)
→ LLM边生成边传给TTS(流式LLM + 流式TTS)
→ 总延迟 ≈ ASR尾部 + LLM TTFT + TTS首字节 ≈ 最快700ms8.3 场景3:视频分析 → 文字报告 → 语音播报
上传视频 → 视频理解(VLM) → 生成文字报告(LLM) → 语音播报(TTS)
| 环节 | 典型耗时(60s视频) | 瓶颈风险 |
|---|---|---|
| 视频上传 | 2~10s (取决于网络) | 大文件上传 |
| 视频理解 | 15~45s | 主瓶颈 |
| 文字报告生成 | 5~15s | 可流式减少感知 |
| TTS合成 | 3~10s | 可流式播放 |
| 总计 | 25~80s |
8.4 场景4:多模态Agent
场景:AI助手看屏幕截图 → 分析当前状态 → 执行操作
步骤:
1. 截取屏幕截图 → ~100ms
2. 图片理解(分析当前界面)→ ~2s
3. LLM决定下一步操作 → ~1s
4. 执行操作(点击/输入)→ ~500ms
5. 等待界面变化 → 1~3s
6. 再截图 → 回到步骤2
一轮循环 ≈ 5~7s
完成一个复杂任务(10步)≈ 50~70s
性能挑战:
→ 每步都有图片编码开销
→ 上下文中累积大量截图Token
→ 操作失败需要重试,耗时翻倍8.5 综合压测方案
TIP
多模态综合压测方案模板
════════════════════════════════════════
流量分配:
图文混合对话 40%
语音对话 25%
视频分析 10%
图片生成 15%
纯文本对话 10%
并发设置(总10并发):
图文对话: 4并发
语音对话: 3并发(ASR+LLM+TTS三级联)
视频分析: 1并发(资源消耗最大)
图片生成: 1并发(GPU显存限制)
纯文本: 1并发(基准对照)
GPU资源监控:
每5秒记录 GPU利用率/显存/温度
特别关注显存峰值(多模态并发容易OOM)
阶梯加压:
总并发 5 → 10 → 15 → 20
每级持续5分钟8.6 测试用例表
| 用例ID | 场景 | 关注指标 | PASS标准 |
|---|---|---|---|
| MM-01 | 5轮图文混合对话 | 各轮TTFT退化曲线 | 第5轮TTFT < 5s |
| MM-02 | 语音实时对话(5轮) | 端到端语音延迟 | 延迟 < 2s |
| MM-03 | 视频分析+文字+播报 | 端到端总耗时 | 60s视频 < 90s处理 |
| MM-04 | 多模态Agent(5步) | 单步延迟 / 总耗时 | 总耗时 < 40s |
| MM-05 | 混合流量综合压测 | 各场景达标率 | 所有场景P95达标 |
| MM-06 | 模态切换延迟 | 从文字切到图片的额外延迟 | 切换开销 < 500ms |
课堂练习
- 设计一个5轮图文混合对话测试,记录每轮的TTFT变化
- 如果你的系统支持语音对话,测量"说完话→听到回复"的端到端延迟
- 构造一个多模态级联场景(如视频分析→报告→播报),测量各环节耗时占比
- 做一次综合压测,观察不同模态并发时GPU显存是否会溢出
9. Agent 执行模式与性能模型
AI Agent是当前大模型应用中最复杂的场景——一个用户请求可能触发数十次LLM调用和工具调用,性能问题被成倍放大。
9.1 Agent的本质
📖 Agent = 多次 LLM 调用 + 多次工具调用 的循环
与普通对话的"一问一答"不同,Agent需要自主思考、规划、执行、观察,直到完成任务。每一步都是一次LLM推理,每次工具使用都是一次外部调用。这些调用串联起来,形成一条长链路。
9.2 三种执行模式
模式1:ReAct(Reasoning + Acting)
循环结构:
思考(Thought) → 行动(Action) → 观察(Observation) → 思考 → ...
示例:"帮我查北京明天的天气,如果下雨就提醒我带伞"
Step 1: 思考 → 需要查天气 → 调用 get_weather("北京","明天")
Step 2: 观察 → 明天小雨
Step 3: 思考 → 下雨了,需要提醒带伞
Step 4: 行动 → 生成回复
特点:每步动态决策,灵活但可能步数不确定模式2:Plan-and-Execute
两阶段结构:
规划阶段 → 生成所有步骤的计划
执行阶段 → 逐步执行计划中的步骤
示例:"帮我订明天飞上海的机票"
Plan: 1.查航班 2.筛选价格 3.选座位 4.下单 5.确认
Execute: 依次执行每一步
特点:步骤确定,可预测,但不够灵活模式3:混合模式
结构:先规划 → 执行时可动态调整
示例:先制定大框架,执行中遇到意外时调整计划
Plan: 1.查航班 2.选座 3.下单
Execute Step 1: 查航班 → 发现航班取消
Re-Plan: 1.改查高铁 2.选座 3.下单
Execute Step 1: 查高铁 → 找到班次
...
特点:兼顾可预测性和灵活性9.3 Agent的性能放大效应
⚠️ Agent性能的"冰山效应"
用户看到的:发了1个请求 → 等了30秒 → 收到回复
水面下实际发生的:
LLM调用 #1: 理解用户意图 3s
LLM调用 #2: 决定调用什么工具 2s
工具调用 #1: 查询数据库 0.5s
LLM调用 #3: 分析查询结果 2s
LLM调用 #4: 决定还需要什么信息 2s
工具调用 #2: 调用外部API 1.5s
工具调用 #3: 计算汇总 0.3s
LLM调用 #5: 生成最终回复 4s
─────────────────────────────────
总计: 5次LLM调用 + 3次工具调用 ≈ 15.3s + 开销 ≈ 18s
放大效应公式:
Agent_latency = Σ(LLM_calls × avg_LLM_time) + Σ(Tool_calls × avg_Tool_time) + overhead
其中 overhead 包括:上下文拼接、结果解析、日志记录等9.4 Agent vs 普通对话的性能对比
| 维度 | 普通对话 | Agent(简单任务) | Agent(复杂任务) |
|---|---|---|---|
| LLM调用次数 | 1 | 2~3 | 5~20 |
| 工具调用次数 | 0~1 | 1~3 | 3~15 |
| 放大系数 | 1~2 | 3~6 | 8~35 |
| 端到端延迟 | 2~10s | 10~30s | 30s~5min |
| Token消耗 | 100~2000 | 2000~10000 | 10000~100000 |
| 10并发的内部压力 | 10次LLM调用 | 30~60次 | 80~350次 |
💡 关键洞察
10个并发用户使用Agent,对LLM的实际压力可能等于100~350次并发LLM调用。在做Agent性能测试时,必须考虑这个放大效应来评估后端服务的承载能力。
课堂练习
- 分析你项目中的Agent场景,画出一个典型任务的完整调用链路图(含每步的LLM调用和工具调用)
- 计算一个典型Agent任务的放大系数:总共多少次LLM调用 + 工具调用?
- 根据放大系数,估算10并发用户对后端LLM服务的实际压力
- 讨论:你的Agent使用的是哪种执行模式(ReAct/Plan-and-Execute/混合)?各有什么性能优劣?
10. ReAct 链路性能分析
ReAct是最常见的Agent执行模式。每一步都包含"思考→行动→观察"三个阶段,理解每步的耗时分布是优化Agent性能的基础。
10.1 ReAct单步耗时分解
| 阶段 | 做什么 | 典型耗时 | 瓶颈原因 |
|---|---|---|---|
| Thinking | LLM推理,决定下一步 | 1~5s | 模型大小、上下文长度 |
| Action | 执行工具调用 | 0.1~30s | 工具本身的延迟差异极大 |
| Observation | 接收工具结果,解析 | 0.1~1s | 结果数据量、解析复杂度 |
| 上下文拼接 | 将结果追加到上下文 | ~10ms | 通常不是瓶颈 |
10.2 典型ReAct任务的性能Profile
简单任务(2-3步):查天气+推荐穿搭
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Step 1: Think(2s) → get_weather(0.5s) → Observe(0.2s) = 2.7s
Step 2: Think(2s) → generate_response(3s) = 5.0s
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
总耗时: ~8s LLM调用: 2次 工具调用: 1次
中等任务(5-8步):帮我订酒店
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Step 1: Think(2s) → search_hotels(2s) → Observe(0.3s) = 4.3s
Step 2: Think(3s) → filter_by_price(0.5s) → Observe(0.2s) = 3.7s
Step 3: Think(2s) → get_reviews(1.5s) → Observe(0.3s) = 3.8s
Step 4: Think(3s) → check_availability(1s)→ Observe(0.2s) = 4.2s
Step 5: Think(2s) → book_room(2s) → Observe(0.3s) = 4.3s
Step 6: Think(3s) → generate_response(4s) = 7.0s
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
总耗时: ~27s LLM调用: 6次 工具调用: 5次
复杂任务(10+步):分析数据并生成报告
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Step 1-3: 数据查询(3步) ~12s
Step 4-6: 数据分析(3步) ~15s
Step 7-8: 生成图表(2步) ~10s
Step 9-10: 汇总报告(2步) ~12s
Step 11: 格式化输出 ~5s
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
总耗时: ~54s LLM调用: 11次 工具调用: 8次10.3 性能测试关注点
上下文递增导致的性能退化
⚠️ 关键问题:随着步数增加,每步LLM推理越来越慢!
原因:每步的思考都需要把之前所有步骤的上下文发给LLM
Step 1: 上下文 ~500 tokens → Think 1.5s
Step 3: 上下文 ~2000 tokens → Think 2.5s
Step 5: 上下文 ~5000 tokens → Think 3.5s
Step 8: 上下文 ~10000 tokens → Think 5.0s
Step 10: 上下文 ~15000 tokens → Think 7.0s
后面步骤的TTFT可能是前面的3~5倍!
如果工具返回了大量数据(如完整SQL结果),上下文膨胀更快死循环检测
常见死循环模式:
Think → 调用工具A → 结果不满意 → Think → 又调用工具A → ...
Think → 决定重新规划 → Think → 又决定重新规划 → ...
性能影响:
→ Token无限消耗(费用爆炸)
→ 连接长时间占用
→ 用户无限等待
检测方法:
→ 设置最大步数限制(如20步)
→ 检测连续N步是否在调用相同工具+相同参数
→ 总执行时间超过阈值(如5分钟)强制终止10.4 测试方法:注入计时点,生成瀑布图
import time
import json
class ReActProfiler:
def __init__(self):
self.steps = []
def record_step(self, step_num, phase, start, end, detail=""):
self.steps.append({
"step": step_num,
"phase": phase,
"start_ms": round(start * 1000, 2),
"end_ms": round(end * 1000, 2),
"duration_ms": round((end - start) * 1000, 2),
"detail": detail
})
def print_waterfall(self):
"""生成瀑布图(文本版)"""
if not self.steps:
return
t0 = self.steps[0]["start_ms"]
for s in self.steps:
offset = s["start_ms"] - t0
bar_len = int(s["duration_ms"] / 100)
bar = "█" * max(bar_len, 1)
spaces = " " * int(offset / 100)
print(f" Step{s['step']:2d} {s['phase']:12s} "
f"{spaces}{bar} {s['duration_ms']:.0f}ms "
f"{s['detail']}")
profiler = ReActProfiler()
async def react_step(step_num, context):
t0 = time.perf_counter()
thought = await llm_call(context)
t1 = time.perf_counter()
profiler.record_step(step_num, "Think", t0, t1)
if thought.needs_tool:
t2 = time.perf_counter()
result = await call_tool(thought.tool, thought.args)
t3 = time.perf_counter()
profiler.record_step(step_num, "Action", t2, t3, thought.tool)
t4 = time.perf_counter()
context = parse_and_append(context, result)
t5 = time.perf_counter()
profiler.record_step(step_num, "Observe", t4, t5)
return context, thought.is_done10.5 测试用例表
| 用例ID | 场景 | 预期步数 | 关注指标 | PASS标准 |
|---|---|---|---|---|
| REACT-01 | 简单查询(2步) | 2~3 | 总耗时 / 每步耗时 | 总耗时 < 15s |
| REACT-02 | 中等任务(5步) | 4~6 | 上下文退化 / 总耗时 | 总耗时 < 45s |
| REACT-03 | 复杂任务(10步) | 8~12 | 退化曲线 / 总耗时 | 总耗时 < 2min |
| REACT-04 | 工具失败重试 | 增加1~3步 | 重试耗时 / 最终结果 | 重试后能完成 |
| REACT-05 | 死循环检测 | 触发步数上限 | 是否检测到循环 | 在20步内终止 |
| REACT-06 | 并发Agent(5) | 各3~5步 | 各Agent延迟/相互影响 | 互不阻塞 |
课堂练习
- 用计时工具为你的Agent注入瀑布图记录,分析每步的Think/Action/Observe耗时分布
- 观察10步Agent任务中,第1步和第10步的Think耗时差异
- 构造一个可能导致死循环的场景(如工具始终返回失败),验证系统的保护机制
- 在5并发下运行Agent任务,观察LLM服务是否扛得住放大后的调用量
11. 工作流引擎性能测试
工作流引擎(如Dify、Coze、n8n)通过可视化DAG(有向无环图)编排AI应用。与自由的ReAct不同,工作流的执行路径是预定义的,性能特征也不同。
11.1 工作流引擎的性能特征
| 平台 | 架构 | 节点执行 | 并发能力 | 性能特点 |
|---|---|---|---|---|
| Dify | Python + Celery | 串行/并行分支 | 中等 | LLM节点是瓶颈 |
| Coze | 云端托管 | 串行/并行 | 受API限流 | 依赖字节LLM服务 |
| n8n | Node.js | 串行为主 | 受内存限制 | HTTP节点快,LLM节点慢 |
11.2 DAG执行引擎的性能瓶颈
典型工作流DAG:
[开始] → [提取意图(LLM)] → [条件分支]
├─→ [查知识库] → [Rerank] → [生成回答(LLM)] → [结束]
├─→ [调工具API] → [格式化(LLM)] → [结束]
└─→ [直接回复] → [结束]
性能瓶颈层次:
1. LLM节点(秒级) ← 最大瓶颈
2. HTTP/API节点(百毫秒级)
3. 代码节点(毫秒级)
4. 条件分支(极快但影响路径选择)
5. 节点调度开销(每次5~20ms)
6. 数据序列化/反序列化(每次1~10ms)11.3 不同节点类型的性能差异
| 节点类型 | 典型延迟 | 变异系数 | 资源消耗 | 可优化空间 |
|---|---|---|---|---|
| LLM节点 | 2~15s | 高(±50%) | GPU | 换更快模型、缩短Prompt |
| 知识库检索 | 50~500ms | 中 | CPU/内存 | 索引优化、缓存 |
| HTTP请求 | 100~2000ms | 高 | 网络 | 超时控制、连接池 |
| 代码执行 | 1~50ms | 低 | CPU | 几乎不需要优化 |
| 条件分支 | < 1ms | 极低 | 无 | — |
| 变量赋值 | < 1ms | 极低 | 无 | — |
11.4 并行分支 vs 串行分支
串行分支:
[LLM-A(3s)] → [LLM-B(4s)] → [LLM-C(2s)]
总耗时 = 3 + 4 + 2 = 9s
并行分支:
[LLM-A(3s)] ─┐
[LLM-B(4s)] ─┤→ [汇总(1s)]
[LLM-C(2s)] ─┘
总耗时 = max(3, 4, 2) + 1 = 5s
性能提升 = 9s / 5s = 1.8x
但注意:并行分支消耗3倍LLM并发!
串行:同一时刻只有1个LLM调用
并行:同一时刻有3个LLM调用
10并发用户 × 3并行LLM = 30个LLM并发请求11.5 嵌套工作流的性能叠加
💡 嵌套工作流的复合延迟
主工作流(5个节点) → 其中第3个节点调用子工作流(4个节点)
→ 子工作流第2个节点又调用孙工作流(3个节点)
总延迟 = 主流程延迟 + 子流程延迟 + 孙流程延迟
= 5节点 + 4节点 + 3节点 = 12节点的串行延迟
如果每个LLM节点3s:12 × 3s = 36s
嵌套越深,延迟越不可控!11.6 压测方法
工作流压测方法:
1. API触发工作流执行
POST /api/workflow/run
{ "workflow_id": "xxx", "inputs": {"query": "test"} }
2. 记录每个节点耗时(从工作流引擎日志提取)
Node1_start → Node1_end → Node2_start → ...
3. 阶梯加压
1 → 3 → 5 → 10 → 20 并发
每级3~5分钟
4. 观察指标:
→ 端到端延迟(从触发到返回结果)
→ 各节点延迟分布
→ LLM节点排队情况
→ 工作流引擎本身的CPU/内存11.7 测试用例表
| 用例ID | 场景 | 工作流结构 | 关注指标 | PASS标准 |
|---|---|---|---|---|
| WF-01 | 简单线性流 | 3节点串行(含1个LLM) | E2E延迟 | < 10s |
| WF-02 | 条件分支流 | 条件判断 → 不同路径 | 各路径延迟 | 最长路径 < 15s |
| WF-03 | 并行分支流 | 3个LLM并行 → 汇总 | 是否真并行 | ≈ max(各分支) |
| WF-04 | 嵌套工作流 | 主流程调用子流程 | 总延迟 | < 各层延迟之和 |
| WF-05 | 并发执行(10) | 10并发同一工作流 | LLM排队/引擎CPU | 错误率 < 1% |
| WF-06 | 长工作流(10+节点) | 10个节点串行 | 总延迟 / 超时 | < 60s |
课堂练习
- 在你的工作流平台(Dify/Coze/n8n)中创建一个包含并行分支的工作流,验证分支是否真的并行执行
- 提取工作流执行日志,分析各节点的耗时分布,找出瓶颈节点
- 用API触发方式对工作流进行并发测试(5/10并发),观察LLM节点的排队情况
- 如果有嵌套工作流,测量嵌套层级对总延迟的影响
12. 多Agent协作性能测试
多Agent系统由多个独立的Agent协作完成复杂任务。每个Agent有自己的角色和能力,通过通信机制协同工作。
12.1 多Agent架构模式
模式1:主从模式(Orchestrator-Worker)
┌─────────────────────────────┐
│ 协调者 Agent (Orchestrator) │
│ 负责任务分解和结果汇总 │
└──┬──────────┬─────────┬─────┘
↓ ↓ ↓
[研究Agent] [写作Agent] [审核Agent]
查资料 写文章 检查质量
耗时 = 协调者分解(3s) + max(研究5s, 写作8s, 审核3s) + 汇总(3s)
≈ 14s(如果并行)或 19s(如果串行)模式2:对等模式(Peer-to-Peer)
[Agent-A] ←→ [Agent-B] ←→ [Agent-C]
↕ ↕ ↕
各自独立工作,需要时互相请求帮助
耗时不确定:取决于互相调用的次数和深度模式3:层级模式(Hierarchical)
[总监Agent]
↓ ↓
[经理Agent-A] [经理Agent-B]
↓ ↓ ↓ ↓
[员工1] [员工2] [员工3] [员工4]
耗时 = 总监分配(2s) + max(经理A链路, 经理B链路) + 汇报(3s)
每层增加2~5s的调度开销12.2 性能挑战
| 挑战 | 具体表现 | 性能影响 | 解决思路 |
|---|---|---|---|
| Agent间通信开销 | 每次通信需要序列化/反序列化上下文 | 每次通信增加100~500ms | 减少通信次数,传递摘要而非全文 |
| 上下文同步延迟 | 协调者需要等待所有Agent完成才能汇总 | 总延迟取决于最慢的Agent | 设置超时,部分结果先返回 |
| LLM资源竞争 | 多个Agent同时调LLM | LLM排队,各Agent都变慢 | LLM连接池/优先级队列 |
| 结果汇总等待 | 协调者等最慢的Agent | 木桶效应 | 异步返回/超时截断 |
| Token消耗爆炸 | N个Agent各自维护上下文 | 费用 ≈ N × 单Agent费用 | 共享上下文/摘要传递 |
12.3 性能测试方法
多Agent性能测试方案:
1. 单Agent基准测试
→ 每个Agent单独运行,记录各自的耗时和资源消耗
→ 作为后续对比的基准
2. 协作性能测试
→ 多Agent协作完成同一任务
→ 记录:协调开销、通信延迟、等待时间、总耗时
→ 与各Agent单独运行的总和对比
3. 并发协作测试
→ 多组Agent同时运行
→ 观察LLM资源竞争导致的性能退化
→ 找出系统能承受的并发Agent组数
4. 故障场景测试
→ 某个Agent超时或失败
→ 协调者如何处理?是否影响其他Agent?
→ 部分结果能否返回?12.4 测试用例表
| 用例ID | 场景 | Agent数量 | 关注指标 | PASS标准 |
|---|---|---|---|---|
| MA-01 | 主从模式(3 Worker) | 1协调+3执行 | 总耗时 vs 串行 | 并行时<串行的50% |
| MA-02 | 层级模式(2级) | 1总监+2经理+4员工 | 层级开销/总耗时 | 总层级开销 < 10s |
| MA-03 | Agent通信延迟 | 2个Agent互相调用 | 通信延迟 | 单次通信 < 500ms |
| MA-04 | LLM资源竞争 | 5个Agent同时调LLM | 各Agent退化程度 | 退化 < 3x |
| MA-05 | 最慢Agent影响 | 3个Agent, 1个特别慢 | 总等待时间 | 有超时截断机制 |
| MA-06 | Agent故障 | 3个Agent, 1个挂掉 | 系统行为 | 不整体崩溃 |
课堂练习
- 如果你的系统使用多Agent,画出Agent之间的通信关系图
- 测量Agent间每次通信的延迟开销
- 构造一个Agent特别慢的场景,验证协调者是否有超时处理
- 对比3个Agent并行工作 vs 串行工作的性能差异
13. Agent 异常与超时控制
Agent的异常和超时问题比普通API调用复杂得多——一个Agent可能执行了10步后才超时,前面9步的工作和Token消耗全部浪费。合理的超时控制是Agent系统的生命线。
13.1 Agent超时机制设计
| 超时层级 | 作用范围 | 典型值 | 触发后行为 |
|---|---|---|---|
| 单步LLM超时 | 单次LLM调用 | 30~60s | 重试1~2次,仍超时则跳过或终止 |
| 单步工具超时 | 单次工具调用 | 10~30s | 返回错误,让Agent决定下一步 |
| 总任务超时 | 整个Agent任务 | 2~10min | 强制终止,返回中间结果 |
| 步数上限 | 最大执行步数 | 10~30步 | 停止循环,总结已有结果 |
13.2 超时测试用例
用例1:工具超时时Agent的行为
场景:Agent需要调用数据库查询工具,但数据库响应极慢
模拟方法:
→ Mock工具接口,设置response_time=60s
→ 或在工具后端注入 sleep(60)
期望行为(按优先级):
A. Agent检测到工具超时 → 换用备选方案(如缓存数据)
B. Agent告知用户"数据查询较慢" → 继续其他步骤
C. Agent等待超时 → 报错但不崩溃
最差行为:
❌ Agent无限等待工具响应
❌ Agent崩溃,前面步骤的结果全丢
❌ 超时的请求泄漏,占用后端资源
判定标准:
✅ 工具超时 < 30s, Agent有替代方案或友好提示用例2:LLM超时时的重试策略
场景:LLM服务暂时不可用或响应极慢
测试矩阵:
LLM超时1次 → 重试 → 成功 → 验证延迟增加是否可接受
LLM超时2次 → 重试 → 成功 → 验证是否有退避策略
LLM连续超时 → 重试次数上限 → 验证是否有降级方案
重试策略检查点:
→ 是否有指数退避(1s → 2s → 4s)
→ 是否有最大重试次数限制
→ 重试期间是否占用并发连接用例3:步数上限时的优雅退出
场景:Agent陷入循环或任务过于复杂,达到步数上限
期望行为:
→ 停止继续执行
→ 总结已完成的步骤和中间结果
→ 告知用户"任务较复杂,已完成X步,以下是目前的结果..."
→ 建议用户拆分任务或提供更多信息
最差行为:
❌ 静默终止,不返回任何信息
❌ 前面所有步骤的中间数据全丢
❌ 返回技术错误信息(如"MaxStepsExceeded")13.3 Agent死循环的检测方法
死循环检测策略:
策略1: 相同动作检测
if 连续3次调用相同工具 + 相同参数:
trigger_loop_break("检测到重复动作")
策略2: 上下文增长停滞
if 最近5步的有效信息增量 < 阈值:
trigger_loop_break("执行无进展")
策略3: 总Token消耗监控
if 累计Token消耗 > 预算上限:
trigger_budget_break("Token预算耗尽")
策略4: 时间窗口检测
if 最近60秒内完成步骤数 > 10:
trigger_rate_break("执行频率异常")(可能在空转)13.4 测试用例表
| 用例ID | 场景 | 模拟方式 | 关注指标 | PASS标准 |
|---|---|---|---|---|
| TO-01 | 工具超时(30s) | Mock工具延迟30s | Agent反应/总延迟 | Agent在30s内切换方案 |
| TO-02 | 工具超时(无限) | Mock工具不响应 | 是否有超时机制 | 有超时保护 |
| TO-03 | LLM超时(单次) | Mock LLM延迟60s | 重试行为 | 重试后成功 |
| TO-04 | LLM持续超时 | Mock LLM不响应 | 降级行为 | 有降级方案 |
| TO-05 | 达到步数上限 | 给复杂任务,步数限制=5 | 退出行为/中间结果 | 返回中间结果 |
| TO-06 | 达到总超时 | 给复杂任务,总超时=60s | 终止行为 | 优雅终止+返回结果 |
| TO-07 | 死循环检测 | 工具始终返回失败 | 是否检测到循环 | < 5次重复后终止 |
| TO-08 | Token预算耗尽 | 复杂任务+低Token预算 | 预算控制 | 有预算保护 |
课堂练习
- 为你的Agent系统设计超时控制策略:确定单步超时、总超时、步数上限的具体值
- 模拟工具超时场景(让某个工具Mock接口返回延迟60秒),观察Agent的实际行为
- 构造一个死循环场景,验证系统是否有循环检测机制
- 达到步数上限时,检查Agent是否返回了有意义的中间结果
14. Agent 性能用例集
以下是一套完整的Agent性能测试用例集,覆盖简单、中等、复杂三种难度,每个用例包含具体的场景描述和判定标准。
14.1 简单任务用例(2~3步)
| 用例ID | 场景描述 | 预期步骤 | 各步骤耗时预期 | 总耗时预期 | 并发测试 | PASS标准 |
|---|---|---|---|---|---|---|
| AG-01 | 查天气并推荐穿搭 | 2步:查天气→推荐 | Think 2s+Tool 0.5s+Think 3s | < 10s | 10并发 | P95 < 15s |
| AG-02 | 查订单状态 | 2步:查订单→回答 | Think 2s+Tool 0.3s+Think 2s | < 8s | 20并发 | P95 < 12s |
| AG-03 | 简单数学计算(使用计算器工具) | 2步:识别→计算→回答 | Think 1.5s+Tool 0.1s+Think 2s | < 6s | 20并发 | P95 < 10s |
14.2 中等任务用例(4~6步)
| 用例ID | 场景描述 | 预期步骤 | 总耗时预期 | 并发测试 | PASS标准 |
|---|---|---|---|---|---|
| AG-04 | 搜索商品+比价+推荐 | 5步 | < 30s | 5并发 | P95 < 45s |
| AG-05 | 查机票+筛选+排序+推荐 | 4步 | < 25s | 5并发 | P95 < 35s |
| AG-06 | 查客户信息+查订单+发邮件 | 5步(含3次工具) | < 35s | 5并发 | P95 < 50s |
| AG-07 | 查知识库+汇总+格式化输出 | 4步 | < 20s | 10并发 | P95 < 30s |
14.3 复杂任务用例(8+步)
| 用例ID | 场景描述 | 预期步骤 | 总耗时预期 | 并发测试 | PASS标准 |
|---|---|---|---|---|---|
| AG-08 | 多数据源分析+生成报告 | 10步 | < 90s | 3并发 | P95 < 120s |
| AG-09 | 代码审查(读代码+分析+建议) | 8步 | < 60s | 3并发 | P95 < 90s |
| AG-10 | 多Agent协作(研究+写作+审核) | 12步(3个Agent) | < 120s | 2并发 | P95 < 180s |
| AG-11 | 端到端项目管理(查Jira+分析+汇报) | 8步(含MCP调用) | < 60s | 3并发 | P95 < 90s |
| AG-12 | 数据ETL(提取+清洗+转换+加载) | 10步 | < 90s | 2并发 | P95 < 150s |
14.4 异常场景用例
| 用例ID | 场景描述 | 期望行为 | PASS标准 |
|---|---|---|---|
| AG-13 | 第3步工具超时 | Agent切换方案或跳过 | 总延迟 < 60s, 有替代结果 |
| AG-14 | 任务触发死循环 | 在步数上限内终止 | < 20步终止, 返回中间结果 |
| AG-15 | LLM返回格式错误 | Agent能自我纠正 | 纠正后继续执行 |
课堂练习
- 从上面的用例集中选择5个最贴合你业务的用例,执行完整测试
- 为每个用例记录:实际步骤数、各步骤耗时、总耗时、Token消耗
- 用瀑布图展示至少一个复杂用例(AG-08~AG-12)的性能Profile
- 执行至少一个异常场景用例(AG-13~AG-15),验证系统的异常处理能力
15. 推理优化技术全景
模型推理优化是提升大模型性能的核心手段。作为测试人员,不需要亲自实施优化,但需要理解每种优化技术的原理以及如何测量优化前后的性能差异。
15.1 推理优化技术分类
推理优化技术全景图:
┌─── 模型层面 ───────────────────────────────────────────┐
│ 量化(Quantization): FP16→INT8→INT4, 减少计算量和显存 │
│ 蒸馏(Distillation): 大模型教小模型, 用小模型替代 │
│ 剪枝(Pruning): 去掉不重要的参数, 减小模型体积 │
│ 稀疏化(Sparsity): MoE架构, 每次只激活部分参数 │
└────────────────────────────────────────────────────────┘
┌─── 系统层面 ───────────────────────────────────────────┐
│ KV Cache: 缓存已计算的Key-Value, 避免重复计算 │
│ 连续批处理(Continuous Batching): 动态合并请求 │
│ PagedAttention: 分页管理KV Cache, 减少显存浪费 │
│ FlashAttention: IO-aware注意力计算, 减少显存访问 │
│ Speculative Decoding: 小模型草稿+大模型验证 │
└────────────────────────────────────────────────────────┘
┌─── 硬件层面 ───────────────────────────────────────────┐
│ GPU选型: H100 vs A100 vs L40S vs RTX 4090 │
│ 多卡并行: Tensor Parallel / Pipeline Parallel │
│ CPU Offload: 部分计算卸载到CPU │
│ 混合精度: FP16计算 + FP32累加 │
└────────────────────────────────────────────────────────┘
┌─── 部署层面 ───────────────────────────────────────────┐
│ 推理框架: vLLM / TGI / TensorRT-LLM / Ollama │
│ 容器化: Docker + NVIDIA Container Toolkit │
│ 负载均衡: 多实例 + 路由策略 │
│ 自动伸缩: 基于GPU利用率的动态扩缩容 │
└────────────────────────────────────────────────────────┘15.2 每种优化的一句话原理
| 优化技术 | 一句话原理 | 性能收益 | 代价 |
|---|---|---|---|
| 量化 | 用更少的位数表示模型权重 | 速度↑ 1.5~3x, 显存↓ 2~4x | 质量略降 |
| 蒸馏 | 大模型的知识压缩到小模型 | 速度↑ 2~10x | 某些能力丢失 |
| 剪枝 | 删除模型中不重要的连接 | 速度↑ 1.2~2x | 需要额外微调 |
| KV Cache | 缓存已算过的注意力,后续Token不重算 | Decode速度↑ 显著 | 显存占用增加 |
| 连续批处理 | 动态合并不同请求一起推理 | 系统吞吐↑ 3~5x | 单请求延迟可能增 |
| PagedAttention | 像操作系统管理内存一样管理KV Cache | 显存利用率↑ 50% | 实现复杂 |
| FlashAttention | 重新排列注意力计算顺序减少内存访问 | 速度↑ 10~20%, 显存↓ | 几乎无代价 |
| Speculative Decoding | 用小模型猜测多个Token再用大模型验证 | 速度↑ 2~3x | 需要额外小模型 |
15.3 测试人员需要关心什么
✅ 测试人员的角色定位
测试人员不需要实施优化,但需要能够:
- 测量:优化前后的TTFT、吞吐、显存、质量等全维度指标
- 对比:制作A/B对比报告,客观展示优化效果
- 验证:优化后质量是否可接受(尤其是量化后的质量损失)
- 发现:优化引入的新问题(如量化后某些场景异常)
15.4 优化技术对测试的影响矩阵
| 优化技术 | 对TTFT的影响 | 对吞吐的影响 | 对显存的影响 | 对质量的影响 | 测试重点 |
|---|---|---|---|---|---|
| FP16→INT8 | 降低 ~20% | 提升 ~30% | 减半 | 轻微下降 | 质量回归测试 |
| FP16→INT4 | 降低 ~40% | 提升 ~60% | 减为1/4 | 明显下降 | 质量回归+边界测试 |
| 连续批处理 | 可能增加 | 大幅提升 | 更高效 | 不影响 | 高并发吞吐测试 |
| 蒸馏 | 显著降低 | 大幅提升 | 大幅降低 | 可能下降 | 能力覆盖测试 |
| 框架替换 | 可能变化 | 可能变化 | 可能变化 | 不应变化 | 全维度A/B测试 |
课堂练习
- 了解你项目中使用的推理优化技术有哪些(量化?连续批处理?框架?)
- 制作一份"优化技术清单":列出当前使用的每项优化 + 对应的性能收益
- 确定下一次优化计划(如从FP16切换到INT8),制定对应的性能对比测试方案
16. 量化(Quantization)与性能测试
量化是当前最常用、性价比最高的推理优化技术。通过降低模型权重的数值精度来减少计算量和显存占用。
16.1 量化基础
📖 量化是什么
FP32 (32位浮点): 1个参数占4字节 → 精度最高,速度最慢
FP16 (16位浮点): 1个参数占2字节 → 训练/推理标准精度
INT8 (8位整数): 1个参数占1字节 → 轻度量化,质量损失小
INT4 (4位整数): 1个参数占0.5字节 → 深度量化,质量有损失
以 Llama 70B 为例:
FP32: 70B × 4 = 280GB → 需要4张A100-80GB
FP16: 70B × 2 = 140GB → 需要2张A100-80GB
INT8: 70B × 1 = 70GB → 需要1张A100-80GB
INT4: 70B × 0.5 = 35GB → 需要1张A100-40GB 或 RTX 409016.2 主流量化方法
| 方法 | 精度 | 需要校准数据 | 推理速度 | 质量保持 | 适用框架 |
|---|---|---|---|---|---|
| GPTQ | INT4/INT8 | 需要(~128条) | 快 | 好 | vLLM, TGI |
| AWQ | INT4 | 需要 | 最快 | 很好 | vLLM, TGI |
| GGUF/GGML | 多种(Q2~Q8) | 不需要 | 中等 | 取决于精度 | llama.cpp, Ollama |
| bitsandbytes | INT8/NF4 | 不需要 | 中等 | 好 | Transformers |
| SmoothQuant | INT8 | 需要 | 快 | 很好 | TensorRT-LLM |
16.3 量化前后的性能对比
Llama 70B 在不同量化下的性能数据(A100-80GB × 2)
| 量化 | 显存占用 | TTFT (1并发) | Token吞吐 | 最大并发 | 质量(MMLU) |
|---|---|---|---|---|---|
| FP16 | 140GB | 800ms | 25 t/s | ~8 | 70.5% |
| INT8 (GPTQ) | 70GB | 550ms | 35 t/s | ~15 | 69.8% |
| INT4 (AWQ) | 38GB | 400ms | 48 t/s | ~25 | 68.2% |
| INT4 (GGUF Q4_K_M) | 40GB | 500ms | 40 t/s | ~20 | 68.5% |
💡 量化的性价比分析
FP16 → INT8: 显存减半,速度+40%,质量损失 < 1% → 强烈推荐
INT8 → INT4: 显存再减半,速度+35%,质量损失 ~2% → 推荐(如果质量可接受)
FP16 → INT4: 显存减为1/4,速度+90%,质量损失 ~3% → 需要评估质量
质量损失的实际影响:
→ 简单问答/分类任务:INT4质量损失几乎不可感知
→ 复杂推理/数学:INT4可能出现明显退化
→ 代码生成:INT4可能增加语法错误
→ 多语种:非主流语言退化更明显16.4 量化性能测试方法
量化性能对比测试流程:
1. 准备测试数据集(固定,用于所有测试)
→ 100条不同类型的Prompt
→ 分类:简单问答(30) + 推理(20) + 代码(20) + 翻译(15) + 数学(15)
2. 基线测试(FP16,无量化)
→ 跑完100条,记录TTFT/吞吐/显存
→ 分别在1/5/10/20并发下测试
→ 记录质量基准(保存所有回答)
3. 量化测试(INT8 / INT4)
→ 用相同的100条Prompt
→ 相同的并发设置
→ 记录相同的指标
4. 对比分析
→ 性能维度:TTFT提升了多少%?吞吐提升了多少%?
→ 质量维度:对比同一Prompt的FP16和INT4回答
→ 显存维度:峰值显存降低了多少?
→ 成本维度:同等服务能力需要几张GPU?16.5 测试用例表
| 用例ID | 场景 | 对比项 | 关注指标 | PASS标准 |
|---|---|---|---|---|
| QT-01 | FP16 vs INT8基准对比 | 同模型, 1并发 | TTFT/吞吐/显存 | INT8速度≥FP16 |
| QT-02 | FP16 vs INT4基准对比 | 同模型, 1并发 | TTFT/吞吐/显存 | INT4速度≥FP16×1.5 |
| QT-03 | 量化后并发能力 | FP16 vs INT8, 阶梯并发 | 最大并发数 | INT8并发 ≥ FP16×1.5 |
| QT-04 | 量化后质量评估 | 同100条Prompt的回答对比 | 质量差异 | 质量降幅 < 5% |
| QT-05 | 量化边界场景 | 数学推理/代码生成 | 特定场景质量 | 记录退化程度 |
课堂练习
- 如果你的模型支持量化,分别用FP16和INT8跑一组基准测试,对比TTFT和吞吐
- 用同一组Prompt对比FP16和INT4的回答质量,找出质量退化最明显的Prompt类型
- 计算量化前后的GPU显存差异,评估是否可以用更少的GPU卡达到相同性能
- 如果无法实际操作量化,查阅模型的量化benchmark数据,制作对比表格
17. KV Cache 与连续批处理
KV Cache和连续批处理是两项系统层面的优化技术,几乎所有现代推理框架都默认启用。理解它们对性能的影响,有助于解释压测中观察到的各种现象。
17.1 KV Cache 原理
📖 KV Cache 是什么
在Transformer架构中,生成每个新Token时需要对之前所有Token做注意力计算(计算Query、Key、Value)。KV Cache将已经计算过的Key和Value缓存起来,生成后续Token时直接复用,避免重复计算。
无KV Cache:生成第N个Token → 重新计算前N-1个Token的K和V → O(N²)
有KV Cache:生成第N个Token → 只计算第N个Token的Q → 用缓存的K,V做注意力 → O(N)
效果:Decode阶段速度提升 10~100x(长序列更明显)
代价:需要额外显存存储KV Cache17.2 KV Cache 对性能的影响
| 场景 | 无KV Cache | 有KV Cache | 提升 |
|---|---|---|---|
| 生成第10个Token | 10ms | 1ms | 10x |
| 生成第100个Token | 100ms | 1ms | 100x |
| 生成第1000个Token | 1000ms | 1ms | 1000x |
KV Cache的显存占用
KV Cache 显存计算公式:
KV_size = 2 × num_layers × num_heads × head_dim × seq_len × bytes_per_element
以 Llama 70B (FP16) 为例:
每Token的KV Cache ≈ 1.2MB
1024 Token上下文 ≈ 1.2GB
4096 Token上下文 ≈ 4.8GB
32K Token上下文 ≈ 38.4GB ← 接近一张A100的全部显存!
问题:长上下文场景下,KV Cache可能比模型权重还占更多显存
10并发 × 4K上下文 = 48GB KV Cache
→ 加上模型权重 → 需要更多GPU⚠️ KV Cache爆显存的常见场景
- 长上下文对话(32K+):单个请求的KV Cache就可能超过30GB
- 高并发 + 中等上下文:20并发 × 4K Token = 大量KV Cache累积
- 多轮对话不清理:上下文持续增长,KV Cache不断膨胀
17.3 连续批处理(Continuous Batching)
传统批处理 vs 连续批处理
传统批处理(Static Batching):
等凑齐一批请求 → 一起推理 → 所有请求完成后返回 → 处理下一批
问题:短请求等长请求
请求A(输出10 token) ─────■ 等待 ──────────────────
请求B(输出100 token) ────■■■■■■■■■■■■■■■■■■■■
请求C(输出30 token) ─────■■■■■■ 等待 ───────────
A和C在B完成前必须等待 → GPU浪费
连续批处理(Continuous Batching):
请求完成一个就立即释放,新请求立即加入
请求A(输出10 token) ─────■ → 完成释放
请求D(新来的) ─────────────■■■■■■■■ → 接替A的位置
请求B(输出100 token) ────■■■■■■■■■■■■■■■■■■■■
请求C(输出30 token) ─────■■■■■■ → 完成释放
请求E(新来的) ────────────────────■■■■■■ → 接替C的位置
GPU始终满载,没有浪费!连续批处理对吞吐量的影响
| 批处理方式 | 系统吞吐(10并发) | 单请求延迟 | GPU利用率 |
|---|---|---|---|
| 无批处理(逐个) | ~30 t/s | 最低 | ~30% |
| 静态批处理(batch=8) | ~150 t/s | 可能增加 | ~70% |
| 连续批处理 | ~250 t/s | 略增加 | ~85% |
| 连续批处理 + PagedAttention | ~350 t/s | 略增加 | ~90% |
17.4 vLLM 的 PagedAttention
📖 PagedAttention 一句话原理
像操作系统的虚拟内存一样管理KV Cache——不需要为每个请求预分配连续的最大显存,而是按需分配小页(page),用完即释放。这样显存利用率可以提高50%以上。
17.5 测试方法
KV Cache和连续批处理的性能测试:
1. 不同batch size下的吞吐测试
→ batch_size = 1, 2, 4, 8, 16, 32
→ 记录系统吞吐和单请求延迟
→ 找到吞吐不再增长的拐点
2. 不同上下文长度下的显存测试
→ 固定并发=5
→ 上下文长度 = 512, 1024, 2048, 4096, 8192, 16384, 32768
→ 记录显存占用(nvidia-smi)
→ 找到OOM的边界
3. 连续批处理效果验证
→ 方法:发送长短混合的请求
→ 短请求(10 token) + 长请求(500 token) 混合
→ 观察短请求是否能在长请求完成前返回课堂练习
- 在不同并发数下测试系统的Token吞吐,画出"并发数-系统总吞吐"曲线,找到吞吐饱和点
- 发送不同长度的上下文(512/2K/8K/32K Tokens),用
nvidia-smi观察显存变化 - 发送混合长短请求,验证短请求是否能在长请求完成前返回(验证连续批处理是否生效)
- 计算你的模型在目标并发数下的KV Cache显存需求,判断是否有OOM风险
18. 推理框架对比测试
不同推理框架对同一模型的性能表现可能有显著差异。选择合适的推理框架是部署决策中的重要环节。
18.1 主流推理框架
| 框架 | 核心技术 | 适用场景 | 部署难度 | 社区活跃度 |
|---|---|---|---|---|
| vLLM | PagedAttention + 连续批处理 | 通用生产部署 | 中等 | 非常活跃 |
| TGI | Flash Attention + 动态批处理 | HuggingFace生态 | 简单(Docker) | 活跃 |
| Ollama | llama.cpp封装 | 个人/开发调试 | 极简 | 非常活跃 |
| TensorRT-LLM | TensorRT + NVIDIA优化 | NVIDIA GPU极致性能 | 复杂 | NVIDIA维护 |
| llama.cpp | 纯C++, CPU/GPU混合推理 | CPU推理/边缘设备 | 简单 | 非常活跃 |
| SGLang | RadixAttention + 前缀缓存 | 多轮对话/共享前缀 | 中等 | 增长中 |
18.2 对比测试方法
📐 推理框架对比测试的标准流程
- 固定变量:同一模型、同一GPU、同一测试数据集、同一并发设置
- 依次部署:在同一硬件上依次部署各框架
- 相同测试:用完全相同的压测脚本和参数
- 多维度记录:TTFT / 吞吐 / 显存 / 错误率 / 部署难度
- 多次运行:每个框架至少跑3次取平均
18.3 对比测试表模板
Qwen-14B, A100-80GB, 100条测试Prompt
| 指标 | vLLM | TGI | Ollama | TensorRT-LLM | llama.cpp |
|---|---|---|---|---|---|
| TTFT P50 (1并发) | 180ms | 220ms | 350ms | 120ms | 400ms |
| TTFT P50 (10并发) | 350ms | 400ms | 2000ms | 250ms | 1500ms |
| Token吞吐 (1并发) | 45 t/s | 42 t/s | 25 t/s | 55 t/s | 20 t/s |
| 系统吞吐 (10并发) | 350 t/s | 300 t/s | 80 t/s | 450 t/s | 60 t/s |
| 最大并发 | ~30 | ~25 | ~5 | ~40 | ~3 |
| GPU显存 | 32GB | 35GB | 30GB | 28GB | 30GB |
| 部署时间 | ~10min | ~5min(Docker) | ~2min | ~2h(编译) | ~5min |
| 支持量化 | AWQ/GPTQ | GPTQ/bitsandbytes | GGUF | SmoothQuant/INT8 | GGUF |
18.4 推理框架选型建议
| 场景 | 推荐框架 | 理由 |
|---|---|---|
| 生产环境(通用) | vLLM | PagedAttention + 连续批处理,性能和稳定性平衡好 |
| 极致性能(NVIDIA GPU) | TensorRT-LLM | 性能最好,但部署复杂度高 |
| 快速上手/开发调试 | Ollama | 一行命令启动,但不适合生产高并发 |
| HuggingFace生态 | TGI | Docker一键部署,与HF模型无缝兼容 |
| CPU/边缘推理 | llama.cpp | 支持纯CPU推理,适合无GPU环境 |
| 多轮对话/共享System Prompt | SGLang | RadixAttention对前缀重用优化好 |
课堂练习
- 选择2个推理框架(如vLLM和Ollama),用同一个模型部署,跑相同的压测对比性能
- 填写上面的对比测试表模板,用你的实际测试数据
- 从性能、部署难度、运维成本三个维度,为你的项目推荐最合适的推理框架
- 如果条件允许,测试同一模型在FP16和INT4量化下、在不同框架中的性能差异
19. 模型蒸馏与剪枝的性能影响
蒸馏和剪枝是模型层面的优化技术,通过减小模型的规模来提升推理速度和降低资源消耗。与量化不同,蒸馏和剪枝改变的是模型结构本身。
19.1 知识蒸馏(Knowledge Distillation)
📖 蒸馏是什么
用一个大的"教师模型"(Teacher)来训练一个小的"学生模型"(Student)。学生模型不仅学习正确答案,还学习教师模型的"思考方式"(输出概率分布)。目标是让小模型尽可能接近大模型的能力。
蒸馏的性能收益
| 对比项 | Teacher (70B) | Student (7B) | 性能差异 |
|---|---|---|---|
| 模型大小 | 140GB (FP16) | 14GB (FP16) | 10x 更小 |
| GPU需求 | 2×A100-80GB | 1×RTX 4090 | 成本大幅降低 |
| TTFT (1并发) | 800ms | 100ms | 8x 更快 |
| Token吞吐 | 25 t/s | 80 t/s | 3x 更快 |
| 最大并发 | ~8 | ~50 | 6x 更多 |
| 质量(MMLU) | 70.5% | 62~65% | 下降5~8% |
蒸馏的质量代价
蒸馏后质量退化分析:
能力保持好的场景:
✅ 简单问答/FAQ → 保持95%以上质量
✅ 文本分类/情感分析 → 保持90%以上
✅ 信息提取/NER → 保持85%以上
能力退化明显的场景:
⚠️ 复杂推理/数学 → 可能退化20~40%
⚠️ 长文生成 → 连贯性下降
⚠️ 小众语言 → 退化更严重
⚠️ 代码生成 → 复杂代码错误率增加
测试建议:
→ 不只测平均分,要测各能力维度的分数
→ 特别关注业务核心场景的质量变化
→ 蒸馏后的模型可能在某些边界情况表现很差19.2 模型剪枝(Pruning)
📖 剪枝是什么
剪枝是去掉模型中"不重要"的参数或结构,从而减小模型体积和计算量。类似于修剪树枝——去掉无用的枝叶,保留核心结构。
结构化剪枝 vs 非结构化剪枝
| 类型 | 做什么 | 速度提升 | 实现难度 | 质量影响 |
|---|---|---|---|---|
| 非结构化剪枝 | 去掉单个不重要的权重(设为0) | 需要稀疏计算硬件支持 | 简单 | 较小 |
| 结构化剪枝 | 去掉整个注意力头/FFN层 | 直接减少计算量 | 复杂(需重新训练) | 较大 |
剪枝的实际性能提升
结构化剪枝示例(去掉30%的注意力头):
原模型(32层×32头):
→ TTFT: 500ms
→ Token吞吐: 40 t/s
→ 显存: 28GB
剪枝后(32层×22头, 约减30%):
→ TTFT: 380ms (-24%)
→ Token吞吐: 52 t/s (+30%)
→ 显存: 20GB (-29%)
→ 质量: MMLU下降3~5%
注意:剪枝后通常需要额外的微调(fine-tuning)来恢复部分质量19.3 蒸馏/剪枝的A/B性能对比方法
Teacher vs Student 全维度对比测试方案:
1. 性能对比(定量)
┌──────────────┬──────────┬──────────┬────────┐
│ 指标 │ Teacher │ Student │ 差异 │
├──────────────┼──────────┼──────────┼────────┤
│ TTFT P50 │ 800ms │ 100ms │ -87.5% │
│ TTFT P95 │ 1200ms │ 180ms │ -85% │
│ 吞吐(单请求) │ 25 t/s │ 80 t/s │ +220% │
│ 吞吐(系统,10c)│ 200 t/s │ 600 t/s │ +200% │
│ 显存占用 │ 140GB │ 14GB │ -90% │
│ 最大并发 │ 8 │ 50 │ +525% │
└──────────────┴──────────┴──────────┴────────┘
2. 质量对比(定量 + 定性)
┌──────────────┬──────────┬──────────┬────────┐
│ 能力维度 │ Teacher │ Student │ 退化 │
├──────────────┼──────────┼──────────┼────────┤
│ 简单问答 │ 95% │ 92% │ -3% │
│ 推理 │ 80% │ 62% │ -18% │
│ 代码 │ 85% │ 70% │ -15% │
│ 翻译 │ 90% │ 82% │ -8% │
│ 数学 │ 75% │ 55% │ -20% │
│ 综合(MMLU) │ 70.5% │ 63% │ -7.5% │
└──────────────┴──────────┴──────────┴────────┘
3. 成本对比
┌──────────────┬──────────┬──────────┬────────┐
│ 成本维度 │ Teacher │ Student │ 节省 │
├──────────────┼──────────┼──────────┼────────┤
│ GPU成本(月) │ ¥20,000 │ ¥3,000 │ 85% │
│ 电费(月) │ ¥2,000 │ ¥400 │ 80% │
│ 运维复杂度 │ 高(多卡) │ 低(单卡) │ ↓ │
└──────────────┴──────────┴──────────┴────────┘课堂练习
- 如果你的团队在考虑用小模型替代大模型,制定一个Teacher vs Student的全维度对比方案
- 列出你业务中最重要的5个场景,分别用大模型和小模型测试质量差异
- 计算从大模型切换到小模型后的GPU成本节省
- 讨论:在哪些场景下质量退化是不可接受的?可以用路由策略(简单任务走小模型,复杂任务走大模型)吗?
20. 优化前后的A/B性能对比方法
无论是量化、蒸馏、框架替换还是任何其他优化,都需要一套标准的A/B对比方法来科学地评估优化效果。本章提供一个完整的方法论和模板。
20.1 A/B对比的标准流程
- 固定环境和数据 → 2. 跑基线(A) → 3. 实施优化 → 4. 跑优化后(B) → 5. 多维度对比
步骤1:固定测试环境和数据
💡 控制变量的重要性
每次只改一个变量!如果同时换了框架+开了量化+升级了CUDA,就无法知道性能提升来自哪个优化。
必须固定的变量:
✅ GPU型号和数量
✅ CUDA版本
✅ 操作系统和驱动
✅ 测试数据集(100条固定Prompt)
✅ 并发数和持续时间
✅ max_tokens和temperature
✅ 测试时间段(避免不同时段的负载干扰)
每次改变的变量(只改一个):
🔄 量化精度(FP16 → INT8)
🔄 推理框架(vLLM → TGI)
🔄 模型版本(14B → 7B蒸馏)
🔄 batch size 参数步骤2~4:执行测试
执行注意事项:
→ 每个配置至少跑3次取平均(降低随机波动影响)
→ 每次测试前重启服务(清除缓存状态)
→ 预热:正式测试前先跑10个请求预热GPU
→ 记录完整的系统指标(GPU/CPU/内存/网络)
→ 保存原始数据(不只是汇总统计)20.2 统计显著性
📐 跑3次取平均 vs 跑1次
跑1次的问题:
→ 可能刚好遇到GPU热节流
→ 可能后台有其他进程抢资源
→ 可能网络刚好不稳定
→ 结论不可靠
跑3次取平均:
结果1: TTFT P50 = 320ms
结果2: TTFT P50 = 345ms
结果3: TTFT P50 = 330ms
平均: 332ms, 标准差: 12.6ms
变异系数: 3.8% → 结果稳定可信
如果3次结果差异 > 20% → 环境不稳定,需要排查
理想情况:跑5次取中位数,更加稳健20.3 A/B对比报告模板
TIP
═══════════════════════════════════════════════════════
A/B 性能对比报告
═══════════════════════════════════════════════════════
1. 对比目的
验证 vLLM FP16 → vLLM INT8 量化后的性能变化
2. 测试环境(固定)
GPU: NVIDIA A100-80GB × 1
模型: Qwen2-14B-Instruct
CUDA: 12.2 | Driver: 535.104
测试数据: 100条固定Prompt(30简单+30中等+40复杂)
并发: 分别在 1/5/10/20 下测试
max_tokens: 200 | temperature: 0.7
每个配置运行3次取平均
3. 变量
A组: vLLM + FP16(无量化)
B组: vLLM + INT8(AWQ量化)
4. 性能对比结果
4.1 TTFT (ms)
┌──────────┬──────┬──────┬──────────┐
│ 并发 │ FP16 │ INT8 │ 提升 │
├──────────┼──────┼──────┼──────────┤
│ 1 │ 250 │ 180 │ -28.0% │
│ 5 │ 380 │ 280 │ -26.3% │
│ 10 │ 650 │ 450 │ -30.8% │
│ 20 │ 1500 │ 900 │ -40.0% │
└──────────┴──────┴──────┴──────────┘
4.2 Token 吞吐 (tokens/s)
┌──────────┬──────┬──────┬──────────┐
│ 并发 │ FP16 │ INT8 │ 提升 │
├──────────┼──────┼──────┼──────────┤
│ 单请求 │ 40 │ 55 │ +37.5% │
│ 系统(10c) │ 320 │ 450 │ +40.6% │
│ 系统(20c) │ 500 │ 720 │ +44.0% │
└──────────┴──────┴──────┴──────────┘
4.3 GPU 资源
┌──────────────┬──────┬──────┬──────────┐
│ 指标 │ FP16 │ INT8 │ 变化 │
├──────────────┼──────┼──────┼──────────┤
│ 显存占用 │ 30GB │ 16GB │ -46.7% │
│ GPU利用率(10c)│ 85% │ 70% │ -15pp │
│ 温度(10c) │ 72°C │ 65°C │ -7°C │
│ 最大并发 │ 25 │ 40 │ +60.0% │
└──────────────┴──────┴──────┴──────────┘
4.4 质量对比(100条Prompt)
┌──────────────┬──────┬──────┬──────────┐
│ 类型 │ FP16 │ INT8 │ 差异 │
├──────────────┼──────┼──────┼──────────┤
│ 简单问答(30) │ 29/30│ 28/30│ -3.3% │
│ 中等任务(30) │ 27/30│ 26/30│ -3.7% │
│ 复杂推理(40) │ 34/40│ 31/40│ -8.8% │
│ 总计 │ 90% │ 85% │ -5.0% │
└──────────────┴──────┴──────┴──────────┘
5. 结论
✅ INT8量化后性能提升显著:
→ TTFT降低28~40%
→ Token吞吐提升37~44%
→ 显存降低47%
→ 最大并发提升60%
⚠️ 质量代价:
→ 简单任务几乎无影响(-3.3%)
→ 复杂推理有一定退化(-8.8%)
→ 综合质量下降5%
📌 建议:
→ 推荐在生产环境启用INT8量化
→ 对复杂推理场景保留FP16回退选项
→ 节省的GPU资源可用于增加并发或部署备份20.4 三方对比示例:vLLM FP16 vs vLLM INT8 vs TGI FP16
| 指标 | vLLM FP16 | vLLM INT8 | TGI FP16 | 最优 |
|---|---|---|---|---|
| TTFT P50 (10并发) | 650ms | 450ms | 700ms | vLLM INT8 |
| 系统吞吐 (10并发) | 320 t/s | 450 t/s | 280 t/s | vLLM INT8 |
| 显存占用 | 30GB | 16GB | 33GB | vLLM INT8 |
| 最大并发 | 25 | 40 | 20 | vLLM INT8 |
| 质量 | 90% | 85% | 90% | vLLM FP16 / TGI |
| 部署难度 | 中等 | 中等 | 简单(Docker) | TGI |
20.5 常见对比测试的坑
⚠️ 常见错误,导致对比结论不可靠
- 不预热:第一次请求触发模型加载,TTFT异常高,拉高平均值
- 同时改多个变量:框架+量化一起换,不知道性能提升归因于哪个
- 只跑1次:单次运行的随机波动可能导致错误结论
- 忽略质量维度:只看速度不看质量,可能推荐了一个"快但质量差"的方案
- 不同时段测试:A组白天测,B组晚上测,GPU温度和系统负载不同
- 测试数据不固定:A组用简单Prompt,B组用复杂Prompt
课堂练习
- 选择你最想优化的一个维度(量化/框架/模型大小),按照本章的标准流程做一次A/B对比
- 确保每个配置跑3次取平均,记录标准差
- 使用本章的报告模板编写一份完整的A/B对比报告
- 在报告中明确标注质量维度的变化——性能提升不能以牺牲业务核心质量为代价
- 将报告分享给团队,讨论优化方案是否可以落地
补充参考答案要点
- 前沿篇练习的答案要特别关注量化、蒸馏、MoE、长上下文和 speculative decoding 对质量与性能的双向影响。
- 前沿优化不能只报吞吐提升,还必须说明是否带来边界退化、格式退化或复杂推理退化。
- 真正合格的答案,应包含实验对照、指标变化和适用场景限制三部分。