CTO no Integrar Plus • Publicado em 14 de September de 2026
Autor: Pedro Dalben (CTO no Integrar Plus)
Publicado em: 14 de September de 2026
URL Canônica Oficial: https://pedrodalben.com.br/blog/migrando-prompts-extensos-de-apis-em-nuvem-para-ollama-armadilhas-de-infraestrutura-e-memoria
Migrar tarefas de inteligência artificial de APIs proprietárias para uma infraestrutura própria é um movimento natural quando buscamos previsibilidade de custos, soberania sobre os dados e menor dependência de terceiros. No entanto, existe uma distância considerável entre o consumo de modelos de fronteira em nuvem, como o Claude Opus, e a operação independente de modelos abertos através do Ollama em servidores dedicados.
O ponto de atrito mais crítico dessa transição costuma ser o tamanho do contexto de entrada. Em APIs gerenciadas, enviar um preprompt de 35 KB contendo regras de negócio, esquemas relacionais e exemplos estruturados parece trivial. A nuvem mascara a complexidade computacional distribuindo a carga em clusters com paralelismo massivo de tensores e cache de prefixo transparente. Ao mover essa mesma carga de trabalho para uma máquina própria com Ollama, a realidade do hardware se impõe imediatamente.
A seguir, analiso os principais gargalos técnicos e trade-offs arquiteturais envolvidos ao executar prompts massivos em nós de inferência auto-hospedados.
O primeiro obstáculo prático não costuma se manifestar como uma falha visível de infraestrutura ou uma resposta HTTP com código de erro. Ele se manifesta como perda silenciosa de precisão lógica.
O Ollama utiliza o motor do llama.cpp sob o capô. Por padrão histórico e conservadorismo de recursos, diversas distribuições e imagens padrão definem a janela de contexto (num_ctx) para valores baixos, frequentemente fixados em 2.048 ou 4.096 tokens, a depender do modelo base.
Um arquivo de texto de 35 KB em português ou com estruturas de código pode consumir facilmente entre 7.000 e 10.000 tokens, variando conforme o vocabulário do tokenizer. Quando o tamanho somado do preprompt e da mensagem do usuário ultrapassa o limite configurado de contexto, o motor simplesmente descarta o início da mensagem ou trunca as instruções do sistema para manter a execução dentro da janela alocada.
O resultado é um modelo que passa a alucinar, esquecer regras de validação ou quebrar formatos de saída, sem disparar exceções no log da aplicação. Para contornar esse comportamento, é obrigatório explicitar o tamanho da janela na definição do modelo por meio de um Modelfile customizado:
FROM llama3.1:8b
PARAMETER num_ctx 16384
PARAMETER temperature 0.2
Essa linha única resolve o truncamento, mas cria imediatamente o segundo e maior gargalo da operação: a explosão do consumo de memória.
Ao contrário da inferência tradicional em aplicações web, onde o uso de memória por processo é relativamente linear e previsível, em modelos de linguagem o consumo de memória escala diretamente com o tamanho da janela de contexto ativa.
Durante a passagem do prompt, o modelo precisa manter na memória de vídeo (VRAM) as matrizes de chaves e valores da atenção para cada camada da rede neural, estrutura conhecida como KV Cache. A fórmula básica para o dimensionamento do KV Cache depende de:
num_ctx).Ao carregar os pesos de um modelo de 8 bilhões de parâmetros quantizado em 4 bits (Q4KM), a ocupação básica da VRAM fica em torno de 5 GB a 6 GB. No entanto, ao expandir o num_ctx para 16.384 ou 32.768 posições para acomodar um preprompt de 35 KB mais a margem de saída, o KV Cache pode exigir vários gigabytes adicionais de memória dedicada.
Em um servidor de aplicação com placas intermediárias ou GPUs para estações de trabalho, essa expansão consome a folga operacional. Se a VRAM total for ultrapassada, o Ollama delega camadas excedentes para a CPU e para a memória RAM do sistema (offloading de camadas). No momento em que uma única camada de atenção precisa ser processada na memória RAM via barramento PCIe, a latência de processamento é multiplicada em ordens de magnitude.
A execução de um modelo ocorre em duas fases distintas: a fase de pré-preenchimento (prefill ou avaliação do prompt) e a fase de decodificação (geração sequencial de tokens).
A fase de prefill é intensiva em operações matemáticas e altamente paralelizável, pois todos os tokens de entrada já são conhecidos. Processar um prompt longo significa que o hardware passará segundos calculando as projeções de atenção para esses milhares de tokens antes de gerar o primeiro caractere de resposta (Time to First Token - TTFT).
Modelos proprietários de nuvem atenuam esse impacto utilizando caches de prompt em nível de cluster. Se cem chamadas consecutivas utilizam o mesmo preprompt de 35 KB, a nuvem reutiliza as representações de atenção pré-computadas.
No Ollama, embora exista cache de contexto em memória para sessões sequenciais na mesma conexão, o comportamento degrada rapidamente quando a infraestrutura recebe requisições concorrentes.
Em uma arquitetura clássica baseada em filas de background (como Solid Queue ou Sidekiq no ecossistema Rails), é comum termos múltiplos workers processando tarefas simultaneamente.
Se quatro workers disparam requisições quase simultâneas para uma única instância do Ollama, e cada requisição carrega variações de dados anexadas ao preprompt de 35 KB, ocorrem dois problemas críticos:
| Cenário de Operação | Alocação de Memória | Impacto Operacional |
|---|---|---|
| Sessões Concorrentes Múltiplas | Espaço multiplicado por cada slot de contexto ativo | Exaustão imediata de VRAM e queda para CPU |
| Sessão Serial com Invalidação | Um slot único que descarta o cache anterior a cada troca de prefixo | Taxa de prefill repetida a cada execução |
Se a sua fila despachar trabalhos em paralelo para um Ollama configurado com suporte a múltiplos slots concorrentes, a memória do KV Cache precisará ser duplicada para cada slot. Sem VRAM suficiente para suportar múltiplos contextos longos, as requisições entrarão em fila interna, gerando timeouts na ponta da aplicação web.
Para controlar essa restrição em um cluster próprio, a melhor abordagem arquitetural é desacoplar o despacho de chamadas LLM da concorrência geral de background:
class HeavyLlmProcessingJob < ApplicationJob
# Limita o processamento a uma fila de concorrencia estrita
limits_concurrency to: 1, key: -> { "ollama_inference_node" }
def perform(payload_id)
payload = Payload.find(payload_id)
InferenceClient.post_prompt(payload.content)
end
end
Definir semáforos estritos ou filas com concorrência unitária por placa aceleradora impede que a fila sature a capacidade de transferência do nó de inferência.
Além das restrições estritas de hardware, existe o trade-off de modelagem. Modelos massivos de fronteira como o Claude Opus possuem uma capacidade ímpar de compreender diretrizes complexas e dispersas em um texto denso de dezenas de kilobytes.
Ao transferir esse mesmo prompt monolítico para modelos abertos menores (como variantes de 7B, 8B ou 14B de parâmetros), observa-se com frequência o fenômeno de perda no meio (lost in the middle). O modelo atende às regras localizadas no início e no final do contexto, mas ignora instruções cruciais posicionadas no meio do preprompt volumoso.
Tentar resolver isso aumentando a temperatura ou inflando ainda mais o texto com avisos redundantes apenas agrava o custo de prefill e a ocupação de memória.
A migração de cargas de trabalho intensivas em contexto para servidores próprios não deve ser tratada como uma simples substituição de endpoint HTTP. A viabilidade técnica exige repensar a distribuição das instruções:
Hospedar a própria pilha de inteligência artificial oferece soberania operacional e custos previsíveis a longo prazo, mas exige tratar o modelo de linguagem pelo que ele realmente é no nível do sistema operacional: um processo intensivo de cálculo matricial limitado rigorosamente pela largura de banda e pela capacidade finita da memória física da sua infraestrutura.
CTO e arquiteto full stack especializado em Ruby on Rails, Vue.js, sistemas multi-tenant e infraestrutura distribuída.