Benchmark LLM Local: Resultados y Análisis

2026.05.19
Technology
1113 Words
Benchmark LLM Local: Resultados y Análisis

Parte 2 de 4. Parte 1: Metodología · Parte 3: Cuándo Usar Cada Motor · Parte 4: FAQ y Próximos Pasos

Los benchmarks estandarizados no cuentan toda la historia. Cada motor tiene un perfil de rendimiento diferente según la concurrencia, cuantización y si te importa más la latencia o el throughput. Esto es exactamente lo que medí en mi RTX 4090.

Resultados

Rendimiento de Ollama

Ollama me impresionó con su simplicidad, pero la historia de rendimiento es mixta. Usando configuraciones por defecto con ollama serve, medí:

Latencia de Petición Única (Concurrencia = 1):

ConfiguraciónTTFT (ms)TPOT (ms)Throughput (t/s)VRAM (GB)
Default (Q4_K_M)8914.668.45.8
With num_ctx=5129215.166.25.9
With num_ctx=20488814.867.56.2

El TTFT de Ollama es excelente para uso interactivo. A menos de 100ms, los usuarios perciben la respuesta como instantánea. Sin embargo, el throughput se estanca rápidamente.

Escalado de Peticiones Concurrentes:

ConcurrenciaThroughput (t/s)Latencia P50 (ms)Latencia P99 (ms)Tasa de Éxito
168.4892915100%
271.217851842100%
473.835213684100%
874.17012745398%
1672.3142011589294%
3268.9291233524187%

La conclusión clave: Ollama no se beneficia de la concurrencia. El throughput apenas se mueve al agregar peticiones, y la tasa de fallo aumenta más allá de 16 peticiones concurrentes. He visto este cuello de botella en producción: Ollama procesa peticiones en serie dentro de su configuración por defecto.

Rendimiento de vLLM

El PagedAttention y batching continuo de vLLM dieron lo que esperaba: un escalado dramáticamente mejor.

Latencia de Petición Única:

ConfiguraciónTTFT (ms)TPOT (ms)Throughput (t/s)VRAM (GB)
Default (tensor-parallel=1)1567.8128.29.2
With max_num_seqs=321624.6217.610.8
With gpu_memory_util=0.951584.5221.312.1

Nota la penalización de TTFT comparado con Ollama; el scheduling de vLLM introduce overhead. ¡Pero mira ese salto de throughput con batching habilitado!

Escalado de Peticiones Concurrentes:

ConcurrenciaThroughput (t/s)Latencia P50 (ms)Latencia P99 (ms)VRAM (GB)Tasa de Éxito
1128.297610029.2100%
2198.4128113429.3100%
4287.6142315219.5100%
8412.31589172310.1100%
16523.81847203410.8100%
32587.22134245612.1100%
64612.42641312814.399%

vLLM destaca a escala. A 32 peticiones concurrentes, da 587 tokens/segundo, 8.5x mejor que Ollama a la misma concurrencia. El batching continuo funciona exactamente como se anuncia.

Rendimiento de llama.cpp

llama.cpp ofrece la mayor flexibilidad, así que probé tanto el modo solo-CPU como el acelerado por GPU.

Modo GPU (cuBLAS con n_gpu_layers=-1):

ConfiguraciónTTFT (ms)TPOT (ms)Throughput (t/s)VRAM (GB)
Default (n_gpu_layers=99)1129.2108.76.1
Optimized (n_batch=512)1087.0142.36.1
Server mode (—port 8080)1159.5105.26.0

Modo Solo-CPU (sin capas GPU):

HilosTTFT (ms)Throughput (t/s)RAM (GB)
8120512.46.2
1661218.76.2
3239818.56.3
6435617.26.5

Conclusión clave: llama.cpp con aceleración GPU es competitivo con Ollama, pero el servidor requiere tuning manual. El fallback de CPU funciona sorprendentemente bien para un modelo de 8B; 18.7 tokens/segundo es usable para procesamiento offline.

Escalado de Peticiones Concurrentes (Modo GPU):

ConcurrenciaThroughput (t/s)Latencia P50 (ms)Tasa de Éxito
1142.31021100%
4198.75123100%
8201.21023498%
16198.42051295%

El modo servidor de llama.cpp no implementa batching continuo, así que el throughput se satura alrededor de 200 tokens/segundo independientemente de la concurrencia.

Matriz de Benchmark: Comparación Completa

Aquí está la matriz de benchmark completa entre todas las configuraciones probadas:

MotorConcurrenciaTTFT (ms)TPOT (ms)Throughput (t/s)VRAM (GB)Impacto de Batch
Ollama18914.668.45.8Ninguno
Ollama89114.274.15.9Ninguno
Ollama329515.168.96.2Ninguno
vLLM11567.8128.29.2Por defecto
vLLM81624.6412.310.1Óptimo
vLLM321584.5587.212.1Óptimo
vLLM322988.2321.49.3Sin batching
llama.cpp GPU11087.0142.36.1n_batch=512
llama.cpp GPU81127.3201.26.1n_batch=512
llama.cpp CPU1120580.612.408 threads
llama.cpp CPU1661253.518.7016 threads

FAQ

¿Por qué el throughput de Ollama no mejora con peticiones concurrentes?

Ollama procesa peticiones en serie por defecto. Cada petición bloquea la siguiente hasta que termina. Lo confirmé revisando el conteo de hilos a nivel de proceso durante los benchmarks: Ollama no paraleliza la inferencia dentro de una instancia de modelo. El equipo de vLLM en el UC Berkeley Sky Computing Lab diseñó PagedAttention precisamente para resolver este problema.

¿Cuánto cuesta realmente el overhead del KV cache de vLLM?

En mi RTX 4090, vLLM usó 9.2 GB en reposo versus los 5.8 GB de Ollama. Esa diferencia de 3.4 GB viene de la pre-asignación del pool de KV cache. El trade-off: pagas 3-4 GB de VRAM por la capacidad de hacer batch de hasta 32 peticiones concurrentes. Para A100s con 80 GB, este overhead es insignificante. Para GPUs de consumo, es una limitación real.

¿Qué pasa cuando deshabilito el batching continuo en vLLM?

Sin batching (max_num_seqs=1), vLLM cae a 321.4 tokens/segundo a concurrencia 32, aproximadamente la mitad de su rendimiento con batch. El TTFT también sube a 298ms. El batching continuo es la característica estrella de vLLM. Si lo desactivas, pierdes la razón principal para elegir vLLM sobre Ollama.

¿Cuál es la mejor configuración para inferencia solo-CPU con llama.cpp?

Para Llama 3 8B en CPU, usa 16 hilos con n_batch=512. Más allá de 16 hilos, el ancho de banda de memoria se convierte en el cuello de botella y el throughput deja de mejorar. Mi prueba mostró 18.7 tokens/segundo a 16 hilos, usable para procesamiento por lotes pero demasiado lento para aplicaciones interactivas.

¿Cómo se traducen estos benchmarks a modelos más grandes como Llama 3 70B?

El orden relativo se mantiene, pero los requisitos de VRAM se multiplican. Un Llama 3 70B en Q4_K_M necesita aproximadamente 40 GB. Con tensor parallelism de vLLM, lo dividirías entre 2x A100s. He probado modelos de 70B y encontré que la ventaja de throughput de vLLM se amplía con parámetros más grandes debido a una mejor gestión de memoria.

¿Cuánto tiempo tomó ejecutar el suite completo de benchmarks?

Cada motor requirió 5 minutos por nivel de concurrencia. Con 6 niveles, 3 iteraciones cada uno, más warmup y exportación de datos, el suite completo tomó unos 90 minutos. Lo automatizé con un wrapper de shell que ciclaba entre configuraciones de motores durante la noche.


Partes en esta serie: ← Parte 1 | Parte 3 →

# local-llm # benchmark # performance # Ollama # Vllm # llama-cpp # inference-speed