Formatos de archivo de modelos
Un lanzamiento de modelo no es un archivo — es un checkpoint que se
reempaqueta por motor. Esta página mapea los formatos que realmente te
encontrarás en local: GGUF para el mundo llama.cpp, safetensors para la
pila PyTorch/HF, cuantizaciones GPU nativas del motor y ONNX para
tiempos de ejecución de borde. Elige primero el motor; el formato sigue.
GGUF: un archivo, todo dentro
Un archivo .gguf empaca los pesos del modelo, el vocabulario del
tokenizador, la plantilla de chat y metadatos por tensor en un solo
binario. Una descarga, configuración cero, y toda app que hable GGUF
corre el mismo archivo: llama.cpp y llama-server, Ollama, LM Studio, Jan,
KoboldCpp. El formato es mapeable en memoria, así que los pesos fluyen
del disco página a página — el arranque es rápido y la caché de páginas
del sistema operativo hace el almacenamiento en caché gratis.
Anatomía del nombre de archivo, campo por campo, paraQwen3-8B-Q4_K_M.gguf:
| Campo | Valor | Significado |
|---|---|---|
Qwen3 |
familia + generación | la arquitectura que construye el motor; también la generación de calidad |
8B |
clase de tamaño | ~8 mil millones de parámetros — el número del que depende tu presupuesto de VRAM |
Q4_K_M |
etiqueta de cuantización | ~4.8 bits por peso, mezcla K-quant «media» — véase cuantización |
.gguf |
contenedor | pesos + tokenizador + plantilla de chat + metadatos, un archivo |
Inspecciona cualquier GGUF sin cargarlo:
python gguf-py/gguf/scripts/gguf_dump.py model.gguf
general.architecture : qwen3
general.name : Qwen3 8B
qwen3.context_length : 32768
tokenizer.ggml.model : gpt2 (BPE)
tokenizer.chat_template : {%- ... a Jinja template ... %}
Ese bloque de metadatos es la razón de que un GGUF «simplemente funcione»
en cinco apps distintas: el motor lee la arquitectura, construye el grafo,
carga el tokenizador, y los frontales de chat aplican la plantilla
incrustada. Sin cazar configuración, sin desajuste de vocabulario, sin
descarga aparte del tokenizador.
Safetensors: el nativo de Hugging Face
Safetensors es un contenedor deliberadamente aburrido: una cabecera JSON
de nombres de tensores, formas y dtypes seguida de bytes crudos.
Almacena solo tensores — sin código ejecutable, a diferencia de los
checkpoints .bin con sabor a pickle que no son seguros de cargar a
ciegas — y soporta mmap de copia cero, razón por la que el arranque de
PyTorch es rápido. Transformers, vLLM, SGLang, TRL y todo el ecosistema
de ajuste fino lo hablan de forma nativa.
Como almacena solo tensores, un modelo funcional es el directorio
completo del repo:
model-00001-of-00004.safetensors ← fragmentos de pesos (~5 GB cada uno)
model-00002-of-00004.safetensors
model-00003-of-00004.safetensors
model-00004-of-00004.safetensors
model.safetensors.index.json ← mapa de fragmentos: nombre de tensor → archivo
config.json ← arquitectura + hiperparámetros
generation_config.json ← ajustes de muestreo por omisión
tokenizer.json ← el tokenizador en sí
tokenizer_config.json ← la plantilla de chat vive aquí
El fragmentado existe porque un checkpoint 70B FP16 son ~140 GB — un solo
archivo sería inmanejable. Si sirves con vLLM descargas todos los
fragmentos; no hay atajo de «solo el archivo de 4 bits» dentro de un
lanzamiento safetensors. El servicio cuantizado es un repo aparte (una
variante AWQ o GPTQ del mismo modelo).
Cuantizaciones GPU nativas del motor: AWQ, GPTQ, EXL2
Estos formatos existen para servidores de inferencia en GPU, donde el
rendimiento importa más que la conveniencia del archivo:
- AWQ — cuantización consciente de activaciones. Prompts de
calibración encuentran el ~1% de canales de pesos del que más dependen
las activaciones; esos reciben escalado protegido, todo lo demás pasa a
4 bits. Calidad casi original a 4 bits con kernels rápidos; la elección
de 4 bits por omisión en vLLM. - GPTQ — la cuantización GPU clásica, descendiente de la cuantización
de cerebro óptimo: cuantiza capa por capa, compensando el error de cada
capa contra los pesos aún no cuantizados. 4 bits, kernels solo GPU,
sigue presente en todas las configuraciones de servicio. - EXL2 — el formato de exllamav2 con bits variables por peso. Un
repo puede quedarse en, digamos, 4.65 bpw mezclando tensores de 2–8
bits para que el total caiga justo bajo tu tope de VRAM. La herramienta
para cuando Q4 no cabe pero Q3 dolería.
Los tres requieren datos de calibración y una conversión única, y ninguno
corre en CPU.
ONNX, MLX, FP16/BF16 crudos
ONNX es el formato portátil de grafos de cómputo: exporta un modelo
de transformers una vez y córrelo donde corra onnxruntime — cajas Windows
sin CUDA, teléfonos, demos WebGPU en el navegador. onnxruntime también
puede cuantizar el grafo a INT8 para CPU. Pagas fricción de configuración
y a menudo velocidad punta; ganas portabilidad a máquinas sin pila
PyTorch. El borde y lo embebido son su terreno, no el chat de escritorio.
MLX es el framework de arrays de Apple para Apple Silicon; la
organización mlx-community reempaqueta la mayoría de los lanzamientos
mayores a formato MLX, 4 y 8 bits incluidos. En una Mac serie M corriendo
mlx-lm, ese es tu formato — véase Apple Silicon.
Los checkpoints FP16/BF16 crudos importan cuando quieres una
referencia sin pérdida, una base de ajuste fino o una fuente de
conversión. BF16 conserva el rango de exponente de 8 bits de FP32 y
troca bits de mantisa por ello — mucho más estable para entrenar que
FP16, a los mismos 2 bytes por peso. Un modelo de 7–8B en FP16/BF16 son
~16 GB de pesos solos, antes de cualquier contexto.
Qué formato para qué motor
| Motor / pila | Formato que consume | Notas |
|---|---|---|
| llama.cpp, Ollama, LM Studio, Jan | GGUF | un archivo; CPU + GPU; toda familia de cuantización |
| vLLM, TGI, SGLang | safetensors, AWQ, GPTQ | rendimiento de servidor; GPU |
| exllamav2 / TabbyAPI | EXL2, GPTQ | bpw variable; GPU |
| transformers / PyTorch | safetensors | entrenamiento, ajuste fino, investigación |
| onnxruntime | ONNX | borde, móvil, navegador |
| mlx-lm | MLX | Apple Silicon |
Mezclar formatos es el error clásico de principiante: apuntar vLLM a un.gguf, o llama.cpp a fragmentos safetensors. Ninguno funciona — el
motor da error o necesita un paso de conversión primero.
Rutas de conversión
La ruta estándar de un repo de Hugging Face a un archivo local son dos
pasos — convierte el checkpoint a un GGUF de 16 bits, luego cuantiza
hacia abajo:
git clone https://github.com/ggerganov/llama.cpp
pip install -r llama.cpp/requirements.txt
# 1. convierte el checkpoint de HF (safetensors) a GGUF
python llama.cpp/convert_hf_to_gguf.py ./Qwen3-8B --outtype bf16 --outfile qwen3-8b-bf16.gguf
# 2. cuantiza al tamaño objetivo
llama-quantize qwen3-8b-bf16.gguf qwen3-8b-Q4_K_M.gguf Q4_K_M
En la práctica rara vez conviertes tú mismo: cuantizadores como bartowski
y mradermacher publican todos los tamaños de cada lanzamiento notable en
cuestión de horas. Convierte por tu cuenta cuando tienes un ajuste fino
privado, quieres una I-quant calibrada con imatrix o necesitas un
objetivo de bits poco habitual — detalles en cuantización.
Los modelos de embedding — la mitad de recuperación de RAG
— se distribuyen en los mismos formatos: GGUF para el endpoint de
embeddings de llama.cpp, safetensors para sentence-transformers. La misma
regla que todo lo anterior: empareja el formato con el motor que de
verdad vas a correr.
Relacionados: Cuantización · Familias de modelos · Motores · RAG