跳转至

六、性能指标与评估

📊 TTFT、TPOT、吞吐量分别代表什么?如何测量?

在LLM推理服务中,这三个指标是衡量用户体验和系统效率的核心。

⏱ TTFT (Time-To-First-Token) —— 首Token延迟

定义:从客户端发送请求到收到第一个生成的token(或第一个有意义的字符)所经历的时间。它反映了模型理解用户输入并开始响应的“反应速度”。

测量范围:严格来说,TTFT包含:

  • 客户端到服务器的网络往返时间(RTT)

  • 请求排队时间(如果在高负载时)

  • Prompt的Prefill时间(模型处理输入、生成KV Cache的时间)

  • 生成第一个token的Decode时间

  • 服务器到客户端的首个token传输时间

在服务端日志中,通常记录从接收到请求到输出第一个token的耗时,但为了端到端评估,应包含网络时间。

测量方法:客户端记录发送请求的时间戳T_send,当接收到第一个data:事件(SSE)或第一个token时,记录时间戳T_first,则TTFT = T_first - T_send。服务端也可记录,但可能不含网络传输和排队。

⏳ TPOT (Time Per Output Token) —— 每Token生成延迟

定义:在生成阶段,每输出一个token所需的时间间隔。通常不包括首个token,因为Prefill和Decode的特性不同。更精确地说,TPOT衡量的是Decode阶段每个step的耗时,它是流式输出“平滑度”的关键指标。

测量方法:对于每个生成的token,记录其输出的时间戳,计算相邻token的时间差。通常以平均值、中位数、P95/P99等统计量来汇报。如果生成过程没有流式,也可用总生成时间除以生成token数得到平均TPOT,但这掩盖了波动。

🚀 吞吐量 (Throughput)

定义:推理服务在单位时间内处理的请求数量或生成的token总数。有两个维度:

  • Requests per second (RPS):每秒完成的请求数。适用于请求长度相近的场景。

  • Tokens per second (TPS):每秒生成的token总数。这是更通用的指标,因为它不受请求长度影响。

测量方法:在一段固定时间内,统计服务端成功处理的请求总token数(prompt+completion),除以时间。通常使用压测工具(如JMeter、Locust、自研脚本)并发发送请求,逐步增加并发,记录系统达到饱和前的最大TPS。

📈 三者关系

  • 对于单个请求,总延迟 = TTFT + (生成token数 - 1) × 平均TPOT(假设首个token后的每个token间隔相近)。

  • 对于服务整体,高吞吐往往意味着较大的批处理,这可能会增加单个请求的TTFT(因为排队和批次等待),但可以降低平均TPOT(因为GPU算力更充分利用)。因此,在SLA约束下最大化吞吐是服务优化的目标。

💡 测量工具:常用 vLLM 的基准测试脚本、TensorRT-LLM 的 gptManagerBenchmark、或 Hugging Face TGI 的 benchmark。结合 Prometheus + Grafana 进行实时监控。


🧭 为什么 TPOT 的 P50 和 P99 都重要?

TPOT 的分布往往不是正态的,存在长尾延迟。P50(中位数)和P99(99百分位)分别揭示了系统性能的不同侧面。

  • P50 TPOT:代表“典型”用户的生成速度。如果中位数很低,大多数用户会感觉回复流畅。优化P50通常涉及提升GPU算力、优化矩阵乘法、使用更高效的解码策略等。

  • P99 TPOT:代表“最差情况下”的表现,直接关系到用户是否会遇到明显卡顿。P99高意味着少数请求的生成延迟很大,可能由于资源竞争、垃圾回收、显存碎片、或长序列导致的带宽瓶颈。这对于高端用户或付费用户的体验至关重要。

📉 长尾延迟的危害

在流式输出中,即使中位数TPOT只有50ms,但如果P99达到500ms,用户会每隔一小段时间就感受到明显的停顿。这比整体慢更让人恼火,因为它是间断的。因此,SLA通常必须同时限制P50和P99,例如“P50<100ms 且 P99<300ms”。

⚙️ 优化P99的策略

  • 资源隔离:使用MIG或时分复用避免干扰。

  • 调度优化:确保decode请求不被prefill长时间阻塞(分段prefill)。

  • 显存管理:防止KV Cache碎片导致的分配停顿。

  • GC调优:避免CUDA或Python GC引发的突发暂停。

💡 实际案例:我们曾遇到TPOT P50约60ms,但P99超过2秒。排查发现是vLLM的block manager在显存紧张时触发了大量的碎片整理,导致偶尔的decode step长时间阻塞。通过降低gpu_memory_utilization并增加节点解决了问题。


🔍 如何评估量化或剪枝后模型的推理质量?

模型压缩后,必须从多个维度评估其对最终应用的影响,而不仅仅是困惑度(PPL)。

📊 评估体系

  1. 标准基准测试
  2. 困惑度 (Perplexity):在通用文本数据集(如WikiText-2、C4)上评估,是最基础的指标。但注意,PPL的微小下降(如1-2%)可能对下游任务影响不大。
  3. 任务特定基准:根据模型用途选择。如MMLU(知识)、HellaSwag(常识推理)、GSM8K(数学)、HumanEval(代码)、TruthfulQA(诚实性)等。观察压缩后得分的绝对变化。
  4. 长文本能力:对于长上下文模型,需用特定基准(如LongBench)测试。

  5. 生成质量评估

  6. 人工评估:盲评是金标准。让人类标注员对压缩前后的模型输出进行成对比较,从有用性、流畅性、事实正确性等维度打分。
  7. 自动评估:使用AlpacaEval、MT-Bench等基于LLM裁判的评估,或用GPT-4作为评判。但需注意裁判模型自身偏好。
  8. 多样性测试:检查生成的文本是否变得重复、模板化。可用distinct n-grams指标。

  9. 特定维度测试

  10. 事实正确性:针对知识密集型任务,检查幻觉率。
  11. 安全对齐:用红队提示集测试压缩是否削弱了安全拒绝机制。
  12. 鲁棒性:测试对同义改写、对抗性输入的敏感性。

🛠️ 实际流程

  • 快速筛查:先看PPL和几个关键基准(如MMLU、HellaSwag)的得分。如果下降超过3%,通常需调优量化参数。

  • A/B测试:在线部署压缩模型,与原始模型进行小流量A/B对比,观察用户点击率、满意度等真实业务指标。

  • 回归测试:建立固定的评估集,每次压缩后自动运行,确保不引入新问题。

💡 注意:量化可能对某些模型组件更敏感,例如注意力层比FFN层更易受影响。因此,混合精度量化(如LLM.int8())往往效果更佳。


📈 推理时的延迟抖动通常由什么引起?如何缓解?

推理延迟抖动(Jitter)是系统不稳定的表现,通常源于资源竞争或调度策略不佳。

🔍 主要原因

  1. 批处理中的“计算气泡”:静态批处理中,短请求等长请求;动态批处理中,如果调度不当,prefill大请求可能会阻塞decode。

  2. 显存管理开销:PagedAttention的物理页分配、回收、碎片整理可能在特定时刻造成突发延迟。

  3. GPU资源竞争:多个进程共享GPU,或与系统其他任务(如CUDA上下文切换)冲突。

  4. 网络与IO:如果模型权重未完全驻留显存(CPU offload),磁盘/网络IO会导致严重抖动。

  5. 垃圾回收 (GC):Python GC或CUDA内存释放可能在某些时刻暂停所有kernel执行。

  6. 硬件与功耗管理:GPU频率动态调整、过热降频也会引起性能抖动。

🛠️ 缓解策略

  • 调度优化:使用分段prefill,限制单次prefill的token数,避免decode饥饿。优先级确保decode不被阻塞。

  • 显存池化与预分配:设置合理的gpu_memory_utilization,预留缓冲区。使用vLLM的block manager v2版本。

  • 资源隔离:为推理服务绑定CPU核心,避免其他进程干扰;使用Docker限制资源;对延时敏感服务,使用独立GPU或MIG实例。

  • GC调优:调整Python GC阈值,或周期性手动触发GC以避免突发;使用torch.cuda.empty_cache()谨慎。

  • 锁频:通过nvidia-smi -lgc锁定GPU频率,消除动态调频带来的抖动。

  • 模型常驻:确保模型完全在显存,关闭CPU offload。使用--mlock 或 vLLM的swap_space配置。

  • 监控与定位:使用Nsight Systems抓取抖动时刻的Timeline,精确找到延迟峰值的kernel或操作。

💡 案例:某服务每10秒出现一次TPOT峰值,经Nsight定位是vLLM的block manager每10秒尝试整理碎片,通过减小max_num_seqs和增加gpu_memory_utilization预留空间后解决。


🌊 面向用户的产品中,流式输出的流畅度如何量化评估?

流式输出的流畅度直接影响用户对“AI智能”的感知。除了TPOT外,还需从客户端体验角度定义指标。

📊 流畅度指标

  1. Token间间隔的变异系数 (CV) 标准差 / 平均值,反映间隔的均匀程度。CV越小,输出越流畅。即使平均TPOT低,若CV很大,用户也会感觉忽快忽慢。

  2. 停顿频率与时长 统计TPOT超过某个阈值(如300ms)的次数和持续时间。一次长时间的停顿比多个微小停顿更让人烦躁。

  3. 首次渲染延迟 (Time to First Paint, TTP) 从用户发送请求到屏幕上首次出现文本的时间(近似TTFT,但包含前端渲染)。这是用户感知“开始回应”的瞬间。

  4. 单位字符刷新率 客户端每秒实际显示的字符数(受网络和前端渲染影响)。高刷新率给用户带来“思维敏捷”的体验。

🎯 评估方法

  • 客户端日志:前端在接收到每个token时记录时间戳,计算间隔、卡顿次数等。

  • 模拟测试:使用Playwright等浏览器自动化工具,注入不同网络条件,测量上述指标。

  • 用户感知调查:通过众包平台,让真实用户观看流式输出录屏,给出1-5分的流畅度评分,与客观指标进行相关性分析。

💡 产品优化:如果流式输出有明显停顿,可以考虑前端实现“打字机效果”的平滑动画,掩盖微小的网络抖动;服务端则努力优化P99 TPOT。


⌛ TTFT(首 token 延迟)具体从哪个时刻算到哪个时刻?包含网络传输时间吗?

TTFT的起止点定义对优化目标至关重要。

  • 起点:客户端发起请求的时刻(例如HTTP POST的发送时间)。这最符合用户体验。

  • 终点:客户端接收到第一个有意义token的时刻(SSE流的第一个data:事件被成功解析的时刻)。

📡 是否包含网络时间?

  • 端到端TTFT:包含网络往返时间、服务端排队、prefill、首个decode以及网络传输。这是产品优化最关注的。

  • 服务端TTFT:仅从服务端收到完整请求开始,到生成第一个token并写入socket缓冲区为止。不包含网络传输,是服务端自身的性能指标。

在实际优化中,两者都要测量。服务端TTFT可用于定位内部瓶颈,端到端TTFT则反映用户真实感受。如果两者差异很大,说明网络延迟或客户端处理有明显问题。


⏱️ TPOT(每 token 生成延迟)通常用什么统计指标来汇报?平均值、中位数、P99?

TPOT通常汇报以下统计量:

  • 平均值 (Mean):反映整体性能水平,但易受极端值影响。

  • 中位数 (P50):反映典型用户体验,比平均值更稳健。

  • P95、P99:用于衡量长尾延迟,是SLA的关键。P99表示99%的token间隔都低于该值。

  • 最大值 (Max):用于发现最极端的卡顿。

📊 汇报方式

通常以表格呈现,例如:

查看内嵌表格

同时,也会绘制TPOT随时间或序列位置的分布图,观察生成过程中是否有变慢的趋势。


📉 为什么 TPOT 在生成长序列时可能会出现波动?与 KV Cache 大小有关吗?

是的,TPOT与KV Cache大小有密切关系。

🔍 原因

  1. KV Cache 增长导致显存带宽压力增大 在Decode阶段,每次生成一个token需要读取整个KV Cache。随着序列变长,KV Cache体积变大,从显存读取的时间线性增加。由于Decode是带宽受限的,这直接导致TPOT逐步升高。

  2. PagedAttention的碎片与重分配 当KV Cache增长到需要新物理页时,可能触发物理页分配,若显存紧张,可能引起碎片整理或换页,导致突发高延迟。

  3. 上下文相关计算 某些注意力模式在长序列下可能变得稀疏或需要更复杂的计算(虽然FlashAttention优化了这一点),但总体影响不如带宽大。

📈 波动表现

通常,随着生成token数增加,TPOT会缓慢上升。在序列长度为4k左右可能出现一个较明显的阶梯,原因是GPU L2缓存或TLB miss增加。

💡 缓解:使用KV Cache量化(INT8)减小体积;采用GQA/MQA降低KV头数;限制最大生成长度。


⚡ 推理吞吐量通常用 tokens/s 还是 requests/s 来衡量?两者如何换算?

  • tokens/s(TPS):每秒生成的token总数,包括prompt token(prefill)和completion token(decode)。这是最通用、最准确的指标,因为它不受请求长度影响,直接反映GPU的利用率。

  • requests/s(RPS):每秒完成的请求数。当请求的prompt和生成长度相近时,RPS更直观。但若长短请求混合,RPS可能掩盖真实性能(例如大量短请求会让RPS虚高,但TPS不高)。

🔄 换算

假设平均每个请求的prompt长度为P,平均生成长度为G,则:

image.png

前提是prefill和decode共享同一吞吐量计算。实际服务中,prefill和decode的TPS能力不同(prefill计算瓶颈,decode带宽瓶颈),所以更精确是分开统计,但通常汇报总TPS。

💡 压测实践:固定请求长度和生成长度,用逐步增加的并发数测试,记录TPS和延迟曲线,找到吞吐饱和点。


🔧 如何设计一个端到端的压测方案,模拟真实用户的多轮对话和随机输入长度?

真实用户场景复杂,压测需模拟多样性。

📋 方案设计

  1. 数据集准备
  2. 从生产日志中采集大量真实的用户prompt,保留其长度分布和语言特征。
  3. 构建多轮对话模板:第一轮短文本,第二轮中长文本,第三轮可能带图像(多模态)。
  4. 将prompt按长度分桶(如0-128, 128-512, 512-2048...),按比例混合,再现真实分布。

  5. 压测工具与场景

  6. 使用 Locust 或 自定义 asyncio 脚本。Locust 支持Python编写复杂用户行为。
  7. 创建“用户任务”,每个任务包含多轮对话,随机决定每轮的 prompt 和 max_tokens
  8. 模拟用户思考时间(Think Time),在每轮之间插入随机延迟(如2-10秒),更真实。
  9. 设置并发用户数阶梯上升,如从10逐步增加到200,每个阶段持续10分钟,观察系统稳定性。

  10. 需要监控的指标

  11. 客户端:TTFT、TPOT分布、请求成功率、错误类型(超时、拒绝)。
  12. 服务端:GPU利用率、显存占用、KV Cache命中率、调度队列长度、Prefill/Decode耗时。

  13. 随机输入长度的处理

  14. 压测脚本在每次发送请求前,从数据池中随机抽取一个prompt。
  15. 如果涉及多模态,随机加入不同分辨率的图片。
  16. 观察服务在长短混合下的延迟抖动和吞吐变化。

📈 结果分析

  • 绘制吞吐量-延迟曲线,找到系统容量上限。

  • 分析不同长度分段下的TTFT和TPOT,发现调度瓶颈。

  • 对比多轮对话首轮与后续轮次的TTFT(后续轮次可能因前缀缓存而更快)。

💡 真实案例:某对话产品压测发现,在100并发时TPOT P99正常,但150并发时突然飙升,定位是显存碎片导致调度停顿,通过调整gpu_memory_utilization和启用分段prefill解决。


🚨 压测时发现 TPOT 的 P99 很高但平均值正常,可能是什么原因?

这种现象明确指示了长尾延迟,是系统存在偶发性瓶颈的典型信号。

🔍 可能原因

  1. 显存分配风暴:当大量请求并发且生成长度不一,PagedAttention 需要频繁分配物理页,或在显存紧张时进行碎片整理,导致某些decode步骤被长时间阻塞。

  2. Prefill 抢占:大Prompt的prefill占用了大量计算资源,导致同时进行的decode请求被短暂阻塞(即使使用了分段prefill,仍可能因调度粒度产生毛刺)。

  3. Python GC / CUDA 同步:PyTorch 或 vLLM 内部偶尔触发 CUDA 同步点,等待所有 GPU 操作完成,瞬间卡住所有请求。

  4. 操作系统调度:CPU 密集型任务(如数据预处理)与 GPU 内核竞争 CPU 时间,导致 GPU 内核提交延迟。

  5. 网络抖动:虽然不直接影响TPOT,但如果测量在客户端进行,网络延迟也会贡献P99。

🛠️ 排查与解决

  • Profiling:使用 Nsight Systems 抓取发生P99高峰时段的Timeline,找出是哪个 kernel 或 CUDA API 调用特别长。

  • 服务日志:检查vLLM的调度日志,看是否频繁出现 “preempt” 或 “block table overflow”。

  • 调整配置:降低 gpu_memory_utilization,留出更多空闲显存给物理页分配缓冲;减小 max_num_batched_tokens 限制prefill的规模。

  • 拆分服务:将大prompt的请求路由到单独的计算池,避免干扰实时decode。

💡 案例:我们曾发现vLLM的block manager在物理页用完时,会触发一次全局的碎片整理,耗时数百毫秒,导致P99飙升。通过降低并发数和增加显存池大小解决了问题。


🔍 推理延迟的抖动通常由什么引起?如何通过调度策略或资源预留来缓解?

这个问题与第11题部分重叠,但更侧重于通用抖动而非仅P99。

抖动来源:

  • 硬件:GPU降频、温度墙。

  • 软件:GC、内存碎片、调度不公平。

  • 负载:请求长度变化、并发波峰。

📏 调度策略缓解

  • 分段 Prefill(Chunked Prefill):将大prefill拆分成多个小块,与decode交替执行,避免decode被长时间阻塞。

  • 公平调度:使用类似于TGI的“水印”机制,限制单个请求的资源占用。优先保证decode请求的执行。

  • 资源预留:为decode请求预留部分GPU算力(例如使用MPS限制prefill的占用上限),但这在共享GPU上较难实现。

📦 资源预留

  • 独立资源池:将推理服务拆分为 prefill 池和 decode 池(Sarathi-Serve论文思路),prefill节点处理大计算,decode节点负责低延迟生成,通过高速网络传递KV Cache。这从根本上解决了互相干扰。

  • KV Cache 量化:减少显存压力,降低因换页导致的抖动。

  • 超额预留显存:gpu_memory_utilization设得比理论最大值低5-10%,用于吸收突发分配。


⚖️ 在对比两个推理框架的性能时,需要控制哪些变量才能做公平对比?

公平对比是评估框架优劣的基础,否则结论无意义。

📊 必须控制的变量

  1. 硬件环境:相同的GPU型号、驱动版本、CUDA版本、内存配置、网络拓扑。

  2. 模型与精度:完全相同的模型架构、权重(相同量化方法、相同量化参数)。使用相同的tokenizer。

  3. 输入数据:相同的测试数据集,相同的prompt分布,包括长度、内容。

  4. 请求负载:相同的并发数、请求速率、生成参数(如max_tokenstemperaturetop_p)。使用相同的批处理大小(如果框架允许设置)。

  5. 性能指标:预先统一定义TTFT、TPOT的测量起止点(是否含网络时间),以及吞吐量的计算方式(是否包含prompt token)。

  6. 框架配置:尽量对齐框架功能,如是否启用前缀缓存、KV Cache量化、PagedAttention等。如果功能不对齐,应在测试报告中声明差异。

  7. 预热:在正式测试前,均进行充分预热,排除模型加载和编译的影响。

  8. 多轮测试:每个配置重复多次,报告统计量,避免偶然因素。

📈 测试流程建议

  • 在相同Docker容器中分别部署两个框架,保证软件环境一致。

  • 使用同一压测脚本,避免客户端差异。

  • 从低并发到高并发逐步测试,记录完整的延迟-吞吐曲线。

  • 分析不同长度分段下的表现,看框架在特定场景是否有优势。

💡 常见陷阱:vLLM默认开启前缀缓存,如果对比的框架没有此功能,应在vLLM中关闭,或者注明。同样,TensorRT-LLM编译engine时的max_batch_sizemax_seq_len设置会影响性能,应与对比框架的实际负载匹配。


量化后模型的质量如何全面评估?除了困惑度,还需要看哪些任务指标?

量化压缩模型体积后,必须确保其在真实业务中的表现不受明显影响。仅仅看困惑度(PPL)是远远不够的,因为它只能反映模型对下一个 token 预测的整体不确定性,而无法揭示量化对特定能力、安全性或生成多样性的微妙损害。

📊 需要评估的维度与指标

查看内嵌表格

🔍 实践流程:

  1. 快速筛查:跑一遍 Open LLM Leaderboard 常用基准(HellaSwag, ARC, GSM8K, MMLU)和 Perplexity。若某项明显下降(>3%),则需要排查量化配置。

  2. 任务定制测试:根据业务场景构建专属测试集。例如客服模型要测情绪识别、槽位提取;代码模型要测特定 API 调用正确率。

  3. 人工评估:随机抽取 200 组 prompt,让量化模型和原模型分别生成,由人工进行成对比较(Win/Tie/Lose),检验量化后的生成质量是否显著下降。

  4. A/B 上线:在生产环境部署量化模型,用小比例流量对比真实用户指标(满意度、完成率、点踩率),这是终极检验。

💡 案例:我们曾将对话模型从 FP16 量化到 INT4,PPL 仅上升 0.5,但人工评估发现生成的回复变得啰嗦且偶尔重复短语,这是因为量化使某些注意力头的分布变尖锐。最终通过 AWQ 替代 GPTQ 解决了该问题。


如何评估投机采样带来的实际加速比?在什么条件下加速效果最好?

投机采样并非总是有效,其加速效果严重依赖于草稿模型质量、主模型计算特征以及生成任务的属性。

📈 加速比的定义与测量

实际加速比 = 使用投机采样的平均每 token 延迟(或端到端延迟) / 不使用时的延迟。测量时需固定硬件、模型、输入 prompt 分布、生成的 max_tokens。

✅ 加速效果最好的条件:

  • 草稿模型接受率高:当草稿模型与主模型输出分布高度相关(如同家族小模型),接受率可达 85%~95%。此时加速比接近每轮的猜测数。

  • 主模型较大、计算密集:主模型越大,一次并行验证多个 token 相比于逐 token 生成的收益越大。例如 70B 模型加速比通常高于 7B。

  • 生成任务确定性强:如代码补全、翻译、事实陈述等,草稿模型容易准确预测;而创意写作、开放式对话接受率较低。

  • batch size 较小:投机采样对单请求延迟改善最明显。大批量时 GPU 已经被计算填满,投机带来的加速有限,甚至因额外通信变慢。

  • 草稿模型极轻量:如 Medusa 头、EAGLE 预测器,开销极小,几乎不影响主模型推理速度。

❌ 效果不佳的场景:

  • 主模型较小(如 1B),一次前向本身很快,投机开销占比大。

  • 高并发、大 batch 服务:此时吞吐主要由批处理效率决定,投机采样对吞吐提升有限。

  • 草稿模型接受率低于 50%,猜测的 token 大部分被拒绝,浪费计算。

📊 评估指标:除了墙钟延迟和吞吐,还要关注每 token 的平均猜测次数、接受率分布(不同序列位置的接受率可能变化)。

💡 实践:我们曾用 TinyLlama-1.1B 作草稿为 LLaMA-7B 加速,代码生成场景加速 2.3x,但在多轮闲聊中仅 1.4x,因为用户输入不可预测。


评估生成质量时,使用 GPT-4 作为裁判比人工评估有什么优势和风险?

使用 GPT-4 等大模型作为自动化裁判(LLM-as-a-Judge)已成为主流,但它是一把双刃剑。

⚖️ 优势

  • 成本极低:单次评判成本约 \(0.01~0.05,远低于人工标注(\)1~2),且可无限并发。

  • 速度惊人:数分钟内完成数千条评判,加速迭代。

  • 高一致性:同一 prompt 下的评判结果高度一致,不会因疲劳或主观偏好波动。

  • 可覆盖长尾:对专业领域(如代码、高等数学),GPT-4 的评判能力可能超越普通标注员。

  • 避免伦理问题:无需人工接触有害、暴力内容。

⚠️ 风险与偏差

  • 位置偏见:偏好第一个出现的回答(Position Bias)。必须采用双向评判(交换顺序评判两次)来缓解。

  • 长度偏见:倾向于给更长的回答更高分,即使内容冗余。需在评判 prompt 中明确禁止。

  • “回声室”效应:GPT-4 自身经过 RLHF,带有特定价值观和风格偏好,用它评判会将其偏见“遗传”给被评模型。

  • 能力天花板:评判模型无法理解超越其自身能力的创新表达或复杂逻辑,可能误判佳作。

  • 事实性核查无能:GPT-4 仍会犯事实错误,用它评判事实准确性并不可靠,需要外部知识源辅助。

🛡️ 缓解措施:

  • 多裁判集成(GPT-4 + Claude + Gemini),取多数票。

  • 关键或高风险样本人工复核。

  • 定期与人工黄金标准对比,监控评判偏差。

💡 建议:GPT-4 裁判适用于大规模、快速、初步的筛选和对比;最终上线决策仍需辅助人工评估。


流式输出的“流畅度”如何量化?用户感知的卡顿和 token 生成间隔的关系是怎样的?

流式输出中,用户对“卡顿”的感知并非仅由平均生成速度决定,而是更受延迟的波动性和极端停顿影响。

📏 量化指标

  • Token 间隔的标准差/变异系数 (CV):间隔越不均匀,用户越感卡顿。

  • 停顿频率与时长:设定阈值(如 200ms),统计超出阈值的停顿次数和最长停顿。一次超过 500ms 的停顿比 10 次 50ms 的更令人烦躁。

  • Token 生成间隔的分布(P50, P95, P99):P99 过高表示偶尔的大卡顿。

  • 视觉流畅度评分:通过前端录屏,让人工或算法评估“卡顿感”。

🧠 用户感知机制:

人眼对匀速运动的物体接受度高。当 token 以均匀间隔出现时,即使整体速度较慢(如每 80ms 一个 token),用户也会觉得“流畅地在写”。但如果间隔忽快忽慢,即使平均速度更快,大脑也会将突然的停顿解读为“系统卡住了”,从而焦虑。

💡 优化方向:

  • 服务端努力将 TPOT 的 P99 压制到用户感知阈值以下(通常 <200ms)。

  • 前端可引入“打字机平滑动画”,对微小抖动进行缓冲,但人为增加延迟可能让灵敏用户反感。


推理服务的 SLA(服务等级协议)通常包含哪些指标?如何监控和告警?

生产环境推理服务必须有明确的 SLA,否则故障责任无法界定。

📋 核心 SLA 指标

  • 可用性:服务正常响应时间占比,通常要求 99.9% 以上。

  • 端到端延迟:P50/P99 TTFT、P50/P99 TPOT。例如“P99 TTFT < 1s, P99 TPOT < 150ms”。

  • 吞吐量下限:保证的最低 tokens/s 或 requests/s。

  • 错误率:非 200 状态码或超时比例,通常要求 <1%。

  • 并发上限:承诺能稳定支持的最大并发请求数。

🚨 监控与告警

  • Prometheus + Grafana:服务端暴露指标(如 vLLM 的 /metrics),使用 Prometheus 抓取,Grafana 展示。

  • 关键告警规则:

  • TTFT P99 > 阈值持续 5 分钟 → 告警。
  • 错误率 > 1% → 紧急告警。
  • GPU 利用率 < 50% 但队列长度 > 10 → 可能死锁或卡住。
  • 显存占用 > 95% 持续 10 分钟 → 可能存在内存泄漏。

  • 客户端探针:定期从外部发送测试请求,测量端到端延迟,避免监控盲区。

💡 实践:我们定义了三级告警:Warning(P99 TTFT 超过 2s)、Critical(错误率 > 2%)、Emergency(可用性 < 99%),分别通知开发、SRE 和值班经理。


如何用可视化工具(如 Grafana)搭建一个推理服务的监控面板?核心面板有哪些?

一个好的 Grafana 面板能让团队在几秒内判断系统健康状况。

🖥️ 面板布局建议(全屏展示,一行一主题)

第一行:服务质量

  • 实时 TTFT (P50, P99) 折线图

  • 实时 TPOT (P50, P99) 折线图

  • 请求成功率(%)和错误类型分布

第二行:吞吐与负载

  • 每秒生成 token 数 (tokens/s) 和 请求数 (req/s)

  • 活跃并发请求数

  • 请求排队长度

第三行:资源利用率

  • GPU 利用率(%)和 显存占用 (GB)

  • CPU 利用率、内存占用

  • 网络吞吐 (Gbps)

第四行:推理引擎内部

  • KV Cache 命中率

  • Prefill/Decode 延迟分布直方图

  • 活跃序列数、preempted 请求数

📊 数据源:vLLM/TGI 等框架内置 Prometheus 指标端点,也可自定义日志解析 exporter。

🔧 技巧:使用 $instance 变量区分不同 GPU 或 Pod,设置 Time range 快速回看故障时段。


GPU 利用率和显存占用都很高,是否代表推理服务处于最佳状态?为什么不一定?

❌ 不一定。 GPU 高利用率可能隐藏着糟糕的调度和资源浪费。

🔍 场景分析

  1. 无效计算:模型正在为即将被丢弃的短请求重复计算大量 padding token(静态批处理),利用率高但有效吞吐低。

  2. 等待而非计算:利用率 100% 可能是因为大量时间花费在显存读写(带宽瓶颈),而非计算核心真正忙碌。此时如果增大 batch size,吞吐可能不会提升。

  3. 计算碎片:Prefill 和 Decode 混杂调度时,可能因为长 Prefill 阻塞所有 decode,decode 算力空转但利用率显示被 Prefill 占满。

  4. 资源竞争:多租户下,一个租户占用所有显存,其他租户排队,整体吞吐低下。

📈 真正的最佳状态:

  • GPU 利用率 > 90%,同时 TPOT P99 依然较低且稳定。

  • 显存占用高,但 KV Cache 命中率也高,没有频繁的 OOM 或碎片整理。

  • 吞吐量达到平台的理论上限附近,且延迟满足 SLA。

💡 经验:如果 GPU 利用率 99% 但 TPOT 很高,通常是带宽瓶颈;如果利用率波动大,可能是调度问题。需要结合延迟和吞吐综合判断。


长文本推理的延迟和短文本相比,瓶颈主要在 prefill 还是 decode?为什么?

📊 长文本推理瓶颈转变:

  • 短文本(<1024 tokens):瓶颈在 Prefill。因为模型需要一次性处理整个 prompt,大量矩阵乘法并行计算,此时 GPU 计算核心是瓶颈。

  • 长文本(>4096 tokens):瓶颈转移到 Decode。因为 KV Cache 变得极其巨大(数十 GB),每次 decode 都要从显存读出整个 KV Cache 和模型权重,显存带宽成为绝对瓶颈。同时,Prefill 阶段因为平方级的注意力计算也会很慢,但 FlashAttention 等优化使其不再主导。

🔬 具体分析:

  • Prefill 瓶颈:注意力矩阵为 [1, 32k, 32k],计算量惊人,但现代 GPU 的 Tensor Core 还能勉强应对。

  • Decode 瓶颈:每生成一个 token,需要读取的 KV Cache 大小 = 2 × L × S × d × sizeof(dtype)。当 S=32k 时,光读取 KV Cache 就可能需要几毫秒,而实际计算只需零点几毫秒。所以 Decode 是带宽受限的。

💡 结论:长文本优化必须优先考虑压缩 KV Cache(GQA、量化、稀疏化)和提升带宽利用率(FlashDecoding、PagedAttention)。


在 A/B 测试新推理框架或新量化方案时,需要收集哪些数据来判断是否达标?

🎯 必收集数据(分硬件层、服务层、业务层)

硬件与资源

  • GPU 利用率、显存占用、功耗

  • CPU/内存使用

服务性能

  • TTFT (P50/P99)、TPOT (P50/P99) 分布

  • 吞吐量 (tokens/s)、并发数

  • 错误率、超时率

  • Prefill/Decode 延迟占比

模型质量

  • 在固定测试集上的自动指标(PPL、MMLU 等)

  • 人类或 GPT-4 评估的胜率(Win/Tie/Lose)

  • 生成长度分布、多样性(distinct n-grams)

业务指标

  • 用户点踩率、满意度评分

  • 任务完成率(如客服问题解决率)

  • 平均对话轮次

📊 对比方法:在同一硬件、相同流量下,双模型并行服务,使用相同分流策略,运行至少数小时,确保统计显著。


对于端侧部署的模型,除了推理速度和精度,还需要评估哪些指标?

📱 端侧特有指标

  • 功耗 (Power):每秒推理的能耗 (mJ/token) 或整体功耗 (W),影响设备续航和发热。

  • 发热 (Thermal):持续推理后芯片温度,过高会导致降频,性能大幅衰减。

  • 内存占用 (RAM):运行时占用的内存,模型太大可能被系统杀死。

  • 存储空间:模型安装包大小,影响下载和更新体验。

  • 冷启动时间:首次加载模型到可以推理的耗时。

  • 稳定性:长时间运行是否出现内存泄漏或崩溃。

  • 适配性:在不同芯片(骁龙、A17、麒麟)上的兼容性和性能差异。

💡 测试方法:使用厂商提供的 Profiler(如 Snapdragon Profiler、Xcode Instruments)测量功耗和发热,配合自动化脚本持续压测。


如何估算一个推理服务在给定硬件配置下的最大并发数?需要哪些输入参数?

🧮 估算公式(以自回归生成为例):

最大并发数 ≈ 可用于 KV Cache 的显存 / 单请求的平均 KV Cache 大小

📥 输入参数:

  • 硬件:GPU 总显存(GB),预留显存比例(用于模型权重和临时缓冲区,通常 10-20%)。

  • 模型:参数量、精度(FP16/INT4)、层数 L、隐藏维度 d、头数及 GQA 头数。

  • 推理配置:最大生成长度 max_tokens,平均 prompt 长度。

  • 框架内存效率:PagedAttention 的碎片率(通常 5-10%)。

🔢 估算步骤:

  1. 权重显存 = 参数量 × 精度字节。

  2. 可用显存 = 总显存 - 权重显存 - 系统预留。

  3. 单 token KV 大小 = 2 × L × (d * (head_ratio)) × sizeof(dtype)

  4. 单请求平均 KV 大小 = (prompt_len + 预计生成_len/2) × 单 token KV 大小(考虑生成过程中缓存逐步增加,取平均)。

  5. 最大并发数 = 可用显存 / (单请求平均 KV 大小 × (1 + 碎片率))。

💡 注意:这只是理论上限。实际并发还受算力、调度效率影响。在达到显存瓶颈前,可能先遇到计算瓶颈(如 Prefill 吞吐限制)。因此需要结合压测确定实际饱和点。


你曾经如何定位和解决推理服务上线后性能衰减的问题?复盘一下你的排查思路。

🕵️ 案例复盘:某在线客服模型上线一周后,TPOT 平均延迟从 40ms 缓慢增长到 80ms,且 P99 飙升至 500ms。

🔍 排查步骤:

  1. 确认变化:对比上线初和当前的监控面板,确认延迟劣化非流量增长所致(并发数未明显增加)。

  2. 检查资源:GPU 利用率仍约 85%,显存占用从 70% 升至 95%,初步怀疑显存碎片或内存泄漏。

  3. 框架日志:vLLM 日志中出现“block table full”和“preempting”警告,表明 KV Cache 物理页不足,触发请求抢占和重计算。

  4. 定位根因:分析请求分布,发现近期用户大量上传长文档进行摘要,平均 prompt 长度从 200 增至 800 tokens。由于 PagedAttention 按需分配页,长 prompt 导致页表迅速膨胀,碎片增多,物理页池提前耗尽。

  5. 解决方案:

  6. 紧急:降低 gpu_memory_utilization 至 0.85,留出更多空闲页;限制 max_model_len 为 2048,阻断超长请求。
  7. 长期:启用分段 prefill,减少长 prompt 对显存的瞬时冲击;增加 --swap-space 利用 CPU 内存作换页缓冲;扩容节点提升整体容量。

  8. 验证与回归:压测模拟长文本负载,确认 TPOT P99 回落至 120ms,且日志无 preempt 错误。

💡 经验:性能衰减往往源于负载特征变化,而显存是推理系统最脆弱的一环。健壮的监控和容量规划需定期回顾。