假设一块边缘计算板标称“18 tokens/s”,这还不能回答用户会等多久。它可能是在短提示、单请求、开放式散热条件下测到的生成速度;你的产品却要从设备手册中检索长段落,同时刷新屏幕,并装进无风扇外壳。两组工作负载不同,速度数字就不能直接比较。
验收时先把一次回答拆开:请求到客户端收到首个内容 token 的等待、首个 token 之后的生成间隔,以及长时间运行后的内存、温度和整机功率。然后固定模型、量化、输入长度、输出长度、并发与环境条件,让候选设备跑同一组请求。缺少这些前提时,不宜依据单个 tokens/s 数字决定采购或产品体验。
封面及下方测试箱图片是测试场景示意,不是本文的设备实测或测试记录。
用户究竟在等哪一段
首个 token 与后续 token 不由同一段工作决定
用户按下“查询”后,设备可能先排队、读取或构造提示词、分词、处理输入,再产生第一个 token。本文把客户端发出请求到收到首个非空内容 token 的间隔记为客户端 TTFT(time to first token);若要评估屏幕上的实际等待,还须另记首字渲染完成时间。若在模型内部打点,得到的只是推理阶段的部分耗时;它不能代表包含网络、检索、排队的客户端 TTFT,更不能代表屏幕首字可见时间。报告必须注明打点位置。
后续 token 的间隔通常称 TPOT(time per output token)。例如要判断一段长回答是否流畅,就需要看连续 token 到达的间隔及其波动,而不是把总输出 token 数除以整段总时间。总时间含首字等待;平均值又可能掩盖偶发停顿。测试记录至少分别给出 TTFT、后续生成速度或 TPOT,以及完整请求耗时,并保留原始逐请求结果。MLCommons 在说明小型 LLM 推理指标时也明确区分输入处理阶段与后续生成阶段,不能用一个总吞吐量替代两者。MLCommons 的 LLM 指标说明
下面的时间链把客户端 TTFT、输入处理、后续 token 到达与屏幕首字分在不同位置;它画的是观察事件,不表示模型内部执行与屏幕渲染不能重叠,也不代表本文已在设备上测得耗时。
快速生成不等于快速回答
假设两个系统后续输出同样快:甲需要先加载模型或处理一段长文档,乙的模型已常驻且输入很短。两者 tokens/s 相近,用户等待首字的感受仍会不同。反过来,一个设备能迅速给出首字,但长回答里频繁停顿,也不算稳定。把这两种失败放进同一个“速度不达标”,后续排障会走错方向。
从业务任务倒推测试形状更可靠。若设备只回答几十字的状态问题,首字等待和短请求失败率应优先;若要持续解释维修步骤,后续 token 间隔和长文本质量也重要。验收表要写明目标任务、允许等待和输出长度。不要从别的模型或设备抄一个通用“合格 TTFT”,因为产品交互和输入形状并不相同。
固定可比条件,再跑候选设备
首先冻结模型文件的标识与校验和、量化格式、运行时版本、加速后端、系统镜像、驱动和散热方式。即使型号相同,改变上下文长度、KV cache 类型、GPU/NPU 卸载比例、采样设置或批处理参数,也可能改变容量和速度。对比表里只写“7B 模型”并不足以让另一位工程师复现测试。
再准备同一组请求。可以把设备实际任务抽象为短状态问答、较长的故障说明和接近允许上限的长文档输入;每一组都记录输入 token 数、预期生成上限、并发数、是否命中提示缓存。这里的短、中、长应由产品真实内容决定,不预设通用的 512 或 4096 token 分界。测试提示本身应版本化,禁止 A 设备使用短提示、B 设备使用复杂提示。若模型输出长度差异很大,应同时保留实际输出 token 数,而不是只比较请求完成时间。
| 固定项 | 记录内容 | 不固定会造成的误判 |
|---|---|---|
| 模型与运行时 | 模型文件 hash、量化格式、运行时和后端版本 | 把软件或精度差异当成硬件优势 |
| 请求形状 | 输入/输出 token、提示集版本、上下文上限、缓存状态 | 把短请求成绩用于长文档场景 |
| 负载 | 单请求、目标并发、后台显示或采集任务 | 忽略整机资源争用 |
| 环境 | 供电、机壳、环境温度、散热和电源管理模式 | 把开放开发板当成封闭产品 |
冷启动与热启动要分开跑。冷启动包括进程及模型装载,适合回答“设备开机后第一位用户要等多久”;热启动用于观察模型常驻后的交互。每种情况都保留逐请求数据和失败请求,不只保存最漂亮的一次。若服务层有队列,增加目标并发后要看请求等待是否陡增;单用户快而两人同时用就超时,通常比单次峰值 tokens/s 更影响产品。
下面是一份可缩放的最小矩阵。每格使用同一模型、提示集版本与采样配置;“短”和“长”的 token 数由产品实际请求分布确定,而非从示例抄固定值。每格要重复运行,并把成功和失败请求一起计入分母。若产品没有后台显示任务,该列可改成真实存在的采集或网络负载;不能虚构并发任务凑表。
| 运行组 | 启动与请求 | 并行条件 | 应回答的问题 |
|---|---|---|---|
| A 首次请求 | 冷启动、短输入、单会话 | 业务常驻服务开启 | 首位用户等待是否被装载拖慢? |
| B 常用交互 | 热启动、短输入、单会话 | 同 A | 常态 TTFT 与 TPOT 的分布如何? |
| C 上限输入 | 热启动、业务长输入、单会话 | 同 A | prefill 与内存是否随上下文恶化? |
| D 真实并发 | 热启动、短长输入混合、目标并发 | 显示/采集等真实后台任务 | 排队、失败与尾部等待是否上升? |
| E 持续运行 | 在目标机壳内重复 B–D | 目标供电与环境 | 热稳态后速度、温度与功率是否漂移? |
这不是“五组跑完就一定合格”的规定:缺少设备实际负载时,矩阵只是待验证协议。真正的验收必须在目标设备上填写每组的输入、输出、并发、重复次数和时间窗口,并由产品负责人预先确定通过条件;观察到失败后再降低目标,会使验收失去意义。
一轮测试从基线到复测怎样走
先确认设备在静置时没有异常后台下载、编译或热更新,把系统镜像、运行时构建号和电源模式写入记录。接着运行短请求,确认客户端与服务端时间戳能对应;再按业务提示集增加输入长度和并发。若某组请求失败,保留失败时的上下文长度和系统事件,不要只重跑成功样本。最后关闭模型进程并重新启动,验证冷启动路径是否与热启动记录被清楚分开。这个顺序的目的不是规定每款产品必须跑同一份提示集,而是避免在测量工具尚未校准时就拿到一张无法解释的排名表。
每换一个模型、量化格式或驱动版本,都应新建一次运行编号;不同运行编号的结果可比较,但不能合并求一个平均值。若结果异常,先复现原条件,再一次只改变一个变量。比如怀疑上下文长度导致内存上涨,就保持模型、并发和功率模式不变,仅改变输入长度;否则即使指标改善,也不知道是哪项变化带来的。
先说清测量层,再选择工具
llama-bench 回答内核问题,不代替产品端打点
llama.cpp 的官方 llama-bench 把 prompt processing、text generation 和二者组合分开测试,可以固定模型并多次重复,输出 JSON 等格式。这适合比较同一环境中输入处理与生成阶段的变化。官方 README 同时说明,其测量不包括分词和采样耗时。因此把 llama-bench 的 prompt processing 结果直接标成“用户端 TTFT”,或者把生成速度直接当成整机应用吞吐,都会扩大工具结果的含义。llama-bench 官方说明
一次可复核的内核对照,至少要保存命令参数、标准输出、模型 hash、二进制构建版本、系统状态与重复结果。提示长度和生成长度要覆盖目标业务,而非只运行默认项。若两种配置的差异小于重复结果的波动,就不能宣布赢家;应检查频率、后台任务与热状态后再测。工具能帮助定位是输入处理还是生成阶段变慢,却无法单独定位网络、检索或 UI 层的延迟。
服务端与用户端要保留各自的时钟
若产品通过 llama-server 提供接口,就在相同请求集上再测服务端。官方 speed-bench 主要用于比较推测解码配置;其输出还会记录完成与失败样本、请求延迟,以及来自服务端的 prompt 和 predicted tokens/s,可连同配置保存为 JSON。借用它观察服务端变化可以,但不能把它叫作边缘设备通用基准,更不能替代 UI 或客户端计时。llama.cpp SPEED-Bench 说明
最外层再从实际客户端记录发送请求、收到首个非空内容 token、收到末 token 的单调时钟时间戳;有屏幕时另记首字渲染完成,并保留错误和中止事件。这样内核快而用户慢时,才能继续查检索、请求排队、网络与前端渲染。若产品是完全离线的本地 UI,就以本地 UI 的真实路径打点,不必为了套用 HTTP 工具额外加入一个服务层。不同层的数值可以帮助定位,但不能互相替代或合并成一个不注明来源的 TTFT。
内存峰值、热衰减和功率要在整机上看
模型文件大小不等于运行峰值内存。模型权重之外,还可能有 KV cache、运行时工作区、操作系统和并发会话占用。记录进程 RSS 的同时,也要记录整机可用内存、交换或 OOM 事件,以及显示、摄像或采集任务的占用。对于内存映射和共享页,单进程 RSS 不是整机实际独占成本;若用它比较两个运行配置,至少确保采集方法一致,并用系统级可用内存和失败记录交叉检查。
短跑适合发现能否启动,不适合推断全天运行。持续负载可按目标产品的工作周期设计;题库建议至少留出 30 分钟观察窗口,但这里的 30 分钟是待执行的测试计划,不是本文已经完成的实验,也不是任何设备的合格线。应在机壳闭合、目标环境和并行任务开启的条件下,连续记录频率、温度、TTFT、TPOT、失败率与内存。若开始五分钟正常,随后温度上升、频率下降、首字等待变长,采购表上那次冷机 tokens/s 就不能代表持续服务。
功率也要注明测量边界。芯片 TDP、外部适配器标称功率与插座侧整机实测不是同一个数。若产品由电池供电,应记录实际电源链路与采样频率;若要比整机能耗,则两设备应采用相同的工作负载与测量点。MLCommons Edge 的结果页把实测系统功率与 TDP 等额定值分开,并说明功率只对所伴随的基准工作负载有效。该原则同样适用于内部验收:不要把空闲瓦数嫁接到满载 tokens/s 上。MLCommons Edge 基准说明

哪些结果不能拿来做采购结论
没有目标设备、目标机壳和指定模型时,本文的方法可以帮助团队准备验收,却不能告诉你哪块板卡更快。只拿开放开发板的冷机结果,也不足以预测密闭机壳里的长期功耗和热衰减。若模型或量化格式尚未冻结,先确认运行时支持与回答质量,再比较性能;否则两种配置即使有相同的 tokens/s,也可能给出不同质量的答案。
对带检索的设备助手,还要保留纯模型与完整 RAG 链路两组结果。纯模型测试适合定位推理瓶颈;完整链路测试才包含文档搜索、权限过滤和提示组装。若只做前一组,不应把其 TTFT 写进用户体验承诺。产品现场若存在弱网、摄像并发或电池老化等额外条件,也必须在交付验收中另行覆盖,不能让实验室基线替代现场证据。
把测试结果写成能复核的验收记录
交给采购或产品团队的不是一列最高速度,而是一张带条件和原始数据位置的记录。每个请求组至少保留成功数、超时与错误数、TTFT 分布、后续生成速度或 TPOT 分布、完整耗时、峰值内存,以及测试开始和结束时的热状态。若团队关注尾部等待,给出分位数时也要写样本量;少量请求算出的 p95 不应包装成稳定服务指标。原始日志与聚合表同时保存,复核者才能排查极端值是偶发排队、模型冷装载还是测量故障。
逐请求记录可用下面的空白字段作为起点。request_sent_ms、first_content_ms 和 last_content_ms 必须来自同一客户端单调时钟;first_visible_ms 只在真实 UI 渲染回调中填写。客户端 TTFT 是前两者的差,完整耗时是首尾之差。TPOT 若按“相邻两个内容 token 的平均到达间隔”计算,应使用首个与末个内容 token 的时差除以后续 token 间隔数;实际 token 数少于两个时记为不可计算,不能填零。若网络把多个 token 合并成一次事件,客户端观察到的是事件间隔而非模型逐 token 间隔,应标明聚合口径,不能伪称模型 TPOT。
持续负载还要有一份与 run_id 关联的时序文件,每行至少包含采样时间、整机瓦数、温度与频率。测试前写明功率测点和采样周期,并事先定义用哪段窗口判断热稳态;不能测完后只挑表现最好的一段。若外部功率计和客户端不共用单调时钟,先记录同步标记及时间偏移,才能把请求组与功率、温度曲线对齐。下面的空白模板同时列出 run 级元数据和逐请求字段;时序原始值存入指定文件,不用起止温度代替曲线。
run_id: # 关联模型 hash、量化、运行时版本、机壳、供电和提示集版本
test_start_utc:
telemetry_path: # 每行记录 elapsed_ms、system_power_w、temperature_c、frequency_mhz
telemetry_sample_interval_ms:
telemetry_clock_alignment: # 与客户端单调时钟的同步标记/偏移
system_power_source: # 插座侧/电池侧/板上计数器,注明实际测点
steady_window_start_elapsed_ms: # 测试前约定稳态判断规则与窗口
steady_window_end_elapsed_ms:
steady_window_rule:
request_id:
group: # A/B/C/D/E
input_tokens:
output_tokens:
request_sent_ms:
first_content_ms:
first_visible_ms: # 无屏幕则留空
last_content_ms:
status: # success / timeout / error / cancelled
error_code:
peak_process_rss_bytes:
system_available_min_bytes:
temperature_start_c:
temperature_end_c:
raw_log_path:
失败率的分母是实际发出的全部请求,包括超时、错误和取消;若取消由用户主动触发,应与系统失败单列,不能悄悄从样本中删掉。聚合时按 A–E 分组报告样本数和分位数,别把冷启动与热启动混成一条均值。更换量化格式时还要让同一业务提示集接受答案质量检查:容量与速度改善若伴随关键事实遗漏,就不能仅凭性能指标判为更优。
验收阈值应从产品任务来:维修人员在设备旁边查询手册,首字等待多长仍可接受?设备同时运行图像采集时允许多少失败?机壳内持续工作的最高温度和功率由谁批准?先约定这些条件,再根据同一提示集测试设备。若只在基准工具层测得一个漂亮的生成速度,而用户端 TTFT、并发超时或长时间功率尚未验收,结论应是“内核性能已测,产品体验未验”,而不是“设备已达到目标”。
结果不达标时也应给出排查顺序。TTFT 高而后续生成稳定,先查冷装载、检索、排队、输入长度和 prefill;首字快而 TPOT 逐渐变慢,查内存争用、热降频和上下文增长;只有并发时异常,查会话缓存、批处理与队列;内存不足或 OOM 时,先核对权重、KV cache 和其他常驻任务,再决定缩短上下文、换量化或更换设备。这些是定位假设,不是没有日志也能断言的根因。每次改动只改变一个主要变量,重跑原请求集,确认问题是否真的消失。
如果现在只能拿到公开规格,先用边缘大模型硬件选型顺序筛出候选,再按本文建立测试协议;运行时格式和后端不确定时,可参考边缘大模型运行时选择。真正的设备结论必须等指定模型和整机负载在目标硬件上留下原始记录。本文只给方法,不提供任何设备的实测排名。