¿Alguna vez has intentado correr un modelo de lenguaje de última generación y te has dado de bruces contra un error de «Out of Memory» o una lentitud desesperante? Si quieres ejecutar modelos como LLaMA, Mistral o Phi en tu portátil, en un servidor sin GPU o incluso en una Raspberry Pi, necesitas entender el motor que hace que la magia ocurra: llama.cpp.
llama.cpp es el motor de inferencia de LLMs escrito en C/C++ que lo hace posible. Es la pieza de bajo nivel sobre la que se construyen herramientas populares como Ollama o LM Studio; si entiendes cómo funciona llama.cpp, entiendes realmente qué ocurre bajo el capó de la IA local.
Esta guía es práctica y dedicada: vamos a ver desde la compilación por backend y el formato GGUF, hasta el uso real del CLI, el servidor y cómo medir el rendimiento para exprimir tu hardware. Si antes de empezar quieres ver cómo encaja esto en el panorama general, te recomiendo revisar primero Ecosistema de Modelos Locales.
¿Por qué compilar en lugar de usar Ollama?
Con llama.cpp tienes control total: eliges flags de compilación, backend de GPU, tipo de cuantización y parámetros de inferencia. Es la opción para producción en hardware limitado, edge devices y cuando necesitas exprimir cada token/segundo.
🧩 Arquitectura en un vistazo
Para dominar la herramienta, primero debemos entender el flujo de trabajo. No pasamos directamente de un modelo de PyTorch a la inferencia; hay un proceso de transformación y optimización de por medio.

El núcleo es ggml, la librería de tensores. Los modelos se distribuyen en GGUF, un formato de fichero único que incluye pesos, tokenizer y metadatos.
📦 Obtener el código
Empecemos por lo básico: bajar el código fuente para poder construirlo a nuestra medida.
git clone https://github.com/ggml-org/llama.cpp
cd llama.cpp
El repositorio se movió
El proyecto vive ahora en ggml-org/llama.cpp (antes ggerganov/llama.cpp). El make manual está deprecado: la vía oficial es CMake.
🔨 Compilación por backend
Aquí es donde ocurre la magia. Dependiendo de tu hardware, querrás que llama.cpp hable un «idioma» específico para aprovechar cada ciclo de reloj.
CPU (por defecto)
Si no tienes una GPU potente, no te preocupes. llama.cpp está increíblemente optimizado para procesadores.
# Configuración y build en Release (optimizado)
cmake -B build
cmake --build build --config Release -j $(nproc)
# Los binarios quedan en build/bin/
ls build/bin/
# llama-cli llama-server llama-quantize llama-bench ...
En CPU, llama.cpp usa automáticamente las instrucciones SIMD disponibles (AVX2, AVX-512, NEON en ARM). Para forzar optimización nativa del host y sacarle el máximo jugo:
cmake -B build -DCMAKE_C_FLAGS="-march=native" -DCMAKE_CXX_FLAGS="-march=native"
cmake --build build --config Release -j $(nproc)
CUDA (NVIDIA)
Si tienes una tarjeta NVIDIA, este es tu camino. Es la forma más común de obtener velocidades de vértigo.
# Requiere el CUDA Toolkit instalado (nvcc en el PATH)
cmake -B build -DGGML_CUDA=ON
cmake --build build --config Release -j $(nproc)
Compilación más rápida y binario más ligero
Limita las arquitecturas de GPU a la tuya con -DCMAKE_CUDA_ARCHITECTURES=86 (86 = Ampere/RTX 30xx, 89 = Ada/RTX 40xx, 90 = Hopper). Reduce mucho el tiempo de build.
Metal (Apple Silicon)
Si eres usuario de Mac con chips M1, M2, M3 o M4, tienes una ventaja competitiva gracias a la memoria unificada.
# En macOS con chips M1/M2/M3/M4, Metal se activa por defecto.
cmake -B build
cmake --build build --config Release -j $(sysctl -n hw.ncpu)
Metal aprovecha la memoria unificada del Apple Silicon, así que puedes cargar modelos grandes sin GPU dedicada. Para forzarlo explícitamente: -DGGML_METAL=ON.
Vulkan (GPU multiplataforma: AMD, Intel, NVIDIA)
¿Tienes una gráfica AMD o una Intel Arc? Vulkan es tu mejor aliado para evitar complicaciones con drivers específicos.
# Requiere el Vulkan SDK (headers y glslc)
cmake -B build -DGGML_VULKAN=ON
cmake --build build --config Release -j $(nproc)
Vulkan es la mejor opción para GPUs AMD/Intel sin depender de ROCm, y funciona en Windows, Linux y ChromeOS.
| Backend | Flag CMake | Hardware objetivo |
|---|---|---|
| CPU | (por defecto) | Cualquier x86_64 / ARM |
| CUDA | -DGGML_CUDA=ON |
GPUs NVIDIA |
| Metal | -DGGML_METAL=ON |
Apple Silicon (M1+) |
| Vulkan | -DGGML_VULKAN=ON |
AMD / Intel / NVIDIA |
| HIP/ROCm | -DGGML_HIP=ON |
GPUs AMD (ROCm) |
| SYCL | -DGGML_SYCL=ON |
Intel GPU / oneAPI |
🗜️ GGUF y cuantización
Entremos en terreno de optimización. GGUF (GPT-Generated Unified Format) es el formato de modelo de llama.cpp. La cuantización reduce la precisión de los pesos (de 16 bits a 4-8 bits) para bajar el uso de RAM/VRAM y acelerar la inferencia, a cambio de una pérdida controlada de calidad. Es lo que permite que un modelo gigante quepa en tu portátil.
Descargar un modelo ya en GGUF
La forma más rápida de empezar es descargar un modelo que alguien ya haya cuantizado. llama-cli y llama-server aceptan el flag -hf para tirar directamente de Hugging Face:
# Descarga automática desde Hugging Face (repo:quant)
./build/bin/llama-cli -hf ggml-org/gemma-3-1b-it-GGUF
Convertir y cuantizar tú mismo
Si tienes un modelo en formato estándar de Hugging Face y quieres convertirlo, sigue estos pasos:
# 1. Convertir el modelo Hugging Face a GGUF en F16
python convert_hf_to_gguf.py ./models/mi-modelo --outfile modelo-f16.gguf --outtype f16
# 2. Cuantizar a Q4_K_M (el mejor equilibrio calidad/tamaño)
./build/bin/llama-quantize modelo-f16.gguf modelo-q4_k_m.gguf Q4_K_M
Tipos de cuantización habituales
¿Cuál elegir? Aquí tienes una tabla para orientarte:
| Tipo | Bits aprox. | Uso de RAM | Calidad | Recomendación |
|---|---|---|---|---|
Q8_0 |
8 | Alta | Casi idéntica a F16 | Máxima calidad práctica |
Q6_K |
6.5 | Media-alta | Excelente | Muy buena opción |
Q5_K_M |
5.5 | Media | Muy buena | Alternativa de calidad |
Q4_K_M |
4.5 | Baja | Buena | Por defecto recomendado |
Q3_K_M |
3.5 | Muy baja | Aceptable | Hardware muy limitado |
Q2_K |
2.6 | Mínima | Degradada | Solo si no hay otra opción |
Regla práctica
Q4_K_M es el punto dulce para la mayoría de casos. Baja a Q3/Q2 solo si no te entra en memoria, y sube a Q6/Q8 si te sobra VRAM y quieres máxima fidelidad.
💻 Uso del CLI: llama-cli
Una vez que tienes tu modelo listo, vamos a usar la terminal para interactuar con él.
Chat interactivo
Para una experiencia de chat clásica:
./build/bin/llama-cli -m modelo-q4_k_m.gguf
Un prompt único (modo no interactivo)
Si solo quieres una respuesta rápida para un script o automatización:
./build/bin/llama-cli -m modelo-q4_k_m.gguf \
-p "Explica qué es Kubernetes en 3 líneas" \
-n 256 \
--no-display-prompt
Flags esenciales
Para sacarle el partido, necesitas conocer estos parámetros:
| Flag | Descripción |
|---|---|
-m |
Ruta al fichero GGUF |
-p |
Prompt de entrada |
-n |
Número máximo de tokens a generar (-1 = infinito) |
-c |
Tamaño del contexto (por defecto 4096; 0 = el del modelo) |
-ngl |
Capas descargadas a la GPU (n-gpu-layers) |
-t |
Número de hilos de CPU |
--temp |
Temperatura de muestreo (0 = determinista) |
-cnv |
Fuerza modo conversación |
Descarga a GPU (GPU offload)
Si tienes GPU, ¡úsala! De lo contrario, estarás desperdiciando potencia.
# -ngl 99 intenta cargar todas las capas en la GPU
./build/bin/llama-cli -m modelo-q4_k_m.gguf -ngl 99 -p "Hola"
¿Cuántas capas caben?
Empieza con -ngl 99 (todas). Si te quedas sin VRAM, baja el número hasta que cargue. Las capas no descargadas se ejecutan en CPU (más lento pero funcional).
🌐 Servidor con API compatible con OpenAI: llama-server
Aquí es donde llama.cpp se vuelve realmente potente para desarrolladores. llama-server levanta un servidor HTTP con endpoints compatibles con la API de OpenAI, además de una interfaz web en http://localhost:8080.
./build/bin/llama-server \
-m modelo-q4_k_m.gguf \
-c 8192 \
-ngl 99 \
--host 0.0.0.0 \
--port 8080
Llamar al endpoint de chat (OpenAI-compatible)
Puedes probarlo con un simple curl:
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "local",
"messages": [
{"role": "system", "content": "Eres un asistente DevOps conciso."},
{"role": "user", "content": "Dame un script bash para backup de PostgreSQL"}
],
"temperature": 0.7
}'
Con el SDK oficial de OpenAI en Python
Si estás integrando esto en una app de Python, la transición es transparente:
from openai import OpenAI
# Apunta al servidor local; la api_key es un placeholder
client = OpenAI(base_url="http://localhost:8080/v1", api_key="sk-no-key-required")
resp = client.chat.completions.create(
model="local",
messages=[{"role": "user", "content": "Explica Docker en 3 líneas"}],
)
print(resp.choices[0].message.content)
Compatibilidad drop-in
Como el endpoint imita a OpenAI, cualquier librería o herramienta que hable con la API de OpenAI (LangChain, LlamaIndex, continue.dev…) funciona cambiando solo base_url. Igual que LM Studio, que también expone un servidor OpenAI-compatible.
📊 Benchmarking con llama-bench
¿Quieres saber qué tan rápido es tu setup? No te bases en sensaciones, usa datos. llama-bench mide el rendimiento de forma reproducible, separando dos métricas clave:
- pp (prompt processing): velocidad de ingesta del prompt (tokens/s).
- tg (text generation): velocidad de generación de tokens (tokens/s).
# Benchmark básico: 512 tokens de prompt, 128 de generación
./build/bin/llama-bench -m modelo-q4_k_m.gguf -p 512 -n 128
# Barrido de niveles de GPU offload para encontrar el óptimo
./build/bin/llama-bench -m modelo-q4_k_m.gguf -ngl 0,20,40,99
Salida típica (resumida):
| model | size | backend | ngl | test | t/s |
| ---------------- | ------ | ------- | --- | ----- | ------ |
| llama 7B Q4_K_M | 3.8GiB | CUDA | 99 | pp512 | 2450.3 |
| llama 7B Q4_K_M | 3.8GiB | CUDA | 99 | tg128 | 118.7 |
Compara peras con peras
Para comparar cuantizaciones o backends, fija siempre los mismos -p y -n. Repite (-r 5) para promediar y reducir ruido.
⚡ Optimización CPU/GPU
Si quieres exprimir hasta la última gota de rendimiento, presta atención a estos detalles técnicos.
En CPU
# Ajusta los hilos al número de núcleos físicos (no lógicos)
./build/bin/llama-cli -m modelo.gguf -t 8 -p "..."
# En NUMA (servidores multi-socket)
./build/bin/llama-cli -m modelo.gguf --numa distribute -p "..."
- Usa núcleos físicos, no hilos lógicos: el hyperthreading rara vez ayuda en inferencia.
- Compila con
-march=nativepara aprovechar AVX-512 si tu CPU lo soporta. - Cuantizaciones
_K(K-quants) están optimizadas para CPU moderna.
En GPU
- Maximiza
-nglhasta llenar la VRAM disponible. - Usa flash attention para ahorrar memoria de contexto:
-fa on. - Para contextos largos, activa la cache KV cuantizada:
--cache-type-k q8_0 --cache-type-v q8_0.
./build/bin/llama-server -m modelo.gguf -ngl 99 -fa on \
--cache-type-k q8_0 --cache-type-v q8_0 -c 16384
Contexto = memoria
El tamaño de contexto (-c) consume VRAM de forma proporcional. Un contexto de 32k puede duplicar el uso de memoria de la cache KV. Cuantízala o reduce -c si te quedas corto.
🎯 Cuándo elegir llama.cpp
Para resumir, llama.cpp es tu mejor opción cuando:
- Edge / hardware limitado: Necesitas correr algo en una Raspberry Pi o un mini-PC sin GPU.
- Producción con control fino: Necesitas decidir exactamente la cuantización, el backend y el muestreo.
- Máximo rendimiento por vatio: Buscas kernels optimizados a mano para tu hardware específico.
Si buscas una experiencia plug and play sin tocar la terminal, usa Ollama (que usa llama.cpp por debajo) o LM Studio para una interfaz gráfica más amigable.
🔗 Recursos adicionales
- Repositorio oficial (ggml-org/llama.cpp)
- Documentación de build
- Documentación de llama-server
- Modelos GGUF en Hugging Face
- Ecosistema de Modelos Locales · Ollama · LM Studio
