乐于分享
好东西不私藏

从“源码”到“机器码”:一文看懂 AI 模型的格式战争

从“源码”到“机器码”:一文看懂 AI 模型的格式战争
如果你用过 Ollama 拉取模型,或者在 HuggingFace 上下载过几个 GB 的文件,你一定见过这些后缀:.gguf.safetensors.onnx.engine……

它们到底是什么?为什么一个模型要搞出这么多格式?为什么有的能直接双击跑,有的只能在机房里发光发热?

这篇文章用大家更为熟悉的编程知识,把这件事一次讲清楚。

AI模型与程序编程对照

AI 模型格式的差异,本质上和"软件分发格式"的差异是一回事。

开发人员写了一段 C++ 代码,最终用户拿到手的是 .exe 还是 .deb 还是 Docker 镜像,取决于它要跑在哪、谁来跑、跑多快。AI 模型也一样——不同的格式,对应不同的"编译阶段"和"运行环境"

理解了这一点,后面所有格式都能对号入座。

第一站:模型的"源码"——Safetensors

训练一个 AI 模型,本质上是在做一件事:用海量数据调整几百亿个浮点数(权重)。训练完之后,这些数字需要存下来。

最早期的 PyTorch 用的是 .bin 文件——本质上就是 Python pickle 序列化。它有个致命的问题:能执行任意代码。如果不小心下载到一个“加料”的模型,加载的瞬间,电脑就可能被种上木马。这不是危言耸听,HuggingFace 上确实出现过恶意模型。

于是 HuggingFace 推出了 Safetensors.safetensors)。它只做一件事:安全地存张量数据——权重叫什么名字、什么形状、什么数据类型、裸字节在哪。不执行任何代码,不支持任何计算逻辑。

类比一下:

AI 模型世界
传统软件世界
Safetensors
.cpp
 源文件(或 .o 目标文件)
包含内容
纯数据,无逻辑
谁用
开发者、训练框架
能不能直接给用户跑
不能,需要"编译"

Safetensors 是今天整个开源 AI 生态的通用语。训练用它、微调用它、HuggingFace 上 90% 的模型仓库底层都是它。它是"起点",但不一定是终点

第二站:给普通人的"可执行文件"——GGUF

Safetensors 的问题是:它太"裸"了。要加载它,需要配套的 config.json(告诉框架模型长什么样)、tokenizer.json(告诉框架怎么切词)、可能还有 quantize_config.json(量化参数)……一堆文件,少一个都跑不起来。

这对开发者没问题,对普通用户就是灾难。

于是 llama.cpp 项目创造了 GGUF.gguf)格式。它干了一件很聪明的事:把所有东西——权重、分词器、架构参数、聊天模板、量化信息——全部打包进一个二进制文件

这就像你用 gcc -static 编了一个静态链接的单文件可执行程序:拷到任何同架构机器上,不需要装任何依赖,直接 ./program 就能跑。

GGUF
静态编译的二进制
一个文件包含所有依赖
一个 ELF 包含所有库
支持 mmap 零拷贝加载
操作系统页缓存
原生支持 CPU/Apple Silicon
跨 Linux/macOS
内建多种量化方案
内置压缩段

Ollama、LM Studio、手机上的 AI 助手——底层全都是 GGUF。你下载一个 4GB 的文件,双击就能跟它聊天,背后就是这个格式在撑。

GGUF 是"端侧推理"这条路线的最终产物。

第三站:给显卡"超频"的量化——GPTQ 与 AWQ

前面说的 Safetensors 存的是 FP16 精度(每个数字 2 字节)。一个 70B 参数的模型,光权重就 140GB——你就算有张 80GB 的 A100 也塞不下。

解决办法是量化:把 2 字节的数字压缩成 1 字节甚至 0.5 字节,精度略有损失,但体积和显存占用直接砍半甚至砍到 1/4。

GPTQ 和 AWQ 就是两种最主流的量化算法。它们不改变容器格式——底层仍然是 Safetensors 文件,只是里面的权重数据经过了不同的压缩算法处理,再配一个 quantize_config.json 告诉加载器"怎么解压"。

类比一个 Zip 压缩文件,一个用 DEFLATE 压缩,一个用 LZMA 压缩。容器一样,算法不同,解压方式不同,压缩率和速度也不同。

但值得注意的是,GPTQ 和 AWQ 的加速内核几乎都只针对 NVIDIA CUDA 优化,适用性和指向性天然受限。如果在 AMD 卡或 Intel 显卡上跑,要么慢如龟爬,要么直接不支持。

第四站:模型的"LLVM IR"——ONNX

现在进入最有意思的部分。

Safetensors 是数据容器,GGUF 是打包好的二进制,GPTQ/AWQ 是压缩版 Safetensors。但如果你是一个硬件厂商——比如想在自己的 NPU 上跑 AI 模型——你面临的挑战是:

我怎么让一个用 PyTorch 写的模型,在我完全自定义的芯片上跑起来?

答案是:中间表示(IR)

ONNX(Open Neural Network Exchange)就是 AI 模型界的 LLVM IR。它定义了一套与框架无关、与硬件无关的计算图表示。PyTorch 模型可以导出成 ONNX,然后各硬件厂商提供自己的编译器,把 ONNX 编译成自家芯片能执行的机器码,生成针对特定硬件深度优化绑定的AI模型。

Safetensors(权重数据)       ↓ 导出ONNX(计算图,无硬件信息)       ↓ 各厂商工具链编译  ┌────┼────────┬──────────┐  ▼    ▼        ▼          ▼.engine  .mlpackage  .xml+.bin   直接 ORT 执行(NVIDIA) (Apple)     (Intel)     (跨平台兜底)
ONNX 生态
传统编译工具链
ONNX 模型
LLVM IR / 汇编
TensorRT / CoreML / OpenVINO
各平台后端编译器
.engine / .mlpackage
机器码
ONNX Runtime
多后端调度器(像 clang 驱动)

普通用户不需要碰 ONNX——你用的是厂商已经编译好的最终产物。但如果你是平台方(AIDC运营、算力租赁等等),要把模型部署到成百上千张特定型号的卡上,ONNX + 厂商工具链就是标准工作流。

这也是为什么很少在个人电脑上看到 ONNX 文件——它就不是给终端用户准备的,它是给"发行版维护者"准备的中间产物。

第五站:厂商级部署——从"编译"到"上线"

到了这一层,格式已经不是最重要的了。TensorRT 编出来的 .engine 文件、CoreML 的 .mlpackage,本质上就是绑定了特定硬件型号的专有模型——换一张不同架构的卡,就得重新编译。

厂商要做的"缝合打包",类比 Linux 世界是这样的:

AI 部署栈
Linux 系统栈
Safetensors
源码包 (.tar.gz + makefile)
ONNX
中间 RPM/DEB 包(跨发行版)
TensorRT .engine
针对特定 CPU 微架构编的二进制包
Triton / BentoML
systemd + nginx(进程管理 + 流量入口)
厂商自研网关/调度
公司内部的 K8s + 业务 sidecar

厂商自己实现的不是计算引擎(那是 NVIDIA/Apple/Intel 的事),而是:

  • • 上层 API 网关(鉴权、限流、计费)
  • • Tokenizer 和前后处理逻辑
  • • 多模型路由和动态批处理策略
  • • 自定义算子插件(遇到新 op 不支持时写个 CUDA Plugin)

全景一张图

┌─────────────────────────────────────────────────────────┐│                   训练完成 (PyTorch)                      │└─────────────────────────┬───────────────────────────────┘                          ▼                 Safetensors(通用权重)                          │          ┌───────────────┼───────────────────┐          ▼               ▼                   ▼    直接加载跑        量化后加载跑          编译部署   (vLLM/SGLang)     (GPTQ/AWQ)          (ONNX 路线)          │               │                   │          │               │          ┌────────┼────────┐          │               │          ▼        ▼        ▼          │               │      TensorRT   CoreML   OpenVINO          │               │      (NVIDIA)   (Apple)  (Intel)          │               │          │        │        │          ▼               ▼          ▼        ▼        ▼     服务端推理         N卡量化    深度绑定硬件的专有模型     (数据中心)        推理        (终端用户/平台部署)          │          ▼     转 GGUF     (llama.cpp/Ollama)          │          ▼     端侧推理(笔记本/手机/CPU)

为什么你需要知道这些?

不是为了让你去手动转换格式——工具链会帮你做。而是为了当你下次看到:

  • • HuggingFace 上同一个模型有 5 个版本(FP16、Q4、AWQ、GPTQ、GGUF)
  • • 某个模型"只支持 NVIDIA"
  • • 某篇新闻说"XX 厂用 TensorRT 优化后吞吐量翻了 3 倍"

你能立刻反应过来:这不是魔法,这是编译链路不同阶段的产物,是"源码→中间表示→机器码"这条老路在 AI 时代的新演绎。

软件工程的很多智慧,在 AI 时代并没有失效——只是换了个战场。