Imported from zhuzhichaoTM/hello_inference_engine (
benches/ana/skills/llm-backend-adaptation/SKILL.md). Install upstream withnpx skills add zhuzhichaoTM/hello_inference_engine --skill llm-backend-adaptation. Copyright stays with the author.
模型选型、部署规划与后端适配
这个技能的核心判断
选型与适配失败的典型形态不是「跑不起来」,而是跑到一半才发现不行:
- 权重装得下,但长上下文时 KV Cache 把显存挤爆
- 换了硬件后性能掉一半,但说不清是硬件差异还是配置没适配
- 把 GPU 的调优经验直接搬到 CPU 上,得出方向相反的结论
共同根因是:没有先算再测。本技能把这三件事变成算术问题:
① 装得下吗? 权重 + KV Cache + 运行时缓冲 ≤ 可用内存 − 安全冗余
② 够快吗? 理论 t/s 上界 = 带宽 ÷ 每步搬运字节数
③ 换后端要改什么? 后端差异只有四件事(加速标志/内存读取/探针/回退代价)
七步在本技能下的形态
| 步 | 本流程下做什么 | 与其他流程的差异 |
|---|---|---|
| 0 | 采集目标设备画像(不是开发机) | 重点:标称带宽、内存容量与配额、加速器能力 |
| 1 | 资源预算 + 可行性结论 + 选型矩阵 | KPI 是「可行性 = 是/否 + 安全冗余」,不是速度 |
| 2 | 在目标设备上建立基线 | 必须真机;不同后端数据不可比 |
| 3 | 后端对比矩阵 | 剖面维度按后端变(见 hardware-backends) |
| 4 | 适配方案(编译标志/量化档位/上下文上限/线程或槽位) | 方案以「能不能跑」优先,其次才是「快不快」 |
| 5 | 跨后端验证 | 只比同后端的数字,跨后端比的是「哪个更优」 |
| 6 | 沉淀设备画像与后端注意事项 | 这份画像可被后续所有流程复用 |
判断一:装得下吗
顺序不能反 —— 装不下的话,速度优化毫无意义。
权重(量化后)
+ KV Cache(随上下文线性增长,是唯一会变的部分)
+ 运行时缓冲(激活 / 临时张量 / 运行时上下文)
≤ 可用内存 − 安全冗余
KV Cache 是最容易算错的一项:
KV 字节 = 层数 × ctx × KV heads × head_dim × 2(K,V) × 每元素字节数
三个陷阱:
- 用「总上下文」还是「单槽上下文」 —— 多槽位时 KV 要乘以槽位数 (或总上下文不变、单槽减半)
- KV 量化档位 —— K 与 V 可以不同精度。实践中 K 保高精度 (Key 决定检索精度)、V 可压得更狠
- 反推的架构超参 ——
n_head_kv与head_dim若为反推值, 算出的 KV 可能差数倍。用模型文件元数据核验(见下)
必须核验架构超参
python3 -m perfkit define --config configs/<project> --run check \
--from-gguf /path/to/model.gguf
这条命令读模型文件头部(毫秒级,不加载权重),把「反推值」换成真值, 并逐字段列出差异。
为什么这件事不能省:整个性能模型建立在架构超参之上。
n_head_kv 填错,KV 预算、长上下文可行性、KV 量化收益全都错。
实践中出现过「模型算 KV 6.5 GiB、实测 2.2 GiB」的 2.95 倍差额 ——
根因就是反推值不准。
安全冗余按后端定,不套用统一值
| 后端 | 典型要求 | 理由 |
|---|---|---|
| 服务器 GPU | 4 GiB 或更多 | 抗并发峰值 + 长 prompt |
| CPU / 统一内存 | 1~2 GiB | 与主机其他进程共享,需要余量 |
| 移动 SoC | 0.5 GiB(按 App 配额比例) | 系统会强杀超配额进程 |
判断二:够快吗
Decode 理论上界 (t/s) = 标称带宽 (GB/s) ÷ 每步搬运字节数 (GB)
注意用标称带宽而不是实测带宽 —— 两者用途不同:
- 标称值 → 算上界(分母)
- 实测值 → 算达成率(达成率低说明还有空间)
如果实测已达上界 80% 以上,说明触及物理天花板, 此时唯一出路是减少每步搬运的字节数(量化 / 投机解码), 而不是提升算力利用率。
判断三:换后端要改什么
后端差异只有四件事。把这四件事抽象出来之后,流程代码零改动:
| 差异点 | GPU | CPU |
|---|---|---|
| 加速标志 | -ngl 99 |
-ngl 0(必须显式钉死) |
| 内存怎么读 | nvidia-smi |
进程 RSS + 系统内存统计 |
| 带宽探针 | 纯读带宽探针 | mmap 真实文件 + 量化矩阵-向量乘 |
| 回退代价 | 昂贵(跨总线) | 不存在回退 |
为什么 CPU 必须显式写 -ngl 0:这不是默认值,而是必须钉死。
开发机若装了 GPU 后端,不写 -ngl 0 时会静默走 GPU ——
与「验证 CPU 可用性」的目标直接相悖,而且不报错。
为什么回退代价会改变结论:CPU 后端的「零回退」不是约束 (根本不存在回退);报告里「跨设备回退代价」一节应从 「跨总线往返吃掉 77% 预算」改为「同步开销仅占 0.9%」。
细节与具体案例见 llm-perf-optimization/references/hardware-backends.md。
后端对比矩阵
对比多个后端时,做成一张表,只比同口径的数字:
| 后端 | 模型 | 量化 | 上下文 | Decode (t/s) | Prefill (t/s) | 峰值内存 | 可行 |
|---|---|---|---|---|---|---|---|
| GPU 24GB | 27B | Q4_K_M | 64K | 47.94 | 85.49 | 18.6 GiB | ✅ |
| CPU x86 | 1.5B | Q4_K_M | 8K | 7.89 | 11.48 | 1.93 GiB | ✅ |
表中只放已实际跑过闭环的后端。没有实测数据时留空并标注「待采集」, 不要用其它设备的经验值填充 —— 不同后端的数字不可移植。
三个要点:
- 同口径 —— 上下文深度、量化档位、生成长度必须一致
- 标注不可比项 —— 若某后端的测量深度不同,显式标注而不是直接排序
- 给结论而非只给表 —— 表是数据,结论是「哪个后端适合哪类负载」
常见错误
| 错误 | 后果 | 修复 |
|---|---|---|
| 只算权重体积 | 长上下文时 KV 挤爆显存 | 按最大上下文算完整预算 |
| 用实测带宽算上界 | 上界偏低,误判「已达天花板」 | 上界用标称值 |
| 把 GPU 模板套到 CPU | 得出方向相反的结论 | 走后端抽象层 |
| 在开发机上测目标设备的性能 | 数据完全不可用 | 必须真机 |
| 换后端时不重新建基线 | 前后对比混入硬件差异 | 每个后端独立基线 |
| 不核验反推的架构超参 | KV 预算可能差数倍 | 读模型元数据核验 |
与其他技能的关系
- 方法论底座:
seven-step-closure - 性能优化(适配完成后的下一步):
llm-perf-optimization - 质量验收(选型后要验证质量):
llm-quality-eval - 内存专项:
llm-memory-cache
判据总结
给出「在 X 设备上、Y 上下文、Z 量化档位下:
- 可行性:是 / 否
- 安全冗余:N GiB
- 理论速度上界:M t/s
- 适配清单:需要改哪几个参数(加速标志 / 线程或槽位 / 量化档位 / 上下文上限)
- 已知风险:该后端特有的坑(如 CPU 的负载敏感性、端侧的热降频)」
