localaiforum
Iniciar sesión
Guía › Ejecución y servicio

Procesamiento por lotes y múltiples usuarios

Una petición a la vez es como empieza toda sesión de escritorio — y
desperdicia una GPU. Todo el juego del servicio son los lotes: conseguir
que una pasada por los pesos sirva a muchas peticiones a la vez. Esta
página cubre por qué funciona eso, qué son en realidad el procesamiento
por lotes continuo y la atención paginada, cuándo necesitas un motor de
servicio de verdad, y cómo dimensionar la cosa.

Por qué el servicio serial desperdicia la GPU

Recuerda la fórmula de velocidad: cada token decodificado lee
esencialmente todos los pesos activos una vez (velocidad).
Sirviendo un flujo, la GPU hace toda esa lectura para el único token de
un único usuario. Ahora agrupa ocho flujos en la misma pasada hacia
adelante: los pesos se leen una vez y se usan para ocho secuencias — la
aritmética extra es casi gratis, porque la decodificación está limitada
por ancho de banda, no por cómputo. La velocidad por flujo apenas baja
mientras el rendimiento total sube casi linealmente, hasta saturar ancho
de banda o memoria KV. Ese único hecho es toda la economía del servicio
local.

Lotes estáticos vs continuos

La versión ingenua — lotes estáticos — agrupa peticiones que llegaron
juntas y corre el lote hasta que termina cada miembro. Funciona, mal:

Lotes estáticos Lotes continuos
Lote formado Una vez, cuando el grupo se reúne Reevaluado en cada paso de decodificación
Unirse a mitad de vuelo No — espera al siguiente lote Sí, los huecos se llenan según llegan peticiones
Petición corta en un lote de largas Se bloquea hasta que termine la más larga Termina y libera su hueco de inmediato
Latencia de cola Mala (bloqueo de cabeza de línea) Buena

El procesamiento por lotes continuo (a nivel de iteración) — el valor por
omisión en vLLM y SGLang — es la razón de que esos motores aguanten
tráfico real mientras los servidores ingenuos colapsan.

Atención paginada: arreglando la fragmentación del KV

Cada petición activa necesita memoria de caché KV (véase
caché KV). El enfoque antiguo reservaba por adelantado
el contexto máximo de cada petición — así que un chat usando 2k tokens
podía mantener reservado un bloque de 32k, bloqueado e inutilizable por
cualquiera más. La mayoría del grupo KV estaba ocioso. La atención
paginada almacena el KV en bloques de tamaño fijo asignados bajo
demanda, como un sistema operativo pagina la memoria: el desperdicio baja
de la mayoría (los autores de vLLM reportaron 60–80% en su paper) a unos
pocos por ciento, caben varias veces más secuencias concurrentes, y el
rendimiento sigue. La misma idea, hoy estándar en todos los motores de
servicio.

Coste para ti: nada visible — es un cambio de asignador; solo ves mayor
capacidad concurrente en la misma GPU.

Cuándo necesitas un motor de servicio de verdad

Carga de trabajo Motor
Tú más el hogar, unos chats secuenciales Ollama / LM Studio — ya está bien
Unos desarrolladores trasteando concurrentemente llama-server con huecos paralelos, o el entorno paralelo de Ollama
Tráfico de producto, chat de equipo, usuarios reales vLLM o SGLang
Flotas de agentes compartiendo prompts de sistema largos SGLang (caché de prefijos) o vLLM

El rincón de juegos de este foro es el ejemplo canónico de la
última fila: las partidas de ajedrez y
janggi corren varios agentes, cada uno pidiendo un
movimiento cada segundo más o menos — prompts pequeños, muchos flujos,
prompts de sistema compartidos. Esa es exactamente la carga que quiere un
motor de servicio con lotes, no ollama run en un bucle (véase
agentes).

Rendimiento vs latencia

Todo control troca uno por el otro: lotes más grandes suben los tok/s
totales mientras bajan ligeramente la velocidad por flujo, y el encolado
sube el TTFT bajo carga. Un asistente de código para una persona quiere
la concurrencia limitada a 1–2 para que el flujo del humano nunca se
encole. Un servicio de chat para treinta personas quiere los lotes
llenos. Decide cuál eres antes de afinar (véase
servicio para el TTFT vs la decodificación como
medidas separadas).

Lo más parecido a un almuerzo gratis es la caché de prefijos (SGLang):
los prompts largos repetidos se vuelven prefill casi cero, y esa es la
mayoría de las cargas agénticas.

Controles prácticos

# llama.cpp: huecos de decodificación paralelos (el contexto se reparte entre huecos)
llama-server -m model.gguf -c 32768 -np 4

# Ollama: peticiones paralelas por modelo (reinicia el servicio tras fijarlo)
export OLLAMA_NUM_PARALLEL=4

# vLLM: los dos que importan
vllm serve model --max-num-seqs 32 --gpu-memory-utilization 0.90

El encolado ocurre aguas arriba de todo esto: cuando todo hueco está
ocupado, las peticiones nuevas esperan. Vigila la profundidad de cola y
el TTFT, no vibraciones.

Pon límites también aguas arriba: un proxy inverso con tope de conexiones
falla rápido y honestamente, donde una cola profunda falla lenta y
misteriosamente.

Planificación de capacidad, aproximadamente

Lo que cuesta una petición más allá de los pesos es la caché KV, por
token, para todo su contexto:

bytes KV/token ≈ 2 × capas × kv_heads × head_dim × bytes_por_valor

Ejemplo resuelto, modelo denso típico de 8B (32 capas, 8 cabezas KV, dim
de cabeza 128, valores fp16):
2 × 32 × 8 × 128 × 2 B ≈ 131 KB por token → una conversación de 2k
tokens ≈ 256 MiB de KV → diez chats así ≈ 2.5 GB encima de los ~5 GB de
pesos.

(el 2 es K y V; véase caché KV). Los agentes de
contexto largo son por tanto mucho más caros por petición que el chat.
Tabla aproximada de comodidad, con fuertes reservas — contextos de
longitud de chat, solo orden de magnitud:

GPU Modelo Chats ligeros concurrentes aprox.
8 GB 7–8B Q4 1–3
24 GB 8B Q4 ~10–30
24 GB 32B Q4 ~3–8
48 GB 70B Q4 ~5–15

Mide con tus prompts reales: la longitud del contexto mueve estos números
más que cualquier otra variable.

Señales de que estás saturado

  • TTFT subiendo de milisegundos a segundos conforme avanza el día.
  • Profundidad de cola persistentemente por encima de cero; peticiones
    esperando antes del primer token.
  • Tok/s por flujo cayendo conforme los lotes se aprietan.
  • Registros de vLLM mostrando preemption o recomputación de KV — presión
    de memoria, no lentitud del modelo.

Ante cualquiera de estas: limita el contexto, cuantiza la caché KV, o
añade GPU — en ese orden de baratura — antes de que tus usuarios se
quejen fuerte.

Grafica el TTFT y la profundidad de cola a lo largo de un día — una subida
constante significa capacidad, un sierra significa ráfagas que puedes
absorber con una cola.

Alquilar vs comprar, esbozado

A fecha de redacción, una GPU alquilada clase 24GB cuesta aproximadamente
$0.50–2/hora, y una tarjeta usada de 24GB cuesta unos cientos de
dólares — el punto de equilibrio en algún lugar alrededor de 300–1,000
horas de generación real. Lo local gana en privacidad, latencia y sin
límites de tasa (el encuadre en por qué local);
alquilar gana en demanda en ráfagas y modelos clase 80GB que ninguna
tarjeta de consumo aloja (véase cálculo de VRAM para
qué cabe dónde). La mayoría de la gente sobreestima sus horas — instrumenta
una semana real antes de decidir.

Relacionados: Velocidad · Caché KV · Servir un endpoint · Cálculo de VRAM