llama.cpp - despliegue y plantilla de arranque
Cómo preparar cualquier modelo GGUF y su script de arranque para un servidor local con llama.cpp y CUDA. El procedimiento vale para cualquier equipo; los ejemplos asumen 16 GB de VRAM y se ajustan con la formula del paso 1.
Reglas de oro (KV cache y contexto)
| Orden | Intento | Contexto | KV cache | Cuándo |
|---|---|---|---|---|
| 1º | 128K | -c 131072 | q8_0 | Siempre que el modelo + KV + overhead quepan en VRAM |
| 2º | 64K | -c 65536 | q8_0 | Si el modelo es más grande y 128K ya no cabe |
| 3º | 64K (o menos) | -c 65536 o inferior | q4_0 | Si de ninguna manera cabe con q8 |
La idea: siempre q8 y el máximo contexto que quepa (128K → 64K), y solo se baja KV a q4 como último recurso. La KV cache q4 tiene pérdida mínima en modelos ya cuantizados, pero q8 es la prioridad.
Regla de VRAM: si el total
modelo + KV + ~2 GB de overheades menor que la VRAM libre, se usa offload completo (-ngl 999). Si no cabe ni a 64K q4, se plantea bajar la cuantización del propio modelo (Q4 en vez de Q8) o usar-cmoe/CPU.
Procedimiento paso a paso (para cualquier modelo)
Paso 1 — Comprobar arquitectura, MTP y dimensionar la KV
Con la librería gguf de Python (instalada):
from gguf import GGUFReader
r = GGUFReader(r"<RUTA_MODELOS>/<MODELO>.gguf")
def val(k):
if k not in r.fields: return None
return r.fields[k].parts[r.fields[k].data[0]].tolist()
# Prefijo de arquitectura: "llama", "qwen2", "qwen3moe", "gemma4", ...
arch = bytes(val("general.architecture")).decode()
layers = val(arch + ".block_count")
hkv = val(arch + ".attention.head_count_kv")
hd = val(arch + ".attention.key_length")
print("arquitectura:", arch, "| capas:", layers, "| KV heads:", hkv, "| head_dim:", hd)
kv_q8 = 2 * layers * hkv * hd / 1e9 # GB por token (q8 = 1 byte/valor)
print(f"KV q8: {kv_q8*1024:.3f} MB/token | 128K={kv_q8*131072:.2f} GB | 64K={kv_q8*65536:.2f} GB")
# MTP: hay tensores MTP/draft?
mtp = [t.name for t in r.tensors if "mtp" in t.name.lower() or "draft" in t.name.lower()]
print("MTP:", "SOPORTADO" if mtp else "NO soportado")- Si
MTP: SOPORTADO→ se puede añadir--spec-type draft-mtp --spec-draft-n-max 2(y el-mdel drafter en--model-draftsi es un archivo aparte). - Si no → se omite MTP y ya está.
- El KV por token es la cifra clave para el Paso 2.
Paso 2 — Elegir contexto y KV según las reglas
Suma al tamaño del GGUF (el peso en GB del archivo) la KV elegida y ~2 GB de overhead. Con 16 GB de VRAM (≈14,6 GB libres en la practica):
| Tamaño GGUF | Contexto | KV | Total aprox. | Resultado |
|---|---|---|---|---|
| ≤ ~9 GB | 128K | q8 | modelo + 3.8 + 2 | ✅ 128K q8 |
| ~9–12 GB | 64K | q8 | modelo + 1.9 + 2 | ✅ 64K q8 |
| ~12–14 GB | 64K | q4 | modelo + 1.0 + 2 | ✅ 64K q4 |
| > ~14 GB | bajar quant / -cmoe | — | — | replantear |
La tabla es orientativa para modelos densos típicos. La fuente de verdad es la fórmula (Paso 1): compara
modelo + KV + 2 GBcontra la VRAM libre (nvidia-smi --query-gpu=memory.free --format=csv). Los MoE hibridos solo hacen atencion completa en una de cada cuatro capas, asi que su KV real es varias veces menor que la formula.
Paso 3 — Elegir binario y puerto
- Binario CUDA:
%USERPROFILE%\.unsloth\llama.cpp\build\bin\Release\llama-server.exe(build más reciente, soporta MTP/jinja/CORS). Alternativa:%USERPROFILE%\AI\llama.cpp-cuda\llama-server.exe. - Puerto libre: elige uno que no use ningun otro servicio (
ss -tulpnonetstat -ano). Si vas a tener varios modelos, reserva un rango y documentalo.
Paso 4 — Crear el .bat con la plantilla
Copia la plantilla de abajo, sustituye SU_CARPETA, SU_MODELO.gguf, SU_PUERTO y los flags de contexto/KV según el Paso 2. Guárdalo junto al modelo. Opcionalmente añádelo al menú AI\models\start-model.bat (ver más abajo).
Plantilla .bat (copiar/pegar)
Guarda como start-NOMBRE.bat en la carpeta del modelo:
@echo off
REM ============================================================
REM NOMBRE DEL MODELO (QUANT) - Servidor local llama.cpp (GPU)
REM Arquitectura : <arch> (ver Paso 1)
REM MTP : <SOPORTADO | NO soportado>
REM KV cache : <q8_0 | q4_0>
REM Contexto : <131072 | 65536> - <cabe | no cabe> en VRAM 16 GB
REM GPU : <VRAM> GB, offload completo (-ngl 999)
REM Puerto : SU_PUERTO
REM Arrancar a MANO: ejecutar este .bat
REM ============================================================
set MODEL=<RUTA_MODELOS>\<MODELO>.gguf
set LLAMA=%USERPROFILE%\.unsloth\llama.cpp\build\bin\Release\llama-server.exe
set CTX=131072 REM 65536 si el modelo es grande (regla 2)
set CTK=q8_0 REM q4_0 si no cabe con q8 (regla 3)
set CTV=q8_0 REM igual que CTK
echo.
echo Arrancando NOMBRE DEL MODELO...
echo Modelo : %MODEL%
echo Context : %CTX% (%CTX%/1024 K)
echo KV : K=%CTK% V=%CTV%
echo GPU : <VRAM> GB (offload completo)
echo Puerto : SU_PUERTO
echo MTP : <SOPORTADO | no soportado>
echo.
"%LLAMA%" ^
-m "%MODEL%" ^
-ngl 999 -fa on ^
-c %CTX% --cache-type-k %CTK% --cache-type-v %CTV% ^
--no-context-shift ^
--jinja ^
--temp 0.7 --top-p 0.80 --top-k 20 ^
--cors-origins localhost ^
--alias SU_ALIAS ^
--port SU_PUERTO ^
--host 127.0.0.1
echo.
echo Servidor detenido.
pauseFlags MTP (SOLO si el Paso 1 dice que está soportado): añade justo tras -m "%MODEL%":
--spec-type draft-mtp --spec-draft-n-max 2 ^Si el drafter es un archivo aparte (mtp-*.gguf), añade además:
--model-draft "%USERPROFILE%\AI\models\SU_CARPETA\mtp-XXXX.gguf" ^Añadirlo al menú start-model.bat
En %USERPROFILE%\AI\models\start-model.bat (el gestor DSH):
- Añade una línea al menú:
echo N) NOMBRE (QUANT) (puerto SU_PUERTO). - Cambia
[1-X]a[1-X+1]en elset /p. - Añade
if "%OPT%"=="N" goto :load_N. - Añade al final un bloque
:load_N:
:load_N
call :KILL
echo [*] Arrancando NOMBRE en http://localhost:SU_PUERTO ...
"%USERPROFILE%\.unsloth\llama.cpp\build\bin\Release\llama-server.exe" ^
-m "<RUTA_MODELOS>\<MODELO>.gguf" ^
-ngl 999 -fa on ^
-c 131072 --cache-type-k q8_0 --cache-type-v q8_0 ^
--no-context-shift --jinja ^
--temp 0.7 --top-p 0.80 --top-k 20 ^
--cors-origins localhost ^
--alias SU_ALIAS --port SU_PUERTO --host 127.0.0.1
echo.
echo [*] NOMBRE detenido. Pulse una tecla para volver al menu.
pause >nul
goto :MENU
:load_Nempieza concall :KILLpara asegurar que solo corre un modelo a la vez (mata el llama-server anterior).
Ejemplo resuelto — WhiteRabbitNeo V3 7B (Q8_0)
- Arquitectura:
qwen2(Qwen2.5-Coder-7B), 28 capas, 4 KV heads, head_dim 128. - KV:
2 × 28 × 4 × 128= 28 KB/token → 128K q8 = 3.76 GB. - Cabe: modelo Q8 (8.1 GB) + KV 3.76 + 2 overhead ≈ 12 GB < 14.6 GB → 128K + q8 (regla 1). MTP no soportado.
- Puerto: 8085. Archivo:
AI\models\7B Neo Rabbit\start-whiterabbitneo.baty entrada 12 del menú.
Referencia rápida — flags
| Flag | Qué hace | Valor habitual |
|---|---|---|
-m | Ruta al GGUF | %USERPROFILE%\AI\models\... |
-ngl 999 | Offload completo a GPU | 999 |
-fa on | Flash Attention (ahorra VRAM, más rápido) | on |
-c | Tamaño de contexto | 131072 / 65536 |
--cache-type-k/v | Cuantización de la KV cache | q8_0 / q4_0 |
--jinja | Usa el chat template Jinja del GGUF | on |
--cors-origins localhost | Blinda CORS contra drive-by (seguridad) | localhost |
--port / --host | Puerta y bind | SU_PUERTO / 127.0.0.1 |
--spec-type draft-mtp | Decodificación especulativa MTP (solo si soporta) | draft-mtp |