尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

本地LLM基准测试全流程:量化选型与性能指标实战

本地LLM基准测试全流程:量化选型与性能指标实战 很多教程会告诉你本地部署一个 7B 模型用 GGUF 量化到 q4_K_M在笔记本上就能跑起来。这话没错但真正上手时会发现问题远不止“能不能跑”这么简单。同一个模型用不同量化精度、不同上下文长度、不同推理引擎去跑速度和内存表现可能相差一倍以上官方 README 里的参数说明也不会直接告诉你你这台笔记本到底应该选哪个量级的模型。这篇文章我就从一台普通开发笔记本的视角出发把本地 LLM 基准测试的完整流程拆开讲透。你会了解该测哪些指标、怎么控制变量、如何用 Ollama / llama.cpp / LM Studio 快速拿到可复现结果以及拿到结果之后怎么在模型质量、速度和硬件占用之间做权衡。1. 背景与核心概念1.1 什么是本地 LLM本地 LLM指的是完全运行在你自己的电脑上、不依赖云端 API 的大语言模型。它和你在网页端使用 ChatGPT、在线大模型 API 最大的区别是推理过程发生在你自己的 CPU 或 GPU 上对话数据、上传的文档、生成的中间结果都不会离开本机。常见的落地形式是把模型量化成 GGUF 格式再配合 llama.cpp、Ollama、LM Studio 这类推理引擎加载运行。本地 LLM 的优势非常直接隐私性更好离线也能用按需定制的能力更强没有按 token 计费的压力。但代价也很明显——你的硬件决定一切。模型文件太大内存装不下GPU 显存不足推理会退回 CPU速度感人上下文一拉长KV Cache 又会吃掉一大块内存。所以在真正把本地模型应用到项目里之前先跑一轮基准测试属于必须做的功课。1.2 为什么要在笔记本上做基准测试笔记本的硬件资源天然是受限的CPU 核心数不够多内存带宽有限显存容量更是和桌面级显卡差了一截。如果不在部署前做一次完整的性能摸底很容易出现两种极端一种是模型选得太大推理速度慢到不可用体验非常糟糕另一种是模型选得太小虽然飞快但理解能力和生成质量跟不上业务需求。所以benchmark 不是跑分爱好者专属的娱乐活动它本质上是一次容量规划。你要回答三个问题第一这个模型能不能在当前笔记本的内存或显存里稳定加载第二它的吞吐速度能不能满足你的应用场景比如聊天、文档摘要、Agent 工具调用第三长时间运行时温度和功耗会不会触发笔记本降频导致性能缩水。只有把这三个问题量化了你才敢把本地模型放进正式项目里。1.3 普通试玩和 Benchmark 的区别普通试玩是你执行一条ollama run命令输入一句话看模型回复顺不顺眼。而 benchmark 是用可复现的方式去衡量系统表现。同样是生成 256 个 token 的任务如果有人说“8B 模型速度还行”这句话其实没有意义因为不同笔记本硬件的差异可能达到 5 到 10 倍甚至在同一台笔记本上不同时间跑的结果也会因为系统负载、温度、降频策略而不同。一份合格的 benchmark 至少要满足几个条件同一份模型文件、同样的量化精度、同样的 prompt、同样的生成参数固定随机种子和温度多次运行取平均值或中位数。这样你才能在不同模型之间、不同量化级别之间、不同推理引擎之间做横向对比。只有做到可复现测试结果才有工程价值。1.4 本地 LLM 的典型场景RAG、Agent 与 MCP如果你只是把本地模型当作聊天玩具性能压力其实不大。但一旦想把本地模型接入 RAG 知识库、Agent 工作流或者 MCP 工具调用性能指标的差异会立刻被放大。RAG 场景里系统检索完知识库之后要生成一段有依据的回答首 token 延迟太高用户就会觉得“卡”Agent 场景中工具调用往往包含多轮推理每秒生成 token 数直接决定一个任务的总耗时MCP 生态这两年越来越活跃本地模型通过 MCP 协议连接数据库、文件系统、浏览器工具每一步都在产生 token链条越长对吞吐的要求就越苛刻。这也是很多开发者开始做“Obsidian 本地模型 LLM Wiki 个人知识库”的原因先跑通离线推理再叠加知识管理再优化检索和生成速度。而所有这些优化的第一步都是先做一次靠谱的本地 benchmark。2. 环境准备与版本说明2.1 先盘点你的笔记本硬件开始之前先明确你的笔记本属于哪种类型这决定了推理路径与测试策略。大方向可以分成三类第一类是带 NVIDIA 显卡的 Windows 笔记本优先使用 CUDA 加速速度和生态最好第二类是 Apple Silicon 的 MacBook利用 Metal 和统一内存跑中小模型的体验也很不错第三类是只有核显或者弱独显的轻薄本主要靠 CPU 计算内存带宽决定上限模型量级要适当调小。内存容量是另一个关键因素。7B 到 8B 参数量的模型用 q4_K_M 量化后大约需要 4 到 6 GB 内存14B 模型大约需要 8 到 11 GB。如果 GPU 显存不足以放下一整层模型推理会退回到 CPU 执行速度会明显下降。所以建议先用系统自带工具确认内存和显卡型号再决定要测哪些模型。版本信息以你的实际环境为准本文重点演示的是“怎么测”的方法而不是某个特定型号的跑分。2.2 推理工具选型Ollama、llama.cpp、LM Studio当前本地 LLM 推理工具里最常用的三套是 Ollama、llama.cpp 和 LM Studio它们的定位不同Ollama安装最简单一行命令下载模型并启动服务适合快速尝试和 API 调用也适合做脚本自动化测试。llama.cpp最接近底层提供了专门的llama-bench工具适合精确对比不同量化级别、不同线程数、不同 GPU 层数下的性能差异。LM Studio图形化界面内置模型下载和参数调整面板提供本地 OpenAI 兼容 API适合不熟悉命令行的用户。对 benchmark 来说我的建议是没有特殊需求先用 Ollama 跑一次拿到基线需要更细粒度对比时再用 llama.cpp 的llama-bench。原因在于llama-bench的功能设计就是基准测试可以自动统计 prompt 处理和生成两个阶段的耗时而 Ollama 更适合日常使用它没有内置的基准命令需要自己写脚本调用 API。两者的结果可以互相印证但不能直接对标。2.3 安装与环境验证先安装 Ollama。Windows 和 macOS 用户直接去官网下载安装包即可Linux 用户可以用官方脚本# Linux 安装 Ollama curl -fsSL https://ollama.com/install.sh | sh # 验证安装 ollama --version然后准备 llama.cpp。如果之前没有用过可以用下面的方式编译。需要说明的是Windows 用户如果要 CUDA 加速需要先安装 CUDA Toolkit没有 NVIDIA 显卡或不想自己编译的可以直接下载官方 release 版本。git clone https://github.com/ggerganov/llama.cpp cd llama.cpp cmake -B build -DCMAKE_BUILD_TYPERelease -DLLAMA_CUBLASON cmake --build build --config Release -j 8如果是 Apple Silicon Mac把-DLLAMA_CUBLASON换成-DLLAMA_METALON让 llama.cpp 走 Metal 加速。编译完成之后在build/bin目录下就能找到llama-bench可执行文件。LM Studio 不需要命令行直接安装然后在界面里下载模型即可。2.4 建立测试目录结构为了避免测试数据散落各处建议先搭一个简单的目录结构benchmark/ ├── scripts/ │ └── run_benchmark.py ├── results/ │ └── benchmark_result.csv └── models/ └── qwen2.5-7b-instruct-q4_K_M.gguf后续所有模型文件、测试脚本、结果 CSV 都放在统一位置一方面方便多次运行对比另一方面也方便把结果分享给团队。3. 基准测试方法论测什么、怎么测才可信3.1 核心指标TTFT、TPS、内存与能耗benchmark 不能只看“生成了多少字”业内常用四个核心指标TTFTTime To First Token从发起请求到模型输出第一个 token 的时间。对话机器人和 RAG 场景最关心这个它决定了用户的第一感知延迟。TPSTokens Per Second生成阶段每秒产出的 token 数量。文档摘要、长篇生成、Agent 多轮任务更依赖这个指标。峰值内存进程在运行期间占用的最大 RAM 或 VRAM。内存不够会触发 swap性能会急剧下降。功耗与温度笔记本与台式机不同散热空间有限长时间高负载会触发降频TPS 会从峰值掉下来。在记录结果时尽量把这几项都记下来因为同一个模型在不同上下文长度下的内存占用差别很大只看 TPS 会漏掉关键信息。3.2 控制变量的测试设计基准测试的意义在于横向对比这就要求控制变量。最基本的测试设计要满足以下条件使用同一份模型文件记录文件大小或哈希值。固定 prompt 的 token 长度避免“问题简单所以回答快”的干扰。固定 max tokens也就是一次生成的最大长度。固定采样参数例如 temperature 0、top_p 1、固定随机种子。同一模型和同一场景至少跑 3 次取平均值或中位数。测试期间关闭后台下载、视频播放、编译任务等无关负载。举个例子如果你想对比 7B 模型的 q4_K_M 和 q5_K_M 两档量化就应该保证两次运行的环境完全相同只替换模型文件。如果上下文长度变了那测试的是“上下文长度对速度的影响”就不能再和前面的结果直接比较了。3.3 理解精度与量化FP16、BF16、FP32 与 GGUF这是新手最容易绕晕的部分也是本地 LLM benchmark 最重要的背景知识。FP32 是单精度浮点数每个权重占 4 字节精度最高但体积最大FP16 是半精度每个权重占 2 字节显存占用减半是目前很多 GPU 原生加速的精度格式BF16 同样是 2 字节但它的指数位范围和 FP32 一致只是尾数精度更低在深度学习场景下更容易保持数值稳定因此大模型训练和推理中很常见。在带 GPU 的机器上常见的做法是用 FP16 或 BF16 做推理而在 CPU 或混合部署场景下GGUF 量化格式更常用。q4_K_M、q5_K_M、q8_0 这些名字表示把权重从 16 位浮点压缩到 4 位、5 位或 8 位整数或低精度浮点模型体积成倍下降推理速度更快但精度会有一定损失。benchmark 的核心目标之一就是帮你找到“速度、体积、质量”三者之间的平衡点。3.4 使用 llama-bench 快速测试llama.cpp 自带的llama-bench是最省事的基准工具。它会在同一个进程里先跑 prompt 处理再跑 token 生成最终输出 TPS 和内存占用不用自己写计时逻辑。基本用法如下./llama-bench -m ./models/qwen2.5-7b-instruct-q4_K_M.gguf \ -p 512 -n 256 -r 3解释一下关键参数-m指定 GGUF 模型文件路径。-pprompt 的 token 长度建议固定为 512 或 1024。-n生成的 token 数量建议固定为 256。-r重复次数建议至少 3 次。-ngl放入 GPU 的层数默认可能为 0需要根据你的显存手动调整常见值如 99 表示尽可能全部放 GPU。执行完成后终端里会输出类似下面的字段prompt t/s、generation t/s、mtest等。其中 generation t/s 就是我们要重点关注的 TPS。3.5 用 Python 脚本做自定义基准测试llama-bench适合测引擎本身但如果你想知道“用户实际请求下模型表现如何”最好直接通过 Ollama 的 API 测这样更贴近真实应用场景。下面是一个最小可用的 Python 脚本它向本地 Ollama 服务发送生成请求然后从响应里解析出 token 数和耗时计算出 TPS。# 文件路径benchmark/scripts/quick_bench.py import time import requests MODEL qwen2.5:7b URL http://localhost:11434/api/generate PROMPT 请用三句话介绍什么是数据库索引并举例说明。 MAX_TOKENS 256 def run_once(): payload { model: MODEL, prompt: PROMPT, stream: False, options: { temperature: 0, num_predict: MAX_TOKENS, }, } t0 time.time() resp requests.post(URL, jsonpayload) data resp.json() elapsed time.time() - t0 eval_count data.get(eval_count, 0) eval_duration data.get(eval_duration, 1) load_duration data.get(load_duration, 0) tps eval_count / (eval_duration / 10**9) return elapsed, tps, eval_count, load_duration / 10**9 if __name__ __main__: elapsed, tps, eval_count, load_sec run_once() print(f总耗时: {elapsed:.2f}s) print(f生成 tokens: {eval_count}) print(fTPS: {tps:.2f}) print(f模型加载耗时: {load_sec:.2f}s)这段脚本里的重点是通过eval_duration计算 TPS而不是用总耗时去除。因为总耗时里包含了网络请求、模型排队和加载时间不能代表真实的生成速度。Ollama 返回的eval_duration单位是纳秒所以要除以 10 的 9 次方换算成秒。4. 完整实战在笔记本上跑一份可复现的 Benchmark4.1 确定测试模型与量化层级先决定测什么。对大多数 16GB 内存的笔记本来说建议从 7B 到 8B 级别的模型开始选择 q4_K_M 和 q5_K_M 两个量化档位对比如果内存比较大比如 32GB 或以上可以再加入 14B 模型测试。下面以 Qwen2.5 7B 和 Llama 3.1 8B 为例。不同模型的精确标签以 Ollama 库的实时列表为准可以用ollama pull拉取。# 拉取两个量化版本的模型作对比 ollama pull qwen2.5:7b ollama pull qwen2.5:7b-instruct-q4_K_M # 可选拉取 Llama 3.1 8B ollama pull llama3.1:8b如果你不确定某个标签是否存在可以先执行ollama list查看本地已有模型或者到模型库页面搜索确认。实测时建议优先使用你已经在用的模型标签这样测试结果直接服务于你的业务。4.2 编写可复用的基准测试脚本单独跑一次脚本只能得到一组数据为了对比模型和量化最好把脚本扩展成批量模式。下面这个脚本会遍历多个模型每个模型重复跑 5 次最后把所有结果写入 CSV 文件方便后续用 Excel 或 pandas 分析。# 文件路径benchmark/scripts/run_benchmark.py import csv import time import statistics import requests MODELS [ qwen2.5:7b-instruct-q4_K_M, qwen2.5:7b-instruct-q5_K_M, ] URL http://localhost:11434/api/generate PROMPT 请解释什么是 B 树以及它在数据库中的典型使用场景。 REPEATS 5 MAX_TOKENS 256 def bench_model(model): samples [] for _ in range(REPEATS): payload { model: model, prompt: PROMPT, stream: False, options: { temperature: 0, num_predict: MAX_TOKENS, }, } t0 time.time() resp requests.post(URL, jsonpayload) data resp.json() elapsed time.time() - t0 eval_count data.get(eval_count, 0) eval_duration data.get(eval_duration, 1) tps eval_count / (eval_duration / 10**9) samples.append({ model: model, elapsed_sec: round(elapsed, 2), eval_count: eval_count, tps: round(tps, 2), load_sec: round(data.get(load_duration, 0) / 10**9, 2), }) return samples def main(): rows [] for model in MODELS: rows.extend(bench_model(model)) with open(results/benchmark_result.csv, w, newline, encodingutf-8) as f: writer csv.DictWriter( f, fieldnames[model, elapsed_sec, eval_count, tps, load_sec] ) writer.writeheader() writer.writerows(rows) for row in rows: print(row) if __name__ __main__: main()脚本的核心逻辑是先把每个模型的多次采样数据收集起来再统一写入 CSV。写文件放在循环外面是为了避免每次请求都打开文件、关闭文件减少 I/O 对测试结果的干扰。4.3 执行测试并记录数据运行脚本前确保 Ollama 服务已经启动。然后执行cd benchmark mkdir -p results python scripts/run_benchmark.py正常运行时会在终端看到每一轮采样的打印信息。测试结束后results/benchmark_result.csv里会保留原始数据。CSV 是文本格式后续不管是画折线图还是做方差分析都很方便。如果你改动了模型文件或引擎版本建议把文件名改成带时间戳的格式比如benchmark_result_20250120.csv避免覆盖旧数据。4.4 观察系统资源占用运行脚本的同时打开系统监控工具观察 CPU、内存、GPU 占用情况。Windows 用户可以打开任务管理器或者单独开一个终端窗口执行# Windows / Linux 下监控 NVIDIA GPU nvidia-smi -l 1-l 1表示每隔 1 秒刷新一次可以看到 GPU 利用率、显存占用和温度。Mac 用户可以用# macOS 下查看内存压力 vm_stat # 安装 htop 后可以看 CPU 和内存实时情况 htop记录下两个关键点第一模型加载完成后进程占用的内存或显存峰值是多少第二生成过程中 GPU 利用率是否跑满如果 GPU 利用率只有 30% 而 CPU 居高不下说明模型没有完全放进 GPU退回了 CPU 推理这时 TPS 通常不会太理想。4.5 整理结果表格测试完成后可以把 CSV 里的数据整理成一张对比表。下面是一个示例格式具体数字需要你在自己的笔记本上实测得到我不建议直接套用别人的结果因为硬件差异太大。模型量化平均 TPS首 token 延迟峰值内存Qwen2.5 7Bq4_K_M待实测待实测待实测Qwen2.5 7Bq5_K_M待实测待实测待实测Llama 3.1 8Bq4_K_M待实测待实测待实测至少跑三次取中位数能有效避免偶然波动。建议在表格后面加一列“备注”记录当时是否开着浏览器、是否处于充电状态、笔记本是否在散热支架上等环境因素因为笔记本的功耗策略会随这些因素变化。5. 结果分析怎样读数据怎样选模型5.1 速度不是唯一指标很多人在跑完 benchmark 后只盯着 TPS 谁高谁低这其实不够全面。如果你的显存或内存有限可能会发现一个残酷事实某个大模型虽然能加载但部分层数退回了 CPU 推理TPS 从几十掉到了个位数。这时与其换更强的硬件不如降低量化级别或者换用更小但更适合任务的模型。内存占用同样重要。同样一个模型在 4096 上下文和 16384 上下文下的内存占用可能相差好几 GB。如果模型在长上下文下会触发 swap你再追求 TPS 都没有意义因为系统会先卡死。所以结果分析的正确顺序是先看内存/显存是否够用再看 TPS 是否达标最后用实际任务验证生成质量。5.2 模型、量化、上下文的三维权衡本地 LLM 的选型本质上是在三个维度之间做权衡模型参数量、量化级别、上下文长度。模型越大生成质量和理解能力通常越好但内存和显存需求更高。量化越低比如从 q8_0 降到 q4_K_M体积更小、速度更快但精度损失更明显具体表现为生成内容偶尔会产生“幻觉”或逻辑不连贯。上下文越长KV Cache 消耗的内存越多相同显卡下生成速度也可能下降。所以不要单独比较“TPS 谁高”而要在同一场景下比较“谁的组合最优”。比如你的应用是长文档分析上下文至少 8192那就优先比较模型在 8192 上下文下的内存和 TPS如果你的应用是短对话上下文 2048 就够那就可以把内存预算省下来选择更大的模型或更高的量化。5.3 用数据做容量规划拿到数据之后要回到真实场景里去判断。如果做的是聊天机器人用户期待 3 秒内看到第一个字那你就重点看 TTFT 是否小于 3 秒如果做的是批量文档摘要一次要生成 1000 个 token那你就重点看 TPS计算总耗时是否在可接受范围内如果是 Agent 多轮工具调用任务可能持续 10 轮以上你要看的是连续多轮的总耗时是否可预测以及显存会不会随着对话轮次增长而溢出。容量规划还有一个技巧给生产环境预留 20% 到 30% 的内存余量。因为操作系统和其他进程也会占用内存如果是 Windows 笔记本后台软件尤其多。千万别把内存算到 99% 满载否则一旦系统开始换页TPS 会断崖式下跌。5.4 相对比较比绝对值更重要不同笔记本之间的数据差异太大所以你的实测值只有和你自己的另一套配置对比时才最有意义。比如你测了 q4_K_M 和 q5_K_M发现 TPS 只下降了 10%但生成质量明显提高那 q5_K_M 就更值得选如果 TPS 下降了 30%而质量提升不明显那就继续用 q4_K_M。这也是为什么要把基准脚本固化的原因——靠“体感”很难判断这 10% 和 30% 的差异。6. 常见问题与排查思路本地 LLM benchmark 过程中下面几个问题出现的频率最高。问题现象常见原因解决思路运行时显存不足报 OOM模型太大或 KV Cache 太长换更小模型、降低量化、缩短上下文模型加载成功但速度骤降GPU 显存不足部分层退回 CPU调整num_gpu或-ngl或换小模型TPS 波动非常大后台进程、笔记本降频、温度墙关闭无关程序多次运行取中位数生成内容前后不一致temperature 未固定设 temperature 0固定随机种子上下文一长就变慢或报错KV Cache 内存不足调低num_ctx或-c参数Windows 下找不到 GPU 加速CUDA 环境未配置好重装 CUDA Toolkit检查驱动版本第一个 OOM 问题处理思路是优先降低上下文长度因为 KV Cache 是线性增长的。比如在 Ollama 里可以设置上下文/set parameter num_ctx 8192设置后生成时的 KV Cache 按 8192 预分配内存占用比 32768 小很多。如果你用的是 llama.cpp 的 server 模式则对应参数是./llama-server -m model.gguf -c 8192 -ngl 99第二个速度骤降问题在 Llama.cpp 中可以通过-ngl控制放入 GPU 的层数。如果显存只有 6GB而模型有 40 层可以先从-ngl 30开始剩下的层跑 CPU。需要注意的是层数分配不是越多越好一旦某层放不进 GPU整次推理仍然会被 CPU 拖慢需要根据nvidia-smi的显存监控逐步调整。第六个 CUDA 环境问题在 Windows 上尤其常见。llama.cpp编译时指定的LLAMA_CUBLASON要求编译环境能检测到 CUDA而运行时又要匹配 NVIDIA 驱动的 CUDA 版本。如果两者不匹配程序会默认走 CPU。最简单的排查方式是在编译完成之后执行llama-bench --list-devices查看是否输出了 GPU 设备。7. 最佳实践与工程建议7.1 把基准测试固化成脚本不要每次都手动复制 prompt、手动计时、手动填表。建议把本文里的脚本保存到项目仓库模型列表、prompt、重复次数都作为可配置参数输出路径统一放在results目录。后续换模型、换引擎版本、换机器都跑同一套脚本数据才能积累起来。配置变量可以这样抽取MODELS [ qwen2.5:
返回列表