SSD Nodes Learn 🎉 VPS desde $4.99/mês
Guias Matt ConnorPor Matt Connor · Atualizado 2026-08-07

Como medir tokens por segundo em um LLM local

Veja como medir tokens por segundo com uma varredura de concorrência e descubra o throughput mínimo para uma GPU alugada superar o custo por token.

Por que tokens por segundo determinam se uma GPU compensa

Tokens por segundo é a taxa a que o seu servidor produz texto de saída. Esse é o valor que determina se alugar uma GPU fica mais barato do que pagar a uma API por token. Uma máquina com GPU é faturada à hora, esteja ocupada ou ociosa. Uma API alojada é faturada por token. Portanto, a GPU só compensa se mantiver uma taxa de saída suficientemente elevada durante a maior parte das horas pagas.

Isto significa que precisa de uma medição, não de um valor consultado noutro lugar. Esta página define os quatro valores que vale a pena registar. Em seguida, apresenta os comandos que os produzem e os cálculos que os transformam numa decisão.

Por que uma taxa publicada de tokens por segundo não é a sua

A DigitalOcean publicou, em julho de 2026, números de throughput para uma única NVIDIA H200 executando llama3.3-70b-instruct em FP8 (ponto flutuante de 8 bits) com vLLM. Esses números são úteis, mas não são os seus.

ChartPublished DigitalOcean H200 figures, llama3.3-70b-instruct FP8, July 2026
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"
  }
]

Todas as linhas acima foram copiadas dessa página, e duas delas correspondem ao limite inferior de um intervalo apresentado nela. Portanto, leia essas duas como um valor mínimo. Nenhum número deste gráfico foi medido por nós.

Comece pelas duas últimas linhas. O valor de destaque é 4,071.6 tok/s, enquanto a taxa apenas de saída é 2,036 tok/s. O valor de destaque contabiliza os tokens de entrada e de saída em conjunto. Esse teste usou 1,024 tokens de entrada e 1,024 tokens de saída, portanto quase metade do valor de destaque corresponde à saída. Essa divisão é importante porque a cobrança é feita sobre a saída, que é a parte mais lenta. O prefill, que lê o prompt, processa todos os tokens de entrada numa única passagem. O decode, que escreve a resposta, produz um token de cada vez. Um valor de throughput total calcula a média entre uma operação barata e outra cara.

Agora, observe a primeira linha. A mesma H200, atendendo uma solicitação de cada vez, produz 47 tok/s. Portanto, o valor saturado é mais de quarenta vezes maior no mesmo hardware. Essa diferença existe porque, durante a maior parte do tempo, uma única etapa de decode deixa a GPU à espera da memória, e as solicitações concorrentes ocupam esse tempo ocioso. A segunda linha, 236 tok/s, corresponde a uma única H100 com o mesmo modelo, limitada pelo KV cache (o cache de chave e valor, ou seja, a memória por solicitação que uma conversa atendida mantém na placa). Uma placa de 80 GB comporta menos solicitações concorrentes para um modelo 70B, por isso atinge a saturação com uma taxa menor.

Altere o modelo ou a proporção entre tokens de entrada e de saída, e todos os números acima mudarão. Os números publicados definem as suas expectativas, não o seu orçamento. A mesma regra se aplica a avaliar honestamente o desempenho de uma VPS em disco e rede.

Os quatro números que importam

  • Tempo até ao primeiro token, TTFT. É o atraso entre o envio de um pedido e a chegada do primeiro token de saída. Inclui o tempo de prefill e o tempo na fila. O utilizador sente diretamente este valor.
  • Tokens de saída por segundo, por stream. Indica a velocidade a que uma resposta é escrita depois de começar. Acima de aproximadamente 20 tok/s, a resposta já é mais rápida do que a maioria das pessoas consegue ler. Por isso, obter mais velocidade neste ponto traz poucos benefícios.
  • Throughput total de saída sob saturação. É a soma de todos os streams concorrentes quando o servidor está totalmente carregado. Este é o valor da capacidade e é o que determina o custo da GPU.
  • TTFT p50 e p99 sob concorrência. p50 é o pedido mediano. p99 é o valor abaixo do qual ficam 99 em cada 100 pedidos. O tempo na fila aparece primeiro no p99.

Os dois primeiros melhoram quando o servidor está pouco ocupado. O terceiro melhora quando o servidor está ocupado. Estes valores entram em conflito, por isso nenhum número isolado descreve um servidor de serving.

Corrija os comprimentos de entrada e saída antes de medir

O throughput depende do formato do tráfego. Um prompt com 4,000 tokens e uma resposta com 50 tokens representa uma carga dominada pelo prefill. Um prompt com 200 tokens e uma resposta com 2,000 tokens representa uma carga dominada pelo decode. O mesmo servidor apresenta valores muito diferentes de tokens por segundo nesses dois casos. Por isso, escolha uma proporção, escreva-a junto de cada valor registado e nunca compare valores de proporções diferentes. 1,024 tokens de entrada e 1,024 tokens de saída é um padrão razoável, porque vários fornecedores publicam resultados nessa proporção. Se conhecer o seu tráfego real, use o tráfego real.

Force também o comprimento da saída. Um modelo que atinge o seu token de paragem após 60 tokens produz uma execução mais curta que parece mais rápida, porque o TTFT representa uma parte maior dessa execução. A flag --ignore-eos no cliente de benchmark do vLLM faz com que cada pedido gere exatamente a quantidade solicitada, mantendo duas execuções comparáveis. A escolha do modelo altera estes valores mais do que qualquer flag: colocar um modelo Qwen 3 numa única GPU de VPS aborda o aspeto de memória dessa escolha.

Medir primeiro um único fluxo

Comece pelo caso mais simples. É uma verificação de coerência e também estabelece um limite superior. O Ollama apresenta os seus próprios tempos.

ollama run llama3.1:8b --verbose "Write 200 words about disk scheduling."

A linha a consultar é eval rate, que corresponde ao número de tokens de saída por segundo. prompt eval rate é a taxa de prefill, e load duration é o tempo gasto a carregar o modelo para a VRAM. Na primeira chamada depois de um arranque a frio, load duration é elevado, por isso total duration é enganador. Execute o comando duas vezes e leia o segundo resultado. Por predefinição, o Ollama descarrega um modelo inativo após cinco minutos, por isso uma pausa longa entre execuções coloca-o novamente no caso de arranque a frio.

Os mesmos campos são disponibilizados pela API, o que facilita a criação de 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á em nanossegundos, por isso a divisão por 1,000,000,000 dá o valor em segundos. Essa divisão é exatamente a que a documentação da API do Ollama prescreve para calcular tokens por segundo. Se o servidor ainda não estiver ativo, alojar um LLM localmente com Ollama numa VPS explica a instalação e a unidade do systemd.

O TTFT requer um pedido de streaming, e o curl pode medir esse tempo por si.

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 é o momento em que chega o primeiro byte do corpo da resposta. Numa conclusão de chat em streaming, esse byte pertence ao primeiro evento enviado pelo servidor, que pode ser o primeiro token de conteúdo ou um delta que contém apenas a função, enviado imediatamente antes dele. Por isso, considere o valor como o TTFT, com uma margem de um evento. É suficientemente preciso para comparar duas execuções no mesmo servidor.

Os números de um único fluxo favorecem o servidor de duas formas. O TTFT está no melhor valor possível, porque não há pedidos à sua frente na fila. A taxa por fluxo também está no melhor valor possível, porque a placa inteira está a servir um único pedido. Nenhum dos dois valores indica a carga que o servidor consegue suportar.

Como executar uma varredura de concorrência?

Uma varredura executa a mesma carga de trabalho fixa com níveis de concorrência crescentes e regista o resultado de cada etapa. O vLLM fornece o cliente para esta tarefa, e ele usa a API OpenAI. Por isso, também funciona com o Ollama e com qualquer outro serviço compatível com a 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 os pedidos em execução, e é a variável que está a ser testada. --num-prompts é o total de pedidos enviados, por isso mantenha-o próximo de dez vezes a concorrência para obter uma média estável. O resumo apresenta Output token throughput (tok/s): e Total token throughput (tok/s):, seguidos de Mean TTFT (ms):, Median TTFT (ms): e P99 TTFT (ms): sob um cabeçalho Time to First Token.

A saída não apresenta a taxa por fluxo, mas é possível obtê-la com uma divisão. Mean TPOT (ms): é o tempo médio por token de saída depois do primeiro. Assim, 25 ms por token correspondem a 40 tokens por segundo por fluxo. Dividir o débito de saída pela concorrência produz o mesmo resultado.

Depois, execute o teste num ciclo e guarde cada execução.

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
Leitura dos ficheiros JSON guardados

Cada execução escreve um ficheiro. Assim, pode extrair de uma só vez os campos pretendidos de todos os ficheiros.

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 é o número de tokens de saída por segundo. total_token_throughput inclui também os tokens de entrada, por isso, numa proporção de 1:1, fica próximo do dobro. p99_ttft_ms existe apenas porque --metric-percentiles incluiu 99; se pedir um percentil que não solicitou, o jq imprime null.

O que é que um sweep de concorrência mostra efetivamente?

ChartIllustrative sweep shape: 8B model, one 24 GB GPU, 1024 in / 1024 out
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
  }
]

Estas 6 linhas ilustram o formato produzido por um sweep numa GPU pequena, alugada, com ordens de grandeza plausíveis. Não são uma medição do seu servidor nem um valor fornecido pelo fabricante. Execute o loop acima e substitua-as pelos seus valores.

Leia o formato, porque é o formato que se generaliza. Com um stream, a máquina inteira produz 92 tokens por segundo, com um TTFT p99 de 61 ms. Em 128 streams, o total chega a 2304 tokens por segundo, 25 vezes mais, enquanto cada stream individual desce para 18 tokens por segundo e o TTFT p99 chega a 3820 ms. O throughput total aumenta porque o batching transforma esperas de memória ociosas em trabalho útil. A velocidade por stream diminui porque o mesmo processamento passa a ser partilhado.

A última duplicação é o indicador decisivo. Passar de 64 para 128 streams acrescenta menos de 6 por cento ao total, enquanto o TTFT p99 quase triplica. Isto significa que a cache KV está cheia e que os pedidos estão a entrar em fila em vez de serem processados. O ponto de operação útil é anterior: com 32 streams, a máquina ainda devolve 1728 tokens por segundo, 75 por cento do pico, a 54 tokens por segundo por stream e com um TTFT p99 de 498 ms. Apresente esse ponto como a sua capacidade. O pico da curva não é um valor a partir do qual possa servir utilizadores.

Ollama e vLLM não medem a mesma coisa

Execute essa varredura contra um servidor Ollama com a configuração padrão e o total quase não vai mudar. OLLAMA_NUM_PARALLEL tem o valor padrão 1, portanto uma solicitação é processada enquanto as restantes aguardam. É a fila que faz o p99 de TTFT aumentar, enquanto o total de saída permanece estável. Aumente esse valor antes de fazer qualquer medição.

sudo systemctl edit ollama.service
[Service]
Environment="OLLAMA_NUM_PARALLEL=8"

Reinicie com sudo systemctl restart ollama e confirme que o modelo ainda cabe. Cada slot paralelo recebe a sua própria parte da janela de contexto. Por isso, a documentação do Ollama observa que um contexto de 2K com 4 solicitações paralelas aloca 8K. Se aumentar demasiado o número de slots, o modelo excede a VRAM. Consulte ollama ps: uma coluna PROCESSOR com um valor semelhante a 48%/52% CPU/GPU indica que parte do modelo está na CPU. Nesse caso, o throughput diminui à medida que aumenta a concorrência, em vez de aumentar. Depois de esgotar os slots paralelos, as solicitações ficam em fila até OLLAMA_MAX_QUEUE, que é 512 por padrão. Depois disso, o servidor responde com 503.

O vLLM usa batching contínuo. Assim, admite novas solicitações no batch em execução à medida que os slots ficam livres, e a curva continua a subir até a cache KV se esgotar. O Ollama é otimizado para um modelo, uma máquina e baixo custo de configuração. Por isso, os dois mecanismos produzem respostas diferentes para a mesma varredura. Esse é o tema principal de Ollama e vLLM comparados como mecanismos de serving. Registre qual mecanismo e qual versão produziram cada valor.

Cinco formas de medir a coisa errada

  • O cliente está longe. Fazer o benchmark a partir do portátil pela Internet adiciona o seu round trip a cada TTFT, pelo que está a medir a sua ligação doméstica. Execute o cliente na mesma região que o servidor.
  • O modelo estava frio. O primeiro pedido inclui o carregamento dos pesos e, no vLLM, também pode incluir a captura do grafo. Envie um lote de aquecimento e descarte o resultado.
  • O cache de prefixos respondeu por si. O vLLM ativa o cache automático de prefixos por predefinição. Assim, enviar o mesmo prompt repetidamente mede o cache em vez do prefill, e o TTFT diminui para uma fração do valor real. --dataset-name random evita isto porque cada prompt é diferente. Para garantir esse comportamento, inicie o servidor com --no-enable-prefix-caching.
  • As respostas eram curtas. Com respostas de 32 tokens, o TTFT domina cada pedido e os seus tokens por segundo descrevem, na realidade, o prefill. Use --ignore-eos com um comprimento de saída realista.
  • Indicou concorrência 1. É o número mais favorável na folha e não tem relação com o custo.

Transforme o número medido numa decisão

Use o throughput de saída saturado do seu teste, não a taxa de fluxo único, e compare-o com o preço por token. O ponto de equilíbrio é uma divisão:

break_even_tok_s = (price_per_hour / price_per_million_output_tokens) * 1000000 / 3600

Faça o cálculo com os preços da DigitalOcean em julho de 2026. O endpoint dedicado de inferência H200 custava $4.47 por hora, e o equivalente serverless custava $0.65 por milhão de tokens. Portanto, 4.47 dividido por 0.65 resulta em 6.88 milhões de tokens por hora. Dividindo por 3,600 segundos, obtém-se cerca de 1,910 tokens de saída por segundo. Os preços são da DigitalOcean. A divisão é nossa.

A palavra decisiva é sustentado. Atingir 1,910 tokens por segundo em saturação durante duas horas por dia não significa sustentar 1,910 tokens por segundo, porque as outras vinte e duas horas também são cobradas. O próprio ponto de crossover da DigitalOcean para o GPU Droplet mais barato, a $3.44 por hora, corresponde a 72.2 por cento de utilização média sustentada. Abaixo desse valor, o preço por token é mais vantajoso. Normalmente, são as horas de GPU ociosas, e não os tokens processados lentamente, que tornam o self-hosting inviável.

A sua decisão tem, portanto, duas entradas. O teste fornece o limite máximo. O seu padrão de tráfego fornece a fração desse limite que realmente utiliza. Multiplique os dois valores e compare o resultado com o ponto de equilíbrio entre GPU VPS e API com preço por token para obter a resposta para o seu volume.

FAQ

Qual é uma boa taxa de tokens por segundo para um LLM alojado localmente?

Há duas respostas, porque esta métrica tem duas finalidades. Para uma pessoa que lê a saída, qualquer valor acima de aproximadamente 20 tokens de saída por segundo por stream já é superior à velocidade de leitura, pelo que um valor maior não ajuda. Para o custo, o valor relevante é o throughput total de saída com a capacidade saturada. Um valor bom é aquele que ultrapassa o ponto de equilíbrio. Com um custo de $0.65 por milhão de tokens e um servidor que custa $4.47 por hora, esse limite fica perto de 1,910 tokens de saída por segundo de forma sustentada, aos preços de July 2026. Um único stream num modelo grande nunca atinge esse valor. É por isso que existe o processamento em lotes.

Porque é que o throughput do Ollama permanece constante quando adiciono pedidos concorrentes?

OLLAMA_NUM_PARALLEL tem o valor predefinido 1, pelo que o servidor processa um pedido de cada vez por modelo e coloca os restantes numa fila, até OLLAMA_MAX_QUEUE (512 por predefinição), antes de devolver 503. A saída total permanece constante enquanto o p99 TTFT aumenta. Este é o padrão típico de uma fila, não de uma GPU ocupada. Defina a variável num drop-in do systemd e reinicie o serviço. Depois, verifique ollama ps, porque cada slot paralelo multiplica o contexto alocado e pode fazer com que parte do modelo seja executada na CPU.

Devo medir o tempo até ao primeiro token ou os tokens por segundo?

Ambos, porque evoluem em sentidos opostos à medida que a carga aumenta. O TTFT é aquilo que o utilizador sente. O throughput de saída com a capacidade saturada é aquilo que se reflete na fatura. Registe o TTFT p50 e p99 em cada nível de concorrência. Depois, escolha o nível de concorrência mais elevado em que o p99 TTFT ainda seja aceitável para si. Apresente o throughput nesse ponto como a sua capacidade. Não use o valor máximo no topo da curva.

Um valor mais elevado de tokens por segundo significa sempre um custo menor por token?

Não. O custo por token é o preço por hora dividido pelo número de tokens que o servidor produziu efetivamente nessa hora. Por isso, um servidor rápido que permanece ocioso durante a maior parte do dia continua a ter um custo elevado por token. O que determina o resultado é a utilização, não a velocidade máxima. Tenha também atenção às unidades: um throughput total de tokens inclui os tokens de entrada. Com uma proporção de entrada para saída de 1:1, esse valor é aproximadamente o dobro da taxa de saída usada para calcular a faturação.

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