SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor

Cómo medir tokens por segundo en un LLM local

Mide tokens por segundo con una prueba de concurrencia y descubre el umbral real de rendimiento antes de elegir entre alquilar una GPU o pagar 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. Es la cifra que determina si alquilar una GPU cuesta menos que pagar una API por token. Una máquina con GPU se factura por hora, tanto si está ocupada como si está inactiva. Una API alojada se factura por token. Por tanto, la GPU sólo resulta más rentable si mantiene una velocidad de salida suficientemente alta durante la mayor parte de las horas pagadas.

Necesita una medición, no una cifra obtenida de otra fuente. En esta página se definen las cuatro cifras que conviene registrar. Después se muestran los comandos que las obtienen y el cálculo que permite convertirlas 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 ejecutando llama3.3-70b-instruct en FP8 (coma flotante de 8 bits) con vLLM. Las cifras son útiles, pero no son las suyas.

GráficoPublished DigitalOcean H200 figures, llama3.3-70b-instruct FP8, July 2026
Los datos de este gráfico
[
  {
    "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"
  }
]

Todas las filas anteriores están citadas de esa página, y dos de ellas corresponden al extremo inferior de un intervalo que proporciona, así que debe interpretar esas dos como un mínimo. No medimos nada de este gráfico.

Empiece por las dos últimas filas. El titular es de 4,071.6 tok/s, mientras que la tasa sólo de salida es de 2,036 tok/s. El titular cuenta juntos los tokens de entrada y de salida. Esa prueba utilizó 1,024 tokens de entrada y 1,024 tokens de salida, por lo que casi exactamente la mitad del titular corresponde a la salida. Esta separación importa porque la salida 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. Un titular 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 lo que la cifra con saturación es más de cuarenta veces superior con el mismo hardware. Esta diferencia existe porque un paso individual de decodificación deja a la GPU esperando a la memoria durante la mayor parte del tiempo, y las solicitudes simultáneas aprovechan ese tiempo inactivo. La segunda fila, 236 tok/s, corresponde a una sola H100 con el mismo modelo, 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 admite menos solicitudes simultáneas para un modelo de 70B, por lo que alcanza la saturación con un rendimiento menor.

Si cambia el modelo o la proporción entre entrada y salida, todas las cifras anteriores cambian. Las cifras publicadas sirven para establecer expectativas, no el presupuesto; la misma regla se aplica a medir honestamente el rendimiento de una VPS en disco y red.

Los cuatro números que importan

  • Tiempo hasta el primer token, TTFT. Es el retraso entre el envío de una solicitud y la llegada del primer token de salida. Incluye el tiempo de prefill y el tiempo en cola. El usuario percibe este valor directamente.
  • Tokens de salida por segundo, por flujo. Indica la velocidad con la que se escribe una respuesta una vez que ha comenzado. Por encima de aproximadamente 20 tok/s, ya es más rápido de lo que lee 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 es el valor de capacidad y el que determina el coste de la GPU.
  • p50 y p99 de TTFT con concurrencia. p50 es la solicitud intermedia. p99 es el valor por debajo del cual quedan 99 de cada 100 solicitudes. La espera en cola siempre aparece primero en p99.

Los dos primeros mejoran cuando el servidor está poco ocupado. 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.

Fije 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 dominada por el prellenado. Un prompt de 200 tokens con una respuesta de 2,000 tokens es una carga dominada por la decodificación. El mismo servidor informa de valores de tokens por segundo muy distintos en ambos casos. Por eso, elija una proporción, anótela junto a cada valor registrado y no compare valores de proporciones distintas. 1,024 tokens de entrada y 1,024 de salida es un valor predeterminado razonable porque varios proveedores publican resultados con esa proporción. Si conoce su 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 no se puede comparar con una ejecución completa. En ese caso, TTFT representa una proporción mayor del tiempo total, lo que reduce el rendimiento de salida que informa el benchmark, aunque cada solicitud termine antes. La opción --ignore-eos del cliente de benchmark 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: cómo ajustar un modelo Qwen 3 en la GPU de un VPS individual explica el aspecto relacionado con la memoria.

Mida primero un único flujo

Empiece por el caso más sencillo. Sirve como comprobación básica y como límite superior. Ollama muestra sus propias mediciones 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 tasa 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 alto, 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 vuelve a situarle en el caso en frío.

Los mismos campos están disponibles en la API, que resulta más fácil de usar en scripts.

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 prescribe 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.

TTFT requiere una solicitud de streaming, y curl puede medir ese tiempo.

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 mediante 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 indique el rol y se envíe justo antes. Por tanto, considere el valor como el TTFT con un margen de un evento. Es suficientemente preciso para comparar dos ejecuciones en el mismo servidor.

Las cifras de un único flujo favorecen al servidor por dos motivos. El TTFT es el mejor resultado posible, porque no hay solicitudes en cola delante de la suya. La tasa por flujo también es la mejor posible, porque toda la tarjeta atiende una sola solicitud. Ninguna de las dos cifras indica qué carga puede soportar el servidor.

¿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 esta tarea 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 que se somete al barrido. --num-prompts es el total enviado, así que manténgalo 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 la tasa por flujo, pero se obtiene con 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"
done
Lectura de los archivos JSON guardados

Cada ejecución escribe un archivo, así que puede extraer de una vez los campos que le interesen de todos ellos.

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"
done

output_throughput es el número de tokens de salida por segundo. total_token_throughput vuelve a incluir los tokens de entrada, por lo que con una proporción de 1:1 el valor se aproxima al doble. p99_ttft_ms existe sólo porque --metric-percentiles incluyó 99; si solicita un percentil que no pidió, jq muestra null.

¿Qué muestra realmente un barrido de concurrencia?

GráficoIllustrative sweep shape: 8B model, one 24 GB GPU, 1024 in / 1024 out
Los datos de este gráfico
[
  {
    "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 una máquina GPU pequeña 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 valores.

Observe la forma, porque esa forma es la que se puede generalizar. Con un flujo, toda la máquina 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 llega a 3820 ms. El rendimiento total aumenta porque el batching convierte las esperas de memoria inactivas en trabajo útil. La velocidad de cada flujo disminuye porque ahora el mismo cómputo se comparte.

La última duplicación es la señal. Pasar de 64 a 128 flujos añade menos de un 6 por ciento al total, mientras que el TTFT p99 se triplica aproximadamente. Esto significa que las peticiones se acumulan en la cola en lugar de ejecutarse, ya sea porque la caché KV está llena o porque el servidor ha alcanzado un límite del planificador, como max_num_seqs de vLLM. El punto de operación útil está antes: con 32 flujos, la máquina 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 ese punto como su capacidad. El máximo de la curva no es una cifra con la que pueda atender 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 es la que hace que aumente el p99 de TTFT, mientras el total de salida permanece estable. Aumente este valor antes de medir nada.

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 recibe 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 se desbordará de la VRAM. Compruebe ollama ps: si una columna PROCESSOR muestra un valor como 48%/52% CPU/GPU, parte del modelo está en la CPU y el rendimiento disminuirá al aumentar la concurrencia en lugar de aumentar. Cuando se ocupan todas 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 utiliza batching continuo. Por tanto, admite nuevas solicitudes en el batch en ejecución a medida que se liberan ranuras. Su curva sigue aumentando hasta que se agota algún recurso, normalmente la caché KV, aunque un límite configurado como max_num_seqs o la sobrecarga de planificación de la CPU pueden aplanarla antes. Ollama está optimizado para un modelo, una máquina y un coste de configuración bajo. Por tanto, los dos motores dan respuestas diferentes a la misma prueba, que es el tema principal de Comparación de Ollama y vLLM como motores de servicio. Registre qué motor y qué versión produjeron cada número.

Cinco formas de medir lo que no corresponde

  • El cliente está lejos. Hacer pruebas desde el portátil a través de Internet añade el tiempo de ida y vuelta de su conexión a cada TTFT, por lo que mide su 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 random evita este problema 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 en realidad el prefill. Use --ignore-eos con una longitud de salida realista.
  • Sólo informó de la concurrencia 1. Proporciona el TTFT más favorable de la tabla y es el dato de coste adecuado únicamente si las peticiones reales nunca se solapan. Si se solapan, el coste depende del rendimiento que mantenga con la concurrencia que genere realmente su tráfico. Por tanto, mídalo también en ese nivel.

Convierte el valor medido en una decisión

Toma el rendimiento de salida que muestra tu prueba con el nivel de concurrencia que alcanza tu tráfico real y compáralo con el precio por token. Esa cifra corresponde al rendimiento saturado sólo si se solapan suficientes solicitudes para mantener lleno el lote. Una carga de trabajo que envía una solicitud cada vez debe usar su rendimiento de un solo flujo. El punto de equilibrio se obtiene con una división, después de calcular el precio de los tokens de entrada que llegan con cada token de salida:

cost_per_million_output = price_out + price_in * (input_tokens / output_tokens)
break_even_tok_s = (price_per_hour / cost_per_million_output) * 1000000 / 3600

Haz el cálculo con los precios de DigitalOcean de julio de 2026. Su endpoint de inferencia dedicado H200 costaba $4.47 por hora, y Llama 3.3 70B serverless costaba $0.65 por millón de tokens de entrada y $0.65 por millón de tokens de salida. Con la proporción 1:1 usada antes, cada millón de tokens de salida incluye un millón de tokens de entrada, por lo que el precio efectivo es de $1.30 por millón de tokens de salida. Por tanto, 4.47 dividido entre 1.30 da aproximadamente 3.44 millones de tokens de salida por hora, y al dividir entre 3,600 segundos se obtienen aproximadamente 955 tokens de salida por segundo, o unos 1,910 tokens por segundo contando conjuntamente la entrada y la salida. Los precios son de DigitalOcean. La división es nuestra. Cuando lo comprobamos el 10 de octubre de 2026, el endpoint H200 seguía costando $4.47 por hora, pero DigitalOcean retiró Llama 3.3 70B serverless el 18 de agosto de 2026 y dirige a los usuarios a Llama 4 Maverick, cuyo precio publicado es de $0.25 por millón de tokens de entrada y $0.87 por millón de tokens de salida. Es un modelo diferente, por lo que necesita su propia prueba antes de que la comparación tenga sentido.

La palabra decisiva es sostenido. Alcanzar 955 tokens de salida por segundo con saturación durante dos horas al día no equivale a mantener 955 tokens de salida por segundo, porque también pagas las otras veintidós horas. Alquilar la tarjeta como GPU Droplet tampoco reduce el umbral: el 10 de octubre de 2026, los precios de Droplet de DigitalOcean mostraban la H200 a $4.47 por hora bajo demanda, igual que el endpoint, y sus GPU Droplets NVIDIA más baratos, la RTX 4000 a $0.76 por hora y la L40S o RTX 6000 a $1.57 por hora, son demasiado pequeños para alojar un modelo 70B en FP8. Por tanto, con las cifras anteriores, una H200 que alcanza 2,036 tokens de salida por segundo con saturación debe promediar aproximadamente el 47 por ciento de ese máximo durante todas las horas que pagas sólo para igualar $0.65 por millón de tokens de entrada y salida; por debajo de ese nivel, gana el precio por token. Las horas de GPU sin uso, y no los tokens lentos, son lo que suele hacer fracasar el alojamiento propio.

Por tanto, tu decisión tiene dos datos de entrada. La prueba te proporciona el límite máximo. Tu patrón de tráfico indica qué fracción de ese límite cobras realmente. Multiplícalos y lleva el resultado a el punto de equilibrio entre GPU VPS y API por token para obtener la respuesta correspondiente a tu volumen.

FAQ

¿Cuál es una buena velocidad 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 el coste, importa el rendimiento total de salida que pueda mantener con su carga real. Una cifra adecuada es la que permite superar el punto de equilibrio. Con un precio de $0.65 por millón de tokens, tanto de entrada como de salida, y un servidor que cuesta $4.47 por hora, ese umbral se sitúa cerca de 955 tokens de salida por segundo mantenidos con una relación 1:1 y los precios de julio de 2026. Un único flujo con un modelo grande nunca lo alcanza. Por eso existe el procesamiento por lotes.

¿Por qué el rendimiento de Ollama se mantiene constante cuando añado solicitudes simultáneas?

OLLAMA_NUM_PARALLEL tiene el valor predeterminado 1, por lo que 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 se mantiene constante mientras aumenta p99 TTFT. Este patrón indica que hay una cola y no que la GPU esté ocupada. Establezca la variable en un drop-in de systemd y reinicie. Después, compruebe ollama ps, porque cada ranura paralela multiplica el contexto asignado y puede hacer que parte del modelo pase a 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 más alto en el que p99 TTFT siga siendo aceptable para usted. Informe del rendimiento en ese punto como su capacidad. No use el máximo situado en la parte superior de la curva.

¿Una cifra mayor de tokens por segundo siempre significa un coste menor por token?

No. El coste por token es el precio por hora dividido entre los tokens que el servidor produjo realmente durante esa hora. Por tanto, un servidor rápido que permanece inactivo la mayor parte del día sigue teniendo un coste por token elevado. Lo determina la utilización, no la velocidad máxima. Revise también las unidades: una cifra citada de rendimiento total de tokens incluye los tokens de entrada. Con una relación 1:1 entre tokens de entrada y de salida, el valor se aproxima al doble de la velocidad de salida. Si la API con la que compara cobra tanto los tokens de entrada como los de salida, calcule el precio de ambas partes antes de compararlas.

#benchmarking#tokens-per-second#vllm#ollama#gpu-vps