SSD Nodes Learn Hosting plans →
Guias Matt ConnorPor Matt Connor · Atualizado 2026-10-06

Como funciona o esforço de raciocínio em LLM local

Entenda como o esforço de raciocínio muda os tokens internos, o tempo no CPU ou GPU e o uso da janela de contexto, sem alterar pesos ou quantização.

Que efeito tem o esforço de raciocínio num LLM local

O esforço de raciocínio é uma definição que indica ao modelo durante quanto tempo deve pensar antes de responder. Altera o comprimento do segmento de raciocínio e nada mais. Os pesos armazenados em disco são idênticos em todos os níveis, a quantização é idêntica e a resposta resulta da mesma passagem direta. O que muda é o número de tokens que o modelo utiliza primeiro no seu bloco de notas interno.

Essa distinção é importante devido ao local onde esses tokens são contabilizados. Numa API alojada, os tokens de raciocínio aparecem na fatura. Num VPS que controla, são pagos em tempo de geração no seu CPU ou GPU e em espaço dentro da janela de contexto. Um modelo deixado no nível máximo de esforço pode utilizar a maior parte da saída para raciocinar antes de apresentar a primeira palavra da resposta. Num hardware autoalojado, isso pode ser a diferença entre uma resposta em dois segundos e outra em dois minutos.

Onde o nível é definido: no template de chat, não nos pesos

Um modelo de raciocínio é treinado para emitir um segmento de raciocínio, normalmente delimitado pelas tags <think> e </think>, antes da resposta final. O nível de esforço é uma instrução que o template de chat escreve no prompt. Esse template é um ficheiro Jinja fornecido com o modelo. Ele lê uma variável como reasoning_effort e gera uma linha diferente ao nível do sistema para cada valor. O modelo foi treinado para encurtar ou alongar o seu bloco de raciocínio em resposta a essa linha.

Isto tem duas consequências. Os nomes dos níveis pertencem ao modelo, não ao runtime. Por isso, um nome indicado no cartão de um modelo pode não significar nada para outro. Além disso, se qualquer componente da cadeia substituir o template de chat do modelo por um template genérico, a variável nunca é gerada e a definição não produz efeito, sem apresentar um erro.

Verificado em 2026-08-20, o cartão do modelo Qwen3.8-27B documenta três níveis de esforço: low, medium e xhigh, sendo xhigh o valor predefinido. Não existe high. O raciocínio é ativado com enable_thinking, que está ativo por predefinição. O cartão também documenta preserve_thinking, igualmente ativo por predefinição, que mantém na conversa o raciocínio de turnos anteriores. O gpt-oss usa low, medium e high. Muitas outras famílias aceitam apenas um valor booleano. Consulte o cartão da versão exata que instalou, porque estes nomes não são um padrão. Colocar um modelo 27B em execução numa VPS é o primeiro passo. Esta página explica o que deve configurar depois de o modelo responder.

Por que o esforço elevado custa mais num VPS

Tokens de saída. Os tokens de raciocínio são tokens gerados. Passam pelo mesmo ciclo de descodificação que a resposta, à mesma velocidade de tokens por segundo que o seu hardware consegue fornecer. Suponha que uma tarefa produz 200 tokens de resposta e 4,000 tokens de raciocínio. Foram gerados 4,200 tokens, mas o leitor viu apenas 200. A velocidade de descodificação é determinada pela largura de banda da memória e por a quantização escolhida, pelo que o único fator ainda ajustável é o número de tokens.

Tempo decorrido. A pessoa espera pelo primeiro token da resposta, porque tudo o que aparece antes disso é um ecrã vazio ou um indicador de carregamento recolhido. O raciocínio é emitido primeiro, pelo que a espera corresponde aproximadamente ao número de tokens de raciocínio dividido pela velocidade de descodificação, mais o processamento do prompt. Duplicar o comprimento do raciocínio duplica essa espera.

Contexto. Os tokens de raciocínio ocupam a janela de contexto como qualquer outro token. Com preserve_thinking ativo, o bloco de trabalho da primeira interação continua no prompt na quinta interação, pelo que o processamento do prompt fica mais lento a cada interação, enquanto a janela é preenchida pelas duas extremidades. Aumentar num_ctx para o acomodar consome memória da cache KV que, num VPS sem GPU, corresponde a RAM do sistema que pode não estar disponível.

Quando aumentar o nível e quando o manter baixo

Aumente-o para tarefas em que um passo intermédio incorreto compromete o resultado: aritmética com várias etapas e conversão de unidades, planeamento de uma alteração em vários ficheiros, código que tem de compilar e problemas de restrições em que uma resposta tem de satisfazer várias condições ao mesmo tempo. Nestes casos, o bloco de trabalho está a fazer trabalho efetivo, e um bloco mais longo é uma forma barata de detetar um erro que, de outro modo, o modelo cometeria.

Mantenha-o baixo quando a resposta já está na entrada e a tarefa consiste em transferi-la. Extração, classificação, etiquetagem, tradução, reescrita, resumo e formatação enquadram-se nesta situação. O segmento de raciocínio limita-se, na maioria dos casos, a repetir a tarefa e dá ao modelo margem para rejeitar a primeira conclusão correta.

Mantenha-o baixo também para qualquer tarefa interativa. Numa caixa de chat ou num editor, está a intervir no processo; por isso, uma resposta rápida que possa corrigir é melhor do que uma resposta lenta pela qual tenha de esperar. Esse é o verdadeiro compromisso de apontar um agente de programação para um modelo local: um agente faz muitas chamadas pequenas, e o custo do raciocínio é cobrado em cada uma delas.

Como definir o nível no llama.cpp

O llama.cpp escreve a variável diretamente no template. Por isso, este é o runtime em que pode confirmar que o nível foi recebido. Aponte -m para o ficheiro GGUF que já tem.

llama-server -m ./qwen3.8-27b-Q4_K_M.gguf \
  --jinja \
  --reasoning-effort medium \
  --reasoning-format deepseek \
  -c 32768 \
  --host 127.0.0.1 --port 8080

--jinja usa o próprio chat template do modelo e está ativado por predefinição nas builds atuais. --reasoning-effort aceita default, minimal, low, medium, high, xhigh ou max, em que default significa manter o valor predefinido do próprio template. Esta lista pertence ao vocabulário do llama.cpp, não ao do modelo. Por isso, passe apenas um nome que o cartão do modelo liste. Um nível que o template não defina pode causar um erro do template no momento do pedido. --reasoning-format deepseek move o raciocínio de message.content para message.reasoning_content. É isso que torna a divisão mensurável na secção seguinte.

Para desativar o raciocínio em vez de o encurtar, defina a variável do template manualmente:

llama-server -m ./qwen3.8-27b-Q4_K_M.gguf --jinja \
  --chat-template-kwargs '{"enable_thinking": false}'

--reasoning-budget é um mecanismo diferente. Limita o segmento de raciocínio em tokens, com 0 a terminá-lo imediatamente e -1 a deixá-lo sem limite, em vez de pedir ao modelo que faça um planeamento mais curto. Ambos os flags são globais ao servidor. O llama-server não aceita reasoning_effort como campo por pedido. Para servir dois níveis de esforço ao mesmo tempo, são necessários dois processos em duas portas.

O vLLM expõe a mesma variável por pedido, dentro do corpo compatível com OpenAI:

{"model": "Qwen/Qwen3.8-27B",
 "messages": [{"role": "user", "content": "Summarise this changelog in two lines."}],
 "chat_template_kwargs": {"reasoning_effort": "medium"}}

Como definir o nível no Ollama

Ollama tem o seu próprio campo, think, em /api/chat e /api/generate. Ele aceita true, false ou um de low, medium, high e max, em que max solicita o nível mais alto disponibilizado pelo modelo. O raciocínio fica ativado por predefinição nos modelos que o suportam.

ollama run qwen3.8:27b --think=low "Draft a one line commit message for a README typo fix"
{"model": "qwen3.8:27b",
 "messages": [{"role": "user", "content": "Which HTTP status code means the request body was too large?"}],
 "think": "low",
 "stream": false}

O raciocínio é devolvido em message.thinking e a resposta em message.content, já separados. Numa sessão interativa de ollama run, /set think e /set nothink ativam ou desativam esta função sem reiniciar a sessão.

Agora repare na incompatibilidade. O vocabulário do Ollama é low, medium, high e max. O template do Qwen3.8 define low, medium e xhigh. É necessário mapear um conjunto para o outro. Além disso, um modelo do Ollama inclui um template no seu próprio tag, em vez do ficheiro Jinja do repositório original. Por isso, o nível que definir só chega ao modelo se o template incluído o encaminhar corretamente. Não assuma que funcionou. A verificação demora cerca de um minuto.

Como medir se o nível foi realmente aplicado

Envie o mesmo prompt com mais de um nível e defina temperature como 0. Depois, compare as contagens de tokens. Aqui, jq monta o corpo para que não tenha de escapar as aspas manualmente.

for level in low medium max; do
  body=$(jq -n --arg lvl "$level" '{
    model: "qwen3.8:27b",
    messages: [{role: "user", content: "A pump fills a 4500 litre tank in 25 minutes. A second pump is 40 percent slower. How long do both together take? Answer in minutes."}],
    think: $lvl,
    stream: false,
    options: {temperature: 0, num_ctx: 8192}
  }')
  echo "== $level"
  curl -s http://localhost:11434/api/chat -d "$body" | jq '{
    thinking_chars: (.message.thinking // "" | length),
    answer_chars: (.message.content | length),
    eval_count: .eval_count,
    seconds: (.total_duration / 1e9),
    tok_per_sec: (.eval_count / (.eval_duration / 1e9))
  }'
done

eval_count corresponde a todos os tokens gerados, incluindo o raciocínio. Por isso, a diferença entre dois níveis é quase toda devida ao raciocínio. thinking_chars apresenta a divisão diretamente. Duas condições devem ser satisfeitas: os números devem variar entre os níveis, e a resposta deve continuar correta no nível inferior. Se eval_count permanecer dentro do ruído nas três execuções, o nível está a ser ignorado. Nesse caso, a correção é usar um runtime que o transmita, não escolher outro nome de nível.

O tempo total é apenas metade da análise. Meça também o intervalo até ao primeiro token da resposta, usando streaming e parando no primeiro bloco content não vazio. Este procedimento requer jq e bc.

start=$(date +%s.%N)
curl -sN http://localhost:11434/api/chat -d '{
  "model": "qwen3.8:27b",
  "messages": [{"role": "user", "content": "Explain what a reverse proxy does, in three sentences."}],
  "think": "low",
  "stream": true
}' |
while IFS= read -r line; do
  if [ -n "$(printf '%s' "$line" | jq -r '.message.content // ""')" ]; then
    echo "first answer token after $(echo "$(date +%s.%N) - $start" | bc)s"
    break
  fi
done

Execute com low e depois novamente com max. A diferença é o tempo de espera que está a adicionar. No llama.cpp, os mesmos números são devolvidos dentro da resposta, sem necessidade de fazer cálculos no shell:

curl -s http://localhost:8080/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{"model": "local", "temperature": 0,
       "messages": [{"role": "user", "content": "A pump fills a 4500 litre tank in 25 minutes. A second pump is 40 percent slower. How long do both together take?"}]}' | jq '{
  reasoning_chars: (.choices[0].message.reasoning_content // "" | length),
  answer_chars: (.choices[0].message.content | length),
  predicted_n: .timings.predicted_n,
  tok_per_sec: .timings.predicted_per_second
}'

Faça este teste no seu próprio servidor. Uma comparação de esforço publicada foi medida num hardware diferente do seu, e a sua taxa de descodificação é o valor que converte uma contagem de tokens em segundos. Medir tokens por segundo no seu próprio servidor fornece esse valor: os tokens de raciocínio divididos pela sua taxa de descodificação correspondem ao tempo de espera que acabou de adicionar.

O que pode correr mal

A resposta é cortada, ou content fica vazio enquanto thinking fica preenchido. O limite de geração foi consumido pelo raciocínio. O num_predict do Ollama limita toda a geração, incluindo o raciocínio, e o raciocínio ocorre primeiro. Por isso, um limite de 512 tokens com esforço elevado pode terminar a resposta antes de esta começar. O Ollama indica "done_reason": "length" nessa resposta. Aumente o limite ou reduza o esforço. Como num_predict conta tokens explica esta interação em detalhe.

O nível não altera nada. As contagens de tokens são idênticas em todos os níveis. Isso significa que o runtime não está a transmitir a variável ou que o template não a lê. Verifique o template que o runtime está realmente a utilizar, e não o template do repositório original. O llama.cpp, com --jinja e --chat-template-kwargs, insere a variável manualmente. Por isso, serve como controlo: se o nível funcionar aí e não funcionar noutro local, o modelo está correto e o outro runtime está a eliminar a variável.

O nome de um nível é rejeitado. Um erro do template no momento do pedido, ou uma falha na primeira mensagem com um servidor que funciona corretamente, normalmente significa que foi transmitido um nível que o template não define, como high para um modelo cujo cartão indica apenas low, medium e xhigh.

As conversas com várias interações ficam mais lentas a cada turno. O raciocínio antigo está a ser mantido no histórico. Defina preserve_thinking como false se o modelo suportar essa opção, ou remova o campo thinking das mensagens que envia novamente. Caso contrário, o processamento do prompt aumenta a cada turno, enquanto as respostas mantêm o mesmo comprimento.

A qualidade diminui com esforço baixo numa tarefa que considerava simples. Nem toda a extração é apenas extração. Se a entrada exigir uma conversão de unidades ou a aplicação ordenada de uma regra, trata-se de uma tarefa de raciocínio com uma saída curta. Aumente o nível apenas nessa chamada, em vez de o aumentar em todo o servidor.

Executar dois níveis ao mesmo tempo

O llama.cpp fixa o nível no arranque. Por isso, um servidor que disponibiliza um editor e uma tarefa batch noturna precisa de dois processos em duas portas, cada um com o seu próprio --reasoning-effort. Dois processos também significam duas cópias dos pesos na memória, a menos que os trabalhos sejam separados no tempo. Num VPS, a opção mais económica costuma ser um servidor com esforço baixo para tudo o que uma pessoa está à espera de ver, além de uma execução agendada com esforço mais elevado para tarefas que ninguém está a acompanhar. O que acontece quando vários utilizadores partilham um modelo local também se aplica aqui: os tokens de raciocínio são trabalho de decode, por isso aumentar o esforço reduz a sua concorrência efetiva aproximadamente pelo mesmo fator em que aumenta a contagem de tokens.

FAQ

Qual é o nível de esforço de raciocínio que devo usar por padrão?

Comece no nível mais baixo disponibilizado pelo modelo e aumente-o apenas para tarefas em que tenha observado falhas. Vários modelos de raciocínio são lançados com um nível padrão elevado, e o Qwen3.8-27B usa xhigh por padrão, o nível máximo, em agosto de 2026. Essa predefinição é escolhida para obter bons resultados em tabelas de benchmarks, mas uma tabela de benchmarks não cobra pelo tempo. No seu próprio hardware, o custo aparece em segundos. Por isso, faça do nível mais elevado uma opção por tarefa, em vez de uma definição herdada por todos os pedidos.

Os tokens de raciocínio contam para a janela de contexto?

Sim. São tokens normais da saída e ocupam espaço na janela de contexto juntamente com todo o resto. A permanência desses tokens no turno seguinte depende do runtime e do modelo. O card do Qwen3.8 documenta preserve_thinking, ativado por padrão, que mantém o raciocínio anterior no histórico. Assim, uma conversa longa transporta todos os scratchpads que o modelo produziu. Defina-o como false ou remova o campo thinking das mensagens que reproduz. Dessa forma, o processamento do prompt deixa de crescer.

Por que mudar o nível de raciocínio não altera a contagem de tokens?

A definição não está a chegar ao chat template. O nível é uma variável do template. Por isso, só funciona se o runtime a transmitir e se o template empacotado a ler. Alguns runtimes incluem o seu próprio template com o modelo, em vez do ficheiro Jinja do repositório original. Nesse caso, a variável é descartada sem que seja apresentada qualquer mensagem de erro. Confirme-o enviando o mesmo prompt no nível mais baixo e no mais alto, com temperature definido como 0, e compare eval_count. Se as contagens coincidirem dentro do ruído de medição, o nível está a ser ignorado.

Um esforço de raciocínio mais baixo torna o modelo menos preciso?

Depende da tarefa. É melhor medir do que presumir. Quando a resposta já está presente na entrada, como em tarefas de extração ou reescrita, um scratchpad mais curto normalmente não altera o resultado. Quando é necessário acertar um passo intermédio antes de produzir o passo final, como em aritmética com várias etapas ou em código que tem de compilar, a precisão diminui com um scratchpad mais curto. Crie um conjunto de vinte prompts do seu workload real, execute-os em dois níveis com temperature definido como 0 e conte as respostas erradas. Esse número é específico do seu workload. Nenhuma tabela publicada pode fornecê-lo.