Resolución de problemas: síntoma → causa → solución
La inferencia local falla en patrones. La misma docena de síntomas
explica casi toda petición de ayuda, y cada uno tiene una causa aburrida
y un arreglo de dos minutos. Escanea la tabla, aplica el arreglo, y luego
lee los números para confirmar que estás arreglado de verdad.
La tabla de diagnóstico
| Síntoma | Causa probable | Arreglo |
|---|---|---|
La salida contiene tokens de rol (user:, `< |
im_start | >`) |
| Respuesta vacía instantánea | La plantilla renderiza un chat «terminado», o token EOS equivocado | Arregla la plantilla; comprueba el EOS: prompting |
| Repite tu pregunta en vez de responder | Modelo base, no un modelo instruct | Usa un GGUF instruct/chat |
| Sin memoria al cargar | Pesos + cuantización exceden la VRAM | Cuantización menor o modelo menor: cálculo de VRAM |
| Sin memoria en mitad de la generación | La caché KV crece más allá del margen | Contexto más corto, caché KV q8_0: caché KV |
| 1–3 tok/s a pesar de tener GPU | Las capas siguen en CPU | Descarga completa (n_gpu_layers): parámetros del motor |
| Primer token lento, flujo rápido después | Limitado por prefill: prompts muy largos | Acorta prompts, lote, prefill más rápido: velocidad |
| Repetición sin fin, bucles de frase | Sampler demasiado permisivo, penalizaciones apagadas | temp ≤ 0.8, repeat_penalty 1.05–1.1: muestreo |
| La salida en coreano es jerigonza o rígida | Modelo débil en coreano | Familias multilingües (Qwen, Gemma): familias de modelos |
| Salida truncada a mitad de frase | Ventana de contexto llena o max_tokens demasiado bajo | Recorta contexto o sube el límite de salida |
| JSON inválido de un modelo bueno | Muestreo en forma libre | Decodificación restringida: salida estructurada |
| El modelo ignora tus instrucciones | Perdido en el medio con prompts largos | Objetivo primero, carga al final, repite la petición: prompting |
| Crash o coredump al cargar | Descarga corrupta | Verifica el checksum, re-descarga |
Léela por síntoma primero, no por causa: empareja lo que ves, aplica el
arreglo, vuelve a medir. La mayoría de los informes de «mi modelo está
roto» terminan en la fila 1, 2 o 6.
El pre-vuelo de cinco minutos
Antes de cualquier depuración profunda, reúne los hechos:
nvidia-smi --query-gpu=name,memory.total,memory.used --format=csv # GPU + VRAM
ls -lh model.gguf # tamaño vs VRAM
llama-server --version # build del motor
Si el archivo del modelo es más grande que la VRAM libre, la fila 4 es tu
respuesta y ningún flag te salvará. Si memory.used sube sin parar
durante la generación, es la caché KV, no una fuga.
Qué aspecto tiene lo normal
Antes de depurar rendimiento, conoce el orden de magnitud. Velocidad de
decodificación para un modelo 7–8B Q4_K_M, lote 1:
| Hardware | Decodificación tok/s |
|---|---|
| GPU de gama media (clase RTX 3060/4060) | 30–60 |
| GPU de gama alta (clase RTX 3090/4090) | 100–150 |
| Apple serie M (memoria unificada) | 20–40 |
| Solo CPU (8 núcleos modernos) | 3–8 |
Dos fórmulas explican la mayor parte:
tok/s decode ≈ ancho de banda de memoria (GB/s) ÷ tamaño del modelo (GB)
VRAM necesaria ≈ pesos + caché KV + 1–2 GB de sobrecarga
Una cuantización 7B de 4.5 GB en una tarjeta de 288 GB/s tops cerca de
64 tok/s en teoría; espera ~45–55 reales. Si estás dentro de 2× de la
tabla, tu hardware no es el bug.
El tiempo al primer token (TTFT) debe estar muy por debajo del segundo
para prompts cortos; crece con la longitud del prompt dividida por el
rendimiento de prefill (que corre a 10–100× la velocidad de
decodificación). Un prompt de 10k tokens que tarda 20 s antes del primer
token está limitado por prefill, no roto.
Contabilidad de VRAM: si los pesos cargaron bien pero tienes OOM después,
es la caché KV o la longitud de contexto, no la cuantización — caché
KV.
El flujo de trabajo: cambia una variable
Los bugs se esconden cuando cambias dos cosas a la vez. Aísla a lo largo
de esta cadena — modelo → motor → configuración → prompt:
- Línea base. Modelo conocido-bueno, motor conocido-bueno, flags por
omisión. ¿Funciona el chat? Entonces la pila está bien. - Cambia el modelo (mismo motor, mismos flags). ¿Se rompe? Es el
archivo o su plantilla. - Cambia el motor (mismo modelo). ¿Se rompe? Bug del motor o
traducción de flags. - Bisecta tus flags. Restaura los valores por omisión, añade flags
de vuelta uno a uno hasta que se rompa. - Vuelca el prompt renderizado. Cuando la salida es rara-pero-corre,
la plantilla renderizada es donde vive la verdad.
Toma notas sobre la marcha — «funciona a temp 0.8, se rompe con min_p
0.2» es un diagnóstico; «probé cosas, sigue mal» no.
Cómo pedir ayuda bien
Un buen post de ayuda es un informe de laboratorio. Incluye:
- Archivo del modelo: nombre exacto, cuantización y fuente
(qwen2.5-7b-instruct-q4_k_m.gguf, qué repo). - Motor y versión: fecha de build de llama.cpp, versión de Ollama,
release de vLLM — los motores cambian cada semana. - Flags o llamada API exactos: toda la línea de comandos o el cuerpo
de la petición, no un parafraseo. - Hardware: GPU + VRAM (o Mac + RAM), CPU si está cargando capas.
- Números observados: tok/s, TTFT, VRAM usada, y el texto exacto del
error si lo hay. - Qué ya probaste y qué cambió como resultado.
Esqueleto para copiar y pegar:
Modelo: qwen2.5-7b-instruct-q4_k_m.gguf (repo de bartowski)
Motor: llama.cpp b4321 (llama-server)
Flags: -ngl 99 -c 8192 --temp 0.7
Hardware: RTX 4060 8GB / Ryzen 7 / 32GB RAM
Observado: carga en 21s, ~35 tok/s, TTFT ~1.2s, luego OOM con ~6k de ctx
Probado: -c 4096 → sin crash; q8_0 KV → sin crash
Con esos seis hechos, la mayoría de los problemas mapean a una fila de la
tabla de arriba en una sola respuesta. Este foro existe justamente para
estos posts — trae el informe de laboratorio y recibirás el arreglo.
Relacionados: parámetros del motor · cálculo de VRAM · caché KV · muestreo