ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

LLM推理基准测试工程指南:关键指标与性能调优

LLM推理基准测试工程指南:关键指标与性能调优 如果业务侧一句话丢过来“这套大模型服务上线之后能撑多大并发单请求延迟能压到多少毫秒显存会不会爆”没有基准测试数据大概率只能回一句“我先看看”。LLM 推理基准测试LLM Inference Benchmarking要解决的就是这件事把“感觉挺快”“显存好像够用”变成可复现、可对比、可预警的量化结论。这篇不是去刷一个测评榜单而是把 LLM 推理基准测试这一整套工程动作拆开讲为什么测、测什么维度、怎么设计测试集、跑完数据怎么分析、最容易在哪个环节翻车。如果你正在做本地部署方案选型、给上层应用做推理服务容量评估或者准备把小模型/大模型接进自己的工具链这篇文章可以直接作为一份落地操作清单来用。现在开始按“先看结论再讲方法最后给排查清单”的顺序展开。1. 核心能力速览先说清楚一件事LLM 推理基准测试不是一个开箱即用的“一键跑分工具”而是一套测试方法论加工具组合。它的核心特性可以这么汇总能力项说明测试目标对比不同推理框架、不同模型版本、不同硬件配置下的性能差异关键指标首 token 延迟、平均生成速度、吞吐量、显存峰值占用、并发能力硬件范围可从纯 CPU 小模型测试到多卡 GPU 大模型测试视推理方案而定启动成本需要先部署一个可被请求的推理服务再跑请求脚本主要产出一份包含压测参数、测试问题集、性能指标和资源占用的可复现报告适用阶段部署前选型、版本升级验证、服务上线前容量评估、日常巡检主要风险测试设计不当会导致结论失真尤其是并发、批处理和上下文长度设置不合理运行方式命令启动服务 脚本发请求 日志记录是否支持 API基准测试依赖推理服务的 HTTP API 或本地 CLI 输出批量任务支持通过脚本实现多请求、多轮次、多种参数组合的批量测试这张表看完你心里要有数真正有价值的 LLM 推理基准测试不是“跑一次看速度”而是“用可控变量跑多轮得到能对比的数据”。2. LLM 推理基准测试要解决的工程问题没有基准测试很多决策就会变成“拍脑袋”。比如要评估“这套基于开源模型的对话系统能不能承载公司内部 100 人同时使用”如果只看单次请求的生成速度可能觉得挺快一旦加上并发显存碎片、排队调度、KV Cache 占用上升实际响应时间可能翻好几倍。这类问题只有通过量化测试回答。再比如换模型版本不是“换了之后看起来更聪明了”就万事大吉。如果新版本的推理延迟多了 30%就需要重新评估缓存策略、并发上限和后端配置。从工程角度看LLM 推理基准测试主要用于四类场景第一选型对比。在不同本地部署框架之间选一个或者在开源模型与云端 API 之间做成本性能权衡。第二容量规划。根据真实的推理请求预期反推需要多大的显存、多少个并发槽位、什么样的批量调度策略。第三回归验证。每次换版本、换参数、换机器后跑同一套基准快速发现性能退化。第四调优验证。改了量化参数、改了批处理大小、改了 prompt 缓存用基准测试确认改动到底是正向还是负向。需要特别提醒一句LLM 推理性能不是单一数字。同一个模型请求 20 个字的“问题”和请求 4000 字“长文档分析”计算模式和瓶颈完全不同。基准测试必须考虑“任务形态”而不仅是“模型大小”。3. 核心指标与概念做 LLM 推理基准测试之前先把下面这些指标的定义对齐。否则收集了一堆日志也不知道怎么解释。3.1 首 token 延迟首 token 延迟指从请求发出到模型输出第一个 token 的时间。这个指标直接影响用户“第一次感觉到响应”的体验。在长上下文问答、代码生成这种场景里prefill 阶段要处理大量输入 token首 token 延迟会比短输入明显拉长。3.2 每 token 生成延迟每 token 生成延迟是指相邻两个输出 token 之间的时间间隔。它决定了一段完整回答能多快写完。生成阶段是逐 token 自回归进行的所以这个指标往往比首 token 延迟更能反映推理引擎的 decode 性能。3.3 吞吐量吞吐量是单位时间内完成的请求数或生成的 token 数比如“每秒生成 token 数”或“每分钟完成请求数”。对后台批量任务更重要例如文档摘要、定时批量推理。3.4 TTFT 与 TPOT 的关系业界常用两个缩写TTFTTime To First Token首个 token 生成时间TPOTTime Per Output Token每个输出 token 的平均生成时间。两者结合可以推算一个请求的端到端耗时请求总耗时 ≈ TTFT TPOT × 预计输出长度具体数值必须按实际推理引擎和硬件计算但公式关系是稳定的。用这个公式可以反推当并发连接数上升时TTFT 和 TPOT 各自如何变化从而定位瓶颈在 prefill 阶段还是 decode 阶段。3.5 显存占用与 KV Cache生成类大模型推理时会缓存历史 token 的 Key 和 Value这部分显存叫 KV Cache。上下文越长、并发批处理越大KV Cache 增长越快。只看模型权重大小远远不够KV Cache 往往是压垮显存的关键。3.6 并发与批处理并发数是指同时处理的请求数。很多推理框架内部会把并发请求动态拼成一个 batch提高 GPU 利用率。但 batch 过大也会增加显存压力。基准测试要区分“并发请求数”和“单请求内部并行度”不能混在一起。4. 环境准备与前置条件一个完整的 LLM 推理基准测试环境包含四个部分推理服务端、模型文件、发压客户端、观测工具。4.1 推理服务端你要先选择一个推理框架并拉起一个 HTTP 服务。常见选择包括vLLM适合高吞吐场景支持 PagedAttention 和连续批处理。TensorRT-LLM适合 NVIDIA GPU 深度优化。llama.cpp / Ollama适合本地 CPU、较小显存环境快速体验。Hugging Face Transformers 直接跑适合功能验证但不适合直接做高并发压测。不同框架的启动命令和参数差异很大这里只给一个通用思路先把模型加载起来用一次普通请求确认服务可访问再进入正式测试阶段。4.2 模型文件基准测试前要确认模型的版本、精度和存储路径。常见的精度选项包括 FP16、INT8、INT4 等量化形式。精度不同显存占用和生成速度会有明显差异。要记录本次测试用的是哪一种方便后续对比。需要强调的内容不在本地运行时可以提前下载保存到本地目录。模型文件的合规性也需要提前确认使用开源模型时要遵守对应许可证的要求。4.3 发压客户端推荐准备一台和推理服务分离的测试机器避免客户端计算干扰服务端。如果暂时没有独立机器至少要在测试过程中避免在服务端机器上跑大型任务。发压客户端需要具备以下工具Python 3.8 以上环境。curl用于快速验证接口连通性。requests、aiohttp 或 httpx用于写并发测试脚本。可选Locust、JMeter 等通用压测工具但需要额外适配流式接口。4.4 观测工具观测维度包括显存占用、GPU 利用率、CPU 占用、网络延迟。NVIDIA GPU 环境可以用nvidia-smi更推荐定期记录而不是只看一次watch -n 1 nvidia-smi如果部署了 Prometheus Grafana 体系也可以把推理服务的指标接进去。基准测试阶段至少要有 nvidia-smi 级别的观测能力。5. 设计一组可复现的基准测试方案基准测试最重要的原则是“控制变量”。下面给出一套可落地的测试设计流程。5.1 定义测试问题集不要只拿一句“你好”做基准测试。LLM 推理的任务形态差异很大问题集至少应该覆盖四类短输入短输出模拟日常问答比如手机能访问的请求场景。短输入长输出模拟文章生成、代码生成问题短但生成内容长。长输入短输出模拟文档问答问题附带一大段资料。长输入长输出模拟内容扩写、报告生成压力和耗时都最高。每次测试固定问题集使用同一组问题文本不做随机变化。问题集的顺序对结果也有影响如果需要严格复现固定顺序并记录在测试报告中。问题集准备完成后可以用 JSON 文件管理[ { name: short_qa, prompt: 介绍一下大模型推理框架的主要组成部分用一句话回答。, max_tokens: 128 }, { name: code_generation, prompt: 写一个 Python 函数批量统计列表中每个元素出现的次数。, max_tokens: 512 }, { name: long_document, prompt: 以下是一段产品说明请提取核心要点并输出三条总结。, max_tokens: 256 } ]5.2 确定变量维度基准测试至少要在以下几组设置下分别跑并发数从 1 开始逐步增加例如 1、4、8、16、32。上下文长度固定输入 token 范围模拟实际业务场景。最大输出长度固定 max_tokens。模型精度和采样参数主要记录是否开启量化、是否使用流式输出。跑完一组后只改变一个变量不要同时改两个。否则数据出来后无法定位性能差异来自哪个改动。5.3 多次运行取稳定值单次测试结果波动很大尤其是并发场景。推荐每种参数组合至少跑 3 次取中位数或均值。第一次请求往往包含模型预热、上下文初始化等额外时间正式记录前应先发几条预热请求。5.4 记录每次环境的指纹信息测试环境会对结果产生很大影响。报告里必须包含模型名称和版本。推理框架名称和版本。GPU 型号、驱动版本、CUDA 版本。服务启动参数与量化配置。测试脚本版本。测试时间和持续时间。有了这些信息换机器后恢复同样的测试才有意义。6. 使用接口 API 做批量性能测试推理服务通常提供 HTTP 接口所以我们可以直接写脚本并发请求。以下用 OpenAI 兼容协议的通用结构举例。先确认服务地址可以访问curl http://127.0.0.1:11434/v1/chat/completions \ -H Content-Type: application/json \ -d { model: your-model-name, messages: [{role: user, content: hello}] }注意具体地址、模型名、鉴权方式要以实际部署的推理服务为准。上面的写法和真实项目不完全相同需要做变量替换。下面给出一个 Python 逐请求计时脚本用来统计首 token 延迟和完整响应时间。import json import time import requests API_URL http://127.0.0.1:11434/v1/chat/completions MODEL_NAME your-model-name def single_request(prompt: str, max_tokens: int 256): payload { model: MODEL_NAME, messages: [{role: user, content: prompt}], max_tokens: max_tokens, stream: False, } start time.perf_counter() response requests.post(API_URL, jsonpayload, timeout180) end time.perf_counter() if response.status_code ! 200: return None, None, response.status_code data response.json() total_time end - start return data, total_time, response.status_code if __name__ __main__: with open(bench_questions.json, r, encodingutf-8) as f: questions json.load(f) for item in questions: data, total_time, status single_request(item[prompt], item.get(max_tokens, 256)) if status ! 200: print(f{item[name]} failed, status{status}) continue usage data.get(usage, {}) completion_tokens usage.get(completion_tokens, 0) total_tokens usage.get(total_tokens, 0) print( f{item[name]}: status{status}, fcompletion_tokens{completion_tokens}, ftotal_tokens{total_tokens}, felapsed{total_time:.3f}s )这个脚本只能统计完整请求耗时拿不到真正的首 token 延迟。想测首 token 延迟需要改用流式接口并记录收到第一个 response 字节的时间。import json import time import requests API_URL http://127.0.0.1:11434/v1/chat/completions MODEL_NAME your-model-name def first_token_latency(prompt: str): payload { model: MODEL_NAME, messages: [{role: user, content: prompt}], max_tokens: 256, stream: True, } start time.perf_counter() first_token_time None try: with requests.post(API_URL, jsonpayload, streamTrue, timeout300) as resp: for line in resp.iter_lines(): if not line: continue if first_token_time is None: first_token_time time.perf_counter() - start line_text line.decode(utf-8) if line_text.startswith(data: [DONE]): break except Exception as exc: return None, str(exc) total_end time.perf_counter() if first_token_time is None: return None, no stream data received return first_token_time, total_end - start流式接口的具体数据格式同样依赖推理服务实现第一行数据可能不是传统data:前缀需要按实际服务返回结果调整解析逻辑。并发测试不建议直接开一堆线程无限发。更合适的做法是固定并发数比如 8 个并发同时发送请求等待所有请求结束记录总耗时和每请求耗时再逐步增加并发。脚本里可以限制最大运行时间避免某个请求卡死导致整个测试停不下来。import concurrent.futures import json import time def worker(args): prompt, max_tokens args return single_request(prompt, max_tokens) def run_concurrent(question_file: str, concurrent_num: int): with open(question_file, r, encodingutf-8) as f: questions json.load(f) tasks [(item[prompt], item.get(max_tokens, 256)) for item in questions] start time.perf_counter() with concurrent.futures.ThreadPoolExecutor(max_workersconcurrent_num) as executor: results list(executor.map(worker, tasks)) end time.perf_counter() total end - start success sum(1 for r in results if r is not None) print(fconcurrent{concurrent_num}, total_requests{len(tasks)}, fsuccess{success}, wall_time{total:.3f}s)批量任务测试的关键是给足超时时间。LLM 推理不像普通 Web API 那样几十毫秒内返回单个较长请求完全可能超过 60 秒。超时设置过短结果全是被中断的失败请求测试结论不准确。7. 资源占用与性能观察方法LLM 推理基准测试不能只看接口耗时还要同步观察服务端资源。7.1 显存与 GPU 利用率如果使用 NVIDIA GPU测试过程中关注这些信息显存总量和已用显存。GPU 利用率。显存温度与功耗。是否因为显存不足发生 swap 或 OOM。观察方法nvidia-smi --query-gpuindex,name,memory.used,memory.total,utilization.gpu,temperature.gpu,power.draw \ --formatcsv固定间隔记录nvidia-smi --query-gpuindex,name,memory.used,memory.total,utilization.gpu,temperature.gpu,power.draw \ --formatcsv -l 5-l 5表示每 5 秒刷新一次。记录一段时间后把输出保存到文件就能看到显存随测试任务变化的过程。7.2 显存不足时的表现当显存接近上限时推理服务可能出现这些现象请求等待时间突然拉长。部分请求报错。服务端日志出现 OOM 关键词。整机变得卡顿。关键点在于显存占用的高峰不一定出现在推理刚开始的时候往往出现在长输出生成的后半段因为 KV Cache 会随着生成 token 数增长持续变大。所以测试每个任务时要保证请求完全跑完再观察显存峰值不能只看服务刚启动的状态。7.3 降低显存占用的思路显存压力过大时可以从这几方面调整降低单请求最大输出长度。减少并发 batch 数量。切换 INT8、INT4 等量化精度。使用更小的模型版本。清理服务日志和无效进程。如果服务支持开启显存碎片整理或按需加载。每一种调整都会影响效果与速度基准测试恰恰用来量化这些调整带来的代价。比如同一个小模型从 FP16 切到 INT4显存占用下降但要确认输出质量是否不可接受。7.4 容易造成误判的细节基准测试中最容易出的问题就是“假吞吐”脚本不断发请求早期请求处理很快中后期因为排队、显存瓶颈速度明显下滑但脚本只统计了总成功数和平均耗时掩盖了尾部延迟。报告中不仅要看平均值还要看 P50、P95、P99 分位延迟。大数据量的结果可以这样记录并发数请求总数成功数平均耗时(s)P50(s)P95(s)P99(s)总吞吐(token/s)13030示例示例示例示例示例43030示例示例示例示例示例这里的“示例”只是填空提示不是真实数据。你实际测试时替换为输出结果。8. 从结果反推优化方向得到基准测试结果后不要急着下结论“模型快”或“模型慢”。先把结果和测试场景关联起来。如果首 token 延迟高而每 token 生成速度正常说明瓶颈多发生在请求预处理和 prefill 阶段。可优化的方向包括输入 prompt 是否过长、是否有大量历史消息被拼接到请求中、是否启用了 prompt 缓存。如果首 token 正常但完整生成速度很慢说明 decode 阶段或输出长度设置是瓶颈。可能原因是生成长度太长、并发 batch 过大导致互相争抢算力、量化方案拖慢了逐 token 生成。如果并发从 1 升到 4 吞吐提升明显从 4 升到 8 反而出现部分请求超时说明服务并发上限就在某个区间附近。继续往上加压已经没有意义应该反推业务的预估并发量为服务预留 20% 到 30% 的余量。如果显存占用没满但 GPU 利用率不高可能是请求的提示词和批处理策略没把算力喂饱。可以考虑在推理框架里开启更优的批处理调度或者用更长的输入任务去测而不是简单理解为“模型跑得不够快”。如果要形成长期积累建议把基准测试沉淀成一个可复用的工程资产。你可以维护一套提问集和测试参数跑完的日志统一保存并用文档记录每次变更。像 Obsidian 这类工具很适合把测试配置、日志、结论组织成一个个可跳转的页面建一个类似“LLM 推理性能测试”的文件夹每个模型版本一份测试报告下次讨论“要不要升级模型”时可以直接对照数据。9. 常见问题与排查方法下面整理 LLM 推理基准测试中常见的问题可直接对照排查。问题现象可能原因排查方式解决方案服务启动后立刻报显存不足模型文件超过当前可用显存查看服务端日志、nvidia-smi 确认显存换小模型、降低精度、清理显存进程单个请求耗时极长模型生成了过长文本或 prompt 太长查看 max_tokens 设置、请求日志 token 数缩短最大输出长度、精简 prompt测试结果多次波动很大并发数、请求参数、机器负载不稳定固定参数重复测试排除其他任务干扰多次取中位数记录机器状态请求返回超时超时时间设置小于模型实际推理时长检查超时参数和单次请求耗时调大 timeout流式接口收不到首 token 时间解析的数据格式不对打印原始响应内容按实际流式格式调整解析GPU 利用率很低batch 太小或请求任务过于碎片化同时观察显存和 GPU 利用率调整批处理策略、增加并发大批量任务跑到一半卡住某个请求进入异常状态查看服务日志、检查死锁和显存在脚本中加单个请求超时和失败重试换了一台机器结果差异大驱动、CUDA、框架版本、量化配置不一致对比环境指纹信息标准化安装流程记录部署依赖接口返回无权限或 403服务设置了鉴权查看服务配置给客户端配置正确的访问凭证显存统计时高时低不同请求的上下文长度差异大观察任务过程中的实时显存变化按输入长度分组测试排查的总原则是先看服务端日志再看客户端状态码和超时设置最后看指标数据。不要一次改多个参数否则问题定位会变成猜谜。10. 最佳实践与使用建议LLM 推理基准测试已经不是一个科研任务而是一项需要长期维护的工程工作。实际运用时要注意几个原则。第一先小规模验证再全量压测。第一次跑测试先用 1 并发、短问题、短输出确认整个链路能通再逐步加压。一上来就开 100 并发一旦出问题很难判断是脚本问题、服务问题还是模型问题。第二保留一套最小可运行配置。如果推理服务参数复杂把能稳定跑的启动命令和测试脚本单独保存遇到问题可以快速回到已知可用状态。第三模型文件、测试脚本、测试问题集、输出结果要分类管理。建议采用下面的目录结构benchmark/ ├── models/ # 模型文件或指向模型目录 ├── scripts/ # 测试脚本 ├── questions/ # 问题集 ├── logs/ # 原始请求日志 ├── reports/ # 汇总报告 └── configs/ # 启动参数和测试配置第四批量测试必须做日志和失败重试。日志至少记录每次请求的 prompt 名称、开始时间、结束时间、状态码、输出 token 数。脚本里要处理单次请求失败但整体任务不中断的情况。第五接口服务要注意访问范围。如果只是本地测试服务不要监听公网地址。默认绑定到 127.0.0.1 比直接绑定 0.0.0.0 更安全。第六合规问题同样要放进测试流程。如果测试数据包含真实用户对话、个人文档或公司内部资料要确认数据使用边界和脱敏要求。涉及人脸、声音、作品版权、个人隐私等内容必须取得合法授权并明确测试用途。模型许可证允许的范围也要遵守尤其是在商用场景下。第七发布或商用前要做效果复核。性能数据不能代替业务效果评估。同一个模型推理速度更快不意味着业务输出更合适。基准测试给出的是“工程上限”业务上仍然要验证输出质量、安全性和可用性。11. 总结与下一步LLM 推理基准测试的核心价值是在模型选型、容量规划、版本升级和性能调优时提供一套可复现、可对比的数据。它真正难的不是安装环境或者跑通脚本而是设计一个能够反映真实场景的测试方案并控制住变量。如果你现在正准备开始建议先做三件事准备一份覆盖短问答、长输入、长输出三类场景的问题集部署一个最简单的本地推理服务并确认接口可访问写一个带超时和日志的请求脚本先跑通 1 并发场景。在这三步完成之后再逐步加入并发、长文本、量化对比和资源观测。最容易踩的坑是拿到结果后不记录环境参数导致测试无法复现其次是只测平均值忽略 P95 和 P99 分位延迟再就是压力测试时没有盯着显存变化直接把服务压到 OOM。后续扩展方向也很清楚把基准测试脚本接入自动化流水线模型更新后自动跑回归把测试报告按统一模板归档让配置、数据和结论随时可查再把业务场景的典型 prompt 持续补充进问题集让基准测试越来越接近真实用户流量。如果只记住一句话LLM 推理基准测试不是赛跑是给推理服务画一张“能力边界图”图越完整后面做架构决策的时候就越有底气。建议把这套测试流程收藏备用下次需要评估模型性能时可以直接照着搭。
返回列表