Ollama: como definir num_ctx e evitar truncamento
O Ollama pode truncar prompts longos sem aviso. Veja como definir num_ctx por pedido ou no servidor e calcular a RAM da cache KV antes de aumentar o limite.
O que num_ctx faz e por que o seu prompt longo foi truncado
O tamanho do contexto do Ollama é o número de tokens que um modelo carregado consegue manter na memória ao mesmo tempo, e num_ctx é a opção que o define. O Ollama escolhe um valor predefinido muito inferior ao máximo anunciado pelo modelo. Por isso, um prompt mais longo é truncado antes de o modelo o ler. A resposta não indica que isso aconteceu.
A biblioteca de modelos do Ollama lista o Llama 3.1 8B com uma janela de contexto de 128k. Um servidor com a configuração padrão não disponibiliza esse valor. A documentação do próprio Ollama apresenta valores predefinidos diferentes em páginas diferentes: a FAQ indica 4096 tokens, a referência do Modelfile indica que num_ctx tem o valor predefinido de 2048, e a página sobre o tamanho do contexto diz que o valor predefinido é escolhido com base na VRAM disponível: 4k abaixo de 24 GiB, 32k de 24 GiB até 48 GiB e 256k a partir de 48 GiB. Cada valor foi válido para alguma versão. A lição útil é esta: consulte o valor no seu próprio servidor em execução, em vez de confiar em qualquer página, incluindo esta.
O truncamento é silencioso porque o modelo continua a responder, e a resposta continua a parecer correta. No entanto, foi produzida a partir do final da sua entrada. Um resumo que não inclui a primeira metade de um documento parece indicar um modelo fraco. Normalmente, indica uma janela de contexto pequena.
Verifique o comprimento de contexto que o servidor Ollama aplicou efetivamente
A verificação que funciona em qualquer build é prompt_eval_count, a contagem de tokens do prompt que o servidor indica ter processado. Envie mais tokens do que o contexto consegue suportar. Esse número para no limite.
sudo apt update && sudo apt install -y jq
LONG=$(python3 -c "print('the quick brown fox jumps over the lazy dog. ' * 2000)")
jq -n --arg p "$LONG" '{model:"llama3.1:8b", prompt:$p, stream:false, options:{num_ctx:4096}}' |
curl -s http://localhost:11434/api/generate -d @- |
jq '{prompt_eval_count, prompt_eval_duration}'Esse prompt tem cerca de 18,000 palavras, muito mais do que 4096 tokens. prompt_eval_count devolve um valor próximo de 4096, e não próximo da contagem real de tokens, porque o servidor descartou o restante. Execute-o novamente com "num_ctx":16384. A contagem aumenta. Se a sua build devolver um erro em vez de truncar o prompt, a conclusão é a mesma, mas o sinal é mais claro.
ollama psA coluna CONTEXT, nas builds que a mostram, contém o comprimento de contexto com que o modelo carregado está a ser executado neste momento. A coluna PROCESSOR, ao lado, mostra onde o modelo está a ser executado. 100% CPU é normal numa VPS sem GPU. Uma divisão como 30%/70% CPU/GPU num servidor com GPU significa que os pesos e a cache já não cabem na VRAM. Um valor elevado em num_ctx é normalmente a causa.
journalctl -u ollama --no-pager | grep -i n_ctx | tail -n 5O runner de inferência mostra o tamanho do contexto numa linha que contém n_ctx. O texto exato varia entre releases. Por isso, interprete uma linha ausente como uma alteração do nome, e não como prova de qualquer conclusão.
Quatro locais para definir num_ctx
No pedido. Envie "options": {"num_ctx": 16384} para /api/generate ou /api/chat. Esta definição tem precedência sobre todas as outras e aplica-se apenas a essa chamada. Se o valor for diferente do valor com que o modelo carregado está a ser executado, o servidor recarrega primeiro o modelo. Isto pode ser observado em load_duration na resposta: o valor passa de quase zero para vários segundos. A mesma espera ocorre quando o modelo fica inativo tempo suficiente para ser descarregado. Por isso, depois de definir o tamanho do contexto, vale a pena manter o modelo residente com keep_alive.
Na sessão interativa. Dentro de ollama run, introduza /set parameter num_ctx 16384. A definição mantém-se durante essa sessão.
Num Modelfile. Isto incorpora o valor num modelo com nome. Assim, todos os clientes recebem esse valor sem alterações do lado do cliente.
FROM llama3.1:8b
PARAMETER num_ctx 16384ollama create llama3.1-16k -f ./Modelfile
ollama run llama3.1-16kNo servidor. OLLAMA_CONTEXT_LENGTH define o valor predefinido para todos os pedidos que não incluam o seu próprio num_ctx. Com systemd, adicione um drop-in em vez de editar o ficheiro da unidade.
sudo systemctl edit ollama.service[Service]
Environment="OLLAMA_CONTEXT_LENGTH=16384"sudo systemctl daemon-reload
sudo systemctl restart ollama
ollama psA precedência é especialmente importante ao depurar o cliente de outra pessoa. Um pedido que inclua num_ctx tem precedência sobre o valor predefinido do servidor. Por isso, um frontend de chat ou um agente que envie silenciosamente um valor reduzido substitui a alteração feita no systemd. Quando apontar um agente de programação para o seu servidor Ollama, verifique o que o cliente envia antes de atribuir o problema ao servidor.
Por que não pode simplesmente definir num_ctx para o máximo do modelo
A atenção faz com que cada token consulte todos os tokens anteriores. As chaves e os valores calculados para os tokens anteriores são mantidos, para não serem recalculados a cada novo token. Esse armazenamento é a KV cache (key/value cache). Ela é alocada para todo o num_ctx quando o modelo é carregado, e não à medida que a conversa cresce. Por isso, um contexto grande consome essa memória mesmo com um prompt de uma linha.
Cada camada mantém um vetor de chave e um vetor de valor por cabeça de chave/valor para cada token. O cálculo cabe numa linha:
kv_bytes_per_token = 2 * layers * kv_heads * head_dim * bytes_per_valueO 2 representa as chaves e os valores separadamente. Consulte os outros números no seu próprio modelo.
curl -s http://localhost:11434/api/show -d '{"model":"llama3.1:8b"}' |
jq '.model_info | {ctx: ."llama.context_length", layers: ."llama.block_count", heads: ."llama.attention.head_count", kv_heads: ."llama.attention.head_count_kv", embed: ."llama.embedding_length"}'O Llama 3.1 8B informa 32 camadas e 8 cabeças de chave/valor. A dimensão da cabeça é embed dividida por heads, portanto 4096 / 32 = 128 neste caso. Alguns modelos publicam esse valor diretamente como llama.attention.key_length. A cache padrão mantém valores f16, portanto bytes_per_value é 2, e 2 32 8 128 2 resulta em 131,072 bytes. Isso corresponde a 128 KiB de cache por cada token de contexto. Multiplique pelo tamanho do contexto e o custo deixa de ser abstrato.
Os dados por trás deste gráfico
[
{
"label": "4k",
"kv_cache_gib": 0.5,
"total_ram_gib": 5.1
},
{
"label": "8k",
"kv_cache_gib": 1,
"total_ram_gib": 5.6
},
{
"label": "16k",
"kv_cache_gib": 2,
"total_ram_gib": 6.6
},
{
"label": "32k",
"kv_cache_gib": 4,
"total_ram_gib": 8.6
},
{
"label": "64k",
"kv_cache_gib": 8,
"total_ram_gib": 12.6
},
{
"label": "128k",
"kv_cache_gib": 16,
"total_ram_gib": 20.6
}
]As 6 linhas são cálculos baseados na fórmula acima, não medições. A coluna total acrescenta o download de 4.9 GB que a biblioteca Ollama indicava para llama3.1:8b em outubro de 2026, equivalente a 4.6 GiB, e não inclui os buffers de computação nem o próprio processo do servidor. Considere este valor um mínimo.
O objetivo é mostrar a dimensão do problema. Com 8k, a cache custa 1 GiB, um valor insignificante junto do espaço ocupado pelos pesos. Com os 128k completos do modelo, custa 16 GiB, mais de três vezes o tamanho dos pesos, para um total próximo de 20.6 GiB. Portanto, uma VPS de 4 GB não consegue carregar este modelo com um contexto útil. Uma VPS de 8 GB funciona confortavelmente com 8k. Uma VPS de 16 GB chega a 32k e ainda deixa memória disponível para o restante sistema. Cada um desses limites aumenta com o tamanho dos pesos. Se estiver a comparar um modelo maior com este 8B, os mesmos cálculos feitos para a tag 27B do Qwen numa VPS apenas com CPU mostram quanto pouco espaço os pesos deixam para o contexto entre 8 e 64 GB.
O que acontece quando a cache KV não cabe
Num VPS apenas com CPU, o processo simplesmente cresce. Monitorize-o enquanto o modelo é carregado e enquanto é executado um pedido longo.
free -m
ps -eo rss,comm --sort=-rss | head -n 5O RSS (tamanho do conjunto residente) é apresentado em kilobytes. Se o uso de swap em free -m começar a aumentar, reduza o contexto. Uma cache KV que fica na swap faz a geração parar durante segundos por token, porque cada novo token lê a cache inteira.
Se o servidor ficar completamente sem memória, o kernel escolhe um processo para terminar, normalmente o que estiver a usar mais memória.
sudo dmesg | grep -i "killed process"Uma linha com Out of memory: Killed process 1234 (ollama) significa que o Ollama foi o processo escolhido pelo kernel, não necessariamente o processo que esgotou a memória. Num servidor onde o Ollama é o único processo grande, um contexto demasiado grande para caber é normalmente a causa. Verifique o que estava a executar antes de reduzir num_ctx. Muitas vezes, o Ollama recusa o pedido antes de chegar a esse ponto. Nesse caso, o pedido falha com uma mensagem que indica a memória pretendida e a memória livre.
Num servidor com GPU, a falha é menos evidente. As camadas passam para a RAM do sistema, ollama ps mostra a divisão entre CPU e GPU, e o débito diminui acentuadamente. A intensidade dessa redução depende do hardware. Por isso, meça os tokens por segundo no seu próprio servidor em cada definição de contexto, em vez de confiar num valor obtido noutra máquina.
O tempo de prefill cresce mais depressa do que o prompt
Prefill é o trabalho realizado sobre a sua entrada antes de aparecer o primeiro token de saída. Cada token do prompt presta atenção a todos os tokens anteriores, por isso o trabalho total cresce com o quadrado do comprimento da entrada. Duplicar o prompt aumenta o tempo de espera pelo primeiro token mais do que para o dobro.
A resposta inclui a medição, por isso não precisa de aceitar esse valor sem confirmação.
jq -n --arg p "$LONG" '{model:"llama3.1:8b", prompt:$p, stream:false, options:{num_ctx:16384}}' |
curl -s http://localhost:11434/api/generate -d @- |
jq '{tokens: .prompt_eval_count, prefill_seconds: (.prompt_eval_duration/1000000000)}'Execute isso com um prompt curto e depois com um prompt longo. Em cada caso, divida o número de tokens pelo tempo em segundos. Numa VPS apenas com CPU, o prefill costuma ser a parte mais lenta de um pedido com contexto longo. Uma métrica de tokens por segundo obtida com um prompt curto não permite prever esse comportamento. Se o prefill ultrapassar o timeout configurado na camada que está à frente do serviço, o pedido longo normalmente termina com prazo de contexto excedido em vez de devolver uma resposta. Antes de reduzir o contexto, descubra qual camada desistiu.
É com a concorrência que este problema mais se agrava. Cada pedido servido precisa da sua própria cache, por isso a memória apresentada no gráfico acima é por pedido, não por servidor. Um pedido longo pode ocupar o servidor enquanto os pedidos curtos ficam em fila atrás dele. Defina OLLAMA_NUM_PARALLEL deliberadamente e leia quantos utilizadores concorrentes um LLM autoalojado pode servir antes de aumentar ambos os valores em conjunto.
Recupere contexto com uma cache menor
bytes_per_value na fórmula é uma definição sob o seu controlo. A FAQ do Ollama documenta OLLAMA_KV_CACHE_TYPE, com f16 como valor predefinido, q8_0 a usar cerca de metade da memória de f16 e q4_0 a usar cerca de um quarto. O valor exato de q8_0 é ligeiramente superior a metade: o llama.cpp armazena cada bloco de 32 valores como 32 valores de um byte mais uma escala de dois bytes, ou seja, 34 bytes, enquanto f16 precisa de 64. Mudar para q8_0 reduz, portanto, a linha de 32k para cerca de 2.1 GiB, em vez de 4 GiB. Quantizar os pesos liberta memória do outro lado do mesmo orçamento, e a tag GLM que efetivamente cabe num VPS é analisada quantização a quantização se preferir essa troca. A mesma FAQ diz que a cache só é quantizada quando o Flash Attention está ativado e documenta OLLAMA_FLASH_ATTENTION=1 para o forçar.
[Service]
Environment="OLLAMA_FLASH_ATTENTION=1"
Environment="OLLAMA_KV_CACHE_TYPE=q8_0"Confirme em vez de assumir: reinicie o serviço, carregue o modelo com o mesmo num_ctx de antes e compare o RSS. O suporte depende do modelo e do backend, portanto uma definição que não altere nada significa que a sua combinação não é suportada. O tipo de cache é uma opção global, por isso todos os modelos no servidor a utilizam. Quanto à qualidade, a FAQ diz que q8_0 normalmente não tem um efeito percetível, enquanto q4_0 perde mais precisão, sobretudo com tamanhos de contexto maiores. Teste q4_0 com os seus próprios prompts antes de depender dele. Se veio aqui por causa destas opções, Ollama e llama.cpp expõem-nas de forma diferente.
Uma receita para escolher num_ctx
- Consulte
/api/showpara obter o contexto máximo do modelo, o número de camadas e o número de cabeças key/value. - Calcule os bytes por token com a fórmula e, em seguida, multiplique pelo contexto pretendido.
- Some o tamanho dos pesos, compare o resultado com a RAM livre e reserve pelo menos 1 GiB para o restante do servidor.
- Defina o valor, carregue o modelo e confirme o que foi aplicado com
ollama pseprompt_eval_count. - Execute a carga de trabalho real enquanto monitoriza
free -me reduza o contexto para metade se o swap começar a ser utilizado.
A maioria das tarefas precisa de menos contexto do que aquele que é normalmente configurado. Resumir um relatório longo cabe em 16k. Um frontend de retrieval que insere cinco blocos de documentos raramente ultrapassa 8k. Um agente de programação que lê ficheiros completos é o caso que realmente precisa de 64k ou mais. É também o caso em que deve dimensionar a máquina em função do contexto, e não o contrário. Se o próprio servidor ainda for novo, comece por uma instalação funcional do Ollama numa VPS e ajuste o contexto depois de os modelos carregarem corretamente.
FAQ
Qual é o comprimento de contexto predefinido no Ollama?
Depende da compilação e do hardware, por isso confirme em vez de assumir. A FAQ do Ollama documenta 4096 tokens, a referência do Modelfile documenta um valor predefinido de num_ctx de 2048, e a página sobre o comprimento de contexto documenta um valor predefinido escolhido com base na VRAM disponível: 4k abaixo de 24 GiB, 32k entre 24 GiB e 48 GiB, e 256k a partir de 48 GiB. Uma VPS apenas com CPU fica no limite inferior. ollama ps apresenta o contexto aplicado nas compilações que incluem essa coluna, e prompt_eval_count numa resposta da API comprova o valor em todas as compilações.
Porque é que o Ollama ignora o início do meu prompt longo?
Porque o prompt era maior do que a janela de contexto. Por isso, o servidor truncou-o antes de o modelo o receber e não devolveu nenhum erro. Envie novamente o mesmo prompt com um num_ctx maior e monitorize o crescimento de prompt_eval_count na resposta. Se esse número não mudar, algo entre o cliente e o servidor está a definir o próprio num_ctx, o que é comum em interfaces de chat e frameworks de agentes.
De quanta RAM adicional precisa um num_ctx maior?
Multiplique o comprimento de contexto pelo custo da cache por token, que é 2 * layers * kv_heads * head_dim * bytes_per_value. Para o Llama 3.1 8B em f16, esse valor é 128 KiB por token. Assim, 32k tokens custam 4 GiB e os 128k completos custam 16 GiB, além dos pesos. A cache é alocada quando o modelo é carregado, por isso um num_ctx elevado consome essa memória mesmo quando os seus prompts são curtos.
Uma janela de contexto maior torna o Ollama mais lento?
Sim, de duas formas. O trabalho de prefill cresce com o quadrado do comprimento do prompt, por isso uma entrada longa atrasa o primeiro token mais do que o seu comprimento faria prever. A cache maior também compete pela memória: num sistema com GPU, faz com que algumas camadas passem para a RAM do sistema; num sistema apenas com CPU, aproxima a máquina da utilização de swap. Um num_ctx elevado que nunca seja preenchido continua a consumir memória, embora não aumente o tempo de prefill.
Posso definir num_ctx permanentemente para um modelo?
Sim. Crie um Modelfile que contenha FROM llama3.1:8b e PARAMETER num_ctx 16384 e execute ollama create llama3.1-16k -f ./Modelfile. Todos os clientes que solicitarem llama3.1-16k usarão esse contexto sem enviar opções. Um pedido que contenha o seu próprio num_ctx continua a ter precedência. Portanto, isto define um valor predefinido, não um limite máximo.