Cómo medir tokens por segundo en un LLM local
Mida tokens por segundo con una prueba de concurrencia y calcule el umbral de rendimiento que necesita para saber si una GPU alquilada supera el pago por token.
Por qué los tokens por segundo determinan si una GPU resulta rentable
Los tokens por segundo son la velocidad a la que el servidor genera texto de salida. Esta cifra determina si alquilar una GPU cuesta menos que pagar una API por token. Un servidor con GPU se factura por hora, tanto si está ocupado como si está inactivo. Una API alojada se factura por token. Por tanto, la GPU sólo resulta más rentable si mantiene una tasa de salida suficientemente alta durante la mayor parte de las horas contratadas.
Necesita una medición, no una cifra obtenida de otra fuente. Esta página define los cuatro valores que conviene registrar. Después muestra los comandos que los generan y las operaciones necesarias para convertirlos en una decisión.
Por qué la cifra publicada de tokens por segundo no es la suya
DigitalOcean publicó en julio de 2026 cifras de rendimiento para una sola NVIDIA H200 con llama3.3-70b-instruct en FP8 (coma flotante de 8 bits) mediante vLLM. Las cifras son útiles, pero no son las que obtendrá usted.
The data behind this chart
[
{
"config": "H200, one stream",
"tok_s": "47"
},
{
"config": "H100, saturated",
"tok_s": "236"
},
{
"config": "H200, saturated",
"tok_s": "2,036"
},
{
"config": "H200, saturated, in+out",
"tok_s": "4,071.6"
}
]Cada fila anterior se ha tomado de esa página. Además, dos de ellas corresponden al extremo inferior de un intervalo indicado allí, así que debe interpretar esos dos valores como un mínimo. Nosotros no medimos ningún valor de esta tabla.
Comience por las dos últimas filas. El valor principal es de 4,071.6 tok/s, mientras que la tasa de salida es de 2,036 tok/s. El valor principal suma los tokens de entrada y de salida. Esa prueba usó 1,024 tokens de entrada y 1,024 tokens de salida, por lo que casi exactamente la mitad del valor principal corresponde a la salida. Esta separación importa porque la facturación se basa en la salida, que además es la parte lenta. El prellenado (la lectura del prompt) procesa todos los tokens de entrada en una sola pasada. La decodificación (la escritura de la respuesta) produce un token cada vez. El valor de rendimiento total promedia una operación barata con otra cara.
Ahora, la primera fila. La misma H200, al atender una solicitud cada vez, produce 47 tok/s. Por tanto, el valor con la GPU saturada es más de cuarenta veces mayor con el mismo hardware. Esta diferencia existe porque, durante la mayor parte de cada paso de decodificación, la GPU espera datos de la memoria, y las solicitudes simultáneas aprovechan ese tiempo inactivo. La segunda fila, 236 tok/s, corresponde a una sola H100 con el mismo modelo y está limitada por la caché KV (la caché de claves y valores, es decir, la memoria por solicitud que una conversación atendida mantiene en la tarjeta). Una tarjeta de 80 GB puede mantener menos solicitudes simultáneas para un modelo de 70B, por lo que alcanza la saturación con un valor menor.
Si cambia el modelo o la proporción entre tokens de entrada y de salida, todos los valores anteriores cambian. Las cifras publicadas sirven para establecer expectativas, no para fijar el presupuesto. La misma regla se aplica al benchmarking honesto de una VPS en disco y red.
Los cuatro números importantes
- Tiempo hasta el primer token, TTFT. Es el retraso entre el envío de una solicitud y la llegada del primer token de salida. Es la suma del tiempo de prellenado y el tiempo en cola. El usuario percibe este valor directamente.
- Tokens de salida por segundo, por flujo. Indica la velocidad a la que se genera una respuesta una vez que ha comenzado. Por encima de aproximadamente 20 tok/s, la generación ya es más rápida que la lectura de la mayoría de las personas, por lo que una velocidad adicional aporta poco.
- Rendimiento total de salida con saturación. Es la suma de todos los flujos simultáneos cuando el servidor está completamente cargado. Este valor representa la capacidad y es el que determina el coste de la GPU.
- p50 y p99 de TTFT con concurrencia. p50 corresponde a la solicitud intermedia. p99 es el valor por debajo del cual se completan 99 de cada 100 solicitudes. La espera en cola siempre aparece primero en p99.
Los dos primeros mejoran cuando el servidor está inactivo. El tercero mejora cuando el servidor está ocupado. Se contraponen, por lo que ningún número por sí solo describe un servidor de inferencia.
Corrija las longitudes de entrada y salida antes de medir
El rendimiento depende de la forma del tráfico. Un prompt de 4,000 tokens con una respuesta de 50 tokens es una carga centrada en el prellenado. Un prompt de 200 tokens con una respuesta de 2,000 tokens es una carga centrada en la decodificación. El mismo servidor muestra valores muy distintos de tokens por segundo en esos dos casos. Por eso, elija una proporción, escríbala junto a cada número que registre y no compare valores de proporciones diferentes. 1,024 tokens de entrada y 1,024 tokens de salida es un valor predeterminado razonable porque varios proveedores publican resultados con esa proporción. Si conoce el tráfico real, use el tráfico real.
Fije también la longitud de salida. Un modelo que alcanza su token de parada después de 60 tokens produce una ejecución más corta que parece más rápida, porque el TTFT representa una proporción mayor de ella. La opción --ignore-eos del cliente de pruebas de rendimiento de vLLM hace que cada solicitud genere exactamente la cantidad solicitada, de modo que las dos ejecuciones sigan siendo comparables. La elección del modelo modifica estos valores más que cualquier opción: ejecutar un modelo Qwen 3 en la GPU de un único VPS explica el aspecto de memoria de esa elección.
Mida primero un flujo
Empiece por el caso más sencillo. Es una comprobación de coherencia y también establece un límite superior. Ollama muestra sus propias métricas de tiempo.
ollama run llama3.1:8b --verbose "Write 200 words about disk scheduling."La línea que debe leer es eval rate, que indica los tokens de salida por segundo. prompt eval rate es la velocidad de prellenado y load duration es el tiempo dedicado a cargar el modelo en la VRAM. En la primera llamada después de un arranque en frío, load duration es grande, por lo que total duration resulta engañoso. Ejecute el comando dos veces y lea el segundo resultado. De forma predeterminada, Ollama descarga un modelo inactivo después de cinco minutos, por lo que una pausa larga entre ejecuciones devuelve la prueba al caso en frío.
Los mismos campos están disponibles mediante la API, que resulta más fácil de automatizar.
curl -s http://127.0.0.1:11434/api/generate -d '{
"model": "llama3.1:8b",
"prompt": "Write 200 words about disk scheduling.",
"stream": false
}' | jq '{eval_count, eval_duration,
tok_s: (.eval_count / (.eval_duration / 1000000000))}'eval_duration está expresado en nanosegundos, por lo que dividirlo entre 1,000,000,000 da el resultado en segundos. Esa división es exactamente la que recomienda la documentación de la API de Ollama para calcular los tokens por segundo. Si el servidor todavía no está activo, alojar un LLM con Ollama en un VPS explica la instalación y la unidad de systemd.
Para medir el TTFT se necesita una solicitud de streaming, y curl puede medirlo directamente.
curl -s -o /dev/null -N \
-w 'ttfb=%{time_starttransfer}s total=%{time_total}s\n' \
http://127.0.0.1:8000/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{"model":"Qwen/Qwen3-8B",
"messages":[{"role":"user","content":"Write 200 words about disk scheduling."}],
"stream":true,"max_tokens":256}'time_starttransfer es el momento en que llega el primer byte del cuerpo de la respuesta. En una finalización de chat con streaming, ese byte pertenece al primer evento enviado por el servidor, que puede contener el primer token de contenido o un delta que sólo contiene el rol y que se envía justo antes. Por tanto, considere el valor como el TTFT, con una variación aproximada de un evento. Es suficientemente preciso para comparar dos ejecuciones en el mismo servidor.
Las cifras de un solo flujo favorecen al equipo por dos motivos. El TTFT es el mejor resultado posible, porque no hay solicitudes en espera delante de la suya. La velocidad por flujo también es la mejor posible, porque toda la tarjeta está atendiendo una sola solicitud. Ninguna de las dos cifras indica qué carga puede soportar el equipo.
¿Cómo se ejecuta un barrido de concurrencia?
Un barrido ejecuta una carga de trabajo fija con una concurrencia cada vez mayor y registra lo que ocurre en cada paso. vLLM incluye el cliente para hacerlo y usa la API de OpenAI, por lo que también funciona con Ollama y con cualquier otro servicio compatible con OpenAI.
vllm bench serve \
--backend openai-chat \
--base-url http://127.0.0.1:8000 \
--endpoint /v1/chat/completions \
--model Qwen/Qwen3-8B \
--dataset-name random \
--random-input-len 1024 \
--random-output-len 1024 \
--ignore-eos \
--num-prompts 160 \
--max-concurrency 16 \
--percentile-metrics ttft,tpot,itl,e2el \
--metric-percentiles 50,99--max-concurrency limita las solicitudes simultáneas y es la variable cuyo valor se incrementa durante el barrido. --num-prompts es el total de solicitudes enviadas, por lo que debe mantenerse cerca de diez veces la concurrencia para obtener un promedio estable. El resumen muestra Output token throughput (tok/s): y Total token throughput (tok/s):, y después Mean TTFT (ms):, Median TTFT (ms): y P99 TTFT (ms): bajo un encabezado Time to First Token.
La salida no incluye una tasa por flujo, pero se obtiene mediante una división. Mean TPOT (ms): es el tiempo medio por token de salida después del primero, por lo que 25 ms por token equivalen a 40 tokens por segundo por flujo. Dividir el rendimiento de salida entre la concurrencia produce el mismo resultado.
A continuación, repita el proceso y guarde cada ejecución.
for C in 1 4 16 32 64 128; do
vllm bench serve \
--backend openai-chat \
--base-url http://127.0.0.1:8000 \
--endpoint /v1/chat/completions \
--model Qwen/Qwen3-8B \
--dataset-name random \
--random-input-len 1024 \
--random-output-len 1024 \
--ignore-eos \
--num-prompts $(( C * 10 )) \
--max-concurrency "$C" \
--percentile-metrics ttft,tpot,itl,e2el \
--metric-percentiles 50,99 \
--save-result --result-filename "sweep-c$C.json"
doneLectura de los archivos JSON guardados
Cada ejecución escribe un archivo, por lo que puede extraer de todos ellos los campos que le interesen de una sola vez.
for f in sweep-c*.json; do
jq -r --arg f "$f" \
'[$f, .output_throughput, .total_token_throughput,
.median_ttft_ms, .p99_ttft_ms] | @tsv' "$f"
doneoutput_throughput es la cantidad de tokens de salida por segundo. total_token_throughput vuelve a sumar los tokens de entrada, por lo que con una proporción de 1:1 se acerca al doble. p99_ttft_ms sólo existe porque --metric-percentiles incluyó 99; si solicita un percentil que no pidió, jq imprime null.
¿Qué muestra realmente un barrido de concurrencia?
The data behind this chart
[
{
"label": "1 stream",
"per_stream_tok_s": 92,
"total_tok_s": 92,
"ttft_p50_ms": 48,
"ttft_p99_ms": 61
},
{
"label": "4 streams",
"per_stream_tok_s": 88,
"total_tok_s": 352,
"ttft_p50_ms": 71,
"ttft_p99_ms": 96
},
{
"label": "16 streams",
"per_stream_tok_s": 71,
"total_tok_s": 1136,
"ttft_p50_ms": 152,
"ttft_p99_ms": 244
},
{
"label": "32 streams",
"per_stream_tok_s": 54,
"total_tok_s": 1728,
"ttft_p50_ms": 287,
"ttft_p99_ms": 498
},
{
"label": "64 streams",
"per_stream_tok_s": 34,
"total_tok_s": 2176,
"ttft_p50_ms": 611,
"ttft_p99_ms": 1240
},
{
"label": "128 streams",
"per_stream_tok_s": 18,
"total_tok_s": 2304,
"ttft_p50_ms": 1490,
"ttft_p99_ms": 3820
}
]Esas 6 filas ilustran la forma que produce un barrido en un equipo GPU pequeño de alquiler, con órdenes de magnitud plausibles. No son una medición de su servidor ni una cifra del proveedor. Ejecute el bucle anterior y sustitúyalas por sus propios datos.
Observe la forma, porque es lo que se puede generalizar. Con un flujo, todo el equipo produce 92 tokens por segundo, con un TTFT p99 de 61 ms. En 128 streams, el total alcanza 2304 tokens por segundo, veinticinco veces más, mientras que cada flujo individual baja a 18 tokens por segundo y el TTFT p99 alcanza 3820 ms. El rendimiento total aumenta porque el batching convierte las esperas de memoria inactivas en trabajo útil. La velocidad por flujo disminuye porque ahora el mismo cómputo se comparte.
La última duplicación es la señal clave. Pasar de 64 a 128 flujos añade menos de un 6 por ciento al total, mientras que el TTFT p99 casi se triplica. Esto significa que la caché KV está llena y las peticiones esperan en cola en lugar de ejecutarse. El punto de operación útil está antes: con 32 flujos, el equipo todavía devuelve 1728 tokens por segundo, el 75 por ciento de su máximo, a 54 tokens por segundo por flujo y con un TTFT p99 de 498 ms. Informe de ese punto como su capacidad. El máximo de la curva no es un valor que pueda ofrecer a los usuarios.
Ollama y vLLM no miden lo mismo
Ejecute esa prueba contra un servidor Ollama con la configuración predeterminada y el total apenas cambiará. OLLAMA_NUM_PARALLEL tiene el valor predeterminado 1, por lo que se ejecuta una solicitud mientras las demás esperan. La cola hace que aumente el TTFT p99, mientras el total de salida permanece estable. Auméntelo antes de medir cualquier cosa.
sudo systemctl edit ollama.service[Service]
Environment="OLLAMA_NUM_PARALLEL=8"Reinicie con sudo systemctl restart ollama y confirme que el modelo sigue cabiendo. Cada ranura paralela obtiene su propia parte de la ventana de contexto, por lo que la documentación de Ollama indica que un contexto de 2K con 4 solicitudes paralelas asigna 8K. Aumente lo suficiente el número de ranuras y el modelo dejará de caber en la VRAM. Compruebe ollama ps: si una columna PROCESSOR muestra algo como 48%/52% CPU/GPU, parte del modelo está en la CPU. En ese caso, el rendimiento disminuirá al aumentar la concurrencia en lugar de aumentar. Una vez ocupadas las ranuras paralelas, las solicitudes se ponen en cola hasta OLLAMA_MAX_QUEUE, cuyo valor predeterminado es 512. Después, el servidor responde con 503.
vLLM usa batching continuo. Por eso admite solicitudes nuevas en el lote en ejecución a medida que se liberan ranuras. Su curva sigue aumentando hasta que se agota la caché KV. Ollama está optimizado para un modelo, una máquina y un coste de configuración bajo. Por tanto, ambos motores producen respuestas diferentes ante la misma prueba. Ese es el tema real de Ollama y vLLM comparados como motores de serving. Registre qué motor y qué versión produjeron cada valor.
Cinco formas de medir lo que no corresponde
- El cliente está lejos. Ejecutar el benchmark desde el portátil a través de Internet añade el tiempo de ida y vuelta a cada TTFT, por lo que se mide la conexión doméstica. Ejecute el cliente en la misma región que el servidor.
- El modelo estaba frío. La primera petición incluye la carga de los pesos y, en vLLM, también puede incluir la captura del grafo. Envíe un lote de calentamiento y descarte el resultado.
- La caché de prefijos respondió por usted. vLLM habilita la caché automática de prefijos de forma predeterminada. Por tanto, enviar el mismo prompt repetidamente mide la caché en lugar del prefill, y el TTFT se reduce a una fracción del valor real.
--dataset-name randomevita esto porque cada prompt es diferente. Para asegurarse, inicie el servidor con--no-enable-prefix-caching. - Las salidas eran cortas. Con respuestas de 32 tokens, el TTFT domina cada petición y los tokens por segundo describen realmente el prefill. Use
--ignore-eoscon una longitud de salida realista. - Informó de una concurrencia de 1. Es el número más favorable de la tabla y no guarda relación con el coste.
Convierte la cifra medida en una decisión
Toma el rendimiento de salida sostenido de tu prueba, no la tasa de un solo flujo, y compáralo con el precio por token. El punto de equilibrio se obtiene con una división:
break_even_tok_s = (price_per_hour / price_per_million_output_tokens) * 1000000 / 3600Haz el cálculo con los precios de DigitalOcean de julio de 2026. Su endpoint de inferencia dedicado H200 costaba $4.47 por hora y el equivalente serverless costaba $0.65 por millón de tokens. Por tanto, 4.47 dividido entre 0.65 son 6.88 millones de tokens por hora. Al dividir entre 3,600 segundos, se obtienen aproximadamente 1,910 tokens de salida por segundo. Los precios son de DigitalOcean. La división es nuestra.
La palabra decisiva es sostenido. Alcanzar 1,910 tokens por segundo a plena carga durante dos horas al día no equivale a mantener 1,910 tokens por segundo, porque también pagas las otras veintidós horas. El propio punto de cruce de DigitalOcean para el GPU Droplet más barato, de $3.44 por hora, se sitúa en una utilización media sostenida del 72.2 por ciento. Por debajo de ese nivel, gana el precio por token. Las horas de GPU inactiva, no los tokens lentos, son las que suelen hacer que el self-hosting deje de ser rentable.
Por tanto, tu decisión tiene dos datos de entrada. La prueba te da el límite máximo. Tu patrón de tráfico te da la fracción de ese límite que realmente utilizas. Multiplícalos y lleva el resultado a el punto de equilibrio entre GPU VPS y API con precio por token para obtener la respuesta correspondiente a tu volumen.
FAQ
¿Cuál es una buena cantidad de tokens por segundo para un LLM autoalojado?
Hay dos respuestas, porque esta métrica cumple dos funciones. Para una persona que lee la salida, cualquier valor superior a aproximadamente 20 tokens de salida por segundo y por flujo ya supera la velocidad de lectura, por lo que una cifra mayor no aporta ventajas. Para calcular el coste, importa el rendimiento total sostenido de salida con el sistema saturado. Un valor adecuado es el que permite superar el punto de equilibrio. Con un coste de $0.65 por millón de tokens en un equipo de $4.47 por hora, ese umbral se sitúa cerca de 1,910 tokens de salida por segundo sostenidos a los precios de julio de 2026. Un solo flujo con un modelo grande nunca lo alcanza. Por eso existe el procesamiento por lotes.
¿Por qué el rendimiento de Ollama no cambia cuando añado solicitudes simultáneas?
OLLAMA_NUM_PARALLEL tiene el valor predeterminado 1. Por tanto, el servidor procesa una solicitud cada vez por modelo y pone las demás en cola, hasta OLLAMA_MAX_QUEUE (512 de forma predeterminada), antes de devolver 503. La salida total permanece estable mientras aumenta p99 TTFT. Este patrón indica que hay una cola, no que la GPU esté ocupada. Establezca la variable en un drop-in de systemd y reinicie el servicio. Después, compruebe ollama ps, porque cada ranura paralela multiplica el contexto asignado y puede hacer que parte del modelo se ejecute en la CPU.
¿Debo medir el tiempo hasta el primer token o los tokens por segundo?
Ambos, porque evolucionan en direcciones opuestas cuando aumenta la carga. TTFT es lo que percibe el usuario, mientras que el rendimiento de salida con el sistema saturado es lo que se refleja en la factura. Registre p50 y p99 TTFT en cada nivel de concurrencia. Después, elija el nivel de concurrencia más alto en el que p99 TTFT siga siendo aceptable para usted. Informe del rendimiento obtenido en ese punto como su capacidad. No use el valor máximo del extremo superior de la curva.
¿Una cifra mayor de tokens por segundo siempre implica un coste menor por token?
No. El coste por token es el precio por hora dividido por los tokens que el equipo produjo realmente durante esa hora. Por tanto, un servidor rápido que permanece inactivo la mayor parte del día sigue teniendo un coste elevado por token. El factor determinante es la utilización, no la velocidad máxima. Preste atención también a las unidades: una cifra de rendimiento total de tokens incluye los tokens de entrada. Con una proporción de entrada a salida de 1:1, esa cifra se aproxima al doble de la tasa de salida que se factura.